summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2017-06-14 13:22:56 +0200
committerCorinna Vinschen <corinna@vinschen.de>2017-06-14 13:22:56 +0200
commit8eada332236791bb3757091d867d3ef5f93a13d3 (patch)
treed2f7cb1246294db37f00b04d3eb05c095707954b
parent0a9edd73e3abb85162f9d79bc57cf4df1f9d8f1e (diff)
downloadcygnal-8eada332236791bb3757091d867d3ef5f93a13d3.tar.gz
cygnal-8eada332236791bb3757091d867d3ef5f93a13d3.tar.bz2
cygnal-8eada332236791bb3757091d867d3ef5f93a13d3.zip
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 <corinna@vinschen.de>
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc71
1 files 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 <dirent.h>
+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