Commit 7e656318 authored by Alexandre Julliard's avatar Alexandre Julliard

Added support for restarting directory scans on platforms where

seekdir return values cannot be reused on a different directory object. Added some checks for invalid file names in DIR_nt_to_unix.
parent 017438cd
...@@ -76,14 +76,22 @@ typedef struct ...@@ -76,14 +76,22 @@ typedef struct
# define O_DIRECTORY 0200000 /* must be directory */ # define O_DIRECTORY 0200000 /* must be directory */
#endif #endif
/* Using the same seekdir value across multiple directories is not portable, */
/* but it works on Linux, and it's a major performance gain so we want to use */
/* it if possible. */
/* FIXME: do some sort of runtime check instead */
#define USE_SEEKDIR
#else /* linux */ #else /* linux */
#undef VFAT_IOCTL_READDIR_BOTH /* just in case... */ #undef VFAT_IOCTL_READDIR_BOTH /* just in case... */
#undef USE_SEEKDIR
#endif /* linux */ #endif /* linux */
#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1') #define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
#define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/') #define IS_SEPARATOR(ch) ((ch) == '\\' || (ch) == '/')
#define INVALID_DOS_CHARS '*','?','<','>','|','"','+','=',',',';','[',']',' ','\345' #define INVALID_NT_CHARS '*','?','<','>','|','"'
#define INVALID_DOS_CHARS INVALID_NT_CHARS,'+','=',',',';','[',']',' ','\345'
#define MAX_DIR_ENTRY_LEN 255 /* max length of a directory entry in chars */ #define MAX_DIR_ENTRY_LEN 255 /* max length of a directory entry in chars */
...@@ -104,6 +112,35 @@ static CRITICAL_SECTION chdir_section = { &critsect_debug, -1, 0, 0, 0, 0 }; ...@@ -104,6 +112,35 @@ static CRITICAL_SECTION chdir_section = { &critsect_debug, -1, 0, 0, 0, 0 };
/*********************************************************************** /***********************************************************************
* seekdir_wrapper
*
* Wrapper for supporting seekdir across multiple directory objects.
*/
static inline void seekdir_wrapper( DIR *dir, off_t pos )
{
#ifdef USE_SEEKDIR
seekdir( dir, pos );
#else
while (pos-- > 0) if (!readdir( dir )) break;
#endif
}
/***********************************************************************
* telldir_wrapper
*
* Wrapper for supporting telldir across multiple directory objects.
*/
static inline off_t telldir_wrapper( DIR *dir, off_t pos, int count )
{
#ifdef USE_SEEKDIR
return telldir( dir );
#else
return pos + count;
#endif
}
/***********************************************************************
* init_options * init_options
* *
* Initialize the show_dir_symlinks and show_dot_files options. * Initialize the show_dir_symlinks and show_dot_files options.
...@@ -521,7 +558,7 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event, ...@@ -521,7 +558,7 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
if (!restart_scan) if (!restart_scan)
{ {
old_pos = lseek( fd, 0, SEEK_CUR ); old_pos = lseek( fd, 0, SEEK_CUR );
seekdir( dir, old_pos ); seekdir_wrapper( dir, old_pos );
} }
io->u.Status = STATUS_SUCCESS; io->u.Status = STATUS_SUCCESS;
...@@ -537,16 +574,18 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event, ...@@ -537,16 +574,18 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
if ((char *)info->FileName + info->FileNameLength > (char *)buffer + length) if ((char *)info->FileName + info->FileNameLength > (char *)buffer + length)
io->u.Status = STATUS_BUFFER_OVERFLOW; io->u.Status = STATUS_BUFFER_OVERFLOW;
else else
old_pos = telldir( dir ); old_pos = telldir_wrapper( dir, old_pos, 1 );
break; break;
} }
old_pos = telldir( dir ); old_pos = telldir_wrapper( dir, old_pos, 1 );
} }
} }
else /* we'll only return full entries, no need to worry about overflow */ else /* we'll only return full entries, no need to worry about overflow */
{ {
int count = 0;
while ((de = readdir( dir ))) while ((de = readdir( dir )))
{ {
count++;
info = append_entry( buffer, &io->Information, length, info = append_entry( buffer, &io->Information, length,
de->d_name, NULL, mask ); de->d_name, NULL, mask );
if (info) if (info)
...@@ -557,7 +596,7 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event, ...@@ -557,7 +596,7 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event,
if (io->Information + max_dir_info_size > length) break; if (io->Information + max_dir_info_size > length) break;
} }
} }
old_pos = telldir( dir ); old_pos = telldir_wrapper( dir, old_pos, count );
} }
lseek( fd, old_pos, SEEK_SET ); /* store dir offset as filepos for fd */ lseek( fd, old_pos, SEEK_SET ); /* store dir offset as filepos for fd */
closedir( dir ); closedir( dir );
...@@ -747,9 +786,12 @@ static inline int get_dos_prefix_len( const UNICODE_STRING *name ) ...@@ -747,9 +786,12 @@ static inline int get_dos_prefix_len( const UNICODE_STRING *name )
NTSTATUS DIR_nt_to_unix( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret, NTSTATUS DIR_nt_to_unix( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret,
int check_last, int check_case ) int check_last, int check_case )
{ {
static const WCHAR uncW[] = {'U','N','C','\\'};
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 };
NTSTATUS status = STATUS_NO_SUCH_FILE; NTSTATUS status = STATUS_NO_SUCH_FILE;
const char *config_dir = wine_get_config_dir(); const char *config_dir = wine_get_config_dir();
const WCHAR *end, *name; const WCHAR *end, *name, *p;
struct stat st; struct stat st;
char *unix_name; char *unix_name;
int pos, ret, name_len, unix_len, used_default; int pos, ret, name_len, unix_len, used_default;
...@@ -757,14 +799,30 @@ NTSTATUS DIR_nt_to_unix( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret ...@@ -757,14 +799,30 @@ NTSTATUS DIR_nt_to_unix( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret
name = nameW->Buffer; name = nameW->Buffer;
name_len = nameW->Length / sizeof(WCHAR); name_len = nameW->Length / sizeof(WCHAR);
if (!name_len || !IS_SEPARATOR(name[0])) return STATUS_OBJECT_PATH_SYNTAX_BAD;
if ((pos = get_dos_prefix_len( nameW ))) if ((pos = get_dos_prefix_len( nameW )))
{ {
name += pos; name += pos;
name_len -= pos; name_len -= pos;
/* check for UNC prefix */
if (name_len > 4 && !memicmpW( name, uncW, 4 ))
{
FIXME( "UNC name %s not supported\n", debugstr_us(nameW) );
return STATUS_NO_SUCH_FILE;
}
/* make sure we have a drive letter */
if (name_len < 3 || !isalphaW(name[0]) || name[1] != ':' || !IS_SEPARATOR(name[2])) if (name_len < 3 || !isalphaW(name[0]) || name[1] != ':' || !IS_SEPARATOR(name[2]))
return STATUS_NO_SUCH_FILE; return STATUS_NO_SUCH_FILE;
name += 2; /* skip drive letter */ name += 2; /* skip drive letter */
name_len -= 2; name_len -= 2;
/* check for invalid characters */
for (p = name; p < name + name_len; p++)
if (*p < 32 || strchrW( invalid_charsW, *p )) return STATUS_OBJECT_NAME_INVALID;
unix_len = ntdll_wcstoumbs( 0, name, name_len, NULL, 0, NULL, NULL ); unix_len = ntdll_wcstoumbs( 0, name, name_len, NULL, 0, NULL, NULL );
unix_len += MAX_DIR_ENTRY_LEN + 3; unix_len += MAX_DIR_ENTRY_LEN + 3;
unix_len += strlen(config_dir) + sizeof("/dosdevices/a:"); unix_len += strlen(config_dir) + sizeof("/dosdevices/a:");
......
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