mirror of https://github.com/reactos/reactos.git
605 lines
15 KiB
C
605 lines
15 KiB
C
/*
|
|
* COPYRIGHT: See COPYRIGHT.TXT
|
|
* PROJECT: Ext2 File System Driver for Windows >= NT
|
|
* FILE: ea.c
|
|
* PROGRAMMER: Matt Wu <mattwu@163.com> Kaho Ng <ngkaho1234@gmail.com>
|
|
* HOMEPAGE: http://www.ext2fsd.com
|
|
* UPDATE HISTORY:
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include "ext2fs.h"
|
|
#include <linux/ext4_xattr.h>
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, Ext2QueryEa)
|
|
#pragma alloc_text(PAGE, Ext2SetEa)
|
|
#pragma alloc_text(PAGE, Ext2IsEaNameValid)
|
|
#endif
|
|
|
|
// Ea iterator
|
|
struct EaIterator {
|
|
// Return only an entry
|
|
BOOLEAN ReturnSingleEntry;
|
|
|
|
// Is the buffer overflowing?
|
|
BOOL OverFlow;
|
|
|
|
// FILE_FULL_EA_INFORMATION output buffer
|
|
PFILE_FULL_EA_INFORMATION FullEa;
|
|
PFILE_FULL_EA_INFORMATION LastFullEa;
|
|
|
|
// UserBuffer's size
|
|
ULONG UserBufferLength;
|
|
|
|
// Remaining UserBuffer's size
|
|
ULONG RemainingUserBufferLength;
|
|
|
|
// Start scanning from this EA
|
|
ULONG EaIndex;
|
|
|
|
// Next EA index returned by Ext2IterateAllEa
|
|
ULONG EaIndexCounter;
|
|
};
|
|
|
|
static int Ext2IterateAllEa(struct ext4_xattr_ref *xattr_ref, struct ext4_xattr_item *item, BOOL is_last)
|
|
{
|
|
struct EaIterator *pEaIterator = xattr_ref->iter_arg;
|
|
ULONG EaEntrySize = 4 + 1 + 1 + 2 + item->name_len + 1 + item->data_size;
|
|
ASSERT(pEaIterator);
|
|
if (!is_last && !pEaIterator->ReturnSingleEntry)
|
|
EaEntrySize = ALIGN_UP(EaEntrySize, ULONG);
|
|
|
|
// Start iteration from index specified
|
|
if (pEaIterator->EaIndexCounter < pEaIterator->EaIndex) {
|
|
pEaIterator->EaIndexCounter++;
|
|
return EXT4_XATTR_ITERATE_CONT;
|
|
}
|
|
pEaIterator->EaIndexCounter++;
|
|
|
|
if (EaEntrySize > pEaIterator->RemainingUserBufferLength) {
|
|
pEaIterator->OverFlow = TRUE;
|
|
return EXT4_XATTR_ITERATE_STOP;
|
|
}
|
|
pEaIterator->FullEa->NextEntryOffset = 0;
|
|
pEaIterator->FullEa->Flags = 0;
|
|
pEaIterator->FullEa->EaNameLength = (UCHAR)item->name_len;
|
|
pEaIterator->FullEa->EaValueLength = (USHORT)item->data_size;
|
|
RtlCopyMemory(&pEaIterator->FullEa->EaName[0],
|
|
item->name,
|
|
item->name_len);
|
|
RtlCopyMemory(&pEaIterator->FullEa->EaName[0] + item->name_len + 1,
|
|
item->data,
|
|
item->data_size);
|
|
|
|
// Link FullEa and LastFullEa together
|
|
if (pEaIterator->LastFullEa) {
|
|
pEaIterator->LastFullEa->NextEntryOffset = (ULONG)
|
|
((PCHAR)pEaIterator->FullEa - (PCHAR)pEaIterator->LastFullEa);
|
|
}
|
|
|
|
pEaIterator->LastFullEa = pEaIterator->FullEa;
|
|
pEaIterator->FullEa = (PFILE_FULL_EA_INFORMATION)
|
|
((PCHAR)pEaIterator->FullEa + EaEntrySize);
|
|
pEaIterator->RemainingUserBufferLength -= EaEntrySize;
|
|
|
|
if (pEaIterator->ReturnSingleEntry)
|
|
return EXT4_XATTR_ITERATE_STOP;
|
|
|
|
return EXT4_XATTR_ITERATE_CONT;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2QueryEa (
|
|
IN PEXT2_IRP_CONTEXT IrpContext
|
|
)
|
|
{
|
|
PIRP Irp = NULL;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
PEXT2_VCB Vcb = NULL;
|
|
PEXT2_FCB Fcb = NULL;
|
|
PEXT2_CCB Ccb = NULL;
|
|
PEXT2_MCB Mcb = NULL;
|
|
|
|
PUCHAR UserEaList;
|
|
ULONG UserEaListLength;
|
|
ULONG UserEaIndex;
|
|
|
|
BOOLEAN RestartScan;
|
|
BOOLEAN ReturnSingleEntry;
|
|
BOOLEAN IndexSpecified;
|
|
|
|
BOOLEAN MainResourceAcquired = FALSE;
|
|
BOOLEAN XattrRefAcquired = FALSE;
|
|
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
struct ext4_xattr_ref xattr_ref;
|
|
PCHAR UserBuffer;
|
|
|
|
ULONG UserBufferLength = 0;
|
|
ULONG RemainingUserBufferLength = 0;
|
|
|
|
PFILE_FULL_EA_INFORMATION FullEa, LastFullEa = NULL;
|
|
|
|
_SEH2_TRY {
|
|
|
|
Ccb = IrpContext->Ccb;
|
|
ASSERT(Ccb != NULL);
|
|
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
|
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
Vcb = (PEXT2_VCB)DeviceObject->DeviceExtension;
|
|
Fcb = IrpContext->Fcb;
|
|
Mcb = Fcb->Mcb;
|
|
Irp = IrpContext->Irp;
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
//
|
|
// Receive input parameter from caller
|
|
//
|
|
UserBuffer = Ext2GetUserBuffer(Irp);
|
|
if (!UserBuffer) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
_SEH2_LEAVE;
|
|
}
|
|
UserBufferLength = IrpSp->Parameters.QueryEa.Length;
|
|
RemainingUserBufferLength = UserBufferLength;
|
|
UserEaList = IrpSp->Parameters.QueryEa.EaList;
|
|
UserEaListLength = IrpSp->Parameters.QueryEa.EaListLength;
|
|
UserEaIndex = IrpSp->Parameters.QueryEa.EaIndex;
|
|
RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
|
|
ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
|
|
IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);
|
|
|
|
if (!Mcb)
|
|
_SEH2_LEAVE;
|
|
|
|
//
|
|
// We do not allow multiple instance gaining EA access to the same file
|
|
//
|
|
if (!ExAcquireResourceExclusiveLite(
|
|
&Fcb->MainResource,
|
|
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
|
|
Status = STATUS_PENDING;
|
|
_SEH2_LEAVE;
|
|
}
|
|
MainResourceAcquired = TRUE;
|
|
|
|
Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref));
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("ext4_fs_get_xattr_ref() failed!\n");
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
|
|
|
|
XattrRefAcquired = TRUE;
|
|
|
|
if (RemainingUserBufferLength)
|
|
RtlZeroMemory(FullEa, RemainingUserBufferLength);
|
|
|
|
if (UserEaList != NULL) {
|
|
int i = 0;
|
|
PFILE_GET_EA_INFORMATION GetEa;
|
|
for (GetEa = (PFILE_GET_EA_INFORMATION)&UserEaList[0];
|
|
GetEa < (PFILE_GET_EA_INFORMATION)((PUCHAR)UserEaList
|
|
+ UserEaListLength);
|
|
GetEa = (GetEa->NextEntryOffset == 0
|
|
? (PFILE_GET_EA_INFORMATION)MAXUINT_PTR
|
|
: (PFILE_GET_EA_INFORMATION)((PUCHAR)GetEa
|
|
+ GetEa->NextEntryOffset))) {
|
|
|
|
size_t ItemSize;
|
|
OEM_STRING Str;
|
|
ULONG EaEntrySize;
|
|
BOOL is_last = !GetEa->NextEntryOffset;
|
|
|
|
Str.MaximumLength = Str.Length = GetEa->EaNameLength;
|
|
Str.Buffer = &GetEa->EaName[0];
|
|
|
|
//
|
|
// At the moment we only need to know whether the item exists
|
|
// and its size.
|
|
//
|
|
Status = Ext2WinntError(ext4_fs_get_xattr(&xattr_ref,
|
|
EXT4_XATTR_INDEX_USER,
|
|
Str.Buffer,
|
|
Str.Length,
|
|
NULL,
|
|
0,
|
|
&ItemSize));
|
|
if (!NT_SUCCESS(Status))
|
|
continue;
|
|
|
|
//
|
|
// We were not able to locate the name therefore we must
|
|
// dummy up a entry for the query. The needed Ea size is
|
|
// the size of the name + 4 (next entry offset) + 1 (flags)
|
|
// + 1 (name length) + 2 (value length) + the name length +
|
|
// 1 (null byte) + Data Size.
|
|
//
|
|
EaEntrySize = 4 + 1 + 1 + 2 + GetEa->EaNameLength + 1 + ItemSize;
|
|
if (!is_last)
|
|
EaEntrySize = ALIGN_UP(EaEntrySize, ULONG);
|
|
|
|
if (EaEntrySize > RemainingUserBufferLength) {
|
|
|
|
Status = i ? STATUS_BUFFER_OVERFLOW : STATUS_BUFFER_TOO_SMALL;
|
|
_SEH2_LEAVE;
|
|
}
|
|
FullEa->NextEntryOffset = 0;
|
|
FullEa->Flags = 0;
|
|
FullEa->EaNameLength = GetEa->EaNameLength;
|
|
FullEa->EaValueLength = (USHORT)ItemSize;
|
|
RtlCopyMemory(&FullEa->EaName[0],
|
|
&GetEa->EaName[0],
|
|
GetEa->EaNameLength);
|
|
|
|
//
|
|
// This query must succeed, or is guarenteed to succeed
|
|
// since we are only looking up
|
|
// an EA entry in a in-memory tree structure.
|
|
// Otherwise that means someone might be operating on
|
|
// the xattr_ref without acquiring Inode lock.
|
|
//
|
|
ASSERT(NT_SUCCESS(Ext2WinntError(
|
|
ext4_fs_get_xattr(&xattr_ref,
|
|
EXT4_XATTR_INDEX_USER,
|
|
Str.Buffer,
|
|
Str.Length,
|
|
&FullEa->EaName[0] + FullEa->EaNameLength + 1,
|
|
ItemSize,
|
|
&ItemSize
|
|
))));
|
|
FullEa->EaValueLength = (USHORT)ItemSize;
|
|
|
|
// Link FullEa and LastFullEa together
|
|
if (LastFullEa)
|
|
LastFullEa->NextEntryOffset = (ULONG)((PCHAR)FullEa -
|
|
(PCHAR)LastFullEa);
|
|
|
|
LastFullEa = FullEa;
|
|
FullEa = (PFILE_FULL_EA_INFORMATION)
|
|
((PCHAR)FullEa + EaEntrySize);
|
|
RemainingUserBufferLength -= EaEntrySize;
|
|
i++;
|
|
}
|
|
} else if (IndexSpecified) {
|
|
struct EaIterator EaIterator;
|
|
//
|
|
// The user supplied an index into the Ea list.
|
|
//
|
|
if (RemainingUserBufferLength)
|
|
RtlZeroMemory(FullEa, RemainingUserBufferLength);
|
|
|
|
EaIterator.OverFlow = FALSE;
|
|
EaIterator.RemainingUserBufferLength = UserBufferLength;
|
|
// In this case, return only an entry.
|
|
EaIterator.ReturnSingleEntry = TRUE;
|
|
EaIterator.FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
|
|
EaIterator.LastFullEa = NULL;
|
|
EaIterator.UserBufferLength = UserBufferLength;
|
|
EaIterator.EaIndex = UserEaIndex;
|
|
EaIterator.EaIndexCounter = 1;
|
|
|
|
xattr_ref.iter_arg = &EaIterator;
|
|
ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa);
|
|
|
|
RemainingUserBufferLength = EaIterator.RemainingUserBufferLength;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
// It seems that the item isn't found
|
|
if (RemainingUserBufferLength == UserBufferLength)
|
|
Status = STATUS_OBJECTID_NOT_FOUND;
|
|
|
|
if (EaIterator.OverFlow) {
|
|
if (RemainingUserBufferLength == UserBufferLength)
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
else
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
} else {
|
|
struct EaIterator EaIterator;
|
|
//
|
|
// Else perform a simple scan, taking into account the restart
|
|
// flag and the position of the next Ea stored in the Ccb.
|
|
//
|
|
if (RestartScan)
|
|
Ccb->EaIndex = 1;
|
|
|
|
if (RemainingUserBufferLength)
|
|
RtlZeroMemory(FullEa, RemainingUserBufferLength);
|
|
|
|
EaIterator.OverFlow = FALSE;
|
|
EaIterator.RemainingUserBufferLength = UserBufferLength;
|
|
EaIterator.ReturnSingleEntry = ReturnSingleEntry;
|
|
EaIterator.FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
|
|
EaIterator.LastFullEa = NULL;
|
|
EaIterator.UserBufferLength = UserBufferLength;
|
|
EaIterator.EaIndex = Ccb->EaIndex;
|
|
EaIterator.EaIndexCounter = 1;
|
|
|
|
xattr_ref.iter_arg = &EaIterator;
|
|
ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa);
|
|
|
|
RemainingUserBufferLength = EaIterator.RemainingUserBufferLength;
|
|
|
|
if (Ccb->EaIndex < EaIterator.EaIndexCounter)
|
|
Ccb->EaIndex = EaIterator.EaIndexCounter;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
if (EaIterator.OverFlow) {
|
|
if (RemainingUserBufferLength == UserBufferLength)
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
else
|
|
Status = STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
}
|
|
}
|
|
_SEH2_FINALLY {
|
|
|
|
if (XattrRefAcquired) {
|
|
if (!NT_SUCCESS(Status)) {
|
|
xattr_ref.dirty = FALSE;
|
|
ext4_fs_put_xattr_ref(&xattr_ref);
|
|
}
|
|
else
|
|
Status = Ext2WinntError(ext4_fs_put_xattr_ref(&xattr_ref));
|
|
}
|
|
|
|
if (MainResourceAcquired) {
|
|
ExReleaseResourceLite(&Fcb->MainResource);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Ext2NotifyReportChange(
|
|
IrpContext,
|
|
Vcb,
|
|
Mcb,
|
|
FILE_NOTIFY_CHANGE_EA,
|
|
FILE_ACTION_MODIFIED);
|
|
Irp->IoStatus.Information = UserBufferLength - RemainingUserBufferLength;
|
|
}
|
|
|
|
if (!_SEH2_AbnormalTermination()) {
|
|
if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
|
|
Status = Ext2QueueRequest(IrpContext);
|
|
}
|
|
else {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
Ext2IsEaNameValid(
|
|
IN OEM_STRING Name
|
|
)
|
|
{
|
|
ULONG Index;
|
|
UCHAR Char;
|
|
|
|
//
|
|
// Empty names are not valid
|
|
//
|
|
|
|
if (Name.Length == 0)
|
|
return FALSE;
|
|
|
|
//
|
|
// Do not allow EA name longer than 255 bytes
|
|
//
|
|
if (Name.Length > 255)
|
|
return FALSE;
|
|
|
|
for (Index = 0; Index < (ULONG)Name.Length; Index += 1) {
|
|
|
|
Char = Name.Buffer[Index];
|
|
|
|
//
|
|
// Skip over and Dbcs chacters
|
|
//
|
|
if (FsRtlIsLeadDbcsCharacter(Char)) {
|
|
|
|
ASSERT(Index != (ULONG)(Name.Length - 1));
|
|
Index += 1;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Make sure this character is legal, and if a wild card, that
|
|
// wild cards are permissible.
|
|
//
|
|
if (!FsRtlIsAnsiCharacterLegalFat(Char, FALSE))
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
NTSTATUS
|
|
Ext2SetEa (
|
|
IN PEXT2_IRP_CONTEXT IrpContext
|
|
)
|
|
{
|
|
PIRP Irp = NULL;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
PDEVICE_OBJECT DeviceObject;
|
|
|
|
PEXT2_VCB Vcb = NULL;
|
|
PEXT2_FCB Fcb = NULL;
|
|
PEXT2_CCB Ccb = NULL;
|
|
PEXT2_MCB Mcb = NULL;
|
|
|
|
BOOLEAN MainResourceAcquired = FALSE;
|
|
BOOLEAN FcbLockAcquired = FALSE;
|
|
BOOLEAN XattrRefAcquired = FALSE;
|
|
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
struct ext4_xattr_ref xattr_ref;
|
|
PCHAR UserBuffer;
|
|
ULONG UserBufferLength;
|
|
|
|
PFILE_FULL_EA_INFORMATION FullEa;
|
|
|
|
_SEH2_TRY {
|
|
|
|
Ccb = IrpContext->Ccb;
|
|
ASSERT(Ccb != NULL);
|
|
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
|
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
Vcb = (PEXT2_VCB)DeviceObject->DeviceExtension;
|
|
Fcb = IrpContext->Fcb;
|
|
Mcb = Fcb->Mcb;
|
|
Irp = IrpContext->Irp;
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
//
|
|
// Receive input parameter from caller
|
|
//
|
|
UserBufferLength = IrpSp->Parameters.SetEa.Length;
|
|
UserBuffer = Irp->UserBuffer;
|
|
|
|
// Check if the EA buffer provided is valid
|
|
Status = IoCheckEaBufferValidity((PFILE_FULL_EA_INFORMATION)UserBuffer,
|
|
UserBufferLength,
|
|
(PULONG)&Irp->IoStatus.Information);
|
|
if (!NT_SUCCESS(Status))
|
|
_SEH2_LEAVE;
|
|
|
|
ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
|
|
FcbLockAcquired = TRUE;
|
|
|
|
if (!Mcb)
|
|
_SEH2_LEAVE;
|
|
|
|
//
|
|
// We do not allow multiple instance gaining EA access to the same file
|
|
//
|
|
if (!ExAcquireResourceExclusiveLite(
|
|
&Fcb->MainResource,
|
|
IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
|
|
Status = STATUS_PENDING;
|
|
_SEH2_LEAVE;
|
|
}
|
|
MainResourceAcquired = TRUE;
|
|
|
|
Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref));
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgPrint("ext4_fs_get_xattr_ref() failed!\n");
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
XattrRefAcquired = TRUE;
|
|
|
|
//
|
|
// Remove all existing EA entries.
|
|
//
|
|
ext4_xattr_purge_items(&xattr_ref);
|
|
xattr_ref.dirty = TRUE;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
// Iterate the whole EA buffer to do inspection
|
|
for (FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
|
|
FullEa < (PFILE_FULL_EA_INFORMATION)&UserBuffer[UserBufferLength];
|
|
FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ?
|
|
&UserBuffer[UserBufferLength] :
|
|
(PCHAR)FullEa + FullEa->NextEntryOffset)) {
|
|
|
|
OEM_STRING EaName;
|
|
|
|
EaName.MaximumLength = EaName.Length = FullEa->EaNameLength;
|
|
EaName.Buffer = &FullEa->EaName[0];
|
|
|
|
// Check if EA's name is valid
|
|
if (!Ext2IsEaNameValid(EaName)) {
|
|
Irp->IoStatus.Information = (PCHAR)FullEa - UserBuffer;
|
|
Status = STATUS_INVALID_EA_NAME;
|
|
_SEH2_LEAVE;
|
|
}
|
|
}
|
|
|
|
// Now add EA entries to the inode
|
|
for (FullEa = (PFILE_FULL_EA_INFORMATION)UserBuffer;
|
|
FullEa < (PFILE_FULL_EA_INFORMATION)&UserBuffer[UserBufferLength];
|
|
FullEa = (PFILE_FULL_EA_INFORMATION)(FullEa->NextEntryOffset == 0 ?
|
|
&UserBuffer[UserBufferLength] :
|
|
(PCHAR)FullEa + FullEa->NextEntryOffset)) {
|
|
|
|
int ret;
|
|
OEM_STRING EaName;
|
|
|
|
EaName.MaximumLength = EaName.Length = FullEa->EaNameLength;
|
|
EaName.Buffer = &FullEa->EaName[0];
|
|
|
|
Status = Ext2WinntError(ret =
|
|
ext4_fs_set_xattr_ordered(&xattr_ref,
|
|
EXT4_XATTR_INDEX_USER,
|
|
EaName.Buffer,
|
|
EaName.Length,
|
|
&FullEa->EaName[0] + FullEa->EaNameLength + 1,
|
|
FullEa->EaValueLength));
|
|
if (!NT_SUCCESS(Status))
|
|
_SEH2_LEAVE;
|
|
|
|
}
|
|
} _SEH2_FINALLY {
|
|
|
|
if (XattrRefAcquired) {
|
|
if (!NT_SUCCESS(Status)) {
|
|
xattr_ref.dirty = FALSE;
|
|
ext4_fs_put_xattr_ref(&xattr_ref);
|
|
} else
|
|
Status = Ext2WinntError(ext4_fs_put_xattr_ref(&xattr_ref));
|
|
}
|
|
|
|
if (FcbLockAcquired) {
|
|
ExReleaseResourceLite(&Vcb->FcbLock);
|
|
FcbLockAcquired = FALSE;
|
|
}
|
|
|
|
if (MainResourceAcquired) {
|
|
ExReleaseResourceLite(&Fcb->MainResource);
|
|
}
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Ext2NotifyReportChange(
|
|
IrpContext,
|
|
Vcb,
|
|
Mcb,
|
|
FILE_NOTIFY_CHANGE_EA,
|
|
FILE_ACTION_MODIFIED);
|
|
}
|
|
|
|
if (!_SEH2_AbnormalTermination()) {
|
|
if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
|
|
Status = Ext2QueueRequest(IrpContext);
|
|
}
|
|
else {
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
}
|
|
} _SEH2_END;
|
|
return Status;
|
|
}
|