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@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