diff --git a/daemon/from_kernel.h b/daemon/from_kernel.h index fbd5c85..eb8d164 100644 --- a/daemon/from_kernel.h +++ b/daemon/from_kernel.h @@ -207,6 +207,35 @@ typedef enum _FSINFOCLASS { FileFsMaximumInformation } FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; +/* ntifs.h */ +#define FILE_CASE_SENSITIVE_SEARCH 0x00000001 +#define FILE_CASE_PRESERVED_NAMES 0x00000002 +#define FILE_UNICODE_ON_DISK 0x00000004 +#define FILE_PERSISTENT_ACLS 0x00000008 +#define FILE_FILE_COMPRESSION 0x00000010 +#define FILE_VOLUME_QUOTAS 0x00000020 +#define FILE_SUPPORTS_SPARSE_FILES 0x00000040 +#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080 +#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100 +#define FILE_VOLUME_IS_COMPRESSED 0x00008000 +#define FILE_SUPPORTS_OBJECT_IDS 0x00010000 +#define FILE_SUPPORTS_ENCRYPTION 0x00020000 +#define FILE_NAMED_STREAMS 0x00040000 +#define FILE_READ_ONLY_VOLUME 0x00080000 +#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000 +#define FILE_SUPPORTS_TRANSACTIONS 0x00200000 +#define FILE_SUPPORTS_HARD_LINKS 0x00400000 +#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000 +#define FILE_SUPPORTS_OPEN_BY_FILE_ID 0x01000000 +#define FILE_SUPPORTS_USN_JOURNAL 0x02000000 + +typedef struct _FILE_FS_ATTRIBUTE_INFORMATION { + ULONG FileSystemAttributes; + LONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[1]; +} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; + /* ntddk.h */ typedef struct _FILE_FS_SIZE_INFORMATION { LARGE_INTEGER TotalAllocationUnits; diff --git a/daemon/nfs41_const.h b/daemon/nfs41_const.h index 0201269..0a74cad 100644 --- a/daemon/nfs41_const.h +++ b/daemon/nfs41_const.h @@ -41,8 +41,11 @@ #define UPCALL_BUF_SIZE 1024 -/* see MaximumComponentNameLength in FileFsAttributeInformation - * in nfs41_driver.c:nfs41_QueryVolumeInformation() */ +/* FileSystemName reported for FileFsAttributeInformation */ +#define NFS41_FILESYSTEM_NAME L"NFS" +#define NFS41_FILESYSTEM_NAME_LEN (sizeof(NFS41_FILESYSTEM_NAME)-sizeof(WCHAR)) + +/* MaximumComponentNameLength reported for FileFsAttributeInformation */ #define NFS41_MAX_COMPONENT_LEN 64 #define NFS41_MAX_PATH_LEN MAX_PATH diff --git a/daemon/nfs41_types.h b/daemon/nfs41_types.h index b0e1fd4..a3a238e 100644 --- a/daemon/nfs41_types.h +++ b/daemon/nfs41_types.h @@ -180,6 +180,8 @@ typedef struct __nfs41_file_info { uint32_t lease_time; /* XXX: per-server */ uint32_t fs_layout_types; /* pnfs, XXX: per-fs */ bool_t hidden; + bool_t case_insensitive; + bool_t case_preserving; } nfs41_file_info; #endif /* !__NFS41_DAEMON_TYPES_H__ */ diff --git a/daemon/nfs41_xdr.c b/daemon/nfs41_xdr.c index 2fd2634..2642f2e 100644 --- a/daemon/nfs41_xdr.c +++ b/daemon/nfs41_xdr.c @@ -1546,6 +1546,14 @@ static bool_t decode_file_attrs( if (!xdr_u_int32_t(xdr, &info->rdattr_error)) return FALSE; } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_CASE_INSENSITIVE) { + if (!xdr_bool(xdr, &info->case_insensitive)) + return FALSE; + } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_CASE_PRESERVING) { + if (!xdr_bool(xdr, &info->case_preserving)) + return FALSE; + } if (attrs->attrmask.arr[0] & FATTR4_WORD0_FILEID) { if (!xdr_u_hyper(xdr, &info->fileid)) return FALSE; diff --git a/daemon/upcall.h b/daemon/upcall.h index 1118394..40f62f9 100644 --- a/daemon/upcall.h +++ b/daemon/upcall.h @@ -140,6 +140,13 @@ typedef struct __volume_upcall_args { union { FILE_FS_SIZE_INFORMATION size; FILE_FS_FULL_SIZE_INFORMATION fullsize; + FILE_FS_ATTRIBUTE_INFORMATION attribute; + + /* attribute.FileSystemName is WCHAR[1], so even though there's + * some extra space in the union from other members, reserve + * enough space for an arbitrary NFS41_FILESYSTEM_NAME_LEN */ + unsigned char buffer[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + + NFS41_FILESYSTEM_NAME_LEN]; } info; } volume_upcall_args; diff --git a/daemon/volume.c b/daemon/volume.c index 9a9e8e6..064b95d 100644 --- a/daemon/volume.c +++ b/daemon/volume.c @@ -22,6 +22,7 @@ */ #include +#include #include #include "nfs41_ops.h" @@ -88,6 +89,59 @@ out: return status; } +static int handle_volume_attributes( + IN nfs41_session *session, + IN volume_upcall_args *args) +{ + /* query the case_ attributes of the root filesystem */ + nfs41_file_info info = { 0 }; + bitmap4 attr_request = { 1, { FATTR4_WORD0_CASE_INSENSITIVE | + FATTR4_WORD0_CASE_PRESERVING } }; + PFILE_FS_ATTRIBUTE_INFORMATION attr = &args->info.attribute; + size_t max_length; + int status = NO_ERROR; + + status = nfs41_getattr(session, NULL, &attr_request, &info); + if (status) { + eprintf("nfs41_getattr() failed with %s\n", + nfs_error_string(status)); + status = nfs_to_windows_error(status, ERROR_BAD_NET_RESP); + goto out; + } + + attr->FileSystemAttributes = FILE_SUPPORTS_REMOTE_STORAGE; + if (info.case_preserving) + attr->FileSystemAttributes |= FILE_CASE_PRESERVED_NAMES; + if (!info.case_insensitive) + attr->FileSystemAttributes |= FILE_CASE_SENSITIVE_SEARCH; + + attr->MaximumComponentNameLength = NFS41_MAX_COMPONENT_LEN; + + /* calculate how much space we have for FileSystemName; args.info.buffer + * should guarantee us enough room for NFS41_FILESYSTEM_NAME */ + max_length = sizeof(args->info) - + FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName); + + if (FAILED(StringCbCopyNW(attr->FileSystemName, max_length, + NFS41_FILESYSTEM_NAME, NFS41_FILESYSTEM_NAME_LEN))) { + status = ERROR_BUFFER_OVERFLOW; + eprintf("FileSystemName '%S' truncated to '%S'! returning %d\n", + NFS41_FILESYSTEM_NAME, attr->FileSystemName, status); + goto out; + } + + attr->FileSystemNameLength = NFS41_FILESYSTEM_NAME_LEN; + args->len = sizeof(args->info.attribute) + NFS41_FILESYSTEM_NAME_LEN; + + dprintf(2, "FileFsAttributeInformation: case_preserving %u, " + "case_insensitive %u, max component %u, name '%S', length %u\n", + info.case_preserving, info.case_insensitive, + attr->MaximumComponentNameLength, + attr->FileSystemName, attr->FileSystemNameLength); +out: + return status; +} + int handle_volume(nfs41_upcall *upcall) { volume_upcall_args *args = &upcall->args.volume; @@ -117,6 +171,10 @@ int handle_volume(nfs41_upcall *upcall) &args->info.fullsize.ActualAvailableAllocationUnits.QuadPart); break; + case FileFsAttributeInformation: + status = handle_volume_attributes(session, args); + break; + default: eprintf("unhandled fs query class %d\n", args->query); status = ERROR_INVALID_PARAMETER;