mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-24 17:32:29 -05:00
653 lines
20 KiB
C
653 lines
20 KiB
C
/**
|
|
* @file sys/ea.c
|
|
*
|
|
* @copyright 2015-2019 Bill Zissimopoulos
|
|
*/
|
|
/*
|
|
* This file is part of WinFsp.
|
|
*
|
|
* You can redistribute it and/or modify it under the terms of the GNU
|
|
* General Public License version 3 as published by the Free Software
|
|
* Foundation.
|
|
*
|
|
* Licensees holding a valid commercial license may use this software
|
|
* in accordance with the commercial license agreement provided in
|
|
* conjunction with the software. The terms and conditions of any such
|
|
* commercial license agreement shall govern, supersede, and render
|
|
* ineffective any application of the GPLv3 license to this software,
|
|
* notwithstanding of any reference thereto in the software or
|
|
* associated repository.
|
|
*/
|
|
|
|
#include <sys/driver.h>
|
|
|
|
static VOID FspFsvolQueryEaGetCopy(
|
|
BOOLEAN CasePreservedExtendedAttributes,
|
|
BOOLEAN ReturnSingleEntry,
|
|
PFILE_GET_EA_INFORMATION GetBufBgn, ULONG GetSize,
|
|
PFILE_FULL_EA_INFORMATION SrcBufBgn, ULONG SrcSize,
|
|
PFILE_FULL_EA_INFORMATION DstBufBgn, ULONG DstSize,
|
|
PIO_STATUS_BLOCK IoStatus);
|
|
static VOID FspFsvolQueryEaIndexCopy(
|
|
BOOLEAN CasePreservedExtendedAttributes,
|
|
BOOLEAN ReturnSingleEntry,
|
|
BOOLEAN IndexSpecified, PULONG PEaIndex,
|
|
PFILE_FULL_EA_INFORMATION SrcBufBgn, ULONG SrcSize,
|
|
PFILE_FULL_EA_INFORMATION DstBufBgn, ULONG DstSize,
|
|
PIO_STATUS_BLOCK IoStatus);
|
|
static VOID FspFsvolQueryEaCopy(
|
|
BOOLEAN CasePreservedExtendedAttributes,
|
|
PIO_STACK_LOCATION IrpSp,
|
|
PFILE_FULL_EA_INFORMATION SrcBufBgn, ULONG SrcSize,
|
|
PFILE_FULL_EA_INFORMATION DstBufBgn, ULONG DstSize,
|
|
PIO_STATUS_BLOCK IoStatus);
|
|
static NTSTATUS FspFsvolQueryEa(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
|
FSP_IOCMPL_DISPATCH FspFsvolQueryEaComplete;
|
|
static FSP_IOP_REQUEST_FINI FspFsvolQueryEaRequestFini;
|
|
static NTSTATUS FspFsvolSetEa(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
|
|
FSP_IOCMPL_DISPATCH FspFsvolSetEaComplete;
|
|
static FSP_IOP_REQUEST_FINI FspFsvolSetEaRequestFini;
|
|
FSP_DRIVER_DISPATCH FspQueryEa;
|
|
FSP_DRIVER_DISPATCH FspSetEa;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, FspFsvolQueryEaGetCopy)
|
|
#pragma alloc_text(PAGE, FspFsvolQueryEaIndexCopy)
|
|
#pragma alloc_text(PAGE, FspFsvolQueryEa)
|
|
#pragma alloc_text(PAGE, FspFsvolQueryEaComplete)
|
|
#pragma alloc_text(PAGE, FspFsvolQueryEaRequestFini)
|
|
#pragma alloc_text(PAGE, FspFsvolSetEa)
|
|
#pragma alloc_text(PAGE, FspFsvolSetEaComplete)
|
|
#pragma alloc_text(PAGE, FspFsvolSetEaRequestFini)
|
|
#pragma alloc_text(PAGE, FspQueryEa)
|
|
#pragma alloc_text(PAGE, FspSetEa)
|
|
#endif
|
|
|
|
enum
|
|
{
|
|
/* QueryEa */
|
|
RequestFileNode = 0,
|
|
RequestEaChangeNumber = 1,
|
|
|
|
/* SetEa */
|
|
//RequestFileNode = 0,
|
|
};
|
|
|
|
static VOID FspFsvolQueryEaGetCopy(
|
|
BOOLEAN CasePreservedExtendedAttributes,
|
|
BOOLEAN ReturnSingleEntry,
|
|
PFILE_GET_EA_INFORMATION GetBufBgn, ULONG GetSize,
|
|
PFILE_FULL_EA_INFORMATION SrcBufBgn, ULONG SrcSize,
|
|
PFILE_FULL_EA_INFORMATION DstBufBgn, ULONG DstSize,
|
|
PIO_STATUS_BLOCK IoStatus)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
PFILE_GET_EA_INFORMATION GetBuf, GetBufEnd = (PVOID)((PUINT8)GetBufBgn + GetSize);
|
|
PFILE_GET_EA_INFORMATION Get;
|
|
PFILE_FULL_EA_INFORMATION SrcBuf, SrcBufEnd = (PVOID)((PUINT8)SrcBufBgn + SrcSize);
|
|
PFILE_FULL_EA_INFORMATION DstBuf, DstBufEnd = (PVOID)((PUINT8)DstBufBgn + DstSize);
|
|
PFILE_FULL_EA_INFORMATION PrevDstBuf;
|
|
PFILE_FULL_EA_INFORMATION Src;
|
|
STRING GetName, Name;
|
|
ULONG CopyLength;
|
|
|
|
IoStatus->Information = 0;
|
|
|
|
DstBuf = DstBufBgn, PrevDstBuf = 0;
|
|
for (GetBuf = GetBufBgn; GetBufEnd > GetBuf; GetBuf = FSP_NEXT_EA(GetBuf, GetBufEnd))
|
|
{
|
|
GetName.Length = GetName.MaximumLength = GetBuf->EaNameLength;
|
|
GetName.Buffer = GetBuf->EaName;
|
|
|
|
/* ignore duplicate names */
|
|
for (Get = GetBufBgn; GetBuf > Get; Get = (PVOID)((PUINT8)Get + Get->NextEntryOffset))
|
|
{
|
|
Name.Length = Name.MaximumLength = Get->EaNameLength;
|
|
Name.Buffer = Get->EaName;
|
|
|
|
if (RtlEqualString(&GetName, &Name, TRUE/* always case-insensitive */))
|
|
break;
|
|
}
|
|
if (GetBuf > Get)
|
|
continue;
|
|
|
|
if (!FspEaNameIsValid(&GetName))
|
|
{
|
|
IoStatus->Status = STATUS_INVALID_EA_NAME;
|
|
IoStatus->Information = (ULONG)((PUINT8)GetBuf - (PUINT8)GetBufBgn);
|
|
return;
|
|
}
|
|
|
|
Src = 0;
|
|
for (SrcBuf = SrcBufBgn; SrcBufEnd > SrcBuf; SrcBuf = FSP_NEXT_EA(SrcBuf, SrcBufEnd))
|
|
{
|
|
Name.Length = Name.MaximumLength = SrcBuf->EaNameLength;
|
|
Name.Buffer = SrcBuf->EaName;
|
|
|
|
if (RtlEqualString(&GetName, &Name, TRUE/* always case-insensitive */))
|
|
{
|
|
Src = SrcBuf;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (0 != Src)
|
|
CopyLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) +
|
|
Src->EaNameLength + 1 + Src->EaValueLength;
|
|
else
|
|
CopyLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) +
|
|
GetBuf->EaNameLength + 1;
|
|
|
|
if ((PUINT8)DstBuf + CopyLength > (PUINT8)DstBufEnd)
|
|
{
|
|
IoStatus->Status = STATUS_BUFFER_OVERFLOW;
|
|
IoStatus->Information = 0;
|
|
return;
|
|
}
|
|
|
|
if (0 != Src)
|
|
RtlMoveMemory(DstBuf, Src, CopyLength);
|
|
else
|
|
{
|
|
DstBuf->Flags = 0;
|
|
DstBuf->EaNameLength = GetBuf->EaNameLength;
|
|
DstBuf->EaValueLength = 0;
|
|
RtlCopyMemory(DstBuf->EaName, GetBuf->EaName, GetBuf->EaNameLength + 1);
|
|
}
|
|
DstBuf->NextEntryOffset = 0;
|
|
if (!CasePreservedExtendedAttributes)
|
|
{
|
|
Name.Length = Name.MaximumLength = DstBuf->EaNameLength;
|
|
Name.Buffer = DstBuf->EaName;
|
|
FspEaNameUpcase(&Name, &Name, 0);
|
|
}
|
|
if (0 != PrevDstBuf)
|
|
PrevDstBuf->NextEntryOffset = (ULONG)((PUINT8)DstBuf - (PUINT8)PrevDstBuf);
|
|
PrevDstBuf = DstBuf;
|
|
IoStatus->Information = (ULONG)((PUINT8)DstBuf - (PUINT8)DstBufBgn + CopyLength);
|
|
DstBuf = (PVOID)((PUINT8)DstBuf + FSP_FSCTL_ALIGN_UP(CopyLength, sizeof(ULONG)));
|
|
|
|
if (ReturnSingleEntry)
|
|
break;
|
|
}
|
|
|
|
IoStatus->Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
static VOID FspFsvolQueryEaIndexCopy(
|
|
BOOLEAN CasePreservedExtendedAttributes,
|
|
BOOLEAN ReturnSingleEntry,
|
|
BOOLEAN IndexSpecified, PULONG PEaIndex,
|
|
PFILE_FULL_EA_INFORMATION SrcBufBgn, ULONG SrcSize,
|
|
PFILE_FULL_EA_INFORMATION DstBufBgn, ULONG DstSize,
|
|
PIO_STATUS_BLOCK IoStatus)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
ULONG EaIndex = 1;
|
|
PFILE_FULL_EA_INFORMATION SrcBuf, SrcBufEnd = (PVOID)((PUINT8)SrcBufBgn + SrcSize);
|
|
PFILE_FULL_EA_INFORMATION DstBuf, DstBufEnd = (PVOID)((PUINT8)DstBufBgn + DstSize);
|
|
PFILE_FULL_EA_INFORMATION PrevDstBuf;
|
|
STRING Name;
|
|
ULONG CopyLength;
|
|
|
|
if (IndexSpecified && 0 == *PEaIndex)
|
|
{
|
|
IoStatus->Status = STATUS_NONEXISTENT_EA_ENTRY;
|
|
IoStatus->Information = 0;
|
|
return;
|
|
}
|
|
|
|
for (SrcBuf = SrcBufBgn; EaIndex < *PEaIndex && SrcBufEnd > SrcBuf;
|
|
SrcBuf = FSP_NEXT_EA(SrcBuf, SrcBufEnd))
|
|
EaIndex++;
|
|
|
|
IoStatus->Information = 0;
|
|
|
|
DstBuf = DstBufBgn, PrevDstBuf = 0;
|
|
for (; SrcBufEnd > SrcBuf; SrcBuf = FSP_NEXT_EA(SrcBuf, SrcBufEnd))
|
|
{
|
|
CopyLength = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) +
|
|
((PFILE_FULL_EA_INFORMATION)SrcBuf)->EaNameLength + 1 +
|
|
((PFILE_FULL_EA_INFORMATION)SrcBuf)->EaValueLength;
|
|
|
|
if ((PUINT8)DstBuf + CopyLength > (PUINT8)DstBufEnd)
|
|
{
|
|
if (0 != PrevDstBuf)
|
|
break;
|
|
IoStatus->Status = STATUS_BUFFER_TOO_SMALL;
|
|
IoStatus->Information = 0;
|
|
return;
|
|
}
|
|
|
|
RtlMoveMemory(DstBuf, SrcBuf, CopyLength);
|
|
DstBuf->NextEntryOffset = 0;
|
|
if (!CasePreservedExtendedAttributes)
|
|
{
|
|
Name.Length = Name.MaximumLength = DstBuf->EaNameLength;
|
|
Name.Buffer = DstBuf->EaName;
|
|
FspEaNameUpcase(&Name, &Name, 0);
|
|
}
|
|
if (0 != PrevDstBuf)
|
|
PrevDstBuf->NextEntryOffset = (ULONG)((PUINT8)DstBuf - (PUINT8)PrevDstBuf);
|
|
PrevDstBuf = DstBuf;
|
|
IoStatus->Information = (ULONG)((PUINT8)DstBuf - (PUINT8)DstBufBgn + CopyLength);
|
|
DstBuf = (PVOID)((PUINT8)DstBuf + FSP_FSCTL_ALIGN_UP(CopyLength, sizeof(ULONG)));
|
|
|
|
EaIndex++;
|
|
|
|
if (ReturnSingleEntry)
|
|
break;
|
|
}
|
|
|
|
if (IndexSpecified)
|
|
{
|
|
if (0 != PrevDstBuf)
|
|
{
|
|
*PEaIndex = EaIndex;
|
|
IoStatus->Status = SrcBufEnd > SrcBuf && !ReturnSingleEntry ?
|
|
STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
IoStatus->Status = *PEaIndex == EaIndex ?
|
|
STATUS_NO_MORE_EAS : STATUS_NONEXISTENT_EA_ENTRY;
|
|
IoStatus->Information = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (0 != PrevDstBuf)
|
|
{
|
|
*PEaIndex = EaIndex;
|
|
IoStatus->Status = SrcBufEnd > SrcBuf && !ReturnSingleEntry ?
|
|
STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
IoStatus->Status = SrcBufBgn == SrcBuf ?
|
|
STATUS_NO_EAS_ON_FILE : STATUS_NO_MORE_EAS;
|
|
IoStatus->Information = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static VOID FspFsvolQueryEaCopy(
|
|
BOOLEAN CasePreservedExtendedAttributes,
|
|
PIO_STACK_LOCATION IrpSp,
|
|
PFILE_FULL_EA_INFORMATION SrcBufBgn, ULONG SrcSize,
|
|
PFILE_FULL_EA_INFORMATION DstBufBgn, ULONG DstSize,
|
|
PIO_STATUS_BLOCK IoStatus)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
|
BOOLEAN RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
|
|
BOOLEAN IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);
|
|
BOOLEAN ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
|
|
PFILE_GET_EA_INFORMATION EaList = IrpSp->Parameters.QueryEa.EaList;
|
|
ULONG EaListLength = IrpSp->Parameters.QueryEa.EaListLength;
|
|
ULONG EaIndex;
|
|
|
|
if (0 != EaList)
|
|
{
|
|
FspFsvolQueryEaGetCopy(
|
|
CasePreservedExtendedAttributes,
|
|
ReturnSingleEntry,
|
|
EaList, EaListLength,
|
|
SrcBufBgn, SrcSize,
|
|
DstBufBgn, DstSize,
|
|
IoStatus);
|
|
}
|
|
else
|
|
{
|
|
if (IndexSpecified)
|
|
EaIndex = IrpSp->Parameters.QueryEa.EaIndex;
|
|
else if (RestartScan)
|
|
EaIndex = 0;
|
|
else
|
|
EaIndex = FileDesc->EaIndex;
|
|
FspFsvolQueryEaIndexCopy(
|
|
CasePreservedExtendedAttributes,
|
|
ReturnSingleEntry,
|
|
IndexSpecified, &EaIndex,
|
|
SrcBufBgn, SrcSize,
|
|
DstBufBgn, DstSize,
|
|
IoStatus);
|
|
if (NT_SUCCESS(IoStatus->Status) || STATUS_BUFFER_OVERFLOW == IoStatus->Status)
|
|
FileDesc->EaIndex = EaIndex;
|
|
}
|
|
}
|
|
|
|
static NTSTATUS FspFsvolQueryEa(
|
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
/* is this a valid FileObject? */
|
|
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
NTSTATUS Result;
|
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
|
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
|
PVOID Buffer = Irp->UserBuffer;
|
|
ULONG Length = IrpSp->Parameters.QueryEa.Length;
|
|
PVOID EaBuffer;
|
|
ULONG EaBufferSize;
|
|
FSP_FSCTL_TRANSACT_REQ *Request;
|
|
|
|
ASSERT(FileNode == FileDesc->FileNode);
|
|
|
|
FspFileNodeAcquireExclusive(FileNode, Main);
|
|
if (FspFileNodeReferenceEa(FileNode, &EaBuffer, &EaBufferSize))
|
|
{
|
|
FspFsvolQueryEaCopy(
|
|
!!FsvolDeviceExtension->VolumeParams.CasePreservedExtendedAttributes,
|
|
IrpSp,
|
|
EaBuffer, EaBufferSize,
|
|
Buffer, Length,
|
|
&Irp->IoStatus);
|
|
FspFileNodeDereferenceEa(EaBuffer);
|
|
FspFileNodeRelease(FileNode, Main);
|
|
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
FspFileNodeConvertExclusiveToShared(FileNode, Main);
|
|
FspFileNodeAcquireShared(FileNode, Pgio);
|
|
|
|
Result = FspBufferUserBuffer(Irp, Length, IoWriteAccess);
|
|
if (!NT_SUCCESS(Result))
|
|
{
|
|
FspFileNodeRelease(FileNode, Full);
|
|
return Result;
|
|
}
|
|
|
|
Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolQueryEaRequestFini, &Request);
|
|
if (!NT_SUCCESS(Result))
|
|
{
|
|
FspFileNodeRelease(FileNode, Full);
|
|
return Result;
|
|
}
|
|
|
|
Request->Kind = FspFsctlTransactQueryEaKind;
|
|
Request->Req.QueryEa.UserContext = FileNode->UserContext;
|
|
Request->Req.QueryEa.UserContext2 = FileDesc->UserContext2;
|
|
|
|
FspFileNodeSetOwner(FileNode, Full, Request);
|
|
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
|
|
|
return FSP_STATUS_IOQ_POST;
|
|
}
|
|
|
|
NTSTATUS FspFsvolQueryEaComplete(
|
|
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
|
|
{
|
|
FSP_ENTER_IOC(PAGED_CODE());
|
|
|
|
if (!NT_SUCCESS(Response->IoStatus.Status))
|
|
{
|
|
Irp->IoStatus.Information = 0;
|
|
Result = Response->IoStatus.Status;
|
|
FSP_RETURN();
|
|
}
|
|
|
|
PDEVICE_OBJECT FsvolDeviceObject = IrpSp->DeviceObject;
|
|
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(FsvolDeviceObject);
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
|
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
ULONG Length = IrpSp->Parameters.QueryEa.Length;
|
|
PVOID EaBuffer = 0;
|
|
ULONG EaBufferSize = 0;
|
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
|
BOOLEAN Success;
|
|
|
|
if (0 != FspIopRequestContext(Request, RequestFileNode))
|
|
{
|
|
/* check that the EA buffer we got back is valid */
|
|
if (Response->Buffer + Response->Rsp.QueryEa.Ea.Size >
|
|
(PUINT8)Response + Response->Size)
|
|
{
|
|
Irp->IoStatus.Information = 0;
|
|
Result = STATUS_EA_LIST_INCONSISTENT;
|
|
FSP_RETURN();
|
|
}
|
|
Irp->IoStatus.Information = 0;
|
|
Result = IoCheckEaBufferValidity((PVOID)Response->Buffer, Response->Rsp.QueryEa.Ea.Size,
|
|
(PULONG)&Irp->IoStatus.Information);
|
|
if (!NT_SUCCESS(Result))
|
|
FSP_RETURN();
|
|
|
|
FspIopRequestContext(Request, RequestEaChangeNumber) = (PVOID)
|
|
FspFileNodeEaChangeNumber(FileNode);
|
|
FspIopRequestContext(Request, RequestFileNode) = 0;
|
|
|
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
|
}
|
|
|
|
Success = DEBUGTEST(90) && FspFileNodeTryAcquireExclusive(FileNode, Main);
|
|
if (!Success)
|
|
{
|
|
FspIopRetryCompleteIrp(Irp, Response, &Result);
|
|
FSP_RETURN();
|
|
}
|
|
|
|
Success = !FspFileNodeTrySetEa(FileNode,
|
|
Response->Buffer, Response->Rsp.QueryEa.Ea.Size,
|
|
(ULONG)(UINT_PTR)FspIopRequestContext(Request, RequestEaChangeNumber));
|
|
Success = Success && FspFileNodeReferenceEa(FileNode, &EaBuffer, &EaBufferSize);
|
|
if (Success)
|
|
{
|
|
FspFsvolQueryEaCopy(
|
|
!!FsvolDeviceExtension->VolumeParams.CasePreservedExtendedAttributes,
|
|
IrpSp,
|
|
EaBuffer, EaBufferSize,
|
|
Buffer, Length,
|
|
&Irp->IoStatus);
|
|
FspFileNodeDereferenceEa(EaBuffer);
|
|
}
|
|
else
|
|
{
|
|
EaBuffer = (PVOID)Response->Buffer;
|
|
EaBufferSize = Response->Rsp.QueryEa.Ea.Size;
|
|
FspFsvolQueryEaCopy(
|
|
!!FsvolDeviceExtension->VolumeParams.CasePreservedExtendedAttributes,
|
|
IrpSp,
|
|
EaBuffer, EaBufferSize,
|
|
Buffer, Length,
|
|
&Irp->IoStatus);
|
|
}
|
|
|
|
FspFileNodeRelease(FileNode, Main);
|
|
|
|
Result = Irp->IoStatus.Status;
|
|
|
|
FSP_LEAVE_IOC("FileObject=%p",
|
|
IrpSp->FileObject);
|
|
}
|
|
|
|
static VOID FspFsvolQueryEaRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4])
|
|
{
|
|
PAGED_CODE();
|
|
|
|
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
|
|
|
|
if (0 != FileNode)
|
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
|
}
|
|
|
|
static NTSTATUS FspFsvolSetEa(
|
|
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
/* is this a valid FileObject? */
|
|
if (!FspFileNodeIsValid(IrpSp->FileObject->FsContext))
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
NTSTATUS Result;
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
|
FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
|
|
PVOID Buffer;
|
|
ULONG Length = IrpSp->Parameters.SetEa.Length;
|
|
FSP_FSCTL_TRANSACT_REQ *Request;
|
|
|
|
ASSERT(FileNode == FileDesc->FileNode);
|
|
|
|
Result = FspBufferUserBuffer(Irp, Length, IoReadAccess);
|
|
if (!NT_SUCCESS(Result))
|
|
return Result;
|
|
|
|
Buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Result = IoCheckEaBufferValidity(Buffer, Length,
|
|
(PULONG)&Irp->IoStatus.Information);
|
|
if (!NT_SUCCESS(Result))
|
|
return Result;
|
|
|
|
for (PFILE_FULL_EA_INFORMATION Ea = Buffer, EaEnd = (PVOID)((PUINT8)Ea + Length);
|
|
EaEnd > Ea; Ea = FSP_NEXT_EA(Ea, EaEnd))
|
|
{
|
|
STRING Name;
|
|
|
|
Name.Length = Name.MaximumLength = Ea->EaNameLength;
|
|
Name.Buffer = Ea->EaName;
|
|
|
|
if (!FspEaNameIsValid(&Name))
|
|
{
|
|
Result = STATUS_INVALID_EA_NAME;
|
|
Irp->IoStatus.Information = (ULONG)((PUINT8)Ea - (PUINT8)Buffer);
|
|
return Result;
|
|
}
|
|
}
|
|
|
|
FspFileNodeAcquireExclusive(FileNode, Full);
|
|
|
|
Result = FspIopCreateRequestEx(Irp, 0, Length, FspFsvolSetEaRequestFini,
|
|
&Request);
|
|
if (!NT_SUCCESS(Result))
|
|
{
|
|
FspFileNodeRelease(FileNode, Full);
|
|
return Result;
|
|
}
|
|
|
|
Request->Kind = FspFsctlTransactSetEaKind;
|
|
Request->Req.SetEa.UserContext = FileNode->UserContext;
|
|
Request->Req.SetEa.UserContext2 = FileDesc->UserContext2;
|
|
Request->Req.SetEa.Ea.Offset = 0;
|
|
Request->Req.SetEa.Ea.Size = (UINT16)Length;
|
|
RtlCopyMemory(Request->Buffer, Buffer, Length);
|
|
|
|
FspFileNodeSetOwner(FileNode, Full, Request);
|
|
FspIopRequestContext(Request, RequestFileNode) = FileNode;
|
|
|
|
return FSP_STATUS_IOQ_POST;
|
|
}
|
|
|
|
NTSTATUS FspFsvolSetEaComplete(
|
|
PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response)
|
|
{
|
|
FSP_ENTER_IOC(PAGED_CODE());
|
|
|
|
if (!NT_SUCCESS(Response->IoStatus.Status))
|
|
{
|
|
Irp->IoStatus.Information = 0;
|
|
Result = Response->IoStatus.Status;
|
|
FSP_RETURN();
|
|
}
|
|
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
FSP_FILE_NODE *FileNode = FileObject->FsContext;
|
|
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
|
|
BOOLEAN Valid;
|
|
|
|
Valid = FALSE;
|
|
if (0 < Response->Rsp.SetEa.Ea.Size &&
|
|
Response->Buffer + Response->Rsp.SetEa.Ea.Size <=
|
|
(PUINT8)Response + Response->Size)
|
|
{
|
|
Irp->IoStatus.Information = 0;
|
|
Result = IoCheckEaBufferValidity((PVOID)Response->Buffer, Response->Rsp.QueryEa.Ea.Size,
|
|
(PULONG)&Irp->IoStatus.Information);
|
|
Valid = NT_SUCCESS(Result);
|
|
}
|
|
|
|
/* if the EA buffer that we got back is valid */
|
|
if (Valid)
|
|
{
|
|
/* update the cached EA */
|
|
FspFileNodeSetEa(FileNode,
|
|
Response->Buffer, Response->Rsp.SetEa.Ea.Size);
|
|
}
|
|
else
|
|
{
|
|
/* invalidate the cached EA */
|
|
FspFileNodeSetEa(FileNode, 0, 0);
|
|
}
|
|
|
|
FspFileNodeNotifyChange(FileNode, FILE_NOTIFY_CHANGE_EA, FILE_ACTION_MODIFIED, FALSE);
|
|
|
|
FspIopRequestContext(Request, RequestFileNode) = 0;
|
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Result = STATUS_SUCCESS;
|
|
|
|
FSP_LEAVE_IOC("FileObject=%p",
|
|
IrpSp->FileObject);
|
|
}
|
|
|
|
static VOID FspFsvolSetEaRequestFini(FSP_FSCTL_TRANSACT_REQ *Request, PVOID Context[4])
|
|
{
|
|
PAGED_CODE();
|
|
|
|
FSP_FILE_NODE *FileNode = Context[RequestFileNode];
|
|
|
|
if (0 != FileNode)
|
|
FspFileNodeReleaseOwner(FileNode, Full, Request);
|
|
}
|
|
|
|
NTSTATUS FspQueryEa(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
FSP_ENTER_MJ(PAGED_CODE());
|
|
|
|
switch (FspDeviceExtension(DeviceObject)->Kind)
|
|
{
|
|
case FspFsvolDeviceExtensionKind:
|
|
FSP_RETURN(Result = FspFsvolQueryEa(DeviceObject, Irp, IrpSp));
|
|
default:
|
|
FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
FSP_LEAVE_MJ("FileObject=%p",
|
|
IrpSp->FileObject);
|
|
}
|
|
|
|
NTSTATUS FspSetEa(
|
|
PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
FSP_ENTER_MJ(PAGED_CODE());
|
|
|
|
switch (FspDeviceExtension(DeviceObject)->Kind)
|
|
{
|
|
case FspFsvolDeviceExtensionKind:
|
|
FSP_RETURN(Result = FspFsvolSetEa(DeviceObject, Irp, IrpSp));
|
|
default:
|
|
FSP_RETURN(Result = STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
|
|
FSP_LEAVE_MJ("FileObject=%p",
|
|
IrpSp->FileObject);
|
|
}
|