diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2008-05-21 09:02:42 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2008-05-21 09:02:42 +0000 |
commit | 0d3f3658816a3759e608d6b944bb22ad194f389c (patch) | |
tree | 376fcd68501dae5d7633427c5600cb64962a4fc4 /winsup/cygwin | |
parent | 2762ac6c1944e320cb880f40866d47475f9892ba (diff) | |
download | cygnal-0d3f3658816a3759e608d6b944bb22ad194f389c.tar.gz cygnal-0d3f3658816a3759e608d6b944bb22ad194f389c.tar.bz2 cygnal-0d3f3658816a3759e608d6b944bb22ad194f389c.zip |
* fhandler.h (dirent_states): Add dirent_nfs_d_ino state and add it to
dirent_info_mask.
* fhandler_disk_file.cc (fhandler_disk_file::opendir): Set
dirent_nfs_d_ino flag for NFS shares. Explain why.
(fhandler_disk_file::readdir): Use FileNamesInformation instead of
FileBothDirectoryInformation info class on NFS clients not supporting
the FileIdBothDirectoryInformation info class. Use local pointers to
accommodate different offsets.
* path.cc (symlink_info::check): Don't test directories for symlinks
on NFS shares. Enhance comment.
Diffstat (limited to 'winsup/cygwin')
-rw-r--r-- | winsup/cygwin/ChangeLog | 13 | ||||
-rw-r--r-- | winsup/cygwin/fhandler.h | 3 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_disk_file.cc | 39 | ||||
-rw-r--r-- | winsup/cygwin/path.cc | 5 |
4 files changed, 50 insertions, 10 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 75ce68da4..499495e78 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,5 +1,18 @@ 2008-05-21 Corinna Vinschen <corinna@vinschen.de> + * fhandler.h (dirent_states): Add dirent_nfs_d_ino state and add it to + dirent_info_mask. + * fhandler_disk_file.cc (fhandler_disk_file::opendir): Set + dirent_nfs_d_ino flag for NFS shares. Explain why. + (fhandler_disk_file::readdir): Use FileNamesInformation instead of + FileBothDirectoryInformation info class on NFS clients not supporting + the FileIdBothDirectoryInformation info class. Use local pointers to + accommodate different offsets. + * path.cc (symlink_info::check): Don't test directories for symlinks + on NFS shares. Enhance comment. + +2008-05-21 Corinna Vinschen <corinna@vinschen.de> + * syscalls.cc (FILTERED_MODE): Define valid chmod mode mask. (chmod): Call fh->fchmod with filtered mode. (fchmod): Ditto. diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 4fe9eade1..82541be6b 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -53,9 +53,10 @@ enum dirent_states dirent_isroot = 0x0008, dirent_set_d_ino = 0x0010, dirent_get_d_ino = 0x0020, + dirent_nfs_d_ino = 0x0040, /* Global flags which must not be deleted on rewinddir or seekdir. */ - dirent_info_mask = 0x0038 + dirent_info_mask = 0x0078 }; enum conn_state diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 318123903..a8558a700 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -1608,12 +1608,21 @@ fhandler_disk_file::opendir (int fd) OS/FS combinations (say, Win2K/CDFS or so). Instead of testing in readdir for yet another error code, let's use FileIdBothDirectoryInformation only on filesystems supporting - persistent ACLs, FileBothDirectoryInformation otherwise. */ + persistent ACLs, FileBothDirectoryInformation otherwise. + + On older NFS clients (up to SFU 3.5), dangling symlinks + are hidden from directory queries, unless you use the + FileNamesInformation info class. Nevertheless, we try + FileIdBothDirectoryInformation first. On newer NFS clients + it works fine, on the older ones it returns "invalid info + class". So we can stick to the above explained mechanism. */ if (pc.hasgood_inode ()) { dir->__flags |= dirent_set_d_ino; if (wincap.has_fileid_dirinfo ()) dir->__flags |= dirent_get_d_ino; + if (pc.fs_is_nfs ()) + dir->__flags |= dirent_nfs_d_ino; } } if (fd >= 0) @@ -1787,6 +1796,8 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de) NTSTATUS status = STATUS_SUCCESS; PFILE_ID_BOTH_DIR_INFORMATION buf = NULL; PWCHAR FileName; + ULONG FileNameLength; + ULONG FileAttributes; IO_STATUS_BLOCK io; UNICODE_STRING fname; @@ -1859,7 +1870,9 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de) if (!(dir->__flags & dirent_get_d_ino)) status = NtQueryDirectoryFile (get_handle (), NULL, NULL, 0, &io, d_cache (dir), DIR_BUF_SIZE, - FileBothDirectoryInformation, + (dir->__flags & dirent_nfs_d_ino) + ? FileNamesInformation + : FileBothDirectoryInformation, FALSE, NULL, dir->__d_position == 0); } @@ -1878,21 +1891,33 @@ go_ahead: if ((dir->__flags & dirent_get_d_ino)) { FileName = buf->FileName; + FileNameLength = buf->FileNameLength; + FileAttributes = buf->FileAttributes; if ((dir->__flags & dirent_set_d_ino)) de->d_ino = buf->FileId.QuadPart; } + else if ((dir->__flags & dirent_nfs_d_ino)) + { + FileName = ((PFILE_NAMES_INFORMATION) buf)->FileName; + FileNameLength = ((PFILE_NAMES_INFORMATION) buf)->FileNameLength; + FileAttributes = 0; + } else - FileName = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileName; - RtlInitCountedUnicodeString (&fname, FileName, buf->FileNameLength); + { + FileName = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileName; + FileNameLength = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileNameLength; + FileAttributes = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileAttributes; + } + RtlInitCountedUnicodeString (&fname, FileName, FileNameLength); de->d_ino = d_mounts (dir)->check_mount (&fname, de->d_ino); if (de->d_ino == 0 && (dir->__flags & dirent_set_d_ino)) { OBJECT_ATTRIBUTES attr; - if (dir->__d_position == 0 && buf->FileNameLength == 2 + if (dir->__d_position == 0 && FileNameLength == 2 && FileName[0] == '.') de->d_ino = get_ino_by_handle (get_handle ()); - else if (dir->__d_position == 1 && buf->FileNameLength == 4 + else if (dir->__d_position == 1 && FileNameLength == 4 && FileName[0] == L'.' && FileName[1] == L'.') if (!(dir->__flags & dirent_isroot)) de->d_ino = readdir_get_ino (get_name (), true); @@ -1922,7 +1947,7 @@ go_ahead: } if (!(res = readdir_helper (dir, de, RtlNtStatusToDosError (status), - buf ? buf->FileAttributes : 0, &fname))) + buf ? FileAttributes : 0, &fname))) dir->__d_position++; else if (!(dir->__flags & dirent_saw_dot)) { diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index d01b7f8a2..92994d1b1 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -2514,8 +2514,9 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt, } /* If the file could be opened with FILE_READ_EA, and if it's on a - NFS share, check if it's a symlink. */ - else if (!no_ea && fs.is_nfs ()) + NFS share, check if it's a symlink. Only files can be symlinks + (which can be symlinks to directories). */ + else if (!no_ea && !(fileattr & FILE_ATTRIBUTE_DIRECTORY) && fs.is_nfs ()) { res = check_nfs_symlink (h); if (!res) |