[PATCH 1/4] ntdll: Make append_entry fail if the new entry doesn't fit.
Matteo Bruni
mbruni at codeweavers.com
Thu Aug 27 14:08:38 CDT 2015
Instead of checking in each helper if there is space for the largest
possible entry just handle append_entry() failure accordingly.
Not sure what's the deal with the "partial" entries mentioned in some
helpers, I couldn't find anything in my tests.
---
dlls/ntdll/directory.c | 195 ++++++++++++++++++++++---------------------------
1 file changed, 87 insertions(+), 108 deletions(-)
diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index 0e02f2e..f9562d2 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -246,11 +246,6 @@ static inline unsigned int dir_info_size( FILE_INFORMATION_CLASS class, unsigned
}
}
-static inline unsigned int max_dir_info_size( FILE_INFORMATION_CLASS class )
-{
- return dir_info_size( class, MAX_DIR_ENTRY_LEN );
-}
-
static inline BOOL has_wildcard( const UNICODE_STRING *mask )
{
return (!mask ||
@@ -1432,8 +1427,8 @@ static union file_directory_info *append_entry( void *info_ptr, IO_STATUS_BLOCK
total_len = dir_info_size( class, long_len );
if (io->Information + total_len > max_length)
{
- total_len = max_length - io->Information;
io->u.Status = STATUS_BUFFER_OVERFLOW;
+ return NULL;
}
info = (union file_directory_info *)((char *)info_ptr + io->Information);
if (st.st_dev != curdir.dev) st.st_ino = 0; /* ignore inode if on a different device */
@@ -1542,69 +1537,48 @@ static int read_directory_vfat( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG
size_t len;
KERNEL_DIRENT *de;
union file_directory_info *info, *last_info = NULL;
+ off_t old_pos;
io->u.Status = STATUS_SUCCESS;
if (restart_scan) lseek( fd, 0, SEEK_SET );
- if (length < max_dir_info_size(class)) /* we may have to return a partial entry here */
- {
- off_t old_pos = lseek( fd, 0, SEEK_CUR );
-
- if (!(de = start_vfat_ioctl( fd ))) return -1; /* not supported */
+ old_pos = lseek( fd, 0, SEEK_CUR );
- while (de[0].d_reclen)
- {
- /* make sure names are null-terminated to work around an x86-64 kernel bug */
- len = min(de[0].d_reclen, sizeof(de[0].d_name) - 1 );
- de[0].d_name[len] = 0;
- len = min(de[1].d_reclen, sizeof(de[1].d_name) - 1 );
- de[1].d_name[len] = 0;
+ if (!(de = start_vfat_ioctl( fd ))) return -1; /* not supported */
- if (de[1].d_name[0])
- info = append_entry( buffer, io, length, de[1].d_name, de[0].d_name, mask, class );
- else
- info = append_entry( buffer, io, length, de[0].d_name, NULL, mask, class );
- if (info)
- {
- last_info = info;
- if (io->u.Status == STATUS_BUFFER_OVERFLOW)
- lseek( fd, old_pos, SEEK_SET ); /* restore pos to previous entry */
- break;
- }
- old_pos = lseek( fd, 0, SEEK_CUR );
- if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) == -1) break;
- }
- }
- else /* we'll only return full entries, no need to worry about overflow */
+ while (de[0].d_reclen)
{
- if (!(de = start_vfat_ioctl( fd ))) return -1; /* not supported */
+ /* make sure names are null-terminated to work around an x86-64 kernel bug */
+ len = min(de[0].d_reclen, sizeof(de[0].d_name) - 1 );
+ de[0].d_name[len] = 0;
+ len = min(de[1].d_reclen, sizeof(de[1].d_name) - 1 );
+ de[1].d_name[len] = 0;
- while (de[0].d_reclen)
+ if (de[1].d_name[0])
+ info = append_entry( buffer, io, length, de[1].d_name, de[0].d_name, mask, class );
+ else
+ info = append_entry( buffer, io, length, de[0].d_name, NULL, mask, class );
+ if (info)
{
- /* make sure names are null-terminated to work around an x86-64 kernel bug */
- len = min(de[0].d_reclen, sizeof(de[0].d_name) - 1 );
- de[0].d_name[len] = 0;
- len = min(de[1].d_reclen, sizeof(de[1].d_name) - 1 );
- de[1].d_name[len] = 0;
-
- if (de[1].d_name[0])
- info = append_entry( buffer, io, length, de[1].d_name, de[0].d_name, mask, class );
- else
- info = append_entry( buffer, io, length, de[0].d_name, NULL, mask, class );
- if (info)
- {
- last_info = info;
- if (single_entry) break;
- /* check if we still have enough space for the largest possible entry */
- if (io->Information + max_dir_info_size(class) > length) break;
- }
- if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) == -1) break;
+ last_info = info;
+ if (single_entry) break;
}
+ else if (io->u.Status == STATUS_BUFFER_OVERFLOW)
+ {
+ lseek( fd, old_pos, SEEK_SET ); /* restore pos to previous entry */
+ if (last_info)
+ io->u.Status = STATUS_SUCCESS;
+ break;
+ }
+ old_pos = lseek( fd, 0, SEEK_CUR );
+ if (ioctl( fd, VFAT_IOCTL_READDIR_BOTH, (long)de ) == -1) break;
}
- if (last_info) last_info->next = 0;
- else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
+ if (last_info)
+ last_info->next = 0;
+ else if (io->u.Status != STATUS_BUFFER_OVERFLOW)
+ io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
return 0;
}
#endif /* VFAT_IOCTL_READDIR_BOTH */
@@ -1749,15 +1723,14 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U
if (filename && (info = append_entry( buffer, io, length, filename, NULL, mask, class )))
{
last_info = info;
+ }
+ else if (filename)
+ {
if (io->u.Status == STATUS_BUFFER_OVERFLOW)
{
lseek( fd, old_pos, SEEK_SET ); /* restore pos to previous entry */
- break;
- }
- /* check if we still have enough space for the largest possible entry */
- if (single_entry || io->Information + max_dir_info_size(class) > length)
- {
- if (res > 0) lseek( fd, next_pos, SEEK_SET ); /* set pos to next entry */
+ if (last_info)
+ io->u.Status = STATUS_SUCCESS;
break;
}
}
@@ -1772,8 +1745,10 @@ static int read_directory_getdents( int fd, IO_STATUS_BLOCK *io, void *buffer, U
}
}
- if (last_info) last_info->next = 0;
- else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
+ if (last_info)
+ last_info->next = 0;
+ else if (io->u.Status != STATUS_BUFFER_OVERFLOW)
+ io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
res = 0;
done:
if (data != local_buffer) RtlFreeHeap( GetProcessHeap(), 0, data );
@@ -1906,13 +1881,6 @@ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buff
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(class) > length)
- {
- lseek( fd, 0, SEEK_SET ); /* reset pos to first entry */
- res = 0;
- }
}
}
@@ -1920,36 +1888,41 @@ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buff
{
res -= dir_reclen(de);
if (de->d_fileno &&
- !(fake_dot_dot && (!strcmp( de->d_name, "." ) || !strcmp( de->d_name, ".." ))) &&
- ((info = append_entry( buffer, io, length, de->d_name, NULL, mask, class ))))
+ !(fake_dot_dot && (!strcmp( de->d_name, "." ) || !strcmp( de->d_name, ".." ))))
{
- last_info = info;
- if (io->u.Status == STATUS_BUFFER_OVERFLOW)
+ if ((info = append_entry( buffer, io, length, de->d_name, NULL, mask, class )))
{
- lseek( fd, (unsigned long)restart_pos, SEEK_SET );
- if (restart_info_pos) /* if we have a complete read already, return it */
+ last_info = info;
+ if (!has_wildcard( mask )) break;
+ /* if we have to return but the buffer contains more data, restart with a smaller size */
+ if (res > 0 && (single_entry || io->Information + max_dir_info_size(class) > length))
{
- io->u.Status = STATUS_SUCCESS;
+ lseek( fd, (unsigned long)restart_pos, SEEK_SET );
+ size = (char *)de + dir_reclen(de) - data;
io->Information = restart_info_pos;
last_info = restart_last_info;
- break;
+ goto restart;
}
- /* otherwise restart from the start with a smaller size */
- size = (char *)de - data;
- if (!size) break;
- io->Information = 0;
- last_info = NULL;
- goto restart;
}
- if (!has_wildcard( mask )) break;
- /* if we have to return but the buffer contains more data, restart with a smaller size */
- if (res > 0 && (single_entry || io->Information + max_dir_info_size(class) > length))
+ else
{
- lseek( fd, (unsigned long)restart_pos, SEEK_SET );
- size = (char *)de + dir_reclen(de) - data;
- io->Information = restart_info_pos;
- last_info = restart_last_info;
- goto restart;
+ if (io->u.Status == STATUS_BUFFER_OVERFLOW)
+ {
+ lseek( fd, (unsigned long)restart_pos, SEEK_SET );
+ if (restart_info_pos) /* if we have a complete read already, return it */
+ {
+ io->u.Status = STATUS_SUCCESS;
+ io->Information = restart_info_pos;
+ last_info = restart_last_info;
+ break;
+ }
+ /* otherwise restart from the start with a smaller size */
+ size = (char *)de - data;
+ if (!size) break;
+ io->Information = 0;
+ last_info = NULL;
+ goto restart;
+ }
}
}
/* move on to the next entry */
@@ -1966,8 +1939,10 @@ static int read_directory_getdirentries( int fd, IO_STATUS_BLOCK *io, void *buff
de = (struct dirent *)data;
}
- if (last_info) last_info->next = 0;
- else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
+ if (last_info)
+ last_info->next = 0;
+ else if (io->u.Status != STATUS_BUFFER_OVERFLOW)
+ io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
res = 0;
done:
if (data != local_buffer) RtlFreeHeap( GetProcessHeap(), 0, data );
@@ -2037,22 +2012,24 @@ static void read_directory_readdir( int fd, IO_STATUS_BLOCK *io, void *buffer, U
if (info)
{
last_info = info;
- if (io->u.Status == STATUS_BUFFER_OVERFLOW)
- {
- old_pos--; /* restore pos to previous entry */
- break;
- }
if (single_entry) break;
- /* check if we still have enough space for the largest possible entry */
- if (io->Information + max_dir_info_size(class) > length) break;
+ }
+ else if (io->u.Status == STATUS_BUFFER_OVERFLOW)
+ {
+ old_pos--; /* restore pos to previous entry */
+ if (last_info)
+ io->u.Status = STATUS_SUCCESS;
+ break;
}
}
lseek( fd, old_pos, SEEK_SET ); /* store dir offset as filepos for fd */
closedir( dir );
- if (last_info) last_info->next = 0;
- else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
+ if (last_info)
+ last_info->next = 0;
+ else if (io->u.Status != STATUS_BUFFER_OVERFLOW)
+ io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
}
/***********************************************************************
@@ -2101,9 +2078,10 @@ static int read_directory_stat( int fd, IO_STATUS_BLOCK *io, void *buffer, ULONG
if (info)
{
info->next = 0;
- if (io->u.Status != STATUS_BUFFER_OVERFLOW) lseek( fd, 1, SEEK_CUR );
+ lseek( fd, 1, SEEK_CUR );
}
- else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
+ else if (io->u.Status != STATUS_BUFFER_OVERFLOW)
+ io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
}
else if (!case_sensitive && ret && (errno == ENOENT || errno == ENOTDIR))
{
@@ -2195,9 +2173,10 @@ static int read_directory_getattrlist( int fd, IO_STATUS_BLOCK *io, void *buffer
if (info)
{
info->next = 0;
- if (io->u.Status != STATUS_BUFFER_OVERFLOW) lseek( fd, 1, SEEK_CUR );
+ lseek( fd, 1, SEEK_CUR );
}
- else io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
+ else if (io->u.Status != STATUS_BUFFER_OVERFLOW)
+ io->u.Status = restart_scan ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES;
}
else if ((errno == ENOENT || errno == ENOTDIR) && !get_dir_case_sensitivity("."))
{
--
2.4.6
More information about the wine-patches
mailing list