Commit df29fd3a authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Always return . and .. as the first two entries in directory searches.

parent a411b858
......@@ -1677,20 +1677,34 @@ HANDLE WINAPI FindFirstFileExW( LPCWSTR filename, FINDEX_INFO_LEVELS level,
CloseHandle( info->handle );
info->handle = 0;
}
else if (!FindNextFileW( (HANDLE)info, data ))
{
TRACE( "%s not found\n", debugstr_w(filename) );
FindClose( (HANDLE)info );
SetLastError( ERROR_FILE_NOT_FOUND );
return INVALID_HANDLE_VALUE;
}
else if (!strpbrkW( info->mask.Buffer, wildcardsW ))
else
{
/* we can't find two files with the same name */
CloseHandle( info->handle );
info->handle = 0;
IO_STATUS_BLOCK io;
NtQueryDirectoryFile( info->handle, 0, NULL, NULL, &io, info->data, sizeof(info->data),
FileBothDirectoryInformation, FALSE, &info->mask, TRUE );
if (io.u.Status)
{
FindClose( info );
SetLastError( RtlNtStatusToDosError( io.u.Status ) );
return INVALID_HANDLE_VALUE;
}
info->data_len = io.Information;
if (!FindNextFileW( info, data ))
{
TRACE( "%s not found\n", debugstr_w(filename) );
FindClose( info );
SetLastError( ERROR_FILE_NOT_FOUND );
return INVALID_HANDLE_VALUE;
}
if (!strpbrkW( info->mask.Buffer, wildcardsW ))
{
/* we can't find two files with the same name */
CloseHandle( info->handle );
info->handle = 0;
}
}
return (HANDLE)info;
return info;
error:
HeapFree( GetProcessHeap(), 0, info );
......
......@@ -107,7 +107,7 @@ typedef struct
char d_name[256];
} KERNEL_DIRENT64;
static inline int getdents64( int fd, KERNEL_DIRENT64 *de, unsigned int size )
static inline int getdents64( int fd, char *de, unsigned int size )
{
int ret;
__asm__( "pushl %%ebx; movl %2,%%ebx; int $0x80; popl %%ebx"
......@@ -1060,15 +1060,15 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U
{
off_t old_pos = 0;
size_t size = length;
int res;
char local_buffer[8192];
KERNEL_DIRENT64 *data, *de;
int res, fake_dot_dot = 1;
char *data, local_buffer[8192];
KERNEL_DIRENT64 *de;
FILE_BOTH_DIR_INFORMATION *info, *last_info = NULL;
if (size <= sizeof(local_buffer) || !(data = RtlAllocateHeap( GetProcessHeap(), 0, size )))
{
size = sizeof(local_buffer);
data = (KERNEL_DIRENT64 *)local_buffer;
data = local_buffer;
}
if (restart_scan) lseek( fd, 0, SEEK_SET );
......@@ -1096,13 +1096,52 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U
goto done;
}
de = data;
de = (KERNEL_DIRENT64 *)data;
if (restart_scan)
{
/* check if we got . and .. from getdents */
if (res > 0)
{
if (!strcmp( de->d_name, "." ) && res > de->d_reclen)
{
KERNEL_DIRENT64 *next_de = (KERNEL_DIRENT64 *)(data + de->d_reclen);
if (!strcmp( next_de->d_name, ".." )) fake_dot_dot = 0;
}
}
/* make sure we have enough room for both entries */
if (fake_dot_dot)
{
static const ULONG min_info_size = (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName[1]) +
FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName[2]) + 3) & ~3;
if (length < min_info_size || single_entry)
{
FIXME( "not enough room %u/%u for fake . and .. entries\n", length, single_entry );
fake_dot_dot = 0;
}
}
if (fake_dot_dot)
{
if ((info = append_entry( buffer, &io->Information, length, ".", NULL, mask )))
last_info = info;
if ((info = append_entry( buffer, &io->Information, length, "..", NULL, mask )))
last_info = info;
/* check if we still have enough space for the largest possible entry */
if (last_info && io->Information + max_dir_info_size > length)
{
lseek( fd, 0, SEEK_SET ); /* reset pos to first entry */
res = 0;
}
}
}
while (res > 0)
{
res -= de->d_reclen;
info = append_entry( buffer, &io->Information, length, de->d_name, NULL, mask );
if (info)
if (!(fake_dot_dot && (!strcmp( de->d_name, "." ) || !strcmp( de->d_name, ".." ))) &&
(info = append_entry( buffer, &io->Information, length, de->d_name, NULL, mask )))
{
last_info = info;
if ((char *)info->FileName + info->FileNameLength > (char *)buffer + length)
......@@ -1124,7 +1163,7 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U
else
{
res = getdents64( fd, data, size );
de = data;
de = (KERNEL_DIRENT64 *)data;
}
}
......@@ -1132,7 +1171,7 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U
else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
res = 0;
done:
if ((char *)data != local_buffer) RtlFreeHeap( GetProcessHeap(), 0, data );
if (data != local_buffer) RtlFreeHeap( GetProcessHeap(), 0, data );
return res;
}
......@@ -1150,7 +1189,7 @@ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buff
long restart_pos;
ULONG_PTR restart_info_pos = 0;
size_t size, initial_size = length;
int res;
int res, fake_dot_dot = 1;
char *data, local_buffer[8192];
struct dirent *de;
FILE_BOTH_DIR_INFORMATION *info, *last_info = NULL, *restart_last_info = NULL;
......@@ -1178,10 +1217,53 @@ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buff
de = (struct dirent *)data;
if (restart_scan)
{
/* check if we got . and .. from getdirentries */
if (res > 0)
{
if (!strcmp( de->d_name, "." ) && res > de->d_reclen)
{
struct dirent *next_de = (struct dirent *)(data + de->d_reclen);
if (!strcmp( next_de->d_name, ".." )) fake_dot_dot = 0;
}
}
/* make sure we have enough room for both entries */
if (fake_dot_dot)
{
static const ULONG min_info_size = (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName[1]) +
FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName[2]) + 3) & ~3;
if (length < min_info_size || single_entry)
{
FIXME( "not enough room %u/%u for fake . and .. entries\n", length, single_entry );
fake_dot_dot = 0;
}
}
if (fake_dot_dot)
{
if ((info = append_entry( buffer, &io->Information, length, ".", NULL, mask )))
last_info = info;
if ((info = append_entry( buffer, &io->Information, length, "..", NULL, mask )))
last_info = info;
restart_last_info = last_info;
restart_info_pos = io->Information;
/* check if we still have enough space for the largest possible entry */
if (last_info && io->Information + max_dir_info_size > length)
{
lseek( fd, 0, SEEK_SET ); /* reset pos to first entry */
res = 0;
}
}
}
while (res > 0)
{
res -= de->d_reclen;
if (de->d_fileno &&
!(fake_dot_dot && (!strcmp( de->d_name, "." ) || !strcmp( de->d_name, ".." ))) &&
((info = append_entry( buffer, &io->Information, length, de->d_name, NULL, mask ))))
{
last_info = info;
......@@ -1266,7 +1348,7 @@ static void read_directory_readdir( int fd, IO_STATUS_BLOCK *io, void *buffer, U
{
old_pos = lseek( fd, 0, SEEK_CUR );
/* skip the right number of entries */
for (i = 0; i < old_pos; i++)
for (i = 0; i < old_pos - 2; i++)
{
if (!readdir( dir ))
{
......@@ -1278,10 +1360,22 @@ static void read_directory_readdir( int fd, IO_STATUS_BLOCK *io, void *buffer, U
}
io->u.Status = STATUS_SUCCESS;
while ((de = readdir( dir )))
for (;;)
{
if (old_pos == 0)
info = append_entry( buffer, &io->Information, length, ".", NULL, mask );
else if (old_pos == 1)
info = append_entry( buffer, &io->Information, length, "..", NULL, mask );
else if ((de = readdir( dir )))
{
if (strcmp( de->d_name, "." ) && strcmp( de->d_name, ".." ))
info = append_entry( buffer, &io->Information, length, de->d_name, NULL, mask );
else
info = NULL;
}
else
break;
old_pos++;
info = append_entry( buffer, &io->Information, length, de->d_name, NULL, mask );
if (info)
{
last_info = info;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment