ntdll: Unify retrieving the attributes of a file.

This commit is contained in:
Erich E. Hoover 2014-08-19 20:31:00 -06:00 committed by Alexandre Julliard
parent 1f7683777b
commit ca51e113e4
3 changed files with 79 additions and 40 deletions

View File

@ -1381,7 +1381,7 @@ static union file_directory_info *append_entry( void *info_ptr, IO_STATUS_BLOCK
WCHAR short_nameW[12]; WCHAR short_nameW[12];
WCHAR *filename; WCHAR *filename;
UNICODE_STRING str; UNICODE_STRING str;
ULONG attributes = 0; ULONG attributes;
io->u.Status = STATUS_SUCCESS; io->u.Status = STATUS_SUCCESS;
long_len = ntdll_umbstowcs( 0, long_name, strlen(long_name), long_nameW, MAX_DIR_ENTRY_LEN ); long_len = ntdll_umbstowcs( 0, long_name, strlen(long_name), long_nameW, MAX_DIR_ENTRY_LEN );
@ -1418,12 +1418,7 @@ static union file_directory_info *append_entry( void *info_ptr, IO_STATUS_BLOCK
if (!match_filename( &str, mask )) return NULL; if (!match_filename( &str, mask )) return NULL;
} }
if (lstat( long_name, &st ) == -1) return NULL; if (get_file_info( long_name, &st, &attributes ) == -1) return NULL;
if (S_ISLNK( st.st_mode ))
{
if (stat( long_name, &st ) == -1) return NULL;
if (S_ISDIR( st.st_mode )) attributes |= FILE_ATTRIBUTE_REPARSE_POINT;
}
if (is_ignored_file( &st )) if (is_ignored_file( &st ))
{ {
TRACE( "ignoring file %s\n", long_name ); TRACE( "ignoring file %s\n", long_name );
@ -1441,10 +1436,9 @@ static union file_directory_info *append_entry( void *info_ptr, IO_STATUS_BLOCK
info = (union file_directory_info *)((char *)info_ptr + io->Information); 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 */ if (st.st_dev != curdir.dev) st.st_ino = 0; /* ignore inode if on a different device */
/* all the structures start with a FileDirectoryInformation layout */ /* all the structures start with a FileDirectoryInformation layout */
fill_stat_info( &st, info, class ); fill_file_info( &st, attributes, info, class );
info->dir.NextEntryOffset = total_len; info->dir.NextEntryOffset = total_len;
info->dir.FileIndex = 0; /* NTFS always has 0 here, so let's not bother with it */ info->dir.FileIndex = 0; /* NTFS always has 0 here, so let's not bother with it */
info->dir.FileAttributes |= attributes;
switch (class) switch (class)
{ {

View File

@ -103,6 +103,51 @@ mode_t FILE_umask = 0;
static const WCHAR ntfsW[] = {'N','T','F','S'}; static const WCHAR ntfsW[] = {'N','T','F','S'};
/* fetch the attributes of a file */
static inline ULONG get_file_attributes( const struct stat *st )
{
ULONG attr;
if (S_ISDIR(st->st_mode))
attr = FILE_ATTRIBUTE_DIRECTORY;
else
attr = FILE_ATTRIBUTE_ARCHIVE;
if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
attr |= FILE_ATTRIBUTE_READONLY;
return attr;
}
/* get the stat info and file attributes for a file (by file descriptor) */
int fd_get_file_info( int fd, struct stat *st, ULONG *attr )
{
int ret;
*attr = 0;
ret = fstat( fd, st );
if (ret == -1) return ret;
*attr |= get_file_attributes( st );
return ret;
}
/* get the stat info and file attributes for a file (by name) */
int get_file_info( const char *path, struct stat *st, ULONG *attr )
{
int ret;
*attr = 0;
ret = lstat( path, st );
if (ret == -1) return ret;
if (S_ISLNK( st->st_mode ))
{
ret = stat( path, st );
if (ret == -1) return ret;
/* is a symbolic link and a directory, consider these "reparse points" */
if (S_ISDIR( st->st_mode )) *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
}
*attr |= get_file_attributes( st );
return ret;
}
/************************************************************************** /**************************************************************************
* FILE_CreateFile (internal) * FILE_CreateFile (internal)
* Open a file. * Open a file.
@ -1774,8 +1819,9 @@ static inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime,
#endif #endif
} }
/* fill in the file information that depends on the stat info */ /* fill in the file information that depends on the stat and attribute info */
NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLASS class ) NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
FILE_INFORMATION_CLASS class )
{ {
switch (class) switch (class)
{ {
@ -1785,10 +1831,7 @@ NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLAS
get_file_times( st, &info->LastWriteTime, &info->ChangeTime, get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
&info->LastAccessTime, &info->CreationTime ); &info->LastAccessTime, &info->CreationTime );
if (S_ISDIR(st->st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; info->FileAttributes = attr;
else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
} }
break; break;
case FileStandardInformation: case FileStandardInformation:
@ -1824,9 +1867,9 @@ NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLAS
case FileAllInformation: case FileAllInformation:
{ {
FILE_ALL_INFORMATION *info = ptr; FILE_ALL_INFORMATION *info = ptr;
fill_stat_info( st, &info->BasicInformation, FileBasicInformation ); fill_file_info( st, attr, &info->BasicInformation, FileBasicInformation );
fill_stat_info( st, &info->StandardInformation, FileStandardInformation ); fill_file_info( st, attr, &info->StandardInformation, FileStandardInformation );
fill_stat_info( st, &info->InternalInformation, FileInternalInformation ); fill_file_info( st, attr, &info->InternalInformation, FileInternalInformation );
} }
break; break;
/* all directory structures start with the FileDirectoryInformation layout */ /* all directory structures start with the FileDirectoryInformation layout */
@ -1842,30 +1885,27 @@ NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLAS
{ {
info->AllocationSize.QuadPart = 0; info->AllocationSize.QuadPart = 0;
info->EndOfFile.QuadPart = 0; info->EndOfFile.QuadPart = 0;
info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
} }
else else
{ {
info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512; info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512;
info->EndOfFile.QuadPart = st->st_size; info->EndOfFile.QuadPart = st->st_size;
info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
} }
if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) info->FileAttributes = attr;
info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
} }
break; break;
case FileIdFullDirectoryInformation: case FileIdFullDirectoryInformation:
{ {
FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr; FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr;
info->FileId.QuadPart = st->st_ino; info->FileId.QuadPart = st->st_ino;
fill_stat_info( st, info, FileDirectoryInformation ); fill_file_info( st, attr, info, FileDirectoryInformation );
} }
break; break;
case FileIdBothDirectoryInformation: case FileIdBothDirectoryInformation:
{ {
FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr; FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr;
info->FileId.QuadPart = st->st_ino; info->FileId.QuadPart = st->st_ino;
fill_stat_info( st, info, FileDirectoryInformation ); fill_file_info( st, attr, info, FileDirectoryInformation );
} }
break; break;
@ -2017,6 +2057,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
struct stat st; struct stat st;
int fd, needs_close = FALSE; int fd, needs_close = FALSE;
ULONG attr;
TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class); TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
@ -2041,21 +2082,21 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
switch (class) switch (class)
{ {
case FileBasicInformation: case FileBasicInformation:
if (fstat( fd, &st ) == -1) if (fd_get_file_info( fd, &st, &attr ) == -1)
io->u.Status = FILE_GetNtStatus(); io->u.Status = FILE_GetNtStatus();
else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
io->u.Status = STATUS_INVALID_INFO_CLASS; io->u.Status = STATUS_INVALID_INFO_CLASS;
else else
fill_stat_info( &st, ptr, class ); fill_file_info( &st, attr, ptr, class );
break; break;
case FileStandardInformation: case FileStandardInformation:
{ {
FILE_STANDARD_INFORMATION *info = ptr; FILE_STANDARD_INFORMATION *info = ptr;
if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else else
{ {
fill_stat_info( &st, info, class ); fill_file_info( &st, attr, info, class );
info->DeletePending = FALSE; /* FIXME */ info->DeletePending = FALSE; /* FIXME */
} }
} }
@ -2069,8 +2110,8 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
} }
break; break;
case FileInternalInformation: case FileInternalInformation:
if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else fill_stat_info( &st, ptr, class ); else fill_file_info( &st, attr, ptr, class );
break; break;
case FileEaInformation: case FileEaInformation:
{ {
@ -2079,22 +2120,22 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
} }
break; break;
case FileEndOfFileInformation: case FileEndOfFileInformation:
if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else fill_stat_info( &st, ptr, class ); else fill_file_info( &st, attr, ptr, class );
break; break;
case FileAllInformation: case FileAllInformation:
{ {
FILE_ALL_INFORMATION *info = ptr; FILE_ALL_INFORMATION *info = ptr;
ANSI_STRING unix_name; ANSI_STRING unix_name;
if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus();
else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
io->u.Status = STATUS_INVALID_INFO_CLASS; io->u.Status = STATUS_INVALID_INFO_CLASS;
else if (!(io->u.Status = server_get_unix_name( hFile, &unix_name ))) else if (!(io->u.Status = server_get_unix_name( hFile, &unix_name )))
{ {
LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName); LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
fill_stat_info( &st, info, FileAllInformation ); fill_file_info( &st, attr, info, FileAllInformation );
info->StandardInformation.DeletePending = FALSE; /* FIXME */ info->StandardInformation.DeletePending = FALSE; /* FIXME */
info->EaInformation.EaSize = 0; info->EaInformation.EaSize = 0;
info->AccessInformation.AccessFlags = 0; /* FIXME */ info->AccessInformation.AccessFlags = 0; /* FIXME */
@ -2445,9 +2486,10 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN ))) if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
{ {
ULONG attributes;
struct stat st; struct stat st;
if (stat( unix_name.Buffer, &st ) == -1) if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
status = FILE_GetNtStatus(); status = FILE_GetNtStatus();
else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
status = STATUS_INVALID_INFO_CLASS; status = STATUS_INVALID_INFO_CLASS;
@ -2456,8 +2498,8 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr,
FILE_BASIC_INFORMATION basic; FILE_BASIC_INFORMATION basic;
FILE_STANDARD_INFORMATION std; FILE_STANDARD_INFORMATION std;
fill_stat_info( &st, &basic, FileBasicInformation ); fill_file_info( &st, attributes, &basic, FileBasicInformation );
fill_stat_info( &st, &std, FileStandardInformation ); fill_file_info( &st, attributes, &std, FileStandardInformation );
info->CreationTime = basic.CreationTime; info->CreationTime = basic.CreationTime;
info->LastAccessTime = basic.LastAccessTime; info->LastAccessTime = basic.LastAccessTime;
@ -2487,15 +2529,16 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC
if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN ))) if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN )))
{ {
ULONG attributes;
struct stat st; struct stat st;
if (stat( unix_name.Buffer, &st ) == -1) if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1)
status = FILE_GetNtStatus(); status = FILE_GetNtStatus();
else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
status = STATUS_INVALID_INFO_CLASS; status = STATUS_INVALID_INFO_CLASS;
else else
{ {
status = fill_stat_info( &st, info, FileBasicInformation ); status = fill_file_info( &st, attributes, info, FileBasicInformation );
if (DIR_is_hidden_file( attr->ObjectName )) if (DIR_is_hidden_file( attr->ObjectName ))
info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
} }

View File

@ -148,7 +148,9 @@ extern NTSTATUS COMM_FlushBuffersFile( int fd ) DECLSPEC_HIDDEN;
/* file I/O */ /* file I/O */
struct stat; struct stat;
extern NTSTATUS FILE_GetNtStatus(void) DECLSPEC_HIDDEN; extern NTSTATUS FILE_GetNtStatus(void) DECLSPEC_HIDDEN;
extern NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLASS class ) DECLSPEC_HIDDEN; extern int get_file_info( const char *path, struct stat *st, ULONG *attr ) DECLSPEC_HIDDEN;
extern NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
FILE_INFORMATION_CLASS class ) DECLSPEC_HIDDEN;
extern NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name ) DECLSPEC_HIDDEN; extern NTSTATUS server_get_unix_name( HANDLE handle, ANSI_STRING *unix_name ) DECLSPEC_HIDDEN;
extern void DIR_init_windows_dir( const WCHAR *windir, const WCHAR *sysdir ) DECLSPEC_HIDDEN; extern void DIR_init_windows_dir( const WCHAR *windir, const WCHAR *sysdir ) DECLSPEC_HIDDEN;
extern BOOL DIR_is_hidden_file( const UNICODE_STRING *name ) DECLSPEC_HIDDEN; extern BOOL DIR_is_hidden_file( const UNICODE_STRING *name ) DECLSPEC_HIDDEN;