From: "Erich E. Hoover" Subject: ntdll: Unify retrieving the attributes of a file. Message-Id: Date: Mon, 15 Dec 2014 14:44:22 -0700 Currently, everywhere that needs to return FILE_INFORMATION_CLASS attributes has to call stat and then apply the flags FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_READONLY, and FILE_ATTRIBUTE_REPARSE_POINT manually. This patch consolidates all of these manual applications into fd_get_file_info (fstat) and get_file_info (stat/lstat).
Currently, everywhere that needs to return FILE_INFORMATION_CLASS attributes has to call stat and then apply the flags FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_READONLY, and FILE_ATTRIBUTE_REPARSE_POINT manually.  This patch consolidates all of these manual applications into fd_get_file_info (fstat) and get_file_info (stat/lstat).
From 08bb6ac76dc83588ec798d1dce6e27ce5fffbaf0 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Tue, 19 Aug 2014 20:31:00 -0600 Subject: ntdll: Unify retrieving the attributes of a file. --- dlls/ntdll/directory.c | 12 ++---- dlls/ntdll/file.c | 107 ++++++++++++++++++++++++++++++++++-------------- dlls/ntdll/ntdll_misc.h | 4 +- 3 files changed, 83 insertions(+), 40 deletions(-) diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index 9b5852a..9b10385 100644 --- a/dlls/ntdll/directory.c +++ b/dlls/ntdll/directory.c @@ -1381,7 +1381,7 @@ static union file_directory_info *append_entry( void *info_ptr, IO_STATUS_BLOCK WCHAR short_nameW[12]; WCHAR *filename; UNICODE_STRING str; - ULONG attributes = 0; + ULONG attributes; io->u.Status = STATUS_SUCCESS; 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 (lstat( long_name, &st ) == -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 (get_file_info( long_name, &st, &attributes ) == -1) return NULL; if (is_ignored_file( &st )) { 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); 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 */ - fill_stat_info( &st, info, class ); + fill_file_info( &st, attributes, info, class ); info->dir.NextEntryOffset = total_len; info->dir.FileIndex = 0; /* NTFS always has 0 here, so let's not bother with it */ - info->dir.FileAttributes |= attributes; switch (class) { diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 56ea398..1a69648 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -103,6 +103,55 @@ mode_t FILE_umask = 0; 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; + /* convert the Unix stat info into file attributes */ + *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; + /* stat the file and don't follow symbol links */ + ret = lstat( path, st ); + if (ret == -1) return ret; + if (S_ISLNK( st->st_mode )) + { + /* stat the file but follow symbol links */ + 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; + } + /* convert the Unix stat info into file attributes */ + *attr |= get_file_attributes( st ); + return ret; +} + /************************************************************************** * FILE_CreateFile (internal) * Open a file. @@ -1774,8 +1823,9 @@ static inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime, #endif } -/* fill in the file information that depends on the stat info */ -NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLASS class ) +/* fill in the file information that depends on the stat and attribute info */ +NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr, + FILE_INFORMATION_CLASS class ) { switch (class) { @@ -1785,10 +1835,7 @@ NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLAS get_file_times( st, &info->LastWriteTime, &info->ChangeTime, &info->LastAccessTime, &info->CreationTime ); - if (S_ISDIR(st->st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; - else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE; - if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) - info->FileAttributes |= FILE_ATTRIBUTE_READONLY; + info->FileAttributes = attr; } break; case FileStandardInformation: @@ -1824,9 +1871,9 @@ NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLAS case FileAllInformation: { FILE_ALL_INFORMATION *info = ptr; - fill_stat_info( st, &info->BasicInformation, FileBasicInformation ); - fill_stat_info( st, &info->StandardInformation, FileStandardInformation ); - fill_stat_info( st, &info->InternalInformation, FileInternalInformation ); + fill_file_info( st, attr, &info->BasicInformation, FileBasicInformation ); + fill_file_info( st, attr, &info->StandardInformation, FileStandardInformation ); + fill_file_info( st, attr, &info->InternalInformation, FileInternalInformation ); } break; /* all directory structures start with the FileDirectoryInformation layout */ @@ -1842,30 +1889,27 @@ NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLAS { info->AllocationSize.QuadPart = 0; info->EndOfFile.QuadPart = 0; - info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; } else { info->AllocationSize.QuadPart = (ULONGLONG)st->st_blocks * 512; info->EndOfFile.QuadPart = st->st_size; - info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE; } - if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) - info->FileAttributes |= FILE_ATTRIBUTE_READONLY; + info->FileAttributes = attr; } break; case FileIdFullDirectoryInformation: { FILE_ID_FULL_DIRECTORY_INFORMATION *info = ptr; info->FileId.QuadPart = st->st_ino; - fill_stat_info( st, info, FileDirectoryInformation ); + fill_file_info( st, attr, info, FileDirectoryInformation ); } break; case FileIdBothDirectoryInformation: { FILE_ID_BOTH_DIRECTORY_INFORMATION *info = ptr; info->FileId.QuadPart = st->st_ino; - fill_stat_info( st, info, FileDirectoryInformation ); + fill_file_info( st, attr, info, FileDirectoryInformation ); } break; @@ -2017,6 +2061,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, struct stat st; int fd, needs_close = FALSE; + ULONG attr; TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class); @@ -2041,21 +2086,21 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, switch (class) { case FileBasicInformation: - if (fstat( fd, &st ) == -1) + 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)) io->u.Status = STATUS_INVALID_INFO_CLASS; else - fill_stat_info( &st, ptr, class ); + fill_file_info( &st, attr, ptr, class ); break; case FileStandardInformation: { 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 { - fill_stat_info( &st, info, class ); + fill_file_info( &st, attr, info, class ); info->DeletePending = FALSE; /* FIXME */ } } @@ -2069,8 +2114,8 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, } break; case FileInternalInformation: - if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); - else fill_stat_info( &st, ptr, class ); + if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); + else fill_file_info( &st, attr, ptr, class ); break; case FileEaInformation: { @@ -2079,22 +2124,22 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, } break; case FileEndOfFileInformation: - if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus(); - else fill_stat_info( &st, ptr, class ); + if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); + else fill_file_info( &st, attr, ptr, class ); break; case FileAllInformation: { FILE_ALL_INFORMATION *info = ptr; 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)) io->u.Status = STATUS_INVALID_INFO_CLASS; else if (!(io->u.Status = server_get_unix_name( hFile, &unix_name ))) { 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->EaInformation.EaSize = 0; info->AccessInformation.AccessFlags = 0; /* FIXME */ @@ -2445,9 +2490,10 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN ))) { + ULONG attributes; struct stat st; - if (stat( unix_name.Buffer, &st ) == -1) + if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1) status = FILE_GetNtStatus(); else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) status = STATUS_INVALID_INFO_CLASS; @@ -2456,8 +2502,8 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC_INFORMATION basic; FILE_STANDARD_INFORMATION std; - fill_stat_info( &st, &basic, FileBasicInformation ); - fill_stat_info( &st, &std, FileStandardInformation ); + fill_file_info( &st, attributes, &basic, FileBasicInformation ); + fill_file_info( &st, attributes, &std, FileStandardInformation ); info->CreationTime = basic.CreationTime; info->LastAccessTime = basic.LastAccessTime; @@ -2487,15 +2533,16 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC if (!(status = nt_to_unix_file_name_attr( attr, &unix_name, FILE_OPEN ))) { + ULONG attributes; struct stat st; - if (stat( unix_name.Buffer, &st ) == -1) + if (get_file_info( unix_name.Buffer, &st, &attributes ) == -1) status = FILE_GetNtStatus(); else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) status = STATUS_INVALID_INFO_CLASS; else { - status = fill_stat_info( &st, info, FileBasicInformation ); + status = fill_file_info( &st, attributes, info, FileBasicInformation ); if (DIR_is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index aac9320..b7ea6dc 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -148,7 +148,9 @@ extern NTSTATUS COMM_FlushBuffersFile( int fd ) DECLSPEC_HIDDEN; /* file I/O */ struct stat; 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 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; -- 1.9.1