OSDN Git Service

* fhandler.h (dirent_states): Add dirent_nfs_d_ino state and add it to
authorcorinna <corinna>
Wed, 21 May 2008 09:02:42 +0000 (09:02 +0000)
committercorinna <corinna>
Wed, 21 May 2008 09:02:42 +0000 (09:02 +0000)
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.

winsup/cygwin/ChangeLog
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_disk_file.cc
winsup/cygwin/path.cc

index 75ce68d..499495e 100644 (file)
@@ -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.
index 4fe9ead..82541be 100644 (file)
@@ -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
index 3181239..a8558a7 100644 (file)
@@ -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))
     {
index d01b7f8..92994d1 100644 (file)
@@ -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)