OSDN Git Service

* fhandler.h (fhandler_base): Change fstat_helper prototype
authorcorinna <corinna>
Wed, 26 Apr 2006 16:51:09 +0000 (16:51 +0000)
committercorinna <corinna>
Wed, 26 Apr 2006 16:51:09 +0000 (16:51 +0000)
to take file size and inode number as 64 bit values.
* fhandler_disk_file.cc (FS_IS_SAMBA): Move to path.cc
(FS_IS_SAMBA_WITH_QUOTA): Ditto.
(path_conv::hasgood_inode): Delete.
(path_conv::is_samba): Delete.
(path_conv::isgood_inode): Centralized function to recognize
a good inode number.
(fhandler_base::fstat_by_handle): Constify fvi_size and fai_size.
Accomodate argument change in fstat_helper.
(fhandler_base::fstat_by_name): Ditto.
(fhandler_base::fstat_helper): Accomodate argument change.  Call
path_conv::isgood_inode to recognize good inodes.
(fhandler_disk_file::opendir): Explain Samba weirdness here.
Call path_conv::fs_is_samba instead of path_conv::is_samba.
(fhandler_disk_file::readdir): Add STATUS_INVALID_INFO_CLASS
as valid return code from NtQueryDirectoryFile to indicate that
FileIdBothDirectoryInformation is not supported.
Call path_conv::isgood_inode to recognize good inodes.
* ntdll.h (STATUS_INVALID_INFO_CLASS): Define.
* path.cc (fs_info::update): Rework file system recognition
and set appropriate flags.
* path.h (struct fs_info): Add is_ntfs, is_samba and is_nfs flags.
Constify pure read accessors.

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

index 708c511..b7a8f46 100644 (file)
@@ -1,3 +1,30 @@
+2006-04-26  Corinna Vinschen  <corinna@vinschen.de>
+
+       * fhandler.h (fhandler_base): Change fstat_helper prototype
+       to take file size and inode number as 64 bit values.
+       * fhandler_disk_file.cc (FS_IS_SAMBA): Move to path.cc
+       (FS_IS_SAMBA_WITH_QUOTA): Ditto.
+       (path_conv::hasgood_inode): Delete.
+       (path_conv::is_samba): Delete.
+       (path_conv::isgood_inode): Centralized function to recognize
+       a good inode number.
+       (fhandler_base::fstat_by_handle): Constify fvi_size and fai_size.
+       Accomodate argument change in fstat_helper.
+       (fhandler_base::fstat_by_name): Ditto.
+       (fhandler_base::fstat_helper): Accomodate argument change.  Call
+       path_conv::isgood_inode to recognize good inodes.
+       (fhandler_disk_file::opendir): Explain Samba weirdness here.
+       Call path_conv::fs_is_samba instead of path_conv::is_samba.
+       (fhandler_disk_file::readdir): Add STATUS_INVALID_INFO_CLASS
+       as valid return code from NtQueryDirectoryFile to indicate that
+       FileIdBothDirectoryInformation is not supported.
+       Call path_conv::isgood_inode to recognize good inodes.
+       * ntdll.h (STATUS_INVALID_INFO_CLASS): Define.
+       * path.cc (fs_info::update): Rework file system recognition
+       and set appropriate flags.
+       * path.h (struct fs_info): Add is_ntfs, is_samba and is_nfs flags.
+       Constify pure read accessors.
+
 2006-04-24  Christopher Faylor  <cgf@timesys.com>
 
        * environ.cc (getearly): Force correct dereference order when
index bd068a8..52e41e2 100644 (file)
@@ -266,11 +266,9 @@ class fhandler_base
                              FILETIME ftLastAccessTime,
                              FILETIME ftLastWriteTime,
                              DWORD dwVolumeSerialNumber,
-                             DWORD nFileSizeHigh,
-                             DWORD nFileSizeLow,
+                             ULONGLONG nFileSize,
                              LONGLONG nAllocSize,
-                             DWORD nFileIndexHigh,
-                             DWORD nFileIndexLow,
+                             ULONGLONG nFileIndex,
                              DWORD nNumberOfLinks,
                              DWORD dwFileAttributes)
     __attribute__ ((regparm (3)));
index 04f312b..7470dcb 100644 (file)
@@ -196,46 +196,15 @@ path_conv::ndisk_links (DWORD nNumberOfLinks)
   return count + saw_dot;
 }
 
-#define FS_IS_SAMBA (FILE_CASE_SENSITIVE_SEARCH \
-                    | FILE_CASE_PRESERVED_NAMES \
-                    | FILE_PERSISTENT_ACLS)
-
-#define FS_IS_SAMBA_WITH_QUOTA \
-                   (FILE_CASE_SENSITIVE_SEARCH \
-                    | FILE_CASE_PRESERVED_NAMES \
-                    | FILE_PERSISTENT_ACLS \
-                    | FILE_VOLUME_QUOTAS)
-
-inline bool
-path_conv::hasgood_inode ()
-{
-  /* Assume that if a drive has ACL support it MAY have valid "inodes".
-     It definitely does not have valid inodes if it does not have ACL
-     support.  Decouple from has_acls() which follows smbntsec setting. */
-  return ((fs_flags () & FILE_PERSISTENT_ACLS)
-         && drive_type () != DRIVE_UNKNOWN);
-}
-
 inline bool
-path_conv::is_samba ()
+path_conv::isgood_inode (__ino64_t ino) const
 {
-  /* Something weird happens on Samba up to version 3.0.21c, which is
-     fixed in 3.0.22.  FileIdBothDirectoryInformation seems to work
-     nicely, but only up to the 128th entry in the directory.  After
-     reaching this entry, the next call to
-     NtQueryDirectoryFile(FileIdBothDirectoryInformation) returns
-     STATUS_INVAILD_LEVEL.  Why should we care, we can just switch to
-     FileBothDirectoryInformation, isn't it?  Nope!  The next call to
-     NtQueryDirectoryFile(FileBothDirectoryInformation) actually returns
-     STATUS_NO_MORE_FILES, regardless how many files are left unread in
-     the directory.  This does not happen when using
-     FileBothDirectoryInformation right from the start.  In that case we
-     can read the whole directory unmolested.  So we have to excempt
-     Samba from the usage of FileIdBothDirectoryInformation entirely,
-     even though Samba returns valid File IDs. */
-  return drive_type () == DRIVE_REMOTE
-        && (fs_flags () == FS_IS_SAMBA
-            || fs_flags () == FS_IS_SAMBA_WITH_QUOTA);
+  /* We can't trust remote inode numbers of only 32 bit.  That means,
+     all remote inode numbers when running under NT4, as well as remote NT4
+     NTFS, as well as shares of Samba version < 3.0.
+     The known exception are SFU NFS shares, which return the valid 32 bit 
+     inode number from the remote file system unchanged. */
+  return hasgood_inode () && (ino > UINT32_MAX || !isremote () || fs_is_nfs ());
 }
 
 int __stdcall
@@ -248,8 +217,9 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
       NTSTATUS status;
       IO_STATUS_BLOCK io;
       /* The entries potentially contain a name of MAX_PATH wide characters. */
-      DWORD fvi_size = 2 * CYG_MAX_PATH + sizeof (FILE_FS_VOLUME_INFORMATION);
-      DWORD fai_size = 2 * CYG_MAX_PATH + sizeof (FILE_ALL_INFORMATION);
+      const DWORD fvi_size = 2 * CYG_MAX_PATH
+                            + sizeof (FILE_FS_VOLUME_INFORMATION);
+      const DWORD fai_size = 2 * CYG_MAX_PATH + sizeof (FILE_ALL_INFORMATION);
 
       PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION)
                                         alloca (fvi_size);
@@ -278,11 +248,9 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
                           *(FILETIME *) &pfai->BasicInformation.LastAccessTime,
                           *(FILETIME *) &pfai->BasicInformation.LastWriteTime,
                           pfvi->VolumeSerialNumber,
-                          pfai->StandardInformation.EndOfFile.HighPart,
-                          pfai->StandardInformation.EndOfFile.LowPart,
+                          pfai->StandardInformation.EndOfFile.QuadPart,
                           pfai->StandardInformation.AllocationSize.QuadPart,
-                          pfai->InternalInformation.FileId.HighPart,
-                          pfai->InternalInformation.FileId.LowPart,
+                          pfai->InternalInformation.FileId.QuadPart,
                           pfai->StandardInformation.NumberOfLinks,
                           pfai->BasicInformation.FileAttributes);
        }
@@ -313,11 +281,11 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
                       local.ftLastAccessTime,
                       local.ftLastWriteTime,
                       local.dwVolumeSerialNumber,
-                      local.nFileSizeHigh,
-                      local.nFileSizeLow,
+                      (ULONGLONG) local.nFileSizeHigh << 32
+                                  | local.nFileSizeLow,
                       -1LL,
-                      local.nFileIndexHigh,
-                      local.nFileIndexLow,
+                      (ULONGLONG) local.nFileIndexHigh << 32
+                                  | local.nFileIndexLow,
                       local.nNumberOfLinks,
                       local.dwFileAttributes);
 }
@@ -344,18 +312,17 @@ fhandler_base::fstat_by_name (struct __stat64 *buf)
                          local.ftLastAccessTime,
                          local.ftLastWriteTime,
                          pc.volser (),
-                         local.nFileSizeHigh,
-                         local.nFileSizeLow,
+                         (ULONGLONG) local.nFileSizeHigh << 32
+                                     | local.nFileSizeLow,
                          -1LL,
-                         0,
-                         0,
+                         0ULL,
                          1,
                          local.dwFileAttributes);
     }
   else if (pc.isdir ())
     {
       FILETIME ft = {};
-      res = fstat_helper (buf, ft, ft, ft, pc.volser (), 0, 0, -1LL, 0, 0, 1,
+      res = fstat_helper (buf, ft, ft, ft, pc.volser (), 0ULL, -1LL, 0ULL, 1,
                          FILE_ATTRIBUTE_DIRECTORY);
     }
   else
@@ -433,11 +400,9 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
                             FILETIME ftLastAccessTime,
                             FILETIME ftLastWriteTime,
                             DWORD dwVolumeSerialNumber,
-                            DWORD nFileSizeHigh,
-                            DWORD nFileSizeLow,
+                            ULONGLONG nFileSize,
                             LONGLONG nAllocSize,
-                            DWORD nFileIndexHigh,
-                            DWORD nFileIndexLow,
+                            ULONGLONG nFileIndex,
                             DWORD nNumberOfLinks,
                             DWORD dwFileAttributes)
 {
@@ -448,7 +413,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
   to_timestruc_t (&ftLastWriteTime, &buf->st_mtim);
   to_timestruc_t (&ftChangeTime, &buf->st_ctim);
   buf->st_dev = dwVolumeSerialNumber ?: pc.volser ();
-  buf->st_size = ((_off64_t) nFileSizeHigh << 32) + nFileSizeLow;
+  buf->st_size = (_off64_t) nFileSize;
   /* The number of links to a directory includes the
      number of subdirectories in the directory, since all
      those subdirectories point to it.
@@ -457,12 +422,9 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
      let's try it with `1' as link count. */
   buf->st_nlink = pc.ndisk_links (nNumberOfLinks);
 
-  /* We can't trust remote inode numbers of only 32 bit.  That means,
-     all remote inode numbers when running under NT4, as well as remote NT4
-     NTFS, as well as shares of Samba version < 3.0. */
-  if (pc.hasgood_inode () && (nFileIndexHigh || !pc.isremote ()))
-    buf->st_ino = (((__ino64_t) nFileIndexHigh) << 32)
-                 | (__ino64_t) nFileIndexLow;
+  /* Enforce namehash as inode number on untrusted file systems. */
+  if (pc.isgood_inode (nFileIndex))
+    buf->st_ino = (__ino64_t) nFileIndex;
   else
     buf->st_ino = get_namehash ();
 
@@ -1586,7 +1548,23 @@ fhandler_disk_file::opendir ()
              if (pc.hasgood_inode ())
                {
                  dir->__flags |= dirent_set_d_ino;
-                 if (wincap.has_fileid_dirinfo () && !pc.is_samba ())
+                 /* Something weird happens on Samba up to version 3.0.21c,
+                    which is fixed in 3.0.22.  FileIdBothDirectoryInformation
+                    seems to work nicely, but only up to the 128th entry in
+                    the directory.  After reaching this entry, the next call
+                    to NtQueryDirectoryFile(FileIdBothDirectoryInformation)
+                    returns STATUS_INVALID_LEVEL.  Why should we care, we can
+                    just switch to FileBothDirectoryInformation, isn't it?
+                    Nope!  The next call to
+                    NtQueryDirectoryFile(FileBothDirectoryInformation)
+                    actually returns STATUS_NO_MORE_FILES, regardless how
+                    many files are left unread in the directory.  This does
+                    not happen when using FileBothDirectoryInformation right
+                    from the start.  In that case we can read the whole
+                    directory unmolested.  So we have to excempt Samba from
+                    the usage of FileIdBothDirectoryInformation entirely,
+                    even though Samba returns valid File IDs. */
+                 if (wincap.has_fileid_dirinfo () && !pc.fs_is_samba ())
                    dir->__flags |= dirent_get_d_ino;
                }
            }
@@ -1736,7 +1714,8 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de)
             back to using a standard directory query in this case and note
             this case using the dirent_get_d_ino flag. */
          if (status == STATUS_INVALID_LEVEL
-             || status == STATUS_INVALID_PARAMETER)
+             || status == STATUS_INVALID_PARAMETER
+             || status == STATUS_INVALID_INFO_CLASS)
            dir->__flags &= ~dirent_get_d_ino;
        }
       if (!(dir->__flags & dirent_get_d_ino))
@@ -1788,10 +1767,8 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de)
                  CloseHandle (hdl);
                }
            }
-         /* We can't trust remote inode numbers of only 32 bit.  That means,
-            all remote inode numbers when running under NT4, as well as
-            remote NT4 NTFS, as well as shares of Samba version < 3.0. */
-         if (de->d_ino <= UINT32_MAX && pc.isremote ())
+         /* Enforce namehash as inode number on untrusted file systems. */
+         if (!pc.isgood_inode (de->d_ino))
            {
              dir->__flags &= ~dirent_set_d_ino;
              de->d_ino = 0;
index 6cdc2ce..265f308 100644 (file)
@@ -8,6 +8,7 @@
    Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
    details. */
 
+#define STATUS_INVALID_INFO_CLASS   ((NTSTATUS) 0xc0000003)
 #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xc0000004)
 #define STATUS_INVALID_PARAMETER    ((NTSTATUS) 0xc000000d)
 #define STATUS_BUFFER_TOO_SMALL     ((NTSTATUS) 0xc0000023)
index 44ceb6c..a95d311 100644 (file)
@@ -423,15 +423,26 @@ fs_info::update (const char *win32_path)
       return false;
     }
 
-  /* FIXME: Samba by default returns "NTFS" in file system name, but
-   * doesn't support Extended Attributes. If there's some fast way to
-   * distinguish between samba and real ntfs, it should be implemented
-   * here.
-   */
-  has_ea (!is_remote_drive () && strcmp (fsname, "NTFS") == 0);
+#define FS_IS_SAMBA (FILE_CASE_SENSITIVE_SEARCH \
+                    | FILE_CASE_PRESERVED_NAMES \
+                    | FILE_PERSISTENT_ACLS)
+#define FS_IS_SAMBA_WITH_QUOTA \
+                   (FILE_CASE_SENSITIVE_SEARCH \
+                    | FILE_CASE_PRESERVED_NAMES \
+                    | FILE_PERSISTENT_ACLS \
+                    | FILE_VOLUME_QUOTAS)
+  is_fat (strncasematch (fsname, "FAT", 3));
+  is_samba (strcmp (fsname, "NTFS") == 0 && is_remote_drive ()
+           && (flags () == FS_IS_SAMBA || flags () == FS_IS_SAMBA_WITH_QUOTA));
+  is_ntfs (strcmp (fsname, "NTFS") == 0 && !is_samba ());
+  is_nfs (strcmp (fsname, "NFS") == 0);
+
+  has_ea (is_ntfs ());
   has_acls ((flags () & FS_PERSISTENT_ACLS)
            && (allow_smbntsec || !is_remote_drive ()));
-  is_fat (strncasematch (fsname, "FAT", 3));
+  hasgood_inode (((flags () & FILE_PERSISTENT_ACLS)
+                 && drive_type () != DRIVE_UNKNOWN)
+                || is_nfs ());
   /* Known file systems with buggy open calls. Further explanation
      in fhandler.cc (fhandler_disk_file::open). */
   has_buggy_open (!strcmp (fsname, "SUNWNFS"));
index 233dd15..d432e70 100644 (file)
@@ -92,8 +92,12 @@ struct fs_info
     unsigned has_buggy_open  : 1;
     unsigned has_ea          : 1;
     unsigned has_acls        : 1;
-    unsigned is_fat          : 1;
+    unsigned hasgood_inode   : 1;
     unsigned drive_type      : 3;
+    unsigned is_fat          : 1;
+    unsigned is_ntfs         : 1;
+    unsigned is_samba        : 1;
+    unsigned is_nfs          : 1;
   } status;
  public:
   void clear ()
@@ -104,18 +108,26 @@ struct fs_info
     has_buggy_open (false);
     has_ea (false);
     has_acls (false);
-    is_fat (false);
+    hasgood_inode (false);
     drive_type (false);
+    is_fat (false);
+    is_ntfs (false);
+    is_samba (false);
+    is_nfs (false);
   }
   inline DWORD& flags () {return status.flags;};
   inline DWORD& serial () {return status.serial;};
 
   IMPLEMENT_STATUS_FLAG (bool, is_remote_drive)
   IMPLEMENT_STATUS_FLAG (bool, has_buggy_open)
-  IMPLEMENT_STATUS_FLAG (bool, is_fat)
   IMPLEMENT_STATUS_FLAG (bool, has_ea)
   IMPLEMENT_STATUS_FLAG (bool, has_acls)
+  IMPLEMENT_STATUS_FLAG (bool, hasgood_inode)
   IMPLEMENT_STATUS_FLAG (DWORD, drive_type)
+  IMPLEMENT_STATUS_FLAG (bool, is_fat)
+  IMPLEMENT_STATUS_FLAG (bool, is_ntfs)
+  IMPLEMENT_STATUS_FLAG (bool, is_samba)
+  IMPLEMENT_STATUS_FLAG (bool, is_nfs)
 
   bool update (const char *);
 };
@@ -133,13 +145,13 @@ class path_conv
   device dev;
   bool case_clash;
 
-  bool isremote () {return fs.is_remote_drive ();}
-  int has_acls () const {return fs.has_acls (); }
+  bool isremote () const {return fs.is_remote_drive ();}
+  bool has_acls () const {return fs.has_acls (); }
+  bool hasgood_inode () const {return fs.hasgood_inode (); }
+  bool isgood_inode (__ino64_t ino) const;
   int has_symlinks () const {return path_flags & PATH_HAS_SYMLINKS;}
-  bool hasgood_inode (); /* Implemented in fhandler_disk_file.cc */
-  bool is_samba ();      /* Implemented in fhandler_disk_file.cc */
   int has_buggy_open () const {return fs.has_buggy_open ();}
-  bool isencoded () {return path_flags & PATH_ENC;}
+  bool isencoded () const {return path_flags & PATH_ENC;}
   int binmode () const
   {
     if (path_flags & PATH_BINARY)
@@ -222,14 +234,17 @@ class path_conv
   operator DWORD &() {return fileattr;}
   operator int () {return fileattr; }
   char operator [](int i) const {return path[i];}
-  DWORD get_devn () {return dev.devn;}
-  short get_unitn () {return dev.minor;}
-  DWORD file_attributes () {return fileattr;}
+  DWORD get_devn () const {return dev.devn;}
+  short get_unitn () const {return dev.minor;}
+  DWORD file_attributes () const {return fileattr;}
   void file_attributes (DWORD new_attr) {fileattr = new_attr;}
-  DWORD drive_type () {return fs.drive_type ();}
+  DWORD drive_type () const {return fs.drive_type ();}
   DWORD fs_flags () {return fs.flags ();}
-  bool fs_has_ea () {return fs.has_ea ();}
-  bool fs_is_fat () {return fs.is_fat ();}
+  bool fs_has_ea () const {return fs.has_ea ();}
+  bool fs_is_fat () const {return fs.is_fat ();}
+  bool fs_is_ntfs () const {return fs.is_ntfs ();}
+  bool fs_is_samba () const {return fs.is_samba ();}
+  bool fs_is_nfs () const {return fs.is_nfs ();}
   void set_path (const char *p) {strcpy (path, p);}
   DWORD volser () { return fs.serial (); }
   void fillin (HANDLE h);