msvcrt-A08: _dup
Jaco Greeff
jaco at puxedo.org
Mon Nov 4 05:56:03 CST 2002
This patch in the msvcrt-A?? series implements the _dup function,
allowing you to duplicate msvcrt file descriptors.
License:
LGPL
Changelog:
* dlls/msvcrt/file.c, dlls/msvcrt/msvcrt.spec: Jaco Greeff <jaco at puxedo.org>
- Implemented the _dup function
--[ inline patch ]--
diff -aurN msvcrt-A07/dlls/msvcrt/file.c msvcrt-A08/dlls/msvcrt/file.c
--- msvcrt-A07/dlls/msvcrt/file.c Mon Nov 4 10:56:46 2002
+++ msvcrt-A08/dlls/msvcrt/file.c Mon Nov 4 13:49:55 2002
@@ -171,6 +171,54 @@
return fd;
}
+/* INTERNAL: duplicate an fd slot */
+static int msvcrt_dup_fd(int fd)
+{
+ HANDLE hand = msvcrt_fdtoh(fd);
+ int newfd = MSVCRT_fdstart;
+
+ TRACE("(fd == %d), handle == %p\n", fd, hand);
+
+ /* make sure we haven't exhausted our files
+ * and that the original fd it does have a valid
+ * handle assigned to it
+ */
+ if (newfd >= MSVCRT_MAX_FILES)
+ {
+ WARN("Files exhausted, increase MSVCRT_MAX_FILES\n");
+ return -1;
+ }
+ else if (hand == INVALID_HANDLE_VALUE)
+ {
+ TRACE("Invalid fd (%d), no associated handle\n", fd);
+ return -1;
+ }
+
+ /* Duplicate the file handle and flags for this fd,
+ * to allow us to have access to the same file as
+ * per the original fd
+ */
+ MSVCRT_handles[newfd] = MSVCRT_handles[fd];
+ MSVCRT_flags[newfd] = MSVCRT_flags[fd];
+
+ /* We don't have a specific MSVCRT_FILE or temp file
+ * associated with this entry, since the handle will
+ * refer to the original assigned entry.
+ */
+ MSVCRT_files[newfd] = NULL;
+ MSVCRT_tempfiles[newfd] = NULL;
+
+ /* locate next free slot as in msvcrt_alloc_fd */
+ if (newfd == MSVCRT_fdend)
+ MSVCRT_fdstart = ++MSVCRT_fdend;
+ else
+ while((MSVCRT_fdstart < MSVCRT_fdend) &&
+ (MSVCRT_handles[MSVCRT_fdstart] != INVALID_HANDLE_VALUE))
+ MSVCRT_fdstart++;
+
+ return newfd;
+}
+
/* INTERNAL: Allocate a FILE* for an fd slot
* This is done lazily to avoid memory wastage for low level open/write
* usage when a FILE* is not requested (but may be later).
@@ -394,42 +442,71 @@
*/
int _close(int fd)
{
- HANDLE hand = msvcrt_fdtoh(fd);
-
- TRACE(":fd (%d) handle (%p)\n",fd,hand);
- if (hand == INVALID_HANDLE_VALUE)
- return -1;
- /* flush stdio buffers */
- if(MSVCRT_files[fd]) {
- if(MSVCRT_files[fd]->_flag & MSVCRT__IOWRT)
-
MSVCRT_fflush(MSVCRT_files[fd]);
-
- if(MSVCRT_files[fd]->_flag & MSVCRT__IOMYBUF)
-
MSVCRT_free(MSVCRT_files[fd]->_base);
- }
+ int i, closed = 0;
+ HANDLE hand = msvcrt_fdtoh(fd);
- /* Dont free std FILE*'s, they are not dynamic */
- if (fd > 2 && MSVCRT_files[fd])
- MSVCRT_free(MSVCRT_files[fd]);
+ TRACE("(fd == %d), handle == %p\n", fd, hand);
- msvcrt_free_fd(fd);
+ if (hand == INVALID_HANDLE_VALUE)
+ return -1;
- if (!CloseHandle(hand))
- {
- WARN(":failed-last error (%ld)\n",GetLastError());
- MSVCRT__set_errno(GetLastError());
- return -1;
- }
- if (MSVCRT_tempfiles[fd])
- {
- TRACE("deleting temporary file '%s'\n",MSVCRT_tempfiles[fd]);
- _unlink(MSVCRT_tempfiles[fd]);
- MSVCRT_free(MSVCRT_tempfiles[fd]);
- MSVCRT_tempfiles[fd] = NULL;
- }
+ /* The handle we are trying to close might have been
+ * _dup'ed, in which case we will need to clean all
+ * occurances of the specific handle in our internal
+ * tables. Hence we run through all and see if the
+ * handles match, if they do, we clean up
+ */
+ for (i = 0; i < MSVCRT_MAX_FILES; i++)
+ {
+ /* Ok, this is one occurace, clean it up */
+ if (MSVCRT_handles[i] == hand)
+ {
+ /* flush stdio buffers */
+ if (MSVCRT_files[i])
+ {
+ if (MSVCRT_files[i]->_flag & MSVCRT__IOWRT)
+ MSVCRT_fflush(MSVCRT_files[i]);
+ if (MSVCRT_files[fd]->_flag & MSVCRT__IOMYBUF)
+ {
+ MSVCRT_free(MSVCRT_files[i]->_base);
+ MSVCRT_files[i]->_base = NULL;
+ }
+ }
+
+ /* Dont free std FILE*'s, they are not dynamic */
+ if (fd > 2 && MSVCRT_files[i])
+ {
+ MSVCRT_free(MSVCRT_files[i]);
+ MSVCRT_files[i] = NULL;
+ }
+
+ msvcrt_free_fd(i);
+
+ /* If we haven't close the handle, do so once, and
+ * only once. This makes sure we don't close already
+ * closed occurances, which will fail
+ */
+ if ((!closed) && (!CloseHandle(hand)))
+ {
+ WARN(":failed-last error (%ld)\n" ,GetLastError());
+ MSVCRT__set_errno(GetLastError());
+ return -1;
+ }
+ MSVCRT_handles[i] = INVALID_HANDLE_VALUE;
+ closed = 1;
+
+ if (MSVCRT_tempfiles[i])
+ {
+ TRACE("deleting temporary file '%s'\n",
MSVCRT_tempfiles[i]);
+ _unlink(MSVCRT_tempfiles[i]);
+ MSVCRT_free(MSVCRT_tempfiles[i]);
+ MSVCRT_tempfiles[i] = NULL;
+ }
+ }
+ }
- TRACE(":ok\n");
- return 0;
+ TRACE(":ok\n");
+ return 0;
}
/*********************************************************************
@@ -629,6 +706,15 @@
MSVCRT_rewind(file);
return file;
+}
+
+/*********************************************************************
+ * _dup (MSVCRT.@)
+ */
+int _dup(int fd)
+{
+ TRACE("(fd == %d)\n", fd);
+ return msvcrt_dup_fd(fd);
}
/*********************************************************************
diff -aurN msvcrt-A07/dlls/msvcrt/msvcrt.spec
msvcrt-A08/dlls/msvcrt/msvcrt.spec
--- msvcrt-A07/dlls/msvcrt/msvcrt.spec Mon Nov 4 10:19:50 2002
+++ msvcrt-A08/dlls/msvcrt/msvcrt.spec Mon Nov 4 12:25:07 2002
@@ -196,7 +196,7 @@
@ cdecl _cwait(ptr long long) _cwait
@ stub _daylight
@ stub _dstbias
-@ stub _dup #(long)
+@ cdecl _dup(long) _dup
@ stub _dup2 #(long long)
@ cdecl _ecvt( double long ptr ptr) ecvt
@ cdecl _endthread () _endthread
More information about the wine-patches
mailing list