Cygwin: fhandler_procsys::readdir: fix NtQueryDirectoryObject usage
As outlined in the previous patch, the non-atomicity of iterating
over a directory in the NT namespace via NtQueryDirectoryObject
one entry each, results in potential duplication of directory entries.
Fix this for fhandler_procsys::readdir as well by fetching the entire
dir inside fhandler_procsys::opendir, storing it in a buffer, and just
return buffer content from fhandler_procsys::readdir.
Fixes: 43f65cdd7d
("fhandler_procsys.cc: New file.")
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
2f05de4dbf
commit
5036d447c5
|
@ -309,59 +309,88 @@ fhandler_procsys::opendir (int fd)
|
||||||
UNICODE_STRING path;
|
UNICODE_STRING path;
|
||||||
OBJECT_ATTRIBUTES attr;
|
OBJECT_ATTRIBUTES attr;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
HANDLE h;
|
HANDLE dir_hdl;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
mk_unicode_path (&path);
|
mk_unicode_path (&path);
|
||||||
InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
||||||
status = NtOpenDirectoryObject (&h, DIRECTORY_QUERY, &attr);
|
status = NtOpenDirectoryObject (&dir_hdl, DIRECTORY_QUERY, &attr);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
__seterrno_from_nt_status (status);
|
__seterrno_from_nt_status (status);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *dbi_buf = NULL;
|
||||||
|
ULONG size = 65536;
|
||||||
|
ULONG context = 0;
|
||||||
|
int iter;
|
||||||
|
for (iter = 0; iter <= 3; ++iter) /* Allows for a 512K buffer */
|
||||||
|
{
|
||||||
|
void *new_buf = realloc (dbi_buf, size);
|
||||||
|
if (!new_buf)
|
||||||
|
goto err;
|
||||||
|
dbi_buf = new_buf;
|
||||||
|
status = NtQueryDirectoryObject (dir_hdl, dbi_buf, size, FALSE, TRUE,
|
||||||
|
&context, NULL);
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (status != STATUS_MORE_ENTRIES)
|
||||||
|
break;
|
||||||
|
size <<= 1;
|
||||||
|
}
|
||||||
|
if (iter > 3)
|
||||||
|
{
|
||||||
|
__seterrno_from_nt_status (STATUS_INSUFFICIENT_RESOURCES);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
if (!(dir = fhandler_virtual::opendir (fd)))
|
if (!(dir = fhandler_virtual::opendir (fd)))
|
||||||
NtClose (h);
|
goto err;
|
||||||
else
|
/* Note that dir->__handle points to the buffer, it does NOT contain an
|
||||||
dir->__handle = h;
|
actual handle! */
|
||||||
|
dir->__handle = dbi_buf;
|
||||||
|
/* dir->__d_internal contains the number of objects returned in the buffer. */
|
||||||
|
dir->__d_internal = context;
|
||||||
return dir;
|
return dir;
|
||||||
|
|
||||||
|
err:
|
||||||
|
NtClose (dir_hdl);
|
||||||
|
free (dbi_buf);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_procsys::readdir (DIR *dir, dirent *de)
|
fhandler_procsys::readdir (DIR *dir, dirent *de)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
PDIRECTORY_BASIC_INFORMATION dbi;
|
||||||
struct fdbi
|
|
||||||
{
|
|
||||||
DIRECTORY_BASIC_INFORMATION dbi;
|
|
||||||
WCHAR buf[2][NAME_MAX + 1];
|
|
||||||
} f;
|
|
||||||
int res = EBADF;
|
int res = EBADF;
|
||||||
|
|
||||||
if (dir->__handle != INVALID_HANDLE_VALUE)
|
if (dir->__handle != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
BOOLEAN restart = dir->__d_position ? FALSE : TRUE;
|
dbi = ((PDIRECTORY_BASIC_INFORMATION) dir->__handle);
|
||||||
status = NtQueryDirectoryObject (dir->__handle, &f, sizeof f, TRUE,
|
dbi += dir->__d_position;
|
||||||
restart, (PULONG) &dir->__d_position,
|
if (dir->__d_position >= (__int32_t) dir->__d_internal
|
||||||
NULL);
|
|| dbi->ObjectName.Length == 0)
|
||||||
if (!NT_SUCCESS (status))
|
|
||||||
res = ENMFILE;
|
res = ENMFILE;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sys_wcstombs (de->d_name, NAME_MAX + 1, f.dbi.ObjectName.Buffer,
|
sys_wcstombs (de->d_name, NAME_MAX + 1, dbi->ObjectName.Buffer,
|
||||||
f.dbi.ObjectName.Length / sizeof (WCHAR));
|
dbi->ObjectName.Length / sizeof (WCHAR));
|
||||||
de->d_ino = hash_path_name (get_ino (), de->d_name);
|
de->d_ino = hash_path_name (get_ino (), de->d_name);
|
||||||
if (RtlEqualUnicodeString (&f.dbi.ObjectTypeName, &ro_u_natdir,
|
if (RtlEqualUnicodeString (&dbi->ObjectTypeName, &ro_u_natdir, FALSE))
|
||||||
FALSE))
|
|
||||||
de->d_type = DT_DIR;
|
de->d_type = DT_DIR;
|
||||||
else if (RtlEqualUnicodeString (&f.dbi.ObjectTypeName, &ro_u_natsyml,
|
else if (RtlEqualUnicodeString (&dbi->ObjectTypeName, &ro_u_natsyml,
|
||||||
FALSE))
|
FALSE))
|
||||||
de->d_type = DT_LNK;
|
de->d_type = DT_LNK;
|
||||||
else if (!RtlEqualUnicodeString (&f.dbi.ObjectTypeName, &ro_u_natdev,
|
else if (!RtlEqualUnicodeString (&dbi->ObjectTypeName, &ro_u_natdev,
|
||||||
FALSE))
|
FALSE))
|
||||||
de->d_type = DT_CHR;
|
de->d_type = DT_CHR;
|
||||||
else /* Can't nail down "Device" objects without further testing. */
|
else /* Can't nail down "Device" objects without further testing. */
|
||||||
de->d_type = DT_UNKNOWN;
|
de->d_type = DT_UNKNOWN;
|
||||||
|
++dir->__d_position;
|
||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,6 +407,11 @@ fhandler_procsys::telldir (DIR *dir)
|
||||||
void
|
void
|
||||||
fhandler_procsys::seekdir (DIR *dir, long pos)
|
fhandler_procsys::seekdir (DIR *dir, long pos)
|
||||||
{
|
{
|
||||||
|
if (pos < 0)
|
||||||
|
dir->__d_position = 0;
|
||||||
|
else if (pos > (__int32_t) dir->__d_internal)
|
||||||
|
dir->__d_position = (__int32_t) dir->__d_internal;
|
||||||
|
else
|
||||||
dir->__d_position = pos;
|
dir->__d_position = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,7 +420,7 @@ fhandler_procsys::closedir (DIR *dir)
|
||||||
{
|
{
|
||||||
if (dir->__handle != INVALID_HANDLE_VALUE)
|
if (dir->__handle != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
NtClose (dir->__handle);
|
free (dir->__handle);
|
||||||
dir->__handle = INVALID_HANDLE_VALUE;
|
dir->__handle = INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
return fhandler_virtual::closedir (dir);
|
return fhandler_virtual::closedir (dir);
|
||||||
|
|
Loading…
Reference in New Issue