Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/file.c | 31 ++++++++++++++++++++++--------- include/winternl.h | 2 +- 2 files changed, 23 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index d4bc712d9d3..7b2e102e536 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -136,8 +136,15 @@ static inline ULONG get_file_attributes( const struct stat *st ) return attr; }
+static BOOL fd_is_mount_point( int fd, const struct stat *st ) +{ + struct stat parent; + return S_ISDIR( st->st_mode ) && !fstatat( fd, "..", &parent, 0 ) + && (parent.st_dev != st->st_dev || parent.st_ino == st->st_ino); +} + /* 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 fd_get_file_info( int fd, unsigned int options, struct stat *st, ULONG *attr ) { int ret;
@@ -145,6 +152,9 @@ int fd_get_file_info( int fd, struct stat *st, ULONG *attr ) ret = fstat( fd, st ); if (ret == -1) return ret; *attr |= get_file_attributes( st ); + /* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */ + if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, st )) + *attr |= FILE_ATTRIBUTE_REPARSE_POINT; return ret; }
@@ -2318,6 +2328,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, struct stat st; int fd, needs_close = FALSE; ULONG attr; + unsigned int options;
TRACE("(%p,%p,%p,0x%08x,0x%08x)\n", hFile, io, ptr, len, class);
@@ -2330,7 +2341,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, if (len < info_sizes[class]) return io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
- if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, NULL ))) + if ((io->u.Status = server_get_unix_fd( hFile, 0, &fd, &needs_close, NULL, &options ))) { if (io->u.Status != STATUS_BAD_DEVICE_TYPE) return io->u.Status; return server_get_file_info( hFile, io, ptr, len, class ); @@ -2339,7 +2350,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, switch (class) { case FileBasicInformation: - if (fd_get_file_info( fd, &st, &attr ) == -1) + if (fd_get_file_info( fd, options, &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; @@ -2350,7 +2361,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, { FILE_STANDARD_INFORMATION *info = ptr;
- if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); + if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); else { fill_file_info( &st, attr, info, class ); @@ -2367,7 +2378,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, } break; case FileInternalInformation: - if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); + if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); else fill_file_info( &st, attr, ptr, class ); break; case FileEaInformation: @@ -2377,7 +2388,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, } break; case FileEndOfFileInformation: - if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); + if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); else fill_file_info( &st, attr, ptr, class ); break; case FileAllInformation: @@ -2385,7 +2396,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, FILE_ALL_INFORMATION *info = ptr; ANSI_STRING unix_name;
- if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); + if (fd_get_file_info( fd, options, &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 ))) @@ -2493,7 +2504,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, } break; case FileIdInformation: - if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); + if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); else { FILE_ID_INFORMATION *info = ptr; @@ -2503,12 +2514,14 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io, } break; case FileAttributeTagInformation: - if (fd_get_file_info( fd, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); + if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = FILE_GetNtStatus(); else { FILE_ATTRIBUTE_TAG_INFORMATION *info = ptr; info->FileAttributes = attr; info->ReparseTag = 0; /* FIXME */ + if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, &st )) + info->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; } break; default: diff --git a/include/winternl.h b/include/winternl.h index d9809c7ad31..19e8965e99f 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1795,7 +1795,7 @@ typedef struct _RTL_HANDLE_TABLE #define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 #define FILE_NO_COMPRESSION 0x00008000 #define FILE_RESERVE_OPFILTER 0x00100000 -#define FILE_TRANSACTED_MODE 0x00200000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 #define FILE_OPEN_OFFLINE_FILE 0x00400000 #define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000