delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2010/08/19/13:05:44

X-Recipient: archive-cygwin AT delorie DOT com
X-Spam-Check-By: sourceware.org
Date: Thu, 19 Aug 2010 19:05:02 +0200
From: Corinna Vinschen <corinna-cygwin AT cygwin DOT com>
To: cygwin AT cygwin DOT com
Subject: Re: cygwin 1.7.6: find skipping over some directories on NTFS mount points
Message-ID: <20100819170502.GA20290@calimero.vinschen.de>
Reply-To: cygwin AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
References: <i4ho35$jsk$1 AT dough DOT gmane DOT org> <20100819083117 DOT GO11340 AT calimero DOT vinschen DOT de> <i4jcq9$hr$1 AT dough DOT gmane DOT org> <20100819144309 DOT GC19001 AT calimero DOT vinschen DOT de> <4C6D5BC5 DOT 6080808 AT redhat DOT com>
MIME-Version: 1.0
In-Reply-To: <4C6D5BC5.6080808@redhat.com>
User-Agent: Mutt/1.5.20 (2009-06-14)
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Unsubscribe: <mailto:cygwin-unsubscribe-archive-cygwin=delorie DOT com AT cygwin DOT com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

On Aug 19 10:28, Eric Blake wrote:
> On 08/19/2010 08:43 AM, Corinna Vinschen wrote:
> > Hmm, digging through Cygwin's readdir code, I have a vague idea.
> > 
> > Eric, does find honor the struct dirent d_type flag?  I'm wondering
> > if d_type is erroneously set to DT_REG for some reason.  If so, we
> > could find this out by augmenting the debug output in the Cygwin DLL.
> 
> find (but not oldfind) relies heavily on the d_type flag.  If that flag
> is incorrect, it could explain why find gets lost.  Could you repeat the
> experiment with 'oldfind' and see if that behaves better?

For further testing purposes I have uploaded a new cygwin1.dll which

a) adds debug output in readdir() which prints DOS attributes as well as
   evaluated d_type value for each readdir entry to strace, and

b) which is heavily tweaked to try harder to get a useful d_type value
   without compromising speed.  The patch is attached, for the records.

Rolf, please try the following Cygwin DLL:

  http://cygwin.de/cygwin-ug-177/new-cygwin1.dll.bz2

  (md5sum compressed   17d66fdd070ce3c57ae735b814cfe527)
  (md5sum uncompressed e30408e665195b351d62d755f3da82ed)

Bunzip the DLL, chmod +x it, and replace your current DLL with that
version.  Then repeat the find.  If it still fails, please send the
strace output again.


Thanks,
Corinna


Index: fhandler_disk_file.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_disk_file.cc,v
retrieving revision 1.332
diff -u -p -r1.332 fhandler_disk_file.cc
--- fhandler_disk_file.cc	18 Aug 2010 10:10:14 -0000	1.332
+++ fhandler_disk_file.cc	19 Aug 2010 16:59:35 -0000
@@ -148,10 +148,15 @@ path_conv::isgood_inode (__ino64_t ino) 
   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
+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
 		  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;
 }
@@ -1826,17 +1840,16 @@ fhandler_disk_file::readdir_helper (DIR 
       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;
     }
 
@@ -1851,19 +1864,29 @@ fhandler_disk_file::readdir_helper (DIR 
 
       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 = 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;
 
@@ -1888,10 +1911,20 @@ fhandler_disk_file::readdir_helper (DIR 
 	      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_FIFO;
+	    }
+	  else if (fpath.is_fs_special ())
 	    {
 	      fname->Length -= 4 * sizeof (WCHAR);
-	      de->d_type = DT_UNKNOWN;
+	      de->d_type = S_ISCHR (fpath.dev.mode) ? DT_CHR : DT_BLK;
 	    }
 	}
     }
@@ -2107,6 +2140,7 @@ go_ahead:
     {
       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;
@@ -2118,13 +2152,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,
+		  buf ? FileAttributes : 0, de->d_type);
   return res;
 }
 


-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019