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