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