* fhandler_disk_file.cc (DIR_NUM_ENTRIES): New define determining
minimum number of dir entries which fit into the readdir cache. (DIR_BUF_SIZE): Define globally as size of readdir cache. (struct __DIR_cache): New structure used for readdir caching on NT. (d_dirname): Accessor for struct __DIR_cache, use throughout. (d_pos): Ditto. (d_cache): Ditto. (fhandler_disk_file::opendir): Allocate __d_dirname to contain readdir cache on NT. (fhandler_disk_file::readdir): Use buf as pointer into readdir cache. Implement readdir caching.
This commit is contained in:
parent
fa3ffdd01a
commit
7ab59dee94
|
@ -1,3 +1,17 @@
|
|||
2006-01-28 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* fhandler_disk_file.cc (DIR_NUM_ENTRIES): New define determining
|
||||
minimum number of dir entries which fit into the readdir cache.
|
||||
(DIR_BUF_SIZE): Define globally as size of readdir cache.
|
||||
(struct __DIR_cache): New structure used for readdir caching on NT.
|
||||
(d_dirname): Accessor for struct __DIR_cache, use throughout.
|
||||
(d_pos): Ditto.
|
||||
(d_cache): Ditto.
|
||||
(fhandler_disk_file::opendir): Allocate __d_dirname to contain readdir
|
||||
cache on NT.
|
||||
(fhandler_disk_file::readdir): Use buf as pointer into readdir cache.
|
||||
Implement readdir caching.
|
||||
|
||||
2006-01-28 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* include/sys/dirent.h (struct dirent): Revert misguided attempt to
|
||||
|
|
|
@ -1341,6 +1341,28 @@ fhandler_disk_file::rmdir ()
|
|||
return res;
|
||||
}
|
||||
|
||||
/* This is the minimal number of entries which fit into the readdir cache.
|
||||
The number of bytes allocated by the cache is determined by this number,
|
||||
To tune caching, just tweak this number. To get a feeling for the size,
|
||||
the size of the readdir cache is DIR_NUM_ENTRIES * 632 + 264 bytes. */
|
||||
|
||||
#define DIR_NUM_ENTRIES 25 /* Cache size 16064 bytes */
|
||||
|
||||
#define DIR_BUF_SIZE (DIR_NUM_ENTRIES \
|
||||
* (sizeof (FILE_ID_BOTH_DIR_INFORMATION) \
|
||||
+ 2 * CYG_MAX_PATH))
|
||||
|
||||
typedef struct __DIR_cache
|
||||
{
|
||||
char __name[CYG_MAX_PATH];
|
||||
ULONG __pos;
|
||||
char __cache[DIR_BUF_SIZE];
|
||||
};
|
||||
|
||||
#define d_dirname(d) (((struct __DIR_cache *) (d)->__d_dirname)->__name)
|
||||
#define d_pos(d) (((struct __DIR_cache *) (d)->__d_dirname)->__pos)
|
||||
#define d_cache(d) (((struct __DIR_cache *) (d)->__d_dirname)->__cache)
|
||||
|
||||
DIR *
|
||||
fhandler_disk_file::opendir ()
|
||||
{
|
||||
|
@ -1355,7 +1377,9 @@ fhandler_disk_file::opendir ()
|
|||
set_errno (ENAMETOOLONG);
|
||||
else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
|
||||
set_errno (ENOMEM);
|
||||
else if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL)
|
||||
else if ((dir->__d_dirname = (char *) malloc (wincap.is_winnt ()
|
||||
? sizeof (struct __DIR_cache)
|
||||
: len + 3)) == NULL)
|
||||
{
|
||||
set_errno (ENOMEM);
|
||||
goto free_dir;
|
||||
|
@ -1370,7 +1394,8 @@ fhandler_disk_file::opendir ()
|
|||
goto free_dirent;
|
||||
else
|
||||
{
|
||||
strcpy (dir->__d_dirname, get_win32_name ());
|
||||
strcpy (d_dirname (dir), get_win32_name ());
|
||||
d_pos (dir) = 0;
|
||||
dir->__d_dirent->__d_version = __DIRENT_VERSION;
|
||||
cygheap_fdnew fd;
|
||||
|
||||
|
@ -1387,9 +1412,9 @@ fhandler_disk_file::opendir ()
|
|||
Appending a "*" is moved right before calling FindFirstFile.
|
||||
Since FindFirstFile is only called once, this should even be a
|
||||
teeny little bit faster. */
|
||||
len = strlen (dir->__d_dirname);
|
||||
if (len && !isdirsep (dir->__d_dirname[len - 1]))
|
||||
strcpy (dir->__d_dirname + len, "\\");
|
||||
len = strlen (d_dirname (dir));
|
||||
if (len && !isdirsep (d_dirname (dir)[len - 1]))
|
||||
strcpy (d_dirname (dir) + len, "\\");
|
||||
dir->__d_cookie = __DIRENT_COOKIE;
|
||||
dir->__handle = INVALID_HANDLE_VALUE;
|
||||
dir->__d_position = 0;
|
||||
|
@ -1470,7 +1495,7 @@ fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err,
|
|||
if (strcasematch (c + len - 4, ".lnk"))
|
||||
{
|
||||
char fbuf[CYG_MAX_PATH];
|
||||
strcpy (fbuf, dir->__d_dirname);
|
||||
strcpy (fbuf, d_dirname (dir));
|
||||
strcat (fbuf, c);
|
||||
path_conv fpath (fbuf, PC_SYM_NOFOLLOW);
|
||||
if (fpath.issymlink () || fpath.is_fs_special ())
|
||||
|
@ -1561,6 +1586,10 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de)
|
|||
{
|
||||
int res = 0;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PFILE_ID_BOTH_DIR_INFORMATION buf = NULL;
|
||||
wchar_t *FileName;
|
||||
char fname[CYG_MAX_PATH];
|
||||
IO_STATUS_BLOCK io;
|
||||
|
||||
if (!dir->__handle)
|
||||
{
|
||||
|
@ -1571,74 +1600,79 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de)
|
|||
if (!wincap.is_winnt ())
|
||||
return readdir_9x (dir, de);
|
||||
|
||||
#define DIR_BUF_SIZE (sizeof (FILE_ID_BOTH_DIR_INFORMATION) + 2 * CYG_MAX_PATH)
|
||||
PFILE_ID_BOTH_DIR_INFORMATION buf = (PFILE_ID_BOTH_DIR_INFORMATION)
|
||||
alloca (DIR_BUF_SIZE);
|
||||
IO_STATUS_BLOCK io;
|
||||
wchar_t *FileName = buf->FileName;
|
||||
char fname[CYG_MAX_PATH];
|
||||
|
||||
if ((dir->__flags & dirent_get_d_ino))
|
||||
/* d_pos always refers to the next cache entry to use. If it's 0, this means
|
||||
we must reload the cache. */
|
||||
if (d_pos (dir) == 0)
|
||||
{
|
||||
status = NtQueryDirectoryFile (dir->__handle, NULL, NULL, 0, &io,
|
||||
buf, DIR_BUF_SIZE,
|
||||
FileIdBothDirectoryInformation,
|
||||
TRUE, NULL, dir->__d_position == 0);
|
||||
/* FileIdBothDirectoryInformation isn't supported for remote drives
|
||||
on NT4 and 2K systems, and it's also not supported on 2K at all,
|
||||
when accessing network drives on any remote OS. We just fall
|
||||
back to using a standard directory query in this case and note
|
||||
this case using the dirent_get_d_ino flag. */
|
||||
if (!status)
|
||||
{
|
||||
if ((dir->__flags & dirent_set_d_ino))
|
||||
de->d_ino = buf->FileId.QuadPart;
|
||||
}
|
||||
else if (status == STATUS_INVALID_LEVEL
|
||||
|| status == STATUS_INVALID_PARAMETER)
|
||||
dir->__flags &= ~dirent_get_d_ino;
|
||||
}
|
||||
if (!(dir->__flags & dirent_get_d_ino))
|
||||
{
|
||||
status = NtQueryDirectoryFile (dir->__handle, NULL, NULL, 0, &io, buf,
|
||||
DIR_BUF_SIZE, FileBothDirectoryInformation,
|
||||
TRUE, NULL, dir->__d_position == 0);
|
||||
FileName = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileName;
|
||||
}
|
||||
if (!status && de->d_ino == 0 && (dir->__flags & dirent_set_d_ino))
|
||||
{
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
|
||||
if (dir->__d_position == 0 && buf->FileNameLength == 2
|
||||
&& FileName[0] == '.')
|
||||
de->d_ino = readdir_get_ino_by_handle (dir->__handle);
|
||||
else if (dir->__d_position == 1 && buf->FileNameLength == 4
|
||||
&& FileName[0] == '.' && FileName[1] == '.')
|
||||
de->d_ino = readdir_get_ino (dir, pc.normalized_path, true);
|
||||
else
|
||||
if ((dir->__flags & dirent_get_d_ino))
|
||||
{
|
||||
HANDLE hdl;
|
||||
UNICODE_STRING upath = {buf->FileNameLength, CYG_MAX_PATH * 2,
|
||||
FileName};
|
||||
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
|
||||
dir->__handle , NULL);
|
||||
if (!NtOpenFile (&hdl, READ_CONTROL, &attr, &io,
|
||||
wincap.shared (), 0))
|
||||
{
|
||||
de->d_ino = readdir_get_ino_by_handle (hdl);
|
||||
CloseHandle (hdl);
|
||||
}
|
||||
status = NtQueryDirectoryFile (dir->__handle, NULL, NULL, 0, &io,
|
||||
d_cache (dir), DIR_BUF_SIZE,
|
||||
FileIdBothDirectoryInformation,
|
||||
FALSE, NULL, dir->__d_position == 0);
|
||||
/* FileIdBothDirectoryInformation isn't supported for remote drives
|
||||
on NT4 and 2K systems, and it's also not supported on 2K at all,
|
||||
when accessing network drives on any remote OS. We just fall
|
||||
back to using a standard directory query in this case and note
|
||||
this case using the dirent_get_d_ino flag. */
|
||||
if (status == STATUS_INVALID_LEVEL
|
||||
|| status == STATUS_INVALID_PARAMETER)
|
||||
dir->__flags &= ~dirent_get_d_ino;
|
||||
}
|
||||
if (!(dir->__flags & dirent_get_d_ino))
|
||||
status = NtQueryDirectoryFile (dir->__handle, NULL, NULL, 0, &io,
|
||||
d_cache (dir), DIR_BUF_SIZE,
|
||||
FileBothDirectoryInformation,
|
||||
FALSE, NULL, dir->__d_position == 0);
|
||||
}
|
||||
|
||||
if (!status)
|
||||
{
|
||||
buf = (PFILE_ID_BOTH_DIR_INFORMATION) (d_cache (dir) + d_pos (dir));
|
||||
if (buf->NextEntryOffset == 0)
|
||||
d_pos (dir) = 0;
|
||||
else
|
||||
d_pos (dir) += buf->NextEntryOffset;
|
||||
if ((dir->__flags & dirent_get_d_ino))
|
||||
{
|
||||
FileName = buf->FileName;
|
||||
if ((dir->__flags & dirent_set_d_ino))
|
||||
de->d_ino = buf->FileId.QuadPart;
|
||||
}
|
||||
else
|
||||
FileName = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileName;
|
||||
|
||||
if (de->d_ino == 0 && (dir->__flags & dirent_set_d_ino))
|
||||
{
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
|
||||
if (dir->__d_position == 0 && buf->FileNameLength == 2
|
||||
&& FileName[0] == '.')
|
||||
de->d_ino = readdir_get_ino_by_handle (dir->__handle);
|
||||
else if (dir->__d_position == 1 && buf->FileNameLength == 4
|
||||
&& FileName[0] == '.' && FileName[1] == '.')
|
||||
de->d_ino = readdir_get_ino (dir, pc.normalized_path, true);
|
||||
else
|
||||
{
|
||||
HANDLE hdl;
|
||||
UNICODE_STRING upath = {buf->FileNameLength, CYG_MAX_PATH * 2,
|
||||
FileName};
|
||||
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
|
||||
dir->__handle , NULL);
|
||||
if (!NtOpenFile (&hdl, READ_CONTROL, &attr, &io,
|
||||
wincap.shared (), 0))
|
||||
{
|
||||
de->d_ino = readdir_get_ino_by_handle (hdl);
|
||||
CloseHandle (hdl);
|
||||
}
|
||||
}
|
||||
}
|
||||
wcstombs (fname, FileName, buf->FileNameLength / 2);
|
||||
fname[buf->FileNameLength / 2] = '\0';
|
||||
}
|
||||
|
||||
if (!(res = readdir_helper (dir, de, RtlNtStatusToDosError (status),
|
||||
buf->FileAttributes, fname)))
|
||||
buf ? buf->FileAttributes : 0, fname)))
|
||||
dir->__d_position++;
|
||||
else if (!(dir->__flags & dirent_saw_dot))
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue