sys: IRP_MJ_SET_VOLUME_INFORMATION/FileFsLabelInformation

This commit is contained in:
Bill Zissimopoulos 2016-02-17 10:27:09 -08:00
parent 003e9a6d91
commit 49cf687de3
7 changed files with 272 additions and 10 deletions

View File

@ -219,6 +219,17 @@ typedef struct
} Rename; } Rename;
} Info; } Info;
} SetInformation; } SetInformation;
struct
{
UINT32 FsInformationClass;
union
{
struct
{
FSP_FSCTL_TRANSACT_BUF VolumeLabel;
} Label;
} Info;
} SetVolumeInformation;
} Req; } Req;
FSP_FSCTL_TRANSACT_BUF FileName; /* {Create,Cleanup,SetInformation/{Disposition,Rename}} */ FSP_FSCTL_TRANSACT_BUF FileName; /* {Create,Cleanup,SetInformation/{Disposition,Rename}} */
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[]; FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
@ -268,6 +279,10 @@ typedef struct
{ {
FSP_FSCTL_VOLUME_INFO VolumeInfo; FSP_FSCTL_VOLUME_INFO VolumeInfo;
} QueryVolumeInformation; } QueryVolumeInformation;
struct
{
FSP_FSCTL_VOLUME_INFO VolumeInfo;
} SetVolumeInformation;
} Rsp; } Rsp;
FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[]; FSP_FSCTL_DECLSPEC_ALIGN UINT8 Buffer[];
} FSP_FSCTL_TRANSACT_RSP; } FSP_FSCTL_TRANSACT_RSP;

View File

@ -38,6 +38,10 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
NTSTATUS (*GetVolumeInfo)(FSP_FILE_SYSTEM *FileSystem, NTSTATUS (*GetVolumeInfo)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_REQ *Request,
FSP_FSCTL_VOLUME_INFO *VolumeInfo); FSP_FSCTL_VOLUME_INFO *VolumeInfo);
NTSTATUS (*SetVolumeLabel)(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PWSTR VolumeLabel,
FSP_FSCTL_VOLUME_INFO *VolumeInfo);
NTSTATUS (*GetSecurity)(FSP_FILE_SYSTEM *FileSystem, NTSTATUS (*GetSecurity)(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, PUINT32 PFileAttributes, PWSTR FileName, PUINT32 PFileAttributes,
PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize); PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize);
@ -180,6 +184,8 @@ FSP_API NTSTATUS FspFileSystemOpSetInformation(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
FSP_API NTSTATUS FspFileSystemOpQueryVolumeInformation(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemOpQueryVolumeInformation(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response); FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
FSP_API NTSTATUS FspFileSystemOpSetVolumeInformation(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response);
static inline static inline
NTSTATUS FspAccessCheck(FSP_FILE_SYSTEM *FileSystem, NTSTATUS FspAccessCheck(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_REQ *Request,

View File

@ -47,6 +47,7 @@ FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
FileSystem->Operations[FspFsctlTransactQueryInformationKind] = FspFileSystemOpQueryInformation; FileSystem->Operations[FspFsctlTransactQueryInformationKind] = FspFileSystemOpQueryInformation;
FileSystem->Operations[FspFsctlTransactSetInformationKind] = FspFileSystemOpSetInformation; FileSystem->Operations[FspFsctlTransactSetInformationKind] = FspFileSystemOpSetInformation;
FileSystem->Operations[FspFsctlTransactQueryVolumeInformationKind] = FspFileSystemOpQueryVolumeInformation; FileSystem->Operations[FspFsctlTransactQueryVolumeInformationKind] = FspFileSystemOpQueryVolumeInformation;
FileSystem->Operations[FspFsctlTransactSetVolumeInformationKind] = FspFileSystemOpSetVolumeInformation;
// !!!: ... // !!!: ...
FileSystem->Interface = Interface; FileSystem->Interface = Interface;

View File

@ -23,3 +23,27 @@ FSP_API NTSTATUS FspFileSystemOpQueryVolumeInformation(FSP_FILE_SYSTEM *FileSyst
memcpy(&Response->Rsp.QueryVolumeInformation.VolumeInfo, &VolumeInfo, sizeof VolumeInfo); memcpy(&Response->Rsp.QueryVolumeInformation.VolumeInfo, &VolumeInfo, sizeof VolumeInfo);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
FSP_API NTSTATUS FspFileSystemOpSetVolumeInformation(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{
NTSTATUS Result;
FSP_FSCTL_VOLUME_INFO VolumeInfo;
Result = STATUS_INVALID_DEVICE_REQUEST;
memset(&VolumeInfo, 0, sizeof VolumeInfo);
switch (Request->Req.SetVolumeInformation.FsInformationClass)
{
case 2/*FileFsLabelInformation*/:
if (0 != FileSystem->Interface->SetVolumeLabel)
Result = FileSystem->Interface->SetVolumeLabel(FileSystem, Request,
(PWSTR)Request->Buffer,
&VolumeInfo);
}
if (!NT_SUCCESS(Result))
return Result;
memcpy(&Response->Rsp.SetVolumeInformation.VolumeInfo, &VolumeInfo, sizeof VolumeInfo);
return STATUS_SUCCESS;
}

View File

@ -22,6 +22,9 @@ static NTSTATUS FspFsvolQueryFsVolumeInformation(
static NTSTATUS FspFsvolQueryVolumeInformation( static NTSTATUS FspFsvolQueryVolumeInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolQueryVolumeInformationComplete; FSP_IOCMPL_DISPATCH FspFsvolQueryVolumeInformationComplete;
static NTSTATUS FspFsvolSetFsLabelInformation(
PDEVICE_OBJECT FsvolDeviceObject, PVOID Buffer, ULONG Length, PULONG PRequestExtraSize,
FSP_FSCTL_TRANSACT_REQ *Request, const FSP_FSCTL_TRANSACT_RSP *Response);
static NTSTATUS FspFsvolSetVolumeInformation( static NTSTATUS FspFsvolSetVolumeInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
FSP_IOCMPL_DISPATCH FspFsvolSetVolumeInformationComplete; FSP_IOCMPL_DISPATCH FspFsvolSetVolumeInformationComplete;
@ -36,6 +39,7 @@ FSP_DRIVER_DISPATCH FspSetVolumeInformation;
#pragma alloc_text(PAGE, FspFsvolQueryFsVolumeInformation) #pragma alloc_text(PAGE, FspFsvolQueryFsVolumeInformation)
#pragma alloc_text(PAGE, FspFsvolQueryVolumeInformation) #pragma alloc_text(PAGE, FspFsvolQueryVolumeInformation)
#pragma alloc_text(PAGE, FspFsvolQueryVolumeInformationComplete) #pragma alloc_text(PAGE, FspFsvolQueryVolumeInformationComplete)
#pragma alloc_text(PAGE, FspFsvolSetFsLabelInformation)
#pragma alloc_text(PAGE, FspFsvolSetVolumeInformation) #pragma alloc_text(PAGE, FspFsvolSetVolumeInformation)
#pragma alloc_text(PAGE, FspFsvolSetVolumeInformationComplete) #pragma alloc_text(PAGE, FspFsvolSetVolumeInformationComplete)
#pragma alloc_text(PAGE, FspQueryVolumeInformation) #pragma alloc_text(PAGE, FspQueryVolumeInformation)
@ -293,12 +297,83 @@ NTSTATUS FspFsvolQueryVolumeInformationComplete(
FsInformationClassSym(IrpSp->Parameters.QueryVolume.FsInformationClass)); FsInformationClassSym(IrpSp->Parameters.QueryVolume.FsInformationClass));
} }
static NTSTATUS FspFsvolSetVolumeInformation( static NTSTATUS FspFsvolSetFsLabelInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp) PDEVICE_OBJECT FsvolDeviceObject, PVOID Buffer, ULONG Length, PULONG PRequestExtraSize,
FSP_FSCTL_TRANSACT_REQ *Request, const FSP_FSCTL_TRANSACT_RSP *Response)
{ {
PAGED_CODE(); PAGED_CODE();
return STATUS_INVALID_DEVICE_REQUEST; if (0 == Request)
{
if (sizeof(FILE_FS_LABEL_INFORMATION) > Length)
return STATUS_INVALID_PARAMETER;
PFILE_FS_LABEL_INFORMATION Info = (PFILE_FS_LABEL_INFORMATION)Buffer;
*PRequestExtraSize = Info->VolumeLabelLength + sizeof(WCHAR);
}
else if (0 == Response)
{
PFILE_FS_LABEL_INFORMATION Info = (PFILE_FS_LABEL_INFORMATION)Buffer;
Request->Req.SetVolumeInformation.Info.Label.VolumeLabel.Offset = 0;
Request->Req.SetVolumeInformation.Info.Label.VolumeLabel.Size =
(UINT16)(Info->VolumeLabelLength + sizeof(WCHAR));
RtlCopyMemory(Request->Buffer, Info->VolumeLabel, Info->VolumeLabelLength);
((PWSTR)Request->Buffer)[Info->VolumeLabelLength / sizeof(WCHAR)] = L'\0';
}
else
FspFsvolSetVolumeInfo(FsvolDeviceObject, &Response->Rsp.SetVolumeInformation.VolumeInfo);
return STATUS_SUCCESS;
}
static NTSTATUS FspFsvolSetVolumeInformation(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
NTSTATUS Result;
FS_INFORMATION_CLASS FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass;
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
ULONG Length = IrpSp->Parameters.SetVolume.Length;
ULONG RequestExtraSize = 0;
switch (FsInformationClass)
{
case FileFsLabelInformation:
Result = FspFsvolSetFsLabelInformation(FsvolDeviceObject, Buffer, Length, &RequestExtraSize, 0, 0);
break;
default:
Result = STATUS_INVALID_PARAMETER;
break;
}
if (!NT_SUCCESS(Result))
return Result;
FSP_FSCTL_TRANSACT_REQ *Request;
Result = FspIopCreateRequest(Irp, 0, RequestExtraSize, &Request);
if (!NT_SUCCESS(Result))
return Result;
Request->Kind = FspFsctlTransactSetVolumeInformationKind;
Request->Req.SetVolumeInformation.FsInformationClass = FsInformationClass;
switch (FsInformationClass)
{
case FileFsLabelInformation:
Result = FspFsvolSetFsLabelInformation(FsvolDeviceObject, Buffer, Length, 0, Request, 0);
break;
default:
ASSERT(0);
Result = STATUS_INVALID_PARAMETER;
break;
}
if (!NT_SUCCESS(Result))
return Result;
return FSP_STATUS_IOQ_POST;
} }
NTSTATUS FspFsvolSetVolumeInformationComplete( NTSTATUS FspFsvolSetVolumeInformationComplete(
@ -306,6 +381,32 @@ NTSTATUS FspFsvolSetVolumeInformationComplete(
{ {
FSP_ENTER_IOC(PAGED_CODE()); FSP_ENTER_IOC(PAGED_CODE());
if (!NT_SUCCESS(Response->IoStatus.Status))
{
Irp->IoStatus.Information = 0;
Result = Response->IoStatus.Status;
FSP_RETURN();
}
FS_INFORMATION_CLASS FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass;
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject;
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
ULONG Length = IrpSp->Parameters.SetFile.Length;
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
switch (FsInformationClass)
{
case FileFsLabelInformation:
Result = FspFsvolSetFsLabelInformation(FsvolDeviceObject, Buffer, Length, 0, Request, Response);
break;
default:
ASSERT(0);
Result = STATUS_INVALID_PARAMETER;
break;
}
Irp->IoStatus.Information = 0;
FSP_LEAVE_IOC("%s", FSP_LEAVE_IOC("%s",
FsInformationClassSym(IrpSp->Parameters.SetVolume.FsInformationClass)); FsInformationClassSym(IrpSp->Parameters.SetVolume.FsInformationClass));
} }

View File

@ -459,6 +459,98 @@ void getvolinfo_test(void)
} }
} }
void setvolinfo_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout)
{
if (-1 == Flags)
return;/* avoid accidentally changing the volume label on our NTFS disk */
if (0 != Prefix)
return;/* cannot do SetVolumeLabel on a network share! */
void *memfs = memfs_start_ex(Flags, FileInfoTimeout);
BOOL Success;
WCHAR FilePath[MAX_PATH];
WCHAR VolumeLabelBuf[MAX_PATH];
DWORD VolumeSerialNumber;
DWORD MaxComponentLength;
DWORD FileSystemFlags;
WCHAR FileSystemNameBuf[MAX_PATH];
StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\",
Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs));
Success = SetVolumeLabelW(FilePath, L"12345678901234567890123456789012");
ASSERT(Success);
Success = GetVolumeInformationW(FilePath,
VolumeLabelBuf, sizeof VolumeLabelBuf,
&VolumeSerialNumber, &MaxComponentLength, &FileSystemFlags,
FileSystemNameBuf, sizeof FileSystemNameBuf);
ASSERT(Success);
if (-1 != Flags)
{
ASSERT(0 == wcscmp(VolumeLabelBuf, L"12345678901234567890123456789012"));
ASSERT(255 == MaxComponentLength);
ASSERT(0 != (FileSystemFlags &
(FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_PERSISTENT_ACLS)));
ASSERT(0 == wcscmp(FileSystemNameBuf, L"WinFsp"));
}
Success = SetVolumeLabelW(FilePath, L"TestLabel");
ASSERT(Success);
Success = GetVolumeInformationW(FilePath,
VolumeLabelBuf, sizeof VolumeLabelBuf,
&VolumeSerialNumber, &MaxComponentLength, &FileSystemFlags,
FileSystemNameBuf, sizeof FileSystemNameBuf);
ASSERT(Success);
if (-1 != Flags)
{
ASSERT(0 == wcscmp(VolumeLabelBuf, L"TestLabel"));
ASSERT(255 == MaxComponentLength);
ASSERT(0 != (FileSystemFlags &
(FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_PERSISTENT_ACLS)));
ASSERT(0 == wcscmp(FileSystemNameBuf, L"WinFsp"));
}
Success = SetVolumeLabelW(FilePath, L"123456789012345678901234567890123");
ASSERT(Success);
Success = GetVolumeInformationW(FilePath,
VolumeLabelBuf, sizeof VolumeLabelBuf,
&VolumeSerialNumber, &MaxComponentLength, &FileSystemFlags,
FileSystemNameBuf, sizeof FileSystemNameBuf);
ASSERT(Success);
if (-1 != Flags)
{
ASSERT(0 == wcscmp(VolumeLabelBuf, L"12345678901234567890123456789012"));
ASSERT(255 == MaxComponentLength);
ASSERT(0 != (FileSystemFlags &
(FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_PERSISTENT_ACLS)));
ASSERT(0 == wcscmp(FileSystemNameBuf, L"WinFsp"));
}
memfs_stop(memfs);
}
void setvolinfo_test(void)
{
#if 0
if (NtfsTests)
setvolinfo_dotest(-1, L"C:", 0);
#endif
if (WinFspDiskTests)
{
setvolinfo_dotest(MemfsDisk, 0, 0);
setvolinfo_dotest(MemfsDisk, 0, 1000);
}
if (WinFspNetTests)
{
setvolinfo_dotest(MemfsNet, L"\\\\memfs\\share", 0);
setvolinfo_dotest(MemfsNet, L"\\\\memfs\\share", 1000);
}
}
void info_tests(void) void info_tests(void)
{ {
TEST(getfileinfo_test); TEST(getfileinfo_test);
@ -466,4 +558,5 @@ void info_tests(void)
TEST(delete_test); TEST(delete_test);
TEST(rename_test); TEST(rename_test);
TEST(getvolinfo_test); TEST(getvolinfo_test);
TEST(setvolinfo_test);
} }

View File

@ -51,6 +51,8 @@ typedef struct _MEMFS
MEMFS_FILE_NODE_MAP *FileNodeMap; MEMFS_FILE_NODE_MAP *FileNodeMap;
ULONG MaxFileNodes; ULONG MaxFileNodes;
ULONG MaxFileSize; ULONG MaxFileSize;
UINT16 VolumeLabelLength;
WCHAR VolumeLabel[32];
CRITICAL_SECTION Lock; CRITICAL_SECTION Lock;
} MEMFS; } MEMFS;
@ -196,17 +198,33 @@ static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_VOLUME_INFO *VolumeInfo) FSP_FSCTL_VOLUME_INFO *VolumeInfo)
{ {
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext; MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
MEMFS_FILE_NODE *RootNode;
RootNode = MemfsFileNodeMapGet(Memfs->FileNodeMap, L"\\");
if (0 == RootNode)
return STATUS_DISK_CORRUPT_ERROR;
VolumeInfo->TotalSize = Memfs->MaxFileNodes * Memfs->MaxFileSize; VolumeInfo->TotalSize = Memfs->MaxFileNodes * Memfs->MaxFileSize;
VolumeInfo->FreeSize = VolumeInfo->FreeSize =
(Memfs->MaxFileNodes - MemfsFileNodeMapCount(Memfs->FileNodeMap)) * Memfs->MaxFileSize; (Memfs->MaxFileNodes - MemfsFileNodeMapCount(Memfs->FileNodeMap)) * Memfs->MaxFileSize;
VolumeInfo->VolumeLabelLength = sizeof L"MEMFS" - sizeof(WCHAR); VolumeInfo->VolumeLabelLength = Memfs->VolumeLabelLength;
memcpy(VolumeInfo->VolumeLabel, L"MEMFS", VolumeInfo->VolumeLabelLength); memcpy(VolumeInfo->VolumeLabel, Memfs->VolumeLabel, Memfs->VolumeLabelLength);
return STATUS_SUCCESS;
}
static NTSTATUS SetVolumeLabel(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request,
PWSTR VolumeLabel,
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
{
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
Memfs->VolumeLabelLength = (UINT16)(wcslen(VolumeLabel) * sizeof(WCHAR));
if (Memfs->VolumeLabelLength > sizeof Memfs->VolumeLabel)
Memfs->VolumeLabelLength = sizeof Memfs->VolumeLabel;
memcpy(Memfs->VolumeLabel, VolumeLabel, Memfs->VolumeLabelLength);
VolumeInfo->TotalSize = Memfs->MaxFileNodes * Memfs->MaxFileSize;
VolumeInfo->FreeSize =
(Memfs->MaxFileNodes - MemfsFileNodeMapCount(Memfs->FileNodeMap)) * Memfs->MaxFileSize;
VolumeInfo->VolumeLabelLength = Memfs->VolumeLabelLength;
memcpy(VolumeInfo->VolumeLabel, Memfs->VolumeLabel, Memfs->VolumeLabelLength);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -538,6 +556,7 @@ NTSTATUS Rename(FSP_FILE_SYSTEM *FileSystem,
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface = static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
{ {
GetVolumeInfo, GetVolumeInfo,
SetVolumeLabel,
GetSecurity, GetSecurity,
Create, Create,
Open, Open,
@ -616,7 +635,10 @@ NTSTATUS MemfsCreate(ULONG Flags, ULONG FileInfoTimeout,
free(Memfs); free(Memfs);
return Result; return Result;
} }
Memfs->FileSystem->UserContext = Memfs; Memfs->FileSystem->UserContext = Memfs;
Memfs->VolumeLabelLength = sizeof L"MEMFS" - sizeof(WCHAR);
memcpy(Memfs->VolumeLabel, L"MEMFS", Memfs->VolumeLabelLength);
InitializeCriticalSection(&Memfs->Lock); InitializeCriticalSection(&Memfs->Lock);