From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/ntdll/unix/file.c | 52 ++++++++++++++++++++++++++++++++++++------ include/winternl.h | 20 ++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 5cabb6c37ff..f6a6c93e036 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -200,6 +200,7 @@ union file_directory_info FILE_BOTH_DIRECTORY_INFORMATION both; FILE_FULL_DIRECTORY_INFORMATION full; FILE_ID_BOTH_DIRECTORY_INFORMATION id_both; + FILE_ID_EXTD_BOTH_DIRECTORY_INFORMATION extd_both; FILE_ID_FULL_DIRECTORY_INFORMATION id_full; FILE_ID_GLOBAL_TX_DIR_INFORMATION id_tx; FILE_NAMES_INFORMATION names; @@ -314,6 +315,8 @@ static inline unsigned int dir_info_size( FILE_INFORMATION_CLASS class, unsigned return offsetof( FILE_FULL_DIRECTORY_INFORMATION, FileName[len] ); case FileIdBothDirectoryInformation: return offsetof( FILE_ID_BOTH_DIRECTORY_INFORMATION, FileName[len] ); + case FileIdExtdBothDirectoryInformation: + return offsetof( FILE_ID_EXTD_BOTH_DIRECTORY_INFORMATION, FileName[len] ); case FileIdFullDirectoryInformation: return offsetof( FILE_ID_FULL_DIRECTORY_INFORMATION, FileName[len] ); case FileIdGlobalTxDirectoryInformation: @@ -1767,7 +1770,7 @@ static NTSTATUS fd_set_file_info( int fd, UINT attr, BOOL force_set_xattr )
/* get the stat info and file attributes for a file (by name) */ -static int get_file_info( const char *path, struct stat *st, ULONG *attr ) +static int get_file_info( const char *path, struct stat *st, ULONG *attr, ULONG *reparse_tag ) { size_t len = strlen( path ); char *parent_path; @@ -1782,7 +1785,11 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) 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; + if (S_ISDIR( st->st_mode )) + { + *attr |= FILE_ATTRIBUTE_REPARSE_POINT; + if (reparse_tag) *reparse_tag = IO_REPARSE_TAG_SYMLINK; + } } else if (S_ISDIR( st->st_mode ) && (parent_path = malloc( len + 4 ))) { @@ -1793,14 +1800,29 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) strcat( parent_path, "/.." ); if (!stat( parent_path, &parent_st ) && (st->st_dev != parent_st.st_dev || st->st_ino == parent_st.st_ino)) + { *attr |= FILE_ATTRIBUTE_REPARSE_POINT; + if (reparse_tag) *reparse_tag = IO_REPARSE_TAG_MOUNT_POINT; + }
free( parent_path ); } *attr |= get_file_attributes( st );
- if (path[len - 1] == '?') + if ((attr_len = xattr_get( path, XATTR_REPARSE, NULL, 0 )) > 0) + { + REPARSE_DATA_BUFFER *buffer; + *attr |= FILE_ATTRIBUTE_REPARSE_POINT; + if (reparse_tag && (buffer = malloc( attr_len ))) + { + if (xattr_get( path, XATTR_REPARSE, buffer, attr_len ) == attr_len) + *reparse_tag = buffer->ReparseTag; + else + ERR( "failed to read, errno %d\n", errno ); + free( buffer ); + } + }
attr_len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, attr_data, sizeof(attr_data)-1 ); if (attr_len != -1) @@ -2068,6 +2090,13 @@ static NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr, fill_file_info( st, attr, info, FileDirectoryInformation ); } break; + case FileIdExtdBothDirectoryInformation: + { + FILE_ID_EXTD_BOTH_DIRECTORY_INFORMATION *info = ptr; + *(ULONGLONG *)&info->FileId = st->st_ino; + fill_file_info( st, attr, info, FileDirectoryInformation ); + } + break; case FileIdGlobalTxDirectoryInformation: { FILE_ID_GLOBAL_TX_DIR_INFORMATION *info = ptr; @@ -2402,9 +2431,9 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I const struct dir_data_names *names = &dir_data->names[dir_data->pos]; union file_directory_info *info; struct stat st; - ULONG name_len, start, dir_size, attributes; + ULONG name_len, start, dir_size, attributes, reparse_tag;
- if (get_file_info( names->unix_name, &st, &attributes ) == -1) + if (get_file_info( names->unix_name, &st, &attributes, &reparse_tag ) == -1) { TRACE( "file no longer exists %s\n", debugstr_a(names->unix_name) ); return STATUS_SUCCESS; @@ -2464,6 +2493,14 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I info->id_both.FileNameLength = name_len; break;
+ case FileIdExtdBothDirectoryInformation: + info->extd_both.EaSize = 0; /* FIXME */ + info->extd_both.ReparsePointTag = reparse_tag; + info->extd_both.ShortNameLength = wcslen( names->short_name ) * sizeof(WCHAR); + memcpy( info->extd_both.ShortName, names->short_name, info->extd_both.ShortNameLength ); + info->extd_both.FileNameLength = name_len; + break; + case FileIdGlobalTxDirectoryInformation: info->id_tx.TxInfoFlags = 0; info->id_tx.FileNameLength = name_len; @@ -2847,6 +2884,7 @@ NTSTATUS WINAPI NtQueryDirectoryFile( HANDLE handle, HANDLE event, PIO_APC_ROUTI case FileBothDirectoryInformation: case FileFullDirectoryInformation: case FileIdBothDirectoryInformation: + case FileIdExtdBothDirectoryInformation: case FileIdFullDirectoryInformation: case FileIdGlobalTxDirectoryInformation: case FileNamesInformation: @@ -4793,7 +4831,7 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, ULONG attributes; struct stat st;
- if (get_file_info( unix_name, &st, &attributes ) == -1) + if (get_file_info( unix_name, &st, &attributes, NULL ) == -1) status = errno_to_status( errno ); else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) status = STATUS_INVALID_INFO_CLASS; @@ -4822,7 +4860,7 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC ULONG attributes; struct stat st;
- if (get_file_info( unix_name, &st, &attributes ) == -1) + if (get_file_info( unix_name, &st, &attributes, NULL ) == -1) status = errno_to_status( errno ); else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) status = STATUS_INVALID_INFO_CLASS; diff --git a/include/winternl.h b/include/winternl.h index d5f761fe0ec..c9e5d8528df 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1798,6 +1798,26 @@ typedef struct _FILE_IO_COMPLETION_NOTIFICATION_INFORMATION { #define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2 #define FILE_SKIP_SET_USER_EVENT_ON_FAST_IO 0x4
+typedef struct _FILE_ID_EXTD_BOTH_DIRECTORY_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + ULONG ReparsePointTag; + FILE_ID_128 FileId; + CHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[ANYSIZE_ARRAY]; +} FILE_ID_EXTD_BOTH_DIRECTORY_INFORMATION, *PFILE_ID_EXTD_BOTH_DIRECTORY_INFORMATION; + #ifdef __WINESRC__ /* data for WineFileUnixNameInformation */ typedef struct