From 8eada332236791bb3757091d867d3ef5f93a13d3 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 14 Jun 2017 13:22:56 +0200 Subject: [PATCH] cygwin: readdir: don't lookup mount target inodes So far Cygwin's readdir returned the inode number of a mount target in d_ino, rather than the actual inode number of the mount point in the underlying filesystem. This not only results in a performance hit if the mount target is a remote FS, it is also not done on other POSIX systems. Remove the code evaluating the mount target inode number. Signed-off-by: Corinna Vinschen --- winsup/cygwin/fhandler_disk_file.cc | 71 ++++++++++++----------------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index f36030444..01a9afe15 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -28,6 +28,12 @@ details. */ #define _COMPILING_NEWLIB #include +enum __DIR_mount_type { + __DIR_mount_none = 0, + __DIR_mount_target, + __DIR_mount_virt_target +}; + class __DIR_mounts { int count; @@ -41,23 +47,6 @@ class __DIR_mounts #define __DIR_CYGDRIVE (MAX_MOUNTS+1) #define __DIR_DEV (MAX_MOUNTS+2) - ino_t eval_ino (int idx) - { - ino_t ino = 0; - char fname[parent_dir_len + mounts[idx].Length + 2]; - struct stat st; - - char *c = stpcpy (fname, parent_dir); - if (c[- 1] != '/') - *c++ = '/'; - sys_wcstombs (c, mounts[idx].Length + 1, - mounts[idx].Buffer, mounts[idx].Length / sizeof (WCHAR)); - path_conv pc (fname, PC_SYM_NOFOLLOW | PC_POSIX | PC_KEEP_HANDLE); - if (!stat_worker (pc, &st)) - ino = st.st_ino; - return ino; - } - public: __DIR_mounts (const char *posix_path) : parent_dir (posix_path) @@ -73,48 +62,47 @@ public: RtlFreeUnicodeString (&mounts[i]); RtlFreeUnicodeString (&cygdrive); } - ino_t check_mount (PUNICODE_STRING fname, ino_t ino, - bool eval = true) + /* For an entry within this dir, check if a mount point exists. */ + bool check_mount (PUNICODE_STRING fname) { if (parent_dir_len == 1) /* root dir */ { if (RtlEqualUnicodeString (fname, &ro_u_proc, FALSE)) { found[__DIR_PROC] = true; - return 2; + return true; } if (RtlEqualUnicodeString (fname, &ro_u_dev, FALSE)) { found[__DIR_DEV] = true; - return 2; + return true; } if (fname->Length / sizeof (WCHAR) == mount_table->cygdrive_len - 2 && RtlEqualUnicodeString (fname, &cygdrive, FALSE)) { found[__DIR_CYGDRIVE] = true; - return 2; + return true; } } for (int i = 0; i < count; ++i) if (RtlEqualUnicodeString (fname, &mounts[i], FALSE)) { found[i] = true; - return eval ? eval_ino (i) : 1; + return true; } - return ino; + return false; } - ino_t check_missing_mount (PUNICODE_STRING retname = NULL) + /* On each call, add another mount point within this directory, which is + not backed by a real subdir. */ + __DIR_mount_type check_missing_mount (PUNICODE_STRING retname = NULL) { for (int i = 0; i < count; ++i) if (!found[i]) { found[i] = true; if (retname) - { - *retname = mounts[i]; - return eval_ino (i); - } - return 1; + *retname = mounts[i]; + return __DIR_mount_target; } if (parent_dir_len == 1) /* root dir */ { @@ -123,14 +111,14 @@ public: found[__DIR_PROC] = true; if (retname) *retname = ro_u_proc; - return 2; + return __DIR_mount_virt_target; } if (!found[__DIR_DEV]) { found[__DIR_DEV] = true; if (retname) *retname = ro_u_dev; - return 2; + return __DIR_mount_virt_target; } if (!found[__DIR_CYGDRIVE]) { @@ -139,11 +127,11 @@ public: { if (retname) *retname = cygdrive; - return 2; + return __DIR_mount_virt_target; } } } - return 0; + return __DIR_mount_none; } void rewind () { memset (found, 0, sizeof found); } }; @@ -1989,16 +1977,17 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err, { if (w32_err) { - bool added = false; - if ((de->d_ino = d_mounts (dir)->check_missing_mount (fname))) - added = true; - if (!added) + switch (d_mounts (dir)->check_missing_mount (fname)) { + case __DIR_mount_none: fname->Length = 0; return geterrno_from_win_error (w32_err); + case __DIR_mount_virt_target: + de->d_type = DT_DIR; + break; + default: + break; } - if (de->d_ino == 2) /* Inode number for virtual dirs. */ - de->d_type = DT_DIR; attr = 0; dir->__flags &= ~dirent_set_d_ino; } @@ -2216,7 +2205,7 @@ go_ahead: ((PFILE_BOTH_DIR_INFORMATION) buf)->FileAttributes; } RtlInitCountedUnicodeString (&fname, FileName, FileNameLength); - de->d_ino = d_mounts (dir)->check_mount (&fname, de->d_ino); + d_mounts (dir)->check_mount (&fname); if (de->d_ino == 0 && (dir->__flags & dirent_set_d_ino)) { /* Don't try to optimize relative to dir->__d_position. On several