Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605/** 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 iteratorstruct 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;}
NTSTATUSExt2QueryEa ( 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;}
BOOLEANExt2IsEaNameValid( 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;}
NTSTATUSExt2SetEa ( 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;}