Mail Archives: cygwin/2010/08/19/13:05:44
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 -