]> sourceware.org Git - newlib-cygwin.git/commitdiff
* fhandler_disk_file.cc (readdir_check_reparse_point): Rename from
authorCorinna Vinschen <corinna@vinschen.de>
Fri, 20 Aug 2010 11:18:58 +0000 (11:18 +0000)
committerCorinna Vinschen <corinna@vinschen.de>
Fri, 20 Aug 2010 11:18:58 +0000 (11:18 +0000)
is_volume_mountpoint.  Return valid d_type value for underlying
reparse point type.
(readdir_get_ino): Don't rely on the handle set in pc.check.  Open
file here if pc.handle() is NULL.
(fhandler_disk_file::readdir_helper): Try to set a correct d_type value
more diligent.
(fhandler_disk_file::readdir): Don't reset dirent_set_d_ino unless
we're really sure it's due to an untrusted FS.  Simplify usage of
FileAttributes, which is 0 if buf is NULL, anyway.  Set d_type
correctly for faked "." and ".." entries.  Improve debug output.
* path.cc (symlink_info::check): Don't keep handle to volume mount
point open.  Explain why.

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

index b7dd1580f3f347759697f0e3d785a5f3fa9cee99..6982493cb7a814e9d037af1d8e0ee61b049fc97e 100644 (file)
@@ -1,3 +1,19 @@
+2010-08-20  Corinna Vinschen  <corinna@vinschen.de>
+
+       * fhandler_disk_file.cc (readdir_check_reparse_point): Rename from
+       is_volume_mountpoint.  Return valid d_type value for underlying
+       reparse point type.
+       (readdir_get_ino): Don't rely on the handle set in pc.check.  Open
+       file here if pc.handle() is NULL.
+       (fhandler_disk_file::readdir_helper): Try to set a correct d_type value
+       more diligent.
+       (fhandler_disk_file::readdir): Don't reset dirent_set_d_ino unless
+       we're really sure it's due to an untrusted FS.  Simplify usage of
+       FileAttributes, which is 0 if buf is NULL, anyway.  Set d_type
+       correctly for faked "." and ".." entries.  Improve debug output.
+       * path.cc (symlink_info::check): Don't keep handle to volume mount
+       point open.  Explain why.
+
 2010-08-20  Corinna Vinschen  <corinna@vinschen.de>
 
        * fhandler_disk_file.cc (fhandler_disk_file::fstatvfs): Revert usage
index 4054941ebb04e59717fcf80cf996c66b69419216..02ce90e61333170a2bf08ad6afc9a8b27187c666 100644 (file)
@@ -148,10 +148,15 @@ path_conv::isgood_inode (__ino64_t ino) const
   return hasgood_inode () && (ino > UINT32_MAX || !isremote () || fs_is_nfs ());
 }
 
-static inline bool
-is_volume_mountpoint (POBJECT_ATTRIBUTES attr)
+/* Check reparse point for type.  IO_REPARSE_TAG_MOUNT_POINT types are
+   either volume mount points, which are treated as directories, or they
+   are directory mount points, which are treated as symlinks.
+   IO_REPARSE_TAG_SYMLINK types are always symlinks.  We don't know
+   anything about other reparse points, so they are treated as unknown.  */
+static inline int
+readdir_check_reparse_point (POBJECT_ATTRIBUTES attr)
 {
-  bool ret = false;
+  DWORD ret = DT_UNKNOWN;
   IO_STATUS_BLOCK io;
   HANDLE reph;
   UNICODE_STRING subst;
@@ -165,15 +170,24 @@ is_volume_mountpoint (POBJECT_ATTRIBUTES attr)
                  alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
       if (NT_SUCCESS (NtFsControlFile (reph, NULL, NULL, NULL,
                      &io, FSCTL_GET_REPARSE_POINT, NULL, 0,
-                     (LPVOID) rp, MAXIMUM_REPARSE_DATA_BUFFER_SIZE))
-         && rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT
-         && (RtlInitCountedUnicodeString (&subst, 
-               (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
-                         + rp->MountPointReparseBuffer.SubstituteNameOffset),
-               rp->MountPointReparseBuffer.SubstituteNameLength),
-             RtlEqualUnicodePathPrefix (&subst, &ro_u_volume, TRUE)))
-       ret = true;
-      NtClose (reph);
+                     (LPVOID) rp, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)))
+       {
+         if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
+           {
+             RtlInitCountedUnicodeString (&subst, 
+                 (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
+                           + rp->MountPointReparseBuffer.SubstituteNameOffset),
+                 rp->MountPointReparseBuffer.SubstituteNameLength);
+             /* Only volume mountpoints are treated as directories. */
+             if (RtlEqualUnicodePathPrefix (&subst, &ro_u_volume, TRUE))
+               ret = DT_DIR;
+             else
+               ret = DT_LNK;
+           }
+         else if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
+           ret = DT_LNK;
+         NtClose (reph);
+       }
     }
   return ret;
 }
@@ -1783,6 +1797,8 @@ readdir_get_ino (const char *path, bool dot_dot)
   char *fname;
   struct __stat64 st;
   HANDLE hdl;
+  OBJECT_ATTRIBUTES attr;
+  IO_STATUS_BLOCK io;
   __ino64_t ino = 0;
 
   if (dot_dot)
@@ -1802,7 +1818,14 @@ readdir_get_ino (const char *path, bool dot_dot)
     }
   else if (!pc.hasgood_inode ())
     ino = hash_path_name (0, pc.get_nt_native_path ());
-  else if ((hdl = pc.handle ()) != NULL)
+  else if ((hdl = pc.handle ()) != NULL
+          || NT_SUCCESS (NtOpenFile (&hdl, READ_CONTROL,
+                                     pc.get_object_attr (attr, sec_none_nih),
+                                     &io, FILE_SHARE_VALID_FLAGS,
+                                     FILE_OPEN_FOR_BACKUP_INTENT
+                                     | (pc.is_rep_symlink ()
+                                     ? FILE_OPEN_REPARSE_POINT : 0)))
+         )
     {
       ino = pc.get_ino_by_handle (hdl);
       if (!ino)
@@ -1830,17 +1853,16 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err,
       dir->__flags &= ~dirent_set_d_ino;
     }
 
-  /* Set d_type if type can be determined from file attributes.
-     FILE_ATTRIBUTE_SYSTEM ommitted to leave DT_UNKNOWN for old symlinks.
-     For new symlinks, d_type will be reset to DT_UNKNOWN below.  */
+  /* Set d_type if type can be determined from file attributes.  For .lnk
+     symlinks, d_type will be reset below.  Reparse points can be NTFS
+     symlinks, even if they have the FILE_ATTRIBUTE_DIRECTORY flag set. */
   if (attr &&
-      !(attr & (  ~FILE_ATTRIBUTE_VALID_FLAGS
-               | FILE_ATTRIBUTE_SYSTEM
-               | FILE_ATTRIBUTE_REPARSE_POINT)))
+      !(attr & (~FILE_ATTRIBUTE_VALID_FLAGS | FILE_ATTRIBUTE_REPARSE_POINT)))
     {
       if (attr & FILE_ATTRIBUTE_DIRECTORY)
        de->d_type = DT_DIR;
-      else
+      /* FILE_ATTRIBUTE_SYSTEM might denote system-bit type symlinks. */
+      else if (!(attr & FILE_ATTRIBUTE_SYSTEM))
        de->d_type = DT_REG;
     }
 
@@ -1855,19 +1877,29 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err,
 
       InitializeObjectAttributes (&attr, fname, pc.objcaseinsensitive (),
                                  get_handle (), NULL);
-      if (is_volume_mountpoint (&attr)
-         && (NT_SUCCESS (NtOpenFile (&reph, READ_CONTROL, &attr, &io,
-                                     FILE_SHARE_VALID_FLAGS,
-                                     FILE_OPEN_FOR_BACKUP_INTENT))))
+      de->d_type = readdir_check_reparse_point (&attr);
+      if (de->d_type == DT_DIR)
        {
-         de->d_ino = pc.get_ino_by_handle (reph);
-         NtClose (reph);
+         /* Volume mountpoints are treated as directories.  We have to fix
+            the inode number, otherwise we have the inode number of the
+            mount point, rather than the inode number of the toplevel
+            directory of the mounted drive. */
+         if (NT_SUCCESS (NtOpenFile (&reph, READ_CONTROL, &attr, &io,
+                                     FILE_SHARE_VALID_FLAGS,
+                                     FILE_OPEN_FOR_BACKUP_INTENT)))
+           {
+             de->d_ino = pc.get_ino_by_handle (reph);
+             NtClose (reph);
+           }
        }
     }
 
-  /* Check for Windows shortcut. If it's a Cygwin or U/WIN
-     symlink, drop the .lnk suffix. */
-  if ((attr & FILE_ATTRIBUTE_READONLY) && fname->Length > 4 * sizeof (WCHAR))
+  /* Check for Windows shortcut. If it's a Cygwin or U/WIN symlink, drop the
+     .lnk suffix and set d_type accordingly. */
+  if ((attr & (FILE_ATTRIBUTE_DIRECTORY
+              | FILE_ATTRIBUTE_REPARSE_POINT
+              | FILE_ATTRIBUTE_READONLY)) == FILE_ATTRIBUTE_READONLY
+      && fname->Length > 4 * sizeof (WCHAR))
     {
       UNICODE_STRING uname;
 
@@ -1892,10 +1924,20 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err,
              fbuf.Length -= 2 * sizeof (WCHAR);
            }
          path_conv fpath (&fbuf, PC_SYM_NOFOLLOW);
-         if (fpath.issymlink () || fpath.is_fs_special ())
+         if (fpath.issymlink ())
+           {
+             fname->Length -= 4 * sizeof (WCHAR);
+             de->d_type = DT_LNK;
+           }
+         else if (fpath.isfifo ())
            {
              fname->Length -= 4 * sizeof (WCHAR);
-             de->d_type = DT_UNKNOWN;
+             de->d_type = DT_FIFO;
+           }
+         else if (fpath.is_fs_special ())
+           {
+             fname->Length -= 4 * sizeof (WCHAR);
+             de->d_type = S_ISCHR (fpath.dev.mode) ? DT_CHR : DT_BLK;
            }
        }
     }
@@ -2094,23 +2136,35 @@ go_ahead:
                                       | FILE_OPEN_REPARSE_POINT);
              if (NT_SUCCESS (f_status))
                {
-                 de->d_ino = pc.get_ino_by_handle (hdl);
+                 /* We call NtQueryInformationFile here, rather than
+                    pc.get_ino_by_handle(), otherwise we can't short-circuit
+                    dirent_set_d_ino correctly. */
+                 FILE_INTERNAL_INFORMATION fai;
+                 f_status = NtQueryInformationFile (hdl, &io, &fai, sizeof fai,
+                                                    FileInternalInformation);
                  NtClose (hdl);
+                 if (NT_SUCCESS (f_status))
+                   {
+                     if (pc.isgood_inode (fai.FileId.QuadPart))
+                       de->d_ino = fai.FileId.QuadPart;
+                     else
+                       /* Untrusted file system.  Don't try to fetch inode
+                          number again. */
+                       dir->__flags &= ~dirent_set_d_ino;
+                   }
                }
            }
-         /* Untrusted file system.  Don't try to fetch inode number again. */
-         if (de->d_ino == 0)
-           dir->__flags &= ~dirent_set_d_ino;
        }
     }
 
   if (!(res = readdir_helper (dir, de, RtlNtStatusToDosError (status),
-                             buf ? FileAttributes : 0, &fname)))
+                             FileAttributes, &fname)))
     dir->__d_position++;
   else if (!(dir->__flags & dirent_saw_dot))
     {
       strcpy (de->d_name , ".");
       de->d_ino = pc.get_ino_by_handle (get_handle ());
+      de->d_type = DT_DIR;
       dir->__d_position++;
       dir->__flags |= dirent_saw_dot;
       res = 0;
@@ -2122,13 +2176,15 @@ go_ahead:
        de->d_ino = readdir_get_ino (get_name (), true);
       else
        de->d_ino = pc.get_ino_by_handle (get_handle ());
+      de->d_type = DT_DIR;
       dir->__d_position++;
       dir->__flags |= dirent_saw_dot_dot;
       res = 0;
     }
 
-  syscall_printf ("%d = readdir (%p, %p) (L\"%lS\" > \"%ls\")", res, dir, &de,
-                 res ? NULL : &fname, res ? "***" : de->d_name);
+  syscall_printf ("%d = readdir (%p, %p) (L\"%lS\" > \"%ls\") (attr %p > type %d)",
+                 res, dir, &de, res ? NULL : &fname, res ? "***" : de->d_name,
+                 FileAttributes, de->d_type);
   return res;
 }
 
index 00a9c1d65aca873ccc82a500530b908697120928..fb4526fd50d3cffb41e0ea3ca36382d374295f85 100644 (file)
@@ -2533,6 +2533,11 @@ restart:
                 This does what we want because fs_info::update opens the
                 handle without FILE_OPEN_REPARSE_POINT. */
              fs.update (&upath, NULL);
+             /* Make sure the open handle is not used in later stat calls.
+                The handle has been opened with the FILE_OPEN_REPARSE_POINT
+                flag, so it's a handle to the reparse point, not a handle
+                to the volumes root dir. */
+             pflags &= ~PC_KEEP_HANDLE;
            }
          else if (res)
            break;
This page took 0.042169 seconds and 5 git commands to generate.