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@puxedo.org> - Full implementation of the _dup and _dup2 functions
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