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>
This commit is contained in:
parent
0a9edd73e3
commit
8eada33223
|
@ -28,6 +28,12 @@ details. */
|
||||||
#define _COMPILING_NEWLIB
|
#define _COMPILING_NEWLIB
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
|
enum __DIR_mount_type {
|
||||||
|
__DIR_mount_none = 0,
|
||||||
|
__DIR_mount_target,
|
||||||
|
__DIR_mount_virt_target
|
||||||
|
};
|
||||||
|
|
||||||
class __DIR_mounts
|
class __DIR_mounts
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
|
@ -41,23 +47,6 @@ class __DIR_mounts
|
||||||
#define __DIR_CYGDRIVE (MAX_MOUNTS+1)
|
#define __DIR_CYGDRIVE (MAX_MOUNTS+1)
|
||||||
#define __DIR_DEV (MAX_MOUNTS+2)
|
#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:
|
public:
|
||||||
__DIR_mounts (const char *posix_path)
|
__DIR_mounts (const char *posix_path)
|
||||||
: parent_dir (posix_path)
|
: parent_dir (posix_path)
|
||||||
|
@ -73,48 +62,47 @@ public:
|
||||||
RtlFreeUnicodeString (&mounts[i]);
|
RtlFreeUnicodeString (&mounts[i]);
|
||||||
RtlFreeUnicodeString (&cygdrive);
|
RtlFreeUnicodeString (&cygdrive);
|
||||||
}
|
}
|
||||||
ino_t check_mount (PUNICODE_STRING fname, ino_t ino,
|
/* For an entry within this dir, check if a mount point exists. */
|
||||||
bool eval = true)
|
bool check_mount (PUNICODE_STRING fname)
|
||||||
{
|
{
|
||||||
if (parent_dir_len == 1) /* root dir */
|
if (parent_dir_len == 1) /* root dir */
|
||||||
{
|
{
|
||||||
if (RtlEqualUnicodeString (fname, &ro_u_proc, FALSE))
|
if (RtlEqualUnicodeString (fname, &ro_u_proc, FALSE))
|
||||||
{
|
{
|
||||||
found[__DIR_PROC] = true;
|
found[__DIR_PROC] = true;
|
||||||
return 2;
|
return true;
|
||||||
}
|
}
|
||||||
if (RtlEqualUnicodeString (fname, &ro_u_dev, FALSE))
|
if (RtlEqualUnicodeString (fname, &ro_u_dev, FALSE))
|
||||||
{
|
{
|
||||||
found[__DIR_DEV] = true;
|
found[__DIR_DEV] = true;
|
||||||
return 2;
|
return true;
|
||||||
}
|
}
|
||||||
if (fname->Length / sizeof (WCHAR) == mount_table->cygdrive_len - 2
|
if (fname->Length / sizeof (WCHAR) == mount_table->cygdrive_len - 2
|
||||||
&& RtlEqualUnicodeString (fname, &cygdrive, FALSE))
|
&& RtlEqualUnicodeString (fname, &cygdrive, FALSE))
|
||||||
{
|
{
|
||||||
found[__DIR_CYGDRIVE] = true;
|
found[__DIR_CYGDRIVE] = true;
|
||||||
return 2;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
if (RtlEqualUnicodeString (fname, &mounts[i], FALSE))
|
if (RtlEqualUnicodeString (fname, &mounts[i], FALSE))
|
||||||
{
|
{
|
||||||
found[i] = true;
|
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)
|
for (int i = 0; i < count; ++i)
|
||||||
if (!found[i])
|
if (!found[i])
|
||||||
{
|
{
|
||||||
found[i] = true;
|
found[i] = true;
|
||||||
if (retname)
|
if (retname)
|
||||||
{
|
*retname = mounts[i];
|
||||||
*retname = mounts[i];
|
return __DIR_mount_target;
|
||||||
return eval_ino (i);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
if (parent_dir_len == 1) /* root dir */
|
if (parent_dir_len == 1) /* root dir */
|
||||||
{
|
{
|
||||||
|
@ -123,14 +111,14 @@ public:
|
||||||
found[__DIR_PROC] = true;
|
found[__DIR_PROC] = true;
|
||||||
if (retname)
|
if (retname)
|
||||||
*retname = ro_u_proc;
|
*retname = ro_u_proc;
|
||||||
return 2;
|
return __DIR_mount_virt_target;
|
||||||
}
|
}
|
||||||
if (!found[__DIR_DEV])
|
if (!found[__DIR_DEV])
|
||||||
{
|
{
|
||||||
found[__DIR_DEV] = true;
|
found[__DIR_DEV] = true;
|
||||||
if (retname)
|
if (retname)
|
||||||
*retname = ro_u_dev;
|
*retname = ro_u_dev;
|
||||||
return 2;
|
return __DIR_mount_virt_target;
|
||||||
}
|
}
|
||||||
if (!found[__DIR_CYGDRIVE])
|
if (!found[__DIR_CYGDRIVE])
|
||||||
{
|
{
|
||||||
|
@ -139,11 +127,11 @@ public:
|
||||||
{
|
{
|
||||||
if (retname)
|
if (retname)
|
||||||
*retname = cygdrive;
|
*retname = cygdrive;
|
||||||
return 2;
|
return __DIR_mount_virt_target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return __DIR_mount_none;
|
||||||
}
|
}
|
||||||
void rewind () { memset (found, 0, sizeof found); }
|
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)
|
if (w32_err)
|
||||||
{
|
{
|
||||||
bool added = false;
|
switch (d_mounts (dir)->check_missing_mount (fname))
|
||||||
if ((de->d_ino = d_mounts (dir)->check_missing_mount (fname)))
|
|
||||||
added = true;
|
|
||||||
if (!added)
|
|
||||||
{
|
{
|
||||||
|
case __DIR_mount_none:
|
||||||
fname->Length = 0;
|
fname->Length = 0;
|
||||||
return geterrno_from_win_error (w32_err);
|
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;
|
attr = 0;
|
||||||
dir->__flags &= ~dirent_set_d_ino;
|
dir->__flags &= ~dirent_set_d_ino;
|
||||||
}
|
}
|
||||||
|
@ -2216,7 +2205,7 @@ go_ahead:
|
||||||
((PFILE_BOTH_DIR_INFORMATION) buf)->FileAttributes;
|
((PFILE_BOTH_DIR_INFORMATION) buf)->FileAttributes;
|
||||||
}
|
}
|
||||||
RtlInitCountedUnicodeString (&fname, FileName, FileNameLength);
|
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))
|
if (de->d_ino == 0 && (dir->__flags & dirent_set_d_ino))
|
||||||
{
|
{
|
||||||
/* Don't try to optimize relative to dir->__d_position. On several
|
/* Don't try to optimize relative to dir->__d_position. On several
|
||||||
|
|
Loading…
Reference in New Issue