Index: devices.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/devices.h,v retrieving revision 1.18 diff -u -p -r1.18 devices.h --- devices.h 10 May 2005 20:56:06 -0000 1.18 +++ devices.h 18 May 2005 04:22:41 -0000 @@ -106,8 +106,6 @@ enum fh_devices DEV_CYGDRIVE_MAJOR = 98, FH_CYGDRIVE= FHDEV (DEV_CYGDRIVE_MAJOR, 0), - FH_CYGDRIVE_A= FHDEV (DEV_CYGDRIVE_MAJOR, 'a'), - FH_CYGDRIVE_Z= FHDEV (DEV_CYGDRIVE_MAJOR, 'z'), DEV_TCP_MAJOR = 30, FH_TCP = FHDEV (DEV_TCP_MAJOR, 36), Index: fhandler.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler.h,v retrieving revision 1.247 diff -u -p -r1.247 fhandler.h --- fhandler.h 17 May 2005 20:34:15 -0000 1.247 +++ fhandler.h 18 May 2005 04:22:42 -0000 @@ -346,6 +346,8 @@ class fhandler_base void operator delete (void *); virtual HANDLE get_guard () const {return NULL;} virtual void set_eof () {} + virtual int mkdir (mode_t mode); + virtual int rmdir (); virtual DIR *opendir (); virtual dirent *readdir (DIR *); virtual _off64_t telldir (DIR *); @@ -664,6 +666,8 @@ class fhandler_disk_file: public fhandle int msync (HANDLE h, caddr_t addr, size_t len, int flags); bool fixup_mmap_after_fork (HANDLE h, DWORD access, int flags, _off64_t offset, DWORD size, void *address); + int mkdir (mode_t mode); + int rmdir (); DIR *opendir (); struct dirent *readdir (DIR *); _off64_t telldir (DIR *); @@ -678,11 +682,9 @@ class fhandler_cygdrive: public fhandler const char *pdrive; void set_drives (); public: - bool iscygdrive_root () { return !dev ().minor; } fhandler_cygdrive (); DIR *opendir (); struct dirent *readdir (DIR *); - _off64_t telldir (DIR *); void seekdir (DIR *, _off64_t); void rewinddir (DIR *); int closedir (DIR *); Index: dir.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/dir.cc,v retrieving revision 1.86 diff -u -p -r1.86 dir.cc --- dir.cc 13 May 2005 15:46:05 -0000 1.86 +++ dir.cc 18 May 2005 04:22:42 -0000 @@ -221,39 +221,21 @@ extern "C" int mkdir (const char *dir, mode_t mode) { int res = -1; - SECURITY_ATTRIBUTES sa = sec_none_nih; - security_descriptor sd; + fhandler_base *fh = NULL; - path_conv real_dir (dir, PC_SYM_NOFOLLOW | PC_WRITABLE); + if (!(fh = build_fh_name (dir, NULL, PC_SYM_NOFOLLOW | PC_WRITABLE))) + goto done; /* errno already set */; - if (real_dir.error) + if (fh->error ()) { - set_errno (real_dir.case_clash ? ECASECLASH : real_dir.error); - goto done; + debug_printf ("got %d error from build_fh_name", fh->error ()); + set_errno (fh->error ()); } + else if (!fh->mkdir (mode)) + res = 0; + delete fh; - nofinalslash (real_dir.get_win32 (), real_dir.get_win32 ()); - - if (allow_ntsec && real_dir.has_acls ()) - set_security_attribute (S_IFDIR | ((mode & 07777) & ~cygheap->umask), - &sa, sd); - - if (CreateDirectoryA (real_dir.get_win32 (), &sa)) - { - if (!allow_ntsec && allow_ntea) - set_file_attribute (false, NULL, real_dir.get_win32 (), - S_IFDIR | ((mode & 07777) & ~cygheap->umask)); -#ifdef HIDDEN_DOT_FILES - char *c = strrchr (real_dir.get_win32 (), '\\'); - if ((c && c[1] == '.') || *real_dir.get_win32 () == '.') - SetFileAttributes (real_dir.get_win32 (), FILE_ATTRIBUTE_HIDDEN); -#endif - res = 0; - } - else - __seterrno (); - -done: + done: syscall_printf ("%d = mkdir (%s, %d)", res, dir, mode); return res; } @@ -263,80 +245,21 @@ extern "C" int rmdir (const char *dir) { int res = -1; + fhandler_base *fh = NULL; - path_conv real_dir (dir, PC_SYM_NOFOLLOW | PC_WRITABLE); + if (!(fh = build_fh_name (dir, NULL, PC_SYM_NOFOLLOW | PC_WRITABLE))) + goto done; /* errno already set */; - if (real_dir.error) - set_errno (real_dir.error); - else if (!real_dir.exists ()) - set_errno (ENOENT); - else if (!real_dir.isdir ()) - set_errno (ENOTDIR); - else + if (fh->error ()) { - /* Even own directories can't be removed if R/O attribute is set. */ - if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY)) - SetFileAttributes (real_dir, - (DWORD) real_dir & ~FILE_ATTRIBUTE_READONLY); - - for (bool is_cwd = false; ; is_cwd = true) - { - DWORD err; - int rc = RemoveDirectory (real_dir); - DWORD att = GetFileAttributes (real_dir); - - /* Sometimes smb indicates failure when it really succeeds, so check for - this case specifically. */ - if (rc || att == INVALID_FILE_ATTRIBUTES) - { - /* RemoveDirectory on a samba drive doesn't return an error if the - directory can't be removed because it's not empty. Checking for - existence afterwards keeps us informed about success. */ - if (att == INVALID_FILE_ATTRIBUTES) - { - res = 0; - break; - } - err = ERROR_DIR_NOT_EMPTY; - } - else - err = GetLastError (); - - /* This kludge detects if we are attempting to remove the current working - directory. If so, we will move elsewhere to potentially allow the - rmdir to succeed. This means that cygwin's concept of the current working - directory != Windows concept but, hey, whaddaregonnado? - Note that this will not cause something like the following to work: - $ cd foo - $ rmdir . - since the shell will have foo "open" in the above case and so Windows will - not allow the deletion. (Actually it does on 9X.) - FIXME: A potential workaround for this is for cygwin apps to *never* call - SetCurrentDirectory. */ - - if (strcasematch (real_dir, cygheap->cwd.win32) - && !strcasematch ("c:\\", cygheap->cwd.win32) - && !is_cwd - && SetCurrentDirectory ("c:\\")) - continue; - - /* On 9X ERROR_ACCESS_DENIED is returned - if you try to remove a non-empty directory. */ - if (err == ERROR_ACCESS_DENIED - && wincap.access_denied_on_delete ()) - err = ERROR_DIR_NOT_EMPTY; - - __seterrno_from_win_error (err); - - /* Directory still exists, restore its characteristics. */ - if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY)) - SetFileAttributes (real_dir, real_dir); - if (is_cwd) - SetCurrentDirectory (real_dir); - break; - } + debug_printf ("got %d error from build_fh_name", fh->error ()); + set_errno (fh->error ()); } + else if (!fh->rmdir ()) + res = 0; + delete fh; + done: syscall_printf ("%d = rmdir (%s)", res, dir); return res; } Index: fhandler.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler.cc,v retrieving revision 1.233 diff -u -p -r1.233 fhandler.cc --- fhandler.cc 28 Apr 2005 03:41:09 -0000 1.233 +++ fhandler.cc 18 May 2005 04:22:42 -0000 @@ -1509,6 +1509,28 @@ fhandler_base::set_nonblocking (int yes) openflags = (openflags & ~O_NONBLOCK_MASK) | new_flags; } +int +fhandler_base::mkdir (mode_t) +{ + if (exists ()) + set_errno (EEXIST); + else + set_errno (EROFS); + return -1; +} + +int +fhandler_base::rmdir () +{ + if (!exists ()) + set_errno (ENOENT); + else if (!pc.isdir ()) + set_errno (ENOTDIR); + else + set_errno (EROFS); + return -1; +} + DIR * fhandler_base::opendir () { Index: fhandler_disk_file.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_disk_file.cc,v retrieving revision 1.125 diff -u -p -r1.125 fhandler_disk_file.cc --- fhandler_disk_file.cc 14 May 2005 21:12:10 -0000 1.125 +++ fhandler_disk_file.cc 18 May 2005 04:22:43 -0000 @@ -1138,6 +1138,114 @@ fhandler_disk_file::lock (int cmd, struc return 0; } +int +fhandler_disk_file::mkdir (mode_t mode) +{ + int res = -1; + SECURITY_ATTRIBUTES sa = sec_none_nih; + security_descriptor sd; + + if (allow_ntsec && has_acls ()) + set_security_attribute (S_IFDIR | ((mode & 07777) & ~cygheap->umask), + &sa, sd); + + if (CreateDirectoryA (get_win32_name (), &sa)) + { + if (!allow_ntsec && allow_ntea) + set_file_attribute (false, NULL, get_win32_name (), + S_IFDIR | ((mode & 07777) & ~cygheap->umask)); +#ifdef HIDDEN_DOT_FILES + char *c = strrchr (real_dir.get_win32 (), '\\'); + if ((c && c[1] == '.') || *get_win32_name () == '.') + SetFileAttributes (get_win32_name (), FILE_ATTRIBUTE_HIDDEN); +#endif + res = 0; + } + else + __seterrno (); + + return res; +} + +int +fhandler_disk_file::rmdir () +{ + int res = -1; + + /* Even own directories can't be removed if R/O attribute is set. */ + if (pc.has_attribute (FILE_ATTRIBUTE_READONLY)) + SetFileAttributes (get_win32_name (), + (DWORD) pc & ~FILE_ATTRIBUTE_READONLY); + + for (bool is_cwd = false; ; is_cwd = true) + { + DWORD err, att = 0; + int rc = RemoveDirectory (get_win32_name ()); + + if (isremote () && exists ()) + att = GetFileAttributes (get_win32_name ()); + + /* Sometimes smb indicates failure when it really succeeds, so check for + this case specifically. */ + if (rc || att == INVALID_FILE_ATTRIBUTES) + { + /* RemoveDirectory on a samba drive doesn't return an error if the + directory can't be removed because it's not empty. Checking for + existence afterwards keeps us informed about success. */ + if (!isremote () || att == INVALID_FILE_ATTRIBUTES) + { + res = 0; + break; + } + err = ERROR_DIR_NOT_EMPTY; + } + else + err = GetLastError (); + + /* This kludge detects if we are attempting to remove the current working + directory. If so, we will move elsewhere to potentially allow the + rmdir to succeed. This means that cygwin's concept of the current working + directory != Windows concept but, hey, whaddaregonnado? + Note that this will not cause something like the following to work: + $ cd foo + $ rmdir . + since the shell will have foo "open" in the above case and so Windows will + not allow the deletion. (Actually it does on 9X.) + FIXME: A potential workaround for this is for cygwin apps to *never* call + SetCurrentDirectory. */ + + extern char windows_system_directory[]; + if (strcasematch (get_win32_name (), cygheap->cwd.win32) + && !strcasematch (windows_system_directory, cygheap->cwd.win32) + && !is_cwd + && SetCurrentDirectory (windows_system_directory)) + continue; + + /* On 9X ERROR_ACCESS_DENIED is returned + if you try to remove a non-empty directory. */ + if (err == ERROR_ACCESS_DENIED + && wincap.access_denied_on_delete ()) + err = ERROR_DIR_NOT_EMPTY; + + __seterrno_from_win_error (err); + + /* Directory still exists, restore its characteristics. */ + if (pc.has_attribute (FILE_ATTRIBUTE_READONLY)) + SetFileAttributes (get_win32_name (), (DWORD) pc); + if (is_cwd) + SetCurrentDirectory (get_win32_name ()); + break; + } + + return res; +} + +_off64_t +fhandler_disk_file::telldir (DIR *dir) +{ + return dir->__d_position; +} + DIR * fhandler_disk_file::opendir () { @@ -1268,12 +1376,6 @@ fhandler_disk_file::readdir (DIR *dir) return res; } -_off64_t -fhandler_disk_file::telldir (DIR *dir) -{ - return dir->__d_position; -} - void fhandler_disk_file::seekdir (DIR *dir, _off64_t loc) { @@ -1326,8 +1428,6 @@ fhandler_cygdrive::set_drives () int fhandler_cygdrive::fstat (struct __stat64 *buf) { - if (!iscygdrive_root ()) - return fhandler_disk_file::fstat (buf); buf->st_mode = S_IFDIR | 0555; if (!ndrives) set_drives (); @@ -1341,7 +1441,7 @@ fhandler_cygdrive::opendir () DIR *dir; dir = fhandler_disk_file::opendir (); - if (dir && iscygdrive_root () && !ndrives) + if (dir && !ndrives) set_drives (); return dir; @@ -1350,8 +1450,6 @@ fhandler_cygdrive::opendir () struct dirent * fhandler_cygdrive::readdir (DIR *dir) { - if (!iscygdrive_root ()) - return fhandler_disk_file::readdir (dir); if (!pdrive || !*pdrive) return NULL; if (GetFileAttributes (pdrive) == INVALID_FILE_ATTRIBUTES) @@ -1369,12 +1467,6 @@ fhandler_cygdrive::readdir (DIR *dir) return dir->__d_dirent; } -_off64_t -fhandler_cygdrive::telldir (DIR *dir) -{ - return fhandler_disk_file::telldir (dir); -} - void fhandler_cygdrive::seekdir (DIR *dir, _off64_t loc) { @@ -1384,8 +1476,6 @@ fhandler_cygdrive::seekdir (DIR *dir, _o void fhandler_cygdrive::rewinddir (DIR *dir) { - if (!iscygdrive_root ()) - return fhandler_disk_file::rewinddir (dir); pdrive = get_win32_name (); dir->__d_position = 0; return; @@ -1394,8 +1484,6 @@ fhandler_cygdrive::rewinddir (DIR *dir) int fhandler_cygdrive::closedir (DIR *dir) { - if (!iscygdrive_root ()) - return fhandler_disk_file::closedir (dir); pdrive = get_win32_name (); return 0; } Index: path.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/path.cc,v retrieving revision 1.376 diff -u -p -r1.376 path.cc --- path.cc 17 May 2005 01:29:27 -0000 1.376 +++ path.cc 18 May 2005 04:22:45 -0000 @@ -671,7 +671,6 @@ path_conv::check (const char *src, unsig fileattr = INVALID_FILE_ATTRIBUTES; goto virtual_component_retry; } - path_flags |= PATH_RO; goto out; } /* devn should not be a device. If it is, then stop parsing now. */ @@ -877,21 +876,16 @@ virtual_component_retry: out: bool strip_tail = false; - /* If the user wants a directory, do not return a symlink */ if ((opt & PC_WRITABLE) && (path_flags & PATH_RO)) { debug_printf ("%s is on a read-only filesystem", path); error = EROFS; return; } - else if (isvirtual_dev (dev.devn) && fileattr == INVALID_FILE_ATTRIBUTES) - { - error = dev.devn == FH_NETDRIVE ? ENOSHARE : ENOENT; - return; - } else if (!need_directory || error) /* nothing to do */; else if (fileattr & FILE_ATTRIBUTE_DIRECTORY) + /* If the user wants a directory, do not return a symlink */ path_flags &= ~PATH_SYMLINK; else {