msvcrt-B05: _dup/_dup2
Jaco Greeff
jaco at puxedo.org
Tue Nov 5 05:23:01 CST 2002
Updated to make sure that the A?? patches applies cleanly to current CVS.
License:
LGPL
Changelog:
* dlls/msvcrt/msvcrt.spec, dlls/msvcrt/file.c: Jaco Greeff <jaco at puxedo.org>
- Full implementation of the _dup and _dup2 functions
-------------- next part --------------
diff -aurN msvcrt-B04/dlls/msvcrt/file.c msvcrt-B05/dlls/msvcrt/file.c
--- msvcrt-B04/dlls/msvcrt/file.c Tue Nov 5 11:49:52 2002
+++ msvcrt-B05/dlls/msvcrt/file.c Tue Nov 5 11:54:24 2002
@@ -146,6 +146,18 @@
MSVCRT_fdstart = fd;
}
+/* INTERNAL: mark the next free slot */
+static void msvcrt_next_free(int fd)
+{
+ /* locate next free slot as in msvcrt_alloc_fd */
+ if (fd == MSVCRT_fdend)
+ MSVCRT_fdstart = ++MSVCRT_fdend;
+ else
+ while((MSVCRT_fdstart < MSVCRT_fdend) &&
+ (MSVCRT_handles[MSVCRT_fdstart] != INVALID_HANDLE_VALUE))
+ MSVCRT_fdstart++;
+}
+
/* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
static int msvcrt_alloc_fd(HANDLE hand, int flag)
{
@@ -160,17 +172,55 @@
MSVCRT_handles[fd] = hand;
MSVCRT_flags[fd] = flag;
- /* locate next free slot */
- if (fd == MSVCRT_fdend)
- MSVCRT_fdstart = ++MSVCRT_fdend;
- else
- while(MSVCRT_fdstart < MSVCRT_fdend &&
- MSVCRT_handles[MSVCRT_fdstart] != INVALID_HANDLE_VALUE)
- MSVCRT_fdstart++;
+ msvcrt_next_free(fd);
return fd;
}
+/* INTERNAL: duplicate an fd slot */
+static int msvcrt_dup_fd(int fd, int newfd)
+{
+ HANDLE newhand, hand = msvcrt_fdtoh(fd);
+
+ /* 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
+ */
+ if (!DuplicateHandle(GetCurrentProcess(), hand,
+ GetCurrentProcess(), &newhand,
+ 0, FALSE, DUPLICATE_SAME_ACCESS))
+ {
+ TRACE("Unable to duplicate source handle\n");
+ return -1;
+ }
+ MSVCRT_handles[newfd] = newhand;
+ 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;
+
+ return 0;
+}
+
/* 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 +444,56 @@
*/
int _close(int fd)
{
- HANDLE hand = msvcrt_fdtoh(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]);
+ TRACE("(fd == %d), handle == %p\n", fd, hand);
- if(MSVCRT_files[fd]->_flag & MSVCRT__IOMYBUF)
- MSVCRT_free(MSVCRT_files[fd]->_base);
- }
+ if (hand == INVALID_HANDLE_VALUE)
+ return -1;
- /* Dont free std FILE*'s, they are not dynamic */
- if (fd > 2 && MSVCRT_files[fd])
- MSVCRT_free(MSVCRT_files[fd]);
+ /* 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);
+ MSVCRT_files[fd]->_base = NULL;
+ }
+ }
- msvcrt_free_fd(fd);
+ /* Dont free std FILE*'s, they are not dynamic */
+ if (fd > 2 && MSVCRT_files[fd])
+ {
+ MSVCRT_free(MSVCRT_files[fd]);
+ MSVCRT_files[fd] = NULL;
+ }
- 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;
- }
+ msvcrt_free_fd(fd);
- TRACE(":ok\n");
- return 0;
+ /* 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 (!CloseHandle(hand))
+ {
+ WARN(":failed-last error (%ld)\n" ,GetLastError());
+ MSVCRT__set_errno(GetLastError());
+ return -1;
+ }
+ MSVCRT_handles[fd] = INVALID_HANDLE_VALUE;
+
+ 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;
+ }
+
+ TRACE(":ok\n");
+ return 0;
}
/*********************************************************************
@@ -629,6 +693,45 @@
MSVCRT_rewind(file);
return file;
+}
+
+/*********************************************************************
+ * _dup (MSVCRT.@)
+ */
+int _dup(int fd)
+{
+ int newfd = MSVCRT_fdstart;
+
+ TRACE("(fd == %d)\n", fd);
+
+ if (msvcrt_dup_fd(fd, newfd) == -1)
+ return -1;
+ msvcrt_next_free(newfd);
+
+ return newfd;
+}
+
+/*********************************************************************
+ * _dup2 (MSVCRT.@)
+ */
+int _dup2(int fd1, int fd2)
+{
+ TRACE("(fd1 == %d, fd2 == %d)\n", fd1, fd2);
+
+ /* Close the file associated with fd2, before
+ * assigning duplicating it with values from fd1
+ */
+ _close(fd2);
+ if (msvcrt_dup_fd(fd1, fd2) == -1)
+ return -1;
+
+ /* If fd2 was marked as the first free file descriptor,
+ * re-allocate it as not to be used
+ */
+ if (fd2 == MSVCRT_fdstart)
+ msvcrt_next_free(fd2);
+
+ return 0;
}
/*********************************************************************
diff -aurN msvcrt-B04/dlls/msvcrt/msvcrt.spec msvcrt-B05/dlls/msvcrt/msvcrt.spec
--- msvcrt-B04/dlls/msvcrt/msvcrt.spec Tue Nov 5 11:49:35 2002
+++ msvcrt-B05/dlls/msvcrt/msvcrt.spec Tue Nov 5 11:54:18 2002
@@ -195,8 +195,8 @@
@ cdecl _cwait(ptr long long) _cwait
@ stub _daylight
@ stub _dstbias
-@ stub _dup #(long)
-@ stub _dup2 #(long long)
+@ cdecl _dup(long) _dup
+@ cdecl _dup2(long long) _dup2
@ cdecl _ecvt( double long ptr ptr) ecvt
@ cdecl _endthread () _endthread
@ cdecl _endthreadex(long) _endthreadex
More information about the wine-patches
mailing list