diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 5ad9aae7d..5f092f7ae 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,29 @@ +2007-06-29 Corinna Vinschen + + * cygwin.din: Export fdopendir. + * dir.cc (opendir): Call fhandler's opendir with fd set to -1. + (fdopendir): New function. + (seekdir64): Use dirent_info_mask. + (rewinddir): Ditto. + (closedir): Only release underlying file descriptor if it has been + reserved by opendir itself. + * fhandler.cc (fhandler_base::opendir): Accommodate new parameter. + * fhandler.h (dirent_states): Add dirent_valid_fd and dirent_info_mask. + (fhander_XXX::opendir): Add file descriptor parameter. Use regparms. + (fhandler_procnet::opendir): Drop declaration. + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Ditto. + If called from fdopendir, use existing handle to re-open directory + with valid flags. Rename fd to cfd. Use only if no valid incoming fd. + (fhandler_cygdrive::opendir): Accommodate new parameter. + * fhandler_process.cc (fhandler_process::opendir): Ditto. + * fhandler_procnet.cc (fhandler_procnet::opendir): Drop definition. + * fhandler_virtual.cc (fhandler_virtual::opendir): Accommodate new + parameter. Only create new file descriptor entry if called from + opendir. Remove duplicated setting of dir->__flags. + * posix.sgml: Add fdopendir to list of implemented Solaris functions. + * include/cygwin/version.h: Bump API minor number. + * include/sys/dirent.h: Declare fdopendir. + 2007-06-28 Brian Dessent * include/cygwin/version.h: Fix comment typo. diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc index 3d0dbae7b..2ce0488c5 100644 --- a/winsup/cygwin/dir.cc +++ b/winsup/cygwin/dir.cc @@ -61,7 +61,7 @@ opendir (const char *name) if (!fh) res = NULL; else if (fh->exists ()) - res = fh->opendir (); + res = fh->opendir (-1); else { set_errno (ENOENT); @@ -73,6 +73,17 @@ opendir (const char *name) return res; } +extern "C" DIR * +fdopendir (int fd) +{ + DIR *res = NULL; + + cygheap_fdget cfd (fd); + if (cfd >= 0) + res = cfd->opendir (fd); + return res; +} + static int readdir_worker (DIR *dir, dirent *de) { @@ -204,7 +215,7 @@ seekdir64 (DIR *dir, _off64_t loc) if (dir->__d_cookie != __DIRENT_COOKIE) return; - dir->__flags &= (dirent_isroot | dirent_get_d_ino | dirent_set_d_ino); + dir->__flags &= dirent_info_mask; return ((fhandler_base *) dir->__fh)->seekdir (dir, loc); } @@ -225,7 +236,7 @@ rewinddir (DIR *dir) if (dir->__d_cookie != __DIRENT_COOKIE) return; - dir->__flags &= (dirent_isroot | dirent_get_d_ino | dirent_set_d_ino); + dir->__flags &= dirent_info_mask; return ((fhandler_base *) dir->__fh)->rewinddir (dir); } @@ -249,7 +260,11 @@ closedir (DIR *dir) int res = ((fhandler_base *) dir->__fh)->closedir (dir); - cygheap->fdtab.release (dir->__d_fd); + /* If the directory has been opened by fdopendir, the descriptor + entry is used elsewhere in the application and must not be removed + from the descriptor table. */ + if (!(dir->__flags & dirent_valid_fd)) + cygheap->fdtab.release (dir->__d_fd); free (dir->__d_dirname); free (dir->__d_dirent); diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 4348b8792..6cabe912a 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -1444,7 +1444,7 @@ fhandler_base::rmdir () } DIR * -fhandler_base::opendir () +fhandler_base::opendir (int fd) { set_errno (ENOTDIR); return NULL; diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 814054399..b41838c5a 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -51,7 +51,11 @@ enum dirent_states dirent_saw_eof = 0x0004, dirent_isroot = 0x0008, dirent_set_d_ino = 0x0010, - dirent_get_d_ino = 0x0020 + dirent_get_d_ino = 0x0020, + dirent_valid_fd = 0x0040, + + /* Global flags which must not be deleted on rewinddir or seekdir. */ + dirent_info_mask = 0x0078 }; enum conn_state @@ -356,7 +360,7 @@ class fhandler_base virtual void set_eof () {} virtual int mkdir (mode_t mode); virtual int rmdir (); - virtual DIR *opendir (); + virtual DIR *opendir (int fd) __attribute__ ((regparm (2))); virtual int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); virtual _off64_t telldir (DIR *); virtual void seekdir (DIR *, _off64_t); @@ -705,7 +709,7 @@ class fhandler_disk_file: public fhandler_base _off64_t offset, DWORD size, void *address); int mkdir (mode_t mode); int rmdir (); - DIR *opendir (); + DIR *opendir (int fd) __attribute__ ((regparm (2))); int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); _off64_t telldir (DIR *); void seekdir (DIR *, _off64_t); @@ -725,7 +729,7 @@ class fhandler_cygdrive: public fhandler_disk_file fhandler_cygdrive (); int open (int flags, mode_t mode); int close (); - DIR *opendir (); + DIR *opendir (int fd) __attribute__ ((regparm (2))); int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); void rewinddir (DIR *); int closedir (DIR *); @@ -1221,7 +1225,7 @@ class fhandler_virtual : public fhandler_base virtual ~fhandler_virtual(); virtual int exists(); - virtual DIR *opendir (); + DIR *opendir (int fd) __attribute__ ((regparm (2))); _off64_t telldir (DIR *); void seekdir (DIR *, _off64_t); void rewinddir (DIR *); @@ -1297,7 +1301,7 @@ class fhandler_process: public fhandler_proc public: fhandler_process (); int exists(); - DIR *opendir (); + DIR *opendir (int fd) __attribute__ ((regparm (2))); int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); int open (int flags, mode_t mode = 0); int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2))); @@ -1310,7 +1314,6 @@ class fhandler_procnet: public fhandler_proc public: fhandler_procnet (); int exists(); - DIR *opendir (); int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); int open (int flags, mode_t mode = 0); int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2))); diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 353c45ba5..d693a9ddb 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -1514,7 +1514,7 @@ struct __DIR_cache #define d_mounts(d) ((__DIR_mounts *) (d)->__d_internal) DIR * -fhandler_disk_file::opendir () +fhandler_disk_file::opendir (int fd) { DIR *dir; DIR *res = NULL; @@ -1542,9 +1542,9 @@ fhandler_disk_file::opendir () { strcpy (d_dirname (dir), get_win32_name ()); dir->__d_dirent->__d_version = __DIRENT_VERSION; - cygheap_fdnew fd; + cygheap_fdnew cfd; - if (fd < 0) + if (cfd < 0 && fd < 0) goto free_dirent; /* FindFirstFile doesn't seem to like duplicate /'s. @@ -1569,15 +1569,28 @@ fhandler_disk_file::opendir () if (!pc.iscygdrive ()) { OBJECT_ATTRIBUTES attr; - WCHAR wpath[CYG_MAX_PATH + 10]; - UNICODE_STRING upath = {0, sizeof (wpath), wpath}; - IO_STATUS_BLOCK io; NTSTATUS status; + IO_STATUS_BLOCK io; + WCHAR wpath[CYG_MAX_PATH + 10] = { 0 }; + UNICODE_STRING upath = {0, sizeof (wpath), wpath}; SECURITY_ATTRIBUTES sa = sec_none; - pc.get_nt_native_path (upath); - InitializeObjectAttributes (&attr, &upath, - OBJ_CASE_INSENSITIVE | OBJ_INHERIT, - NULL, sa.lpSecurityDescriptor); + + if (fd >= 0 && get_handle ()) + { + /* fdopendir() case. Just initialize with the emtpy upath + and reuse the exisiting handle. */ + InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, + get_handle (), NULL); + } + else + { + /* opendir() case. Initialize with given directory name and + NULL directory handle. */ + pc.get_nt_native_path (upath); + InitializeObjectAttributes (&attr, &upath, + OBJ_CASE_INSENSITIVE | OBJ_INHERIT, + NULL, sa.lpSecurityDescriptor); + } status = NtOpenFile (&dir->__handle, SYNCHRONIZE | FILE_LIST_DIRECTORY, &attr, &io, FILE_SHARE_VALID_FLAGS, @@ -1605,13 +1618,22 @@ fhandler_disk_file::opendir () dir->__flags |= dirent_get_d_ino; } } - /* Filling fd with `this' (aka storing this in the file descriptor table - should only happen after it's clear that opendir doesn't fail, - otherwise we end up cfree'ing the fhandler twice, once in opendir() - in dir.cc, the second time on exit. Nasty, nasty... */ - fd = this; - fd->nohandle (true); - dir->__d_fd = fd; + if (fd >= 0) + { + dir->__flags |= dirent_valid_fd; + dir->__d_fd = fd; + } + else + { + /* Filling cfd with `this' (aka storing this in the file + descriptor table should only happen after it's clear that + opendir doesn't fail, otherwise we end up cfree'ing the + fhandler twice, once in opendir() in dir.cc, the second + time on exit. Nasty, nasty... */ + cfd = this; + cfd->nohandle (true); + dir->__d_fd = cfd; + } dir->__fh = this; res = dir; } @@ -2011,11 +2033,11 @@ fhandler_cygdrive::fstat (struct __stat64 *buf) } DIR * -fhandler_cygdrive::opendir () +fhandler_cygdrive::opendir (int fd) { DIR *dir; - dir = fhandler_disk_file::opendir (); + dir = fhandler_disk_file::opendir (fd); if (dir && !ndrives) set_drives (); diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc index 1abb99dfd..6ba9fd4cc 100644 --- a/winsup/cygwin/fhandler_process.cc +++ b/winsup/cygwin/fhandler_process.cc @@ -198,15 +198,11 @@ fhandler_process::fstat (struct __stat64 *buf) } DIR * -fhandler_process::opendir () +fhandler_process::opendir (int fd) { - DIR *dir = fhandler_virtual::opendir (); - if (dir) - { - if (fileid == PROCESS_FD) - fill_filebuf (); - dir->__flags = 0; - } + DIR *dir = fhandler_virtual::opendir (fd); + if (dir && fileid == PROCESS_FD) + fill_filebuf (); return dir; } diff --git a/winsup/cygwin/fhandler_procnet.cc b/winsup/cygwin/fhandler_procnet.cc index 8201a0d1d..82c5f0a84 100644 --- a/winsup/cygwin/fhandler_procnet.cc +++ b/winsup/cygwin/fhandler_procnet.cc @@ -107,15 +107,6 @@ fhandler_procnet::fstat (struct __stat64 *buf) } } -DIR * -fhandler_procnet::opendir () -{ - DIR *dir = fhandler_virtual::opendir (); - if (dir) - dir->__flags = 0; - return dir; -} - int fhandler_procnet::readdir (DIR *dir, dirent *de) { diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc index 13f8e1fd4..4045c2d5e 100644 --- a/winsup/cygwin/fhandler_virtual.cc +++ b/winsup/cygwin/fhandler_virtual.cc @@ -46,7 +46,7 @@ fhandler_virtual::fixup_after_exec () } DIR * -fhandler_virtual::opendir () +fhandler_virtual::opendir (int fd) { DIR *dir; DIR *res = NULL; @@ -73,20 +73,30 @@ fhandler_virtual::opendir () { strcpy (dir->__d_dirname, get_name ()); dir->__d_dirent->__d_version = __DIRENT_VERSION; - cygheap_fdnew fd; + dir->__d_cookie = __DIRENT_COOKIE; + dir->__handle = INVALID_HANDLE_VALUE; + dir->__d_position = 0; + dir->__flags = 0; + if (fd >= 0) - { - fd = this; - fd->nohandle (true); + { + dir->__flags |= dirent_valid_fd; dir->__d_fd = fd; - dir->__fh = this; - dir->__d_cookie = __DIRENT_COOKIE; - dir->__handle = INVALID_HANDLE_VALUE; - dir->__d_position = 0; - // dir->__d_dirhash = get_namehash (); - dir->__flags = dirent_saw_dot | dirent_saw_dot_dot; res = dir; - res->__flags = 0; + dir->__fh = this; + res = dir; + } + else + { + cygheap_fdnew cfd; + if (cfd >= 0) + { + cfd = this; + cfd->nohandle (true); + dir->__d_fd = cfd; + dir->__fh = this; + res = dir; + } } } diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 9059ecdec..478387517 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -315,12 +315,13 @@ details. */ 172: Export getifaddrs, freeifaddrs. 173: Export __assert_func. 174: Export stpcpy, stpncpy. + 175: Export fdopendir. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 174 +#define CYGWIN_VERSION_API_MINOR 175 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/sys/dirent.h b/winsup/cygwin/include/sys/dirent.h index d4e5e1333..24cde06d6 100644 --- a/winsup/cygwin/include/sys/dirent.h +++ b/winsup/cygwin/include/sys/dirent.h @@ -1,6 +1,6 @@ /* Posix dirent.h for WIN32. - Copyright 2001, 2002, 2003, 2005, 2006 Red Hat, Inc. + Copyright 2001, 2002, 2003, 2005, 2006, 2007 Red Hat, Inc. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for @@ -56,6 +56,7 @@ typedef struct __DIR #pragma pack(pop) DIR *opendir (const char *); +DIR *fdopendir (int); struct dirent *readdir (DIR *); int readdir_r (DIR *, struct dirent *, struct dirent **); void rewinddir (DIR *); diff --git a/winsup/cygwin/posix.sgml b/winsup/cygwin/posix.sgml index 2567195e7..28717eb21 100644 --- a/winsup/cygwin/posix.sgml +++ b/winsup/cygwin/posix.sgml @@ -993,6 +993,7 @@ also ISO/IEC 9945:2003 and IEEE Std 1003.1-2001 (POSIX.1-2001). acltotext endmntent facl + fdopendir getmntent memalign setmntent