#include <pseh/pseh2.h>
#include <limits.h>
#include <dfs.h>
+#include <copysup.h>
#define NDEBUG
#include <debug.h>
RxAddToTopLevelIrpAllocatedContextsList(
PRX_TOPLEVELIRP_CONTEXT TopLevelContext);
+VOID
+RxAssert(
+ PVOID Assert,
+ PVOID File,
+ ULONG Line,
+ PVOID Message);
+
NTSTATUS
NTAPI
RxCommonCleanup(
RxLowIoReadShellCompletion(
PRX_CONTEXT RxContext);
+NTSTATUS
+RxLowIoWriteShell(
+ IN PRX_CONTEXT RxContext);
+
+NTSTATUS
+NTAPI
+RxLowIoWriteShellCompletion(
+ PRX_CONTEXT RxContext);
+
PVOID
RxNewMapUserBuffer(
PRX_CONTEXT RxContext);
FILE_INFORMATION_CLASS FileInfoClass,
PVOID Buffer);
+VOID
+RxPurgeNetFcb(
+ PFCB Fcb,
+ PRX_CONTEXT LocalContext);
+
NTSTATUS
RxQueryAlternateNameInfo(
PRX_CONTEXT RxContext,
ACCESS_MASK DesiredAccess,
ULONG ShareAccess);
+NTSTATUS
+RxSetAllocationInfo(
+ PRX_CONTEXT RxContext);
+
+NTSTATUS
+RxSetBasicInfo(
+ PRX_CONTEXT RxContext);
+
+NTSTATUS
+RxSetDispositionInfo(
+ PRX_CONTEXT RxContext);
+
+NTSTATUS
+RxSetEndOfFileInfo(
+ PRX_CONTEXT RxContext);
+
+NTSTATUS
+RxSetPipeInfo(
+ PRX_CONTEXT RxContext);
+
+NTSTATUS
+RxSetPositionInfo(
+ PRX_CONTEXT RxContext);
+
+NTSTATUS
+RxSetRenameInfo(
+ PRX_CONTEXT RxContext);
+
+NTSTATUS
+RxSetSimpleInfo(
+ PRX_CONTEXT RxContext);
+
VOID
RxSetupNetFileObject(
PRX_CONTEXT RxContext);
RxXXXControlFileCallthru(
PRX_CONTEXT Context);
+PVOID
+NTAPI
+_RxAllocatePoolWithTag(
+ _In_ POOL_TYPE PoolType,
+ _In_ SIZE_T NumberOfBytes,
+ _In_ ULONG Tag);
+
+VOID
+NTAPI
+_RxFreePool(
+ _In_ PVOID Buffer);
+
+VOID
+NTAPI
+_RxFreePoolWithTag(
+ _In_ PVOID Buffer,
+ _In_ ULONG Tag);
+
WCHAR RxStarForTemplate = '*';
WCHAR Rx8QMdot3QM[] = L">>>>>>>>.>>>*";
BOOLEAN DisableByteRangeLockingOnReadOnlyFiles = FALSE;
FAST_MUTEX RxContextPerFileSerializationMutex;
RDBSS_DATA RxData;
FCB RxDeviceFCB;
+BOOLEAN RxLoudLowIoOpsEnabled = FALSE;
RX_FSD_DISPATCH_VECTOR RxDeviceFCBVector[IRP_MJ_MAXIMUM_FUNCTION + 1] =
{
{ RxCommonDispatchProblem },
KSPIN_LOCK TopLevelIrpSpinLock;
LIST_ENTRY TopLevelIrpAllocatedContextsList;
BOOLEAN RxForceQFIPassThrough = FALSE;
+BOOLEAN RxNoAsync = FALSE;
DECLARE_CONST_UNICODE_STRING(unknownId, L"???");
+#if RDBSS_ASSERTS
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#define ASSERT(exp) \
+ if (!(exp)) \
+ { \
+ RxAssert(#exp, __FILE__, __LINE__, NULL); \
+ }
+#endif
+
+#if RX_POOL_WRAPPER
+#undef RxAllocatePool
+#undef RxAllocatePoolWithTag
+#undef RxFreePool
+
+#define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0)
+#define RxAllocatePoolWithTag _RxAllocatePoolWithTag
+#define RxFreePool _RxFreePool
+#define RxFreePoolWithTag _RxFreePoolWithTag
+#endif
+
/* FUNCTIONS ****************************************************************/
+/*
+ * @implemented
+ */
VOID
CheckForLoudOperations(
PRX_CONTEXT RxContext)
{
- UNIMPLEMENTED;
+ PAGED_CODE();
+
+#define ALLSCR_LENGTH (sizeof(L"all.scr") - sizeof(UNICODE_NULL))
+
+ /* Are loud operations enabled? */
+ if (RxLoudLowIoOpsEnabled)
+ {
+ PFCB Fcb;
+
+ /* If so, the operation will be loud only if filename ends with all.scr */
+ Fcb = (PFCB)RxContext->pFcb;
+ if (RtlCompareMemory(Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, (Fcb->PrivateAlreadyPrefixedName.Length - ALLSCR_LENGTH)),
+ L"all.scr", ALLSCR_LENGTH) == ALLSCR_LENGTH)
+ {
+ SetFlag(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_LOUDOPS);
+ }
+ }
+#undef ALLSCR_LENGTH
}
/*
}
}
-NTSTATUS
-NTAPI
-RxAcquireExclusiveFcbResourceInMRx(
- _Inout_ PMRX_FCB Fcb)
+/*
+ * @implemented
+ */
+VOID
+__RxWriteReleaseResources(
+ PRX_CONTEXT RxContext,
+ BOOLEAN ResourceOwnerSet,
+ ULONG LineNumber,
+ PCSTR FileName,
+ ULONG SerialNumber)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
+ PFCB Fcb;
-BOOLEAN
-NTAPI
-RxAcquireFcbForLazyWrite(
- PVOID Context,
- BOOLEAN Wait)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ PAGED_CODE();
-BOOLEAN
-NTAPI
-RxAcquireFcbForReadAhead(
- PVOID Context,
- BOOLEAN Wait)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ ASSERT(RxContext != NULL);
-VOID
-NTAPI
-RxAcquireFileForNtCreateSection(
- PFILE_OBJECT FileObject)
-{
- UNIMPLEMENTED;
-}
+ Fcb = (PFCB)RxContext->pFcb;
+ ASSERT(Fcb != NULL);
-NTSTATUS
-NTAPI
-RxAcquireForCcFlush(
- PFILE_OBJECT FileObject,
- PDEVICE_OBJECT DeviceObject)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ /* If FCB resource was acquired, release it */
+ if (RxContext->FcbResourceAcquired)
+ {
+ /* Taking care of owner */
+ if (ResourceOwnerSet)
+ {
+ RxReleaseFcbForThread(RxContext, Fcb, RxContext->LowIoContext.ResourceThreadId);
+ }
+ else
+ {
+ RxReleaseFcb(RxContext, Fcb);
+ }
+
+ RxContext->FcbResourceAcquired = FALSE;
+ }
+
+ /* If FCB paging resource was acquired, release it */
+ if (RxContext->FcbPagingIoResourceAcquired)
+ {
+ /* Taking care of owner */
+ if (ResourceOwnerSet)
+ {
+ RxReleasePagingIoResourceForThread(RxContext, Fcb, RxContext->LowIoContext.ResourceThreadId);
+ }
+ else
+ {
+ RxReleasePagingIoResource(RxContext, Fcb);
+ }
+
+ /* No need to release boolean here, RxReleasePagingIoResource() takes care of it */
+ }
}
/*
* @implemented
*/
VOID
+NTAPI
RxAddToWorkque(
IN PRX_CONTEXT RxContext,
IN PIRP Irp)
ExQueueWorkItem((PWORK_QUEUE_ITEM)&RxContext->WorkQueueItem, Queue);
}
+/*
+ * @implemented
+ */
+VOID
+RxAdjustFileTimesAndSize(
+ PRX_CONTEXT Context)
+{
+ PFCB Fcb;
+ PFOBX Fobx;
+ NTSTATUS Status;
+ PFILE_OBJECT FileObject;
+ LARGE_INTEGER CurrentTime;
+ FILE_BASIC_INFORMATION FileBasicInfo;
+ FILE_END_OF_FILE_INFORMATION FileEOFInfo;
+ BOOLEAN FileModified, SetLastChange, SetLastAccess, SetLastWrite, NeedUpdate;
+
+ PAGED_CODE();
+
+ FileObject = Context->CurrentIrpSp->FileObject;
+ /* If Cc isn't initialized, the file was not read nor written, nothing to do */
+ if (FileObject->PrivateCacheMap == NULL)
+ {
+ return;
+ }
+
+ /* Get now */
+ KeQuerySystemTime(&CurrentTime);
+
+ Fobx = (PFOBX)Context->pFobx;
+ /* Was the file modified? */
+ FileModified = BooleanFlagOn(FileObject->Flags, FO_FILE_MODIFIED);
+ /* We'll set last write if it was modified and user didn't update yet */
+ SetLastWrite = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
+ /* File was accessed if: written or read (fastio), we'll update last access if user didn't */
+ SetLastAccess = SetLastWrite ||
+ (BooleanFlagOn(FileObject->Flags, FO_FILE_FAST_IO_READ) &&
+ !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS));
+ /* We'll set last change if it was modified and user didn't update yet */
+ SetLastChange = FileModified && !BooleanFlagOn(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
+
+ /* Nothing to update? Job done */
+ if (!FileModified && !SetLastWrite && !SetLastAccess && !SetLastChange)
+ {
+ return;
+ }
+
+ Fcb = (PFCB)Context->pFcb;
+ /* By default, we won't issue any MRxSetFileInfoAtCleanup call */
+ NeedUpdate = FALSE;
+ RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
+
+ /* Update lastwrite time if required */
+ if (SetLastWrite)
+ {
+ NeedUpdate = TRUE;
+ Fcb->LastWriteTime.QuadPart = CurrentTime.QuadPart;
+ FileBasicInfo.LastWriteTime.QuadPart = CurrentTime.QuadPart;
+ }
+
+ /* Update lastaccess time if required */
+ if (SetLastAccess)
+ {
+ NeedUpdate = TRUE;
+ Fcb->LastAccessTime.QuadPart = CurrentTime.QuadPart;
+ FileBasicInfo.LastAccessTime.QuadPart = CurrentTime.QuadPart;
+ }
+
+ /* Update lastchange time if required */
+ if (SetLastChange)
+ {
+ NeedUpdate = TRUE;
+ Fcb->LastChangeTime.QuadPart = CurrentTime.QuadPart;
+ FileBasicInfo.ChangeTime.QuadPart = CurrentTime.QuadPart;
+ }
+
+ /* If one of the date was modified, issue a call to mini-rdr */
+ if (NeedUpdate)
+ {
+ Context->Info.FileInformationClass = FileBasicInformation;
+ Context->Info.Buffer = &FileBasicInfo;
+ Context->Info.Length = sizeof(FileBasicInfo);
+
+ MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
+ (void)Status;
+ }
+
+ /* If the file was modified, update its EOF */
+ if (FileModified)
+ {
+ FileEOFInfo.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
+
+ Context->Info.FileInformationClass = FileEndOfFileInformation;
+ Context->Info.Buffer = &FileEOFInfo;
+ Context->Info.Length = sizeof(FileEOFInfo);
+
+ MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxSetFileInfoAtCleanup, (Context));
+ (void)Status;
+ }
+}
+
/*
* @implemented
*/
return STATUS_OBJECT_PATH_INVALID;
}
- CanonicalName->Buffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, CanonicalLength, RX_MISC_POOLTAG);
+ CanonicalName->Buffer = RxAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, CanonicalLength, RX_MISC_POOLTAG);
if (CanonicalName->Buffer == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
return STATUS_SUCCESS;
}
+/*
+ * @implemented
+ */
+VOID
+RxCancelNotifyChangeDirectoryRequestsForFobx(
+ PFOBX Fobx)
+{
+ KIRQL OldIrql;
+ PLIST_ENTRY Entry;
+ PRX_CONTEXT Context;
+ LIST_ENTRY ContextsToCancel;
+
+ /* Init a list for the contexts to cancel */
+ InitializeListHead(&ContextsToCancel);
+
+ /* Lock our list lock */
+ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
+
+ /* Now, browse all the active contexts, to find the associated ones */
+ Entry = RxActiveContexts.Flink;
+ while (Entry != &RxActiveContexts)
+ {
+ Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
+ Entry = Entry->Flink;
+
+ /* Not the IRP we're looking for, ignore */
+ if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
+ Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
+ {
+ continue;
+ }
+
+ /* Not the FOBX we're looking for, ignore */
+ if ((PFOBX)Context->pFobx != Fobx)
+ {
+ continue;
+ }
+
+ /* No cancel routine (can't be cancel, then), ignore */
+ if (Context->MRxCancelRoutine == NULL)
+ {
+ continue;
+ }
+
+ /* Mark our context as cancelled */
+ SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
+
+ /* Move it to our list */
+ RemoveEntryList(&Context->ContextListEntry);
+ InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
+
+ InterlockedIncrement((volatile long *)&Context->ReferenceCount);
+ }
+
+ /* Done with the contexts */
+ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
+
+ /* Now, handle all our "extracted" contexts */
+ while (!IsListEmpty(&ContextsToCancel))
+ {
+ Entry = RemoveHeadList(&ContextsToCancel);
+ Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
+
+ /* If they had an associated IRP (should be always true) */
+ if (Context->CurrentIrp != NULL)
+ {
+ /* Then, call cancel routine */
+ ASSERT(Context->MRxCancelRoutine != NULL);
+ DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
+ Context->MRxCancelRoutine(Context);
+ }
+
+ /* And delete the context */
+ RxDereferenceAndDeleteRxContext(Context);
+ }
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxCancelNotifyChangeDirectoryRequestsForVNetRoot(
+ PV_NET_ROOT VNetRoot,
+ BOOLEAN ForceFilesClosed)
+{
+ KIRQL OldIrql;
+ NTSTATUS Status;
+ PLIST_ENTRY Entry;
+ PRX_CONTEXT Context;
+ LIST_ENTRY ContextsToCancel;
+
+ /* Init a list for the contexts to cancel */
+ InitializeListHead(&ContextsToCancel);
+
+ /* Lock our list lock */
+ KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql);
+
+ /* Now, browse all the active contexts, to find the associated ones */
+ Entry = RxActiveContexts.Flink;
+ while (Entry != &RxActiveContexts)
+ {
+ Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
+ Entry = Entry->Flink;
+
+ /* Not the IRP we're looking for, ignore */
+ if (Context->MajorFunction != IRP_MJ_DIRECTORY_CONTROL ||
+ Context->MinorFunction != IRP_MN_NOTIFY_CHANGE_DIRECTORY)
+ {
+ continue;
+ }
+
+ /* Not the VNetRoot we're looking for, ignore */
+ if (Context->pFcb == NULL ||
+ (PV_NET_ROOT)Context->NotifyChangeDirectory.pVNetRoot != VNetRoot)
+ {
+ continue;
+ }
+
+ /* No cancel routine (can't be cancel, then), ignore */
+ if (Context->MRxCancelRoutine == NULL)
+ {
+ continue;
+ }
+
+ /* At that point, we found a matching context
+ * If we're not asked to force close, then fail - it's still open
+ */
+ if (!ForceFilesClosed)
+ {
+ Status = STATUS_FILES_OPEN;
+ break;
+ }
+
+ /* Mark our context as cancelled */
+ SetFlag(Context->Flags, RX_CONTEXT_FLAG_CANCELLED);
+
+ /* Move it to our list */
+ RemoveEntryList(&Context->ContextListEntry);
+ InsertTailList(&ContextsToCancel, &Context->ContextListEntry);
+
+ InterlockedIncrement((volatile long *)&Context->ReferenceCount);
+ }
+
+ /* Done with the contexts */
+ KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql);
+
+ if (Status != STATUS_SUCCESS)
+ {
+ return Status;
+ }
+
+ /* Now, handle all our "extracted" contexts */
+ while (!IsListEmpty(&ContextsToCancel))
+ {
+ Entry = RemoveHeadList(&ContextsToCancel);
+ Context = CONTAINING_RECORD(Entry, RX_CONTEXT, ContextListEntry);
+
+ /* If they had an associated IRP (should be always true) */
+ if (Context->CurrentIrp != NULL)
+ {
+ /* Then, call cancel routine */
+ ASSERT(Context->MRxCancelRoutine != NULL);
+ DPRINT1("Canceling %p with %p\n", Context, Context->MRxCancelRoutine);
+ Context->MRxCancelRoutine(Context);
+ }
+
+ /* And delete the context */
+ RxDereferenceAndDeleteRxContext(Context);
+ }
+
+ return Status;
+}
+
VOID
NTAPI
RxCancelRoutine(
}
/* Validate name is correct */
- for (NextChar = 0; CurChar + 1 < MaxChars; NextChar = CurChar + 1)
+ for (NextChar = 0, CurChar = 0; CurChar + 1 < MaxChars; NextChar = CurChar + 1)
{
USHORT i;
return Status;
}
-NTSTATUS
+VOID
NTAPI
-RxChangeBufferingState(
- PSRV_OPEN SrvOpen,
- PVOID Context,
- BOOLEAN ComputeNewState)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-VOID
-NTAPI
-RxCheckFcbStructuresForAlignment(
- VOID)
+RxCheckFcbStructuresForAlignment(
+ VOID)
{
UNIMPLEMENTED;
}
+#if DBG
NTSTATUS
RxCheckShareAccess(
_In_ ACCESS_MASK DesiredAccess,
return IoCheckShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess, Update);
}
+#endif
/*
* @implemented
return STATUS_SUCCESS;
}
+VOID
+RxCleanupPipeQueues(
+ PRX_CONTEXT Context)
+{
+ UNIMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
NTSTATUS
RxCloseAssociatedSrvOpen(
IN PFOBX Fobx,
IN PRX_CONTEXT RxContext OPTIONAL)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PFCB Fcb;
+ NTSTATUS Status;
+ PSRV_OPEN SrvOpen;
+ BOOLEAN CloseSrvOpen;
+ PRX_CONTEXT LocalContext;
+
+ PAGED_CODE();
+
+ /* Assume SRV_OPEN is already closed */
+ CloseSrvOpen = FALSE;
+ /* If we have a FOBX, we'll have to close it */
+ if (Fobx != NULL)
+ {
+ /* If the FOBX isn't closed yet */
+ if (!BooleanFlagOn(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED))
+ {
+ SrvOpen = Fobx->SrvOpen;
+ Fcb = (PFCB)SrvOpen->pFcb;
+ /* Check whether we've to close SRV_OPEN first */
+ if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
+ {
+ CloseSrvOpen = TRUE;
+ }
+ else
+ {
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+
+ /* Not much to do */
+ SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
+
+ if (SrvOpen->OpenCount > 0)
+ {
+ --SrvOpen->OpenCount;
+ }
+ }
+ }
+
+ /* No need to close SRV_OPEN, so close FOBX */
+ if (!CloseSrvOpen)
+ {
+ RxMarkFobxOnClose(Fobx);
+
+ return STATUS_SUCCESS;
+ }
+ }
+ else
+ {
+ /* No FOBX? No RX_CONTEXT, ok, job done! */
+ if (RxContext == NULL)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /* Get the FCB from RX_CONTEXT */
+ Fcb = (PFCB)RxContext->pFcb;
+ SrvOpen = NULL;
+ }
+
+ /* If we don't have RX_CONTEXT, allocte one, we'll need it */
+ if (RxContext == NULL)
+ {
+ ASSERT(Fobx != NULL);
+
+ LocalContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT);
+ if (LocalContext == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ LocalContext->MajorFunction = 2;
+ LocalContext->pFcb = RX_GET_MRX_FCB(Fcb);
+ LocalContext->pFobx = (PMRX_FOBX)Fobx;
+ LocalContext->pRelevantSrvOpen = (PMRX_SRV_OPEN)Fobx->SrvOpen;
+ }
+ else
+ {
+ LocalContext = RxContext;
+ }
+
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+
+ /* Now, close the FOBX */
+ if (Fobx != NULL)
+ {
+ RxMarkFobxOnClose(Fobx);
+ }
+ else
+ {
+ InterlockedDecrement((volatile long *)&Fcb->OpenCount);
+ }
+
+ /* If not a "standard" file, SRV_OPEN can be null */
+ if (SrvOpen == NULL)
+ {
+ ASSERT((NodeType(Fcb) == RDBSS_NTC_OPENTARGETDIR_FCB) || (NodeType(Fcb) == RDBSS_NTC_IPC_SHARE) || (NodeType(Fcb) == RDBSS_NTC_MAILSLOT));
+ RxDereferenceNetFcb(Fcb);
+
+ if (LocalContext != RxContext)
+ {
+ RxDereferenceAndDeleteRxContext(LocalContext);
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ /* If SRV_OPEN isn't in a good condition, nothing to close */
+ if (SrvOpen->Condition != Condition_Good)
+ {
+ if (LocalContext != RxContext)
+ {
+ RxDereferenceAndDeleteRxContext(LocalContext);
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ /* Decrease open count */
+ if (SrvOpen->OpenCount > 0)
+ {
+ --SrvOpen->OpenCount;
+ }
+
+ /* If we're the only one left, is there a FOBX handled by Scavenger? */
+ if (SrvOpen->OpenCount == 1)
+ {
+ if (!IsListEmpty(&SrvOpen->FobxList))
+ {
+ if (!IsListEmpty(&CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks)->ScavengerFinalizationList))
+ {
+ SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
+ }
+ }
+ }
+
+ /* Nothing left, purge FCB */
+ if (SrvOpen->OpenCount == 0 && RxContext == NULL)
+ {
+ RxPurgeNetFcb(Fcb, LocalContext);
+ }
+
+ /* Already closed? Job done! */
+ SrvOpen = Fobx->SrvOpen;
+ if (SrvOpen == NULL ||
+ (SrvOpen->OpenCount != 0 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) ||
+ BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED))
+ {
+ SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
+ if (LocalContext != RxContext)
+ {
+ RxDereferenceAndDeleteRxContext(LocalContext);
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+
+ /* Inform mini-rdr about closing */
+ MINIRDR_CALL(Status, LocalContext, Fcb->MRxDispatch, MRxCloseSrvOpen, (LocalContext));
+ DPRINT("MRxCloseSrvOpen returned: %lx, called with RX_CONTEXT %p for FOBX %p (FCB %p, SRV_OPEN %p)\n ",
+ Status, RxContext, Fobx, Fcb, SrvOpen);
+
+ /* And mark as such */
+ SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSED);
+ SrvOpen->Key = (PVOID)-1;
+
+ /* If we were delayed, we're not! */
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED))
+ {
+ InterlockedDecrement(&((PSRV_CALL)Fcb->pNetRoot->pSrvCall)->NumberOfCloseDelayedFiles);
+ }
+
+ /* Clear access */
+ RxRemoveShareAccessPerSrvOpens(SrvOpen);
+ RxPurgeChangeBufferingStateRequestsForSrvOpen(SrvOpen);
+
+ /* Dereference */
+ RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld);
+
+ /* Mark the FOBX closed as well */
+ SetFlag(Fobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED);
+
+ if (LocalContext != RxContext)
+ {
+ RxDereferenceAndDeleteRxContext(LocalContext);
+ }
+
+ return Status;
}
/*
return Status;
}
+/*
+ * @implemented
+ */
NTSTATUS
NTAPI
RxCommonCleanup(
#define BugCheckFileId RDBSS_BUG_CHECK_CLEANUP
PFCB Fcb;
PFOBX Fobx;
+ ULONG OpenCount;
NTSTATUS Status;
- BOOLEAN NeedPurge;
+ PNET_ROOT NetRoot;
PFILE_OBJECT FileObject;
+ LARGE_INTEGER TruncateSize;
+ PLARGE_INTEGER TruncateSizePtr;
+ BOOLEAN NeedPurge, FcbTableAcquired, OneLeft, IsFile, FcbAcquired, LeftForDelete;
PAGED_CODE();
return Status;
}
+ FcbAcquired = TRUE;
+
Fobx->AssociatedFileObject = NULL;
/* In case SRV_OPEN used is part of FCB */
return STATUS_SUCCESS;
}
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-#undef BugCheckFileId
-}
-
-NTSTATUS
-NTAPI
-RxCommonClose(
- PRX_CONTEXT Context)
-{
-#define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
- PFCB Fcb;
- PFOBX Fobx;
- NTSTATUS Status;
- PFILE_OBJECT FileObject;
- BOOLEAN DereferenceFobx, AcquiredFcb;
+ /* Report the fact that file could be set as delete on close */
+ if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
+ {
+ SetFlag(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE);
+ }
- PAGED_CODE();
+ /* Cancel any pending notification */
+ RxCancelNotifyChangeDirectoryRequestsForFobx(Fobx);
- Fcb = (PFCB)Context->pFcb;
- Fobx = (PFOBX)Context->pFobx;
- FileObject = Context->CurrentIrpSp->FileObject;
- DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context, Fobx, Fcb, FileObject);
+ /* Backup open count before we start playing with it */
+ OpenCount = Fcb->ShareAccess.OpenCount;
- Status = RxAcquireExclusiveFcb(Context, Fcb);
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
+ NetRoot = (PNET_ROOT)Fcb->pNetRoot;
+ FcbTableAcquired = FALSE;
+ LeftForDelete = FALSE;
+ OneLeft = (Fcb->UncleanCount == 1);
- AcquiredFcb = TRUE;
_SEH2_TRY
{
- BOOLEAN Freed;
+ /* Unclean count and delete on close? Verify whether we're the one */
+ if (OneLeft && BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE))
+ {
+ if (RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE))
+ {
+ FcbTableAcquired = TRUE;
+ }
+ else
+ {
+ RxReleaseFcb(Context, Fcb);
- /* Check our FCB type is expected */
- if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
- (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY || (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE &&
- (NodeType(Fcb) < RDBSS_NTC_SPOOLFILE || NodeType(Fcb) > RDBSS_NTC_OPENTARGETDIR_FCB))))
+ RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
+
+ Status = RxAcquireExclusiveFcb(Context, Fcb);
+ if (Status != STATUS_SUCCESS)
+ {
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ return Status;
+ }
+
+ FcbTableAcquired = TRUE;
+ }
+
+ /* That means we'll perform the delete on close! */
+ if (Fcb->UncleanCount == 1)
+ {
+ LeftForDelete = TRUE;
+ }
+ else
+ {
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ FcbTableAcquired = FALSE;
+ }
+ }
+
+ IsFile = FALSE;
+ TruncateSizePtr = NULL;
+ /* Handle cleanup for pipes and printers */
+ if (NetRoot->Type == NET_ROOT_PIPE || NetRoot->Type == NET_ROOT_PRINT)
{
- RxBugCheck(NodeType(Fcb), 0, 0);
+ RxCleanupPipeQueues(Context);
}
+ /* Handle cleanup for files */
+ else if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
+ {
+ Context->LowIoContext.Flags |= LOWIO_CONTEXT_FLAG_SAVEUNLOCKS;
+ if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
+ {
+ /* First, unlock */
+ FsRtlFastUnlockAll(&Fcb->Specific.Fcb.FileLock, FileObject, RxGetRequestorProcess(Context), Context);
- RxReferenceNetFcb(Fcb);
+ /* If there are still locks to release, proceed */
+ if (Context->LowIoContext.ParamsFor.Locks.LockList != NULL)
+ {
+ RxInitializeLowIoContext(&Context->LowIoContext, LOWIO_OP_UNLOCK_MULTIPLE);
+ Context->LowIoContext.ParamsFor.Locks.Flags = 0;
+ Status = RxLowIoLockControlShell(Context);
+ }
- DereferenceFobx = FALSE;
- /* If we're not closing FS */
- if (Fobx != NULL)
- {
- PSRV_OPEN SrvOpen;
- PSRV_CALL SrvCall;
+ /* Fix times and size */
+ RxAdjustFileTimesAndSize(Context);
- SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
- SrvCall = (PSRV_CALL)Fcb->pNetRoot->pSrvCall;
- /* Handle delayed close */
- if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
- {
- if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE | FCB_STATE_ORPHANED))
+ /* If we're the only one left... */
+ if (OneLeft)
{
- if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED))
+ /* And if we're supposed to delete on close */
+ if (LeftForDelete)
{
- DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx, SrvOpen);
+ /* Update the sizes */
+ RxAcquirePagingIoResource(Context, Fcb);
+ Fcb->Header.FileSize.QuadPart = 0;
+ Fcb->Header.ValidDataLength.QuadPart = 0;
+ RxReleasePagingIoResource(Context, Fcb);
+ }
+ /* Otherwise, call the mini-rdr to adjust sizes */
+ else
+ {
+ /* File got grown up, fill with zeroes */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) &&
+ (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart))
+ {
+ MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxZeroExtend, (Context));
+ Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
+ }
- if (SrvOpen->OpenCount == 1 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED))
+ /* File was truncated, let mini-rdr proceed */
+ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE))
{
- if (InterlockedIncrement(&SrvCall->NumberOfCloseDelayedFiles) >= SrvCall->MaximumNumberOfCloseDelayedFiles)
- {
- InterlockedDecrement(&SrvCall->NumberOfCloseDelayedFiles);
- }
- else
- {
- DereferenceFobx = TRUE;
- SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
- }
+ MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxTruncate, (Context));
+ ClearFlag(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE);
+
+ /* Keep track of file change for Cc uninit */
+ TruncateSize.QuadPart = Fcb->Header.FileSize.QuadPart;
+ TruncateSizePtr = &TruncateSize;
}
}
}
- }
-
- /* If we reach maximum of delayed close/or if there are no delayed close */
- if (!DereferenceFobx)
- {
- PNET_ROOT NetRoot;
- NetRoot = (PNET_ROOT)Fcb->pNetRoot;
- if (NetRoot->Type != NET_ROOT_PRINT)
+ /* If RxMarkFobxOnCleanup() asked for purge, make sure we're the only one left first */
+ if (NeedPurge)
{
- /* Delete if asked */
- if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
+ if (!OneLeft)
{
- RxScavengeRelatedFobxs(Fcb);
- RxSynchronizeWithScavenger(Context);
-
- RxReleaseFcb(Context, Fcb);
-
- RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
- RxOrphanThisFcb(Fcb);
- RxReleaseFcbTableLock(&NetRoot->FcbTable);
-
- Status = RxAcquireExclusiveFcb(Context, Fcb);
- ASSERT(NT_SUCCESS(Status));
+ NeedPurge = FALSE;
}
}
- }
+ /* Otherwise, try to see whether we can purge */
+ else
+ {
+ NeedPurge = (OneLeft && (LeftForDelete || !BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED)));
+ }
- RxMarkFobxOnClose(Fobx);
+ IsFile = TRUE;
+ }
}
- if (DereferenceFobx)
+ /* We have to still be there! */
+ ASSERT(Fcb->UncleanCount != 0);
+ InterlockedDecrement((volatile long *)&Fcb->UncleanCount);
+
+ if (BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
{
- ASSERT(Fobx != NULL);
- RxDereferenceNetFobx(Fobx, LHS_SharedLockHeld);
+ --Fcb->UncachedUncleanCount;
}
- else
- {
- RxCloseAssociatedSrvOpen(Fobx, Context);
- if (Fobx != NULL)
+
+ /* Inform mini-rdr about ongoing cleanup */
+ MINIRDR_CALL(Status, Context, Fcb->MRxDispatch, MRxCleanupFobx, (Context));
+
+ ASSERT(Fobx->SrvOpen->UncleanFobxCount != 0);
+ --Fobx->SrvOpen->UncleanFobxCount;
+
+ /* Flush cache */
+ if (DisableFlushOnCleanup)
+ {
+ /* Only if we're the last standing */
+ if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL &&
+ Fcb->UncleanCount == Fcb->UncachedUncleanCount)
+ {
+ DPRINT("Flushing %p due to last cached handle cleanup\n", Context);
+ RxFlushFcbInSystemCache(Fcb, TRUE);
+ }
+ }
+ else
+ {
+ /* Always */
+ if (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
+ {
+ DPRINT("Flushing %p on cleanup\n", Context);
+ RxFlushFcbInSystemCache(Fcb, TRUE);
+ }
+ }
+
+ /* If only remaining uncached & unclean, then flush and purge */
+ if (!BooleanFlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING))
+ {
+ if (Fcb->UncachedUncleanCount != 0)
+ {
+ if (Fcb->UncachedUncleanCount == Fcb->UncleanCount &&
+ Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
+ {
+ DPRINT("Flushing FCB in system cache for %p\n", Context);
+ RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, TRUE);
+ }
+ }
+ }
+
+ /* If purge required, and not about to delete, flush */
+ if (!LeftForDelete && NeedPurge)
+ {
+ DPRINT("Flushing FCB in system cache for %p\n", Context);
+ RxFlushFcbInSystemCache(Fcb, TRUE);
+ }
+
+ /* If it was a file, drop cache */
+ if (IsFile)
+ {
+ DPRINT("Uninit cache map for file\n");
+ RxUninitializeCacheMap(Context, FileObject, TruncateSizePtr);
+ }
+
+ /* If that's the one left for deletion, or if it needs purge, flush */
+ if (LeftForDelete || NeedPurge)
+ {
+ RxPurgeFcbInSystemCache(Fcb, NULL, 0, FALSE, !LeftForDelete);
+ /* If that's for deletion, also remove from FCB table */
+ if (LeftForDelete)
+ {
+ RxRemoveNameNetFcb(Fcb);
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ FcbTableAcquired = FALSE;
+ }
+ }
+
+ /* Remove any share access */
+ if (OpenCount != 0 && NetRoot->Type == NET_ROOT_DISK)
+ {
+ RxRemoveShareAccess(FileObject, &Fcb->ShareAccess, "Cleanup the share access", "ClnUpShr");
+ }
+
+ /* In case there's caching, on a file, and we were asked to drop collapsing, handle it */
+ if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE && BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING) &&
+ RxWriteCacheingAllowed(Fcb, Fobx->pSrvOpen))
+ {
+ NTSTATUS InternalStatus;
+ PRX_CONTEXT InternalContext;
+
+ /* If we can properly set EOF, there's no need to drop collapsing, try to do it */
+ InternalStatus = STATUS_UNSUCCESSFUL;
+ InternalContext = RxCreateRxContext(Context->CurrentIrp,
+ Fcb->RxDeviceObject,
+ RX_CONTEXT_FLAG_WAIT | RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING);
+ if (InternalContext != NULL)
+ {
+ FILE_END_OF_FILE_INFORMATION FileEOF;
+
+ InternalStatus = STATUS_SUCCESS;
+
+ /* Initialize the context for file information set */
+ InternalContext->pFcb = RX_GET_MRX_FCB(Fcb);
+ InternalContext->pFobx = (PMRX_FOBX)Fobx;
+ InternalContext->pRelevantSrvOpen = Fobx->pSrvOpen;
+
+ /* Get EOF from the FCB */
+ FileEOF.EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
+ InternalContext->Info.FileInformationClass = FileEndOfFileInformation;
+ InternalContext->Info.Buffer = &FileEOF;
+ InternalContext->Info.Length = sizeof(FileEOF);
+
+ /* Call the mini-rdr */
+ MINIRDR_CALL_THROUGH(InternalStatus, Fcb->MRxDispatch, MRxSetFileInfo, (InternalContext));
+
+ /* We're done */
+ RxDereferenceAndDeleteRxContext(InternalContext);
+ }
+
+ /* We tried, so, clean the FOBX flag */
+ ClearFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
+ /* If it failed, then, disable collapsing on the FCB */
+ if (!NT_SUCCESS(InternalStatus))
+ {
+ ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
+ }
+ }
+
+ /* We're clean! */
+ SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
+
+ FcbAcquired = FALSE;
+ RxReleaseFcb(Context, Fcb);
+ }
+ _SEH2_FINALLY
+ {
+ if (FcbAcquired)
+ {
+ RxReleaseFcb(Context, Fcb);
+ }
+
+ if (FcbTableAcquired)
+ {
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ }
+ }
+ _SEH2_END;
+
+ return Status;
+#undef BugCheckFileId
+}
+
+NTSTATUS
+NTAPI
+RxCommonClose(
+ PRX_CONTEXT Context)
+{
+#define BugCheckFileId RDBSS_BUG_CHECK_CLOSE
+ PFCB Fcb;
+ PFOBX Fobx;
+ NTSTATUS Status;
+ PFILE_OBJECT FileObject;
+ BOOLEAN DereferenceFobx, AcquiredFcb;
+
+ PAGED_CODE();
+
+ Fcb = (PFCB)Context->pFcb;
+ Fobx = (PFOBX)Context->pFobx;
+ FileObject = Context->CurrentIrpSp->FileObject;
+ DPRINT("RxCommonClose(%p); FOBX: %p, FCB: %p, FO: %p\n", Context, Fobx, Fcb, FileObject);
+
+ Status = RxAcquireExclusiveFcb(Context, Fcb);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ AcquiredFcb = TRUE;
+ _SEH2_TRY
+ {
+ BOOLEAN Freed;
+
+ /* Check our FCB type is expected */
+ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
+ (NodeType(Fcb) < RDBSS_NTC_STORAGE_TYPE_DIRECTORY || (NodeType(Fcb) > RDBSS_NTC_STORAGE_TYPE_FILE &&
+ (NodeType(Fcb) < RDBSS_NTC_SPOOLFILE || NodeType(Fcb) > RDBSS_NTC_OPENTARGETDIR_FCB))))
+ {
+ RxBugCheck(NodeType(Fcb), 0, 0);
+ }
+
+ RxReferenceNetFcb(Fcb);
+
+ DereferenceFobx = FALSE;
+ /* If we're not closing FS */
+ if (Fobx != NULL)
+ {
+ PSRV_OPEN SrvOpen;
+ PSRV_CALL SrvCall;
+
+ SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
+ SrvCall = (PSRV_CALL)Fcb->pNetRoot->pSrvCall;
+ /* Handle delayed close */
+ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
+ {
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE | FCB_STATE_ORPHANED))
+ {
+ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED))
+ {
+ DPRINT("Delay close for FOBX: %p, SrvOpen %p\n", Fobx, SrvOpen);
+
+ if (SrvOpen->OpenCount == 1 && !BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_COLLAPSING_DISABLED))
+ {
+ if (InterlockedIncrement(&SrvCall->NumberOfCloseDelayedFiles) >= SrvCall->MaximumNumberOfCloseDelayedFiles)
+ {
+ InterlockedDecrement(&SrvCall->NumberOfCloseDelayedFiles);
+ }
+ else
+ {
+ DereferenceFobx = TRUE;
+ SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED);
+ }
+ }
+ }
+ }
+ }
+
+ /* If we reach maximum of delayed close/or if there are no delayed close */
+ if (!DereferenceFobx)
+ {
+ PNET_ROOT NetRoot;
+
+ NetRoot = (PNET_ROOT)Fcb->pNetRoot;
+ if (NetRoot->Type != NET_ROOT_PRINT)
+ {
+ /* Delete if asked */
+ if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_DELETE_ON_CLOSE))
+ {
+ RxScavengeRelatedFobxs(Fcb);
+ RxSynchronizeWithScavenger(Context);
+
+ RxReleaseFcb(Context, Fcb);
+
+ RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE);
+ RxOrphanThisFcb(Fcb);
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+
+ Status = RxAcquireExclusiveFcb(Context, Fcb);
+ ASSERT(NT_SUCCESS(Status));
+ }
+ }
+ }
+
+ RxMarkFobxOnClose(Fobx);
+ }
+
+ if (DereferenceFobx)
+ {
+ ASSERT(Fobx != NULL);
+ RxDereferenceNetFobx(Fobx, LHS_SharedLockHeld);
+ }
+ else
+ {
+ RxCloseAssociatedSrvOpen(Fobx, Context);
+ if (Fobx != NULL)
{
RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld);
}
#undef BugCheckFileId
}
+/*
+ * @implemented
+ */
NTSTATUS
NTAPI
RxCommonCreate(
Status = RxCreateFromNetRoot(Context, &NetRootName);
if (Status == STATUS_SHARING_VIOLATION)
{
- UNIMPLEMENTED;
+ ASSERT(!BooleanFlagOn(Context->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE));
+
+ /* If that happens for file creation, fail for real */
+ if (Context->Create.NtCreateParameters.Disposition == FILE_CREATE)
+ {
+ Status = STATUS_OBJECT_NAME_COLLISION;
+ }
+ else
+ {
+ /* Otherwise, if possible, attempt to scavenger current FOBX
+ * to check whether a dormant FOBX is the reason for sharing violation
+ */
+ if (Context->Create.TryForScavengingOnSharingViolation &&
+ !Context->Create.ScavengingAlreadyTried)
+ {
+ /* Only doable with a VNetRoot */
+ if (Context->Create.pVNetRoot != NULL)
+ {
+ PV_NET_ROOT VNetRoot;
+ NT_CREATE_PARAMETERS SavedParameters;
+
+ /* Save create parameters */
+ RtlCopyMemory(&SavedParameters, &Context->Create.NtCreateParameters, sizeof(NT_CREATE_PARAMETERS));
+
+ /* Reference the VNetRoot for the scavenging time */
+ VNetRoot = (PV_NET_ROOT)Context->Create.pVNetRoot;
+ RxReferenceVNetRoot(VNetRoot);
+
+ /* Prepare the RX_CONTEXT for reuse */
+ RxpPrepareCreateContextForReuse(Context);
+ RxReinitializeContext(Context);
+
+ /* Copy what we saved */
+ RtlCopyMemory(&Context->Create.NtCreateParameters, &SavedParameters, sizeof(NT_CREATE_PARAMETERS));
+
+ /* And recopy what can be */
+ RxCopyCreateParameters(Context);
+
+ /* And start purging, then scavenging FOBX */
+ RxPurgeRelatedFobxs((PNET_ROOT)VNetRoot->pNetRoot, Context,
+ DONT_ATTEMPT_FINALIZE_ON_PURGE, NULL);
+ RxScavengeFobxsForNetRoot((PNET_ROOT)VNetRoot->pNetRoot,
+ NULL, TRUE);
+
+ /* Ask for a second round */
+ Status = STATUS_MORE_PROCESSING_REQUIRED;
+
+ /* Keep track we already scavenged */
+ Context->Create.ScavengingAlreadyTried = TRUE;
+
+ /* Reference our SRV_CALL for CBS handling */
+ RxReferenceSrvCall(VNetRoot->pNetRoot->pSrvCall);
+ RxpProcessChangeBufferingStateRequests((PSRV_CALL)VNetRoot->pNetRoot->pSrvCall, FALSE);
+
+ /* Drop our extra reference */
+ RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld);
+ }
+ }
+ }
}
else if (Status == STATUS_REPARSE)
{
/* Our FOBX if set, has to be a VNetRoot */
if (NetRoot != NULL)
{
- RxAcquirePrefixTableLockShared(Context->RxDeviceObject->pRxNetNameTable, TRUE);
+ RxAcquirePrefixTableLockExclusive(Context->RxDeviceObject->pRxNetNameTable, TRUE);
if (NetRoot->NodeTypeCode == RDBSS_NTC_V_NETROOT)
{
--NetRoot->NumberOfOpens;
RxCommonFileSystemControl(
PRX_CONTEXT Context)
{
+ PIRP Irp;
+ ULONG ControlCode;
+ PIO_STACK_LOCATION Stack;
+
+ PAGED_CODE();
+
+ Irp = Context->CurrentIrp;
+ Stack = Context->CurrentIrpSp;
+ ControlCode = Stack->Parameters.FileSystemControl.FsControlCode;
+
+ DPRINT1("RxCommonFileSystemControl: %p, %p, %d, %lx\n", Context, Irp, Stack->MinorFunction, ControlCode);
+
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
if (!NT_SUCCESS(Irp->IoStatus.Status))
{
+ Status = Irp->IoStatus.Status;
_SEH2_LEAVE;
}
ClearFlag(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED);
}
- /* If it's consistent, forward to mini-rdr */
- if (Fcb->CachedNetRootType != NET_ROOT_DISK || BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) ||
- ByteOffset.QuadPart < Fcb->Header.ValidDataLength.QuadPart)
+ /* If it's consistent, forward to mini-rdr */
+ if (Fcb->CachedNetRootType != NET_ROOT_DISK || BooleanFlagOn(Fcb->FcbState, FCB_STATE_READAHEAD_DEFERRED) ||
+ ByteOffset.QuadPart < Fcb->Header.ValidDataLength.QuadPart)
+ {
+ LowIoContext->ParamsFor.ReadWrite.ByteCount = ReadLength;
+ LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
+
+ RxItsTheSameContext();
+
+ if (InFsp && ReadCachingDisabled)
+ {
+ ExSetResourceOwnerPointer((PagingIo ? Fcb->Header.PagingIoResource : Fcb->Header.Resource),
+ (PVOID)((ULONG_PTR)RxContext | 3));
+ OwnerSet = TRUE;
+ }
+
+ Status = RxLowIoReadShell(RxContext);
+
+ RxItsTheSameContext();
+ }
+ else
+ {
+ if (ByteOffset.QuadPart > FileSize)
+ {
+ ReadLength = 0;
+ Irp->IoStatus.Information = ReadLength;
+ _SEH2_LEAVE;
+ }
+
+ if (ByteOffset.QuadPart + ReadLength > FileSize)
+ {
+ ReadLength = FileSize - ByteOffset.QuadPart;
+ }
+
+ SystemBuffer = RxNewMapUserBuffer(RxContext);
+ RtlZeroMemory(SystemBuffer, ReadLength);
+ Irp->IoStatus.Information = ReadLength;
+ }
+ }
+ }
+ _SEH2_FINALLY
+ {
+ RxItsTheSameContext();
+
+ /* Post if required */
+ if (PostRequest)
+ {
+ InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
+ Status = RxFsdPostRequest(RxContext);
+ }
+ else
+ {
+ /* Update FO in case of sync IO */
+ if (!IsPipe && !PagingIo)
+ {
+ if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+ {
+ FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
+ }
+ }
+ }
+
+ /* Set FastIo if read was a success */
+ if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
+ {
+ if (!IsPipe && !PagingIo)
+ {
+ SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
+ }
+ }
+
+ /* In case we're done (not expected any further processing */
+ if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostRequest)
+ {
+ /* Release everything that can be */
+ if (ReadCachingDisabled)
+ {
+ if (PagingIo)
+ {
+ if (OwnerSet)
+ {
+ RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
+ }
+ else
+ {
+ RxReleasePagingIoResource(RxContext, Fcb);
+ }
+ }
+ else
+ {
+ if (OwnerSet)
+ {
+ RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
+ }
+ else
+ {
+ RxReleaseFcb(RxContext, Fcb);
+ }
+ }
+ }
+
+ /* Dereference/Delete context */
+ if (PostRequest)
+ {
+ RxDereferenceAndDeleteRxContext(RxContext);
+ }
+ else
+ {
+ if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
+ {
+ RxResumeBlockedOperations_Serially(RxContext, &Fobx->Specific.NamedPipe.ReadSerializationQueue);
+ }
+ }
+
+ /* We cannot return more than asked */
+ if (Status == STATUS_SUCCESS)
+ {
+ ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
+ }
+ }
+ else
+ {
+ ASSERT(!Sync);
+
+ RxDereferenceAndDeleteRxContext(RxContext);
+ }
+ }
+ _SEH2_END;
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+RxCommonSetEa(
+ PRX_CONTEXT Context)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxCommonSetInformation(
+ PRX_CONTEXT Context)
+{
+ PIRP Irp;
+ PFCB Fcb;
+ PFOBX Fobx;
+ NTSTATUS Status;
+ PNET_ROOT NetRoot;
+ PIO_STACK_LOCATION Stack;
+ FILE_INFORMATION_CLASS Class;
+ BOOLEAN CanWait, FcbTableAcquired, FcbAcquired;
+
+ PAGED_CODE();
+
+ Fcb = (PFCB)Context->pFcb;
+ Fobx = (PFOBX)Context->pFobx;
+ DPRINT("RxCommonSetInformation(%p), FCB: %p, FOBX: %p\n", Context, Fcb, Fobx);
+
+ Irp = Context->CurrentIrp;
+ Stack = Context->CurrentIrpSp;
+ Class = Stack->Parameters.SetFile.FileInformationClass;
+ DPRINT("Buffer: %p, Length: %lx, Class: %ld, ReplaceIfExists: %d\n",
+ Irp->AssociatedIrp.SystemBuffer, Stack->Parameters.SetFile.Length,
+ Class, Stack->Parameters.SetFile.ReplaceIfExists);
+
+ Status = STATUS_SUCCESS;
+ CanWait = BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_WAIT);
+ FcbTableAcquired = FALSE;
+ FcbAcquired = FALSE;
+ NetRoot = (PNET_ROOT)Fcb->pNetRoot;
+
+#define _SEH2_TRY_RETURN(S) S; goto try_exit
+
+ _SEH2_TRY
+ {
+ /* Valide the node type first */
+ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_UNKNOWN &&
+ NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
+ {
+ if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_FILE)
+ {
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
+ {
+ Status = STATUS_SUCCESS;
+ }
+ }
+ else if (NodeType(Fcb) != RDBSS_NTC_SPOOLFILE)
+ {
+ if (NodeType(Fcb) == RDBSS_NTC_MAILSLOT)
+ {
+ _SEH2_TRY_RETURN(Status = STATUS_NOT_IMPLEMENTED);
+ }
+ else
+ {
+ DPRINT1("Illegal type of file provided: %x\n", NodeType(Fcb));
+ _SEH2_TRY_RETURN(Status = STATUS_INVALID_PARAMETER);
+ }
+ }
+ }
+
+ /* We don't autorize advance operation */
+ if (Class == FileEndOfFileInformation && Stack->Parameters.SetFile.AdvanceOnly)
+ {
+ DPRINT1("Not allowed\n");
+
+ _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
+ }
+
+ /* For these to classes, we'll have to deal with the FCB table (removal)
+ * We thus need the exclusive FCB table lock
+ */
+ if (Class == FileDispositionInformation || Class == FileRenameInformation)
+ {
+ RxPurgeRelatedFobxs(NetRoot, Context, TRUE, Fcb);
+ RxScavengeFobxsForNetRoot(NetRoot, Fcb, TRUE);
+
+ if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, CanWait))
+ {
+ Context->PostRequest = TRUE;
+ _SEH2_TRY_RETURN(Status = STATUS_PENDING);
+ }
+
+ FcbTableAcquired = TRUE;
+ }
+
+ /* Finally, if not paging file, we need exclusive FCB lock */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE))
+ {
+ Status = RxAcquireExclusiveFcb(Context, Fcb);
+ if (Status == STATUS_LOCK_NOT_GRANTED)
+ {
+ Context->PostRequest = TRUE;
+ _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
+ }
+ else if (Status != STATUS_SUCCESS)
+ {
+ _SEH2_LEAVE;
+ }
+
+ FcbAcquired = TRUE;
+ }
+
+ Status = STATUS_SUCCESS;
+
+ /* And now, perform the job! */
+ switch (Class)
+ {
+ case FileBasicInformation:
+ Status = RxSetBasicInfo(Context);
+ break;
+
+ case FileDispositionInformation:
+ {
+ PFILE_DISPOSITION_INFORMATION FDI;
+
+ /* Check whether user wants deletion */
+ FDI = Irp->AssociatedIrp.SystemBuffer;
+ if (FDI->DeleteFile)
+ {
+ /* If so, check whether it's doable */
+ if (!MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForDelete))
+ {
+ Status = STATUS_CANNOT_DELETE;
+ }
+
+ /* And if doable, already remove from FCB table */
+ if (Status == STATUS_SUCCESS)
+ {
+ ASSERT(FcbAcquired && FcbTableAcquired);
+ RxRemoveNameNetFcb(Fcb);
+
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ FcbTableAcquired = FALSE;
+ }
+ }
+
+ /* If it succeed, perform the operation */
+ if (Status == STATUS_SUCCESS)
+ {
+ Status = RxSetDispositionInfo(Context);
+ }
+
+ break;
+ }
+
+ case FilePositionInformation:
+ Status = RxSetPositionInfo(Context);
+ break;
+
+ case FileAllocationInformation:
+ Status = RxSetAllocationInfo(Context);
+ break;
+
+ case FileEndOfFileInformation:
+ Status = RxSetEndOfFileInfo(Context);
+ break;
+
+ case FilePipeInformation:
+ case FilePipeLocalInformation:
+ case FilePipeRemoteInformation:
+ Status = RxSetPipeInfo(Context);
+ break;
+
+ case FileRenameInformation:
+ case FileLinkInformation:
+ case FileMoveClusterInformation:
+ /* If we can wait, try to perform the operation right now */
+ if (CanWait)
+ {
+ /* Of course, collapsing is not doable anymore, file is
+ * in an inbetween state
+ */
+ ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED);
+
+ /* Set the information */
+ Status = RxSetRenameInfo(Context);
+ /* If it succeed, drop the current entry from FCB table */
+ if (Status == STATUS_SUCCESS && Class == FileRenameInformation)
+ {
+ ASSERT(FcbAcquired && FcbTableAcquired);
+ RxRemoveNameNetFcb(Fcb);
+ }
+ _SEH2_TRY_RETURN(Status);
+ }
+ /* Can't wait? Post for async retry */
+ else
+ {
+ Status = RxFsdPostRequest(Context);
+ _SEH2_TRY_RETURN(Status);
+ }
+ break;
+
+ case FileValidDataLengthInformation:
+ if (!MmCanFileBeTruncated(&Fcb->NonPaged->SectionObjectPointers, NULL))
+ {
+ Status = STATUS_USER_MAPPED_FILE;
+ }
+ break;
+
+ case FileShortNameInformation:
+ Status = RxSetSimpleInfo(Context);
+ break;
+
+ default:
+ DPRINT1("Insupported class: %x\n", Class);
+ Status = STATUS_INVALID_PARAMETER;
+
+ break;
+ }
+
+try_exit: NOTHING;
+ /* If mini-rdr was OK and wants a re-post on this, do it */
+ if (Status == STATUS_SUCCESS)
+ {
+ if (Context->PostRequest)
+ {
+ Status = RxFsdPostRequest(Context);
+ }
+ }
+ }
+ _SEH2_FINALLY
+ {
+ /* Release any acquired lock */
+ if (FcbAcquired)
+ {
+ RxReleaseFcb(Context, Fcb);
+ }
+
+ if (FcbTableAcquired)
+ {
+ RxReleaseFcbTableLock(&NetRoot->FcbTable);
+ }
+ }
+ _SEH2_END;
+
+#undef _SEH2_TRY_RETURN
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+RxCommonSetQuotaInformation(
+ PRX_CONTEXT Context)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RxCommonSetSecurity(
+ PRX_CONTEXT Context)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RxCommonSetVolumeInformation(
+ PRX_CONTEXT Context)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RxCommonUnimplemented(
+ PRX_CONTEXT Context)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+RxCommonWrite(
+ PRX_CONTEXT RxContext)
+{
+ PIRP Irp;
+ PFCB Fcb;
+ PFOBX Fobx;
+ NTSTATUS Status;
+ PNET_ROOT NetRoot;
+ PSRV_OPEN SrvOpen;
+ PFILE_OBJECT FileObject;
+ PIO_STACK_LOCATION Stack;
+ LARGE_INTEGER ByteOffset;
+ NODE_TYPE_CODE NodeTypeCode;
+ PLOWIO_CONTEXT LowIoContext;
+ PRDBSS_DEVICE_OBJECT RxDeviceObject;
+ ULONG WriteLength, CapturedRxContextSerialNumber = RxContext->SerialNumber;
+ LONGLONG FileSize, ValidDataLength, InitialFileSize, InitialValidDataLength;
+ BOOLEAN CanWait, PagingIo, NoCache, Sync, NormalFile, WriteToEof, IsPipe, NoPreposting, InFsp, RecursiveWriteThrough, CalledByLazyWriter, SwitchBackToAsync, ExtendingFile, ExtendingValidData, UnwindOutstandingAsync, ResourceOwnerSet, PostIrp, ContextReferenced;
+
+ PAGED_CODE();
+
+ Fcb = (PFCB)RxContext->pFcb;
+ NodeTypeCode = NodeType(Fcb);
+ /* Validate FCB type */
+ if (NodeTypeCode != RDBSS_NTC_STORAGE_TYPE_FILE && NodeTypeCode != RDBSS_NTC_VOLUME_FCB &&
+ NodeTypeCode != RDBSS_NTC_SPOOLFILE && NodeTypeCode != RDBSS_NTC_MAILSLOT)
+ {
+ return STATUS_INVALID_DEVICE_REQUEST;
+ }
+
+ /* We'll write to file, keep track of it */
+ Fcb->IsFileWritten = TRUE;
+
+ Stack = RxContext->CurrentIrpSp;
+ /* Set write through if asked */
+ if (BooleanFlagOn(Stack->Flags, SL_WRITE_THROUGH))
+ {
+ SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH);
+ }
+
+ Fobx = (PFOBX)RxContext->pFobx;
+ DPRINT("RxCommonWrite(%p) FOBX: %p, FCB: %p\n", RxContext, Fobx, Fcb);
+
+ /* Get some parameters */
+ Irp = RxContext->CurrentIrp;
+ NoPreposting = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED);
+ InFsp = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP);
+ CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
+ PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
+ NoCache = BooleanFlagOn(Irp->Flags, IRP_NOCACHE);
+ Sync = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
+ WriteLength = Stack->Parameters.Write.Length;
+ ByteOffset.QuadPart = Stack->Parameters.Write.ByteOffset.QuadPart;
+ DPRINT("Writing: %lx@%I64x %s %s %s %s\n", WriteLength, ByteOffset.QuadPart,
+ (CanWait ? "CW" : "!CW"), (PagingIo ? "PI" : "!PI"), (NoCache ? "NC" : "!NC"), (Sync ? "S" : "!S"));
+
+ RxItsTheSameContext();
+
+ RxContext->FcbResourceAcquired = FALSE;
+ RxContext->FcbPagingIoResourceAcquired = FALSE;
+
+ LowIoContext = &RxContext->LowIoContext;
+ CheckForLoudOperations(RxContext);
+ if (BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_LOUDOPS))
+ {
+ DPRINT("LoudWrite %I64x/%lx on %lx vdl/size/alloc %I64x/%I64x/%I64x\n",
+ ByteOffset, WriteLength,
+ Fcb, Fcb->Header.ValidDataLength, Fcb->Header.FileSize, Fcb->Header.AllocationSize);
+ }
+
+ RxDeviceObject = RxContext->RxDeviceObject;
+ /* Update stats */
+ if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP) && Fcb->CachedNetRootType == NET_ROOT_DISK)
+ {
+ InterlockedIncrement((volatile long *)&RxDeviceObject->WriteOperations);
+
+ if (ByteOffset.QuadPart != Fobx->Specific.DiskFile.PredictedWriteOffset)
+ {
+ InterlockedIncrement((volatile long *)&RxDeviceObject->RandomWriteOperations);
+ }
+ Fobx->Specific.DiskFile.PredictedWriteOffset = ByteOffset.QuadPart + WriteLength;
+
+ if (PagingIo)
+ {
+ ExInterlockedAddLargeStatistic(&RxDeviceObject->PagingWriteBytesRequested, WriteLength);
+ }
+ else if (NoCache)
+ {
+ ExInterlockedAddLargeStatistic(&RxDeviceObject->NonPagingWriteBytesRequested, WriteLength);
+ }
+ else
+ {
+ ExInterlockedAddLargeStatistic(&RxDeviceObject->CacheWriteBytesRequested, WriteLength);
+ }
+ }
+
+ NetRoot = (PNET_ROOT)Fcb->NetRoot;
+ IsPipe = (NetRoot->Type == NET_ROOT_PIPE);
+ /* Keep track for normal writes */
+ if (NetRoot->Type == NET_ROOT_DISK || NetRoot->Type == NET_ROOT_WILD)
+ {
+ NormalFile = TRUE;
+ }
+ else
+ {
+ NormalFile = FALSE;
+ }
+
+ /* Zero-length write is immediate success */
+ if (NormalFile && WriteLength == 0)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ /* Check whether we have input data */
+ if (Irp->UserBuffer == NULL && Irp->MdlAddress == NULL)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Are we writting to EOF? */
+ WriteToEof = ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == -1));
+ /* FIXME: validate length/offset */
+
+ /* Get our SRV_OPEN in case of normal write */
+ if (Fobx != NULL)
+ {
+ SrvOpen = (PSRV_OPEN)Fobx->pSrvOpen;
+ }
+ else
+ {
+ SrvOpen = NULL;
+ }
+
+ FileObject = Stack->FileObject;
+
+ /* If we have caching enabled, check whether we have to defer write */
+ if (!NoCache)
+ {
+ if (RxWriteCacheingAllowed(Fcb, SrvOpen))
+ {
+ if (!CcCanIWrite(FileObject, WriteLength,
+ (CanWait && !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP)),
+ BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE)))
+ {
+ BOOLEAN Retrying;
+
+ Retrying = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE);
+
+ RxPrePostIrp(RxContext, Irp);
+
+ SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_DEFERRED_WRITE);
+
+ CcDeferWrite(FileObject, (PCC_POST_DEFERRED_WRITE)RxAddToWorkque, RxContext, Irp, WriteLength, Retrying);
+
+ return STATUS_PENDING;
+ }
+ }
+ }
+
+ /* Initialize the low IO context for write */
+ RxInitializeLowIoContext(LowIoContext, LOWIO_OP_WRITE);
+
+ /* Initialize our (many) booleans */
+ RecursiveWriteThrough = FALSE;
+ CalledByLazyWriter = FALSE;
+ SwitchBackToAsync = FALSE;
+ ExtendingFile = FALSE;
+ ExtendingValidData = FALSE;
+ UnwindOutstandingAsync = FALSE;
+ ResourceOwnerSet = FALSE;
+ PostIrp = FALSE;
+ ContextReferenced = FALSE;
+
+#define _SEH2_TRY_RETURN(S) S; goto try_exit
+
+ _SEH2_TRY
+ {
+ /* No volume FCB here! */
+ ASSERT((NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE) ||
+ (NodeTypeCode == RDBSS_NTC_SPOOLFILE) ||
+ (NodeTypeCode == RDBSS_NTC_MAILSLOT));
+
+ /* Writing to EOF on a paging file is non sense */
+ ASSERT(!(WriteToEof && PagingIo));
+
+ RxItsTheSameContext();
+
+ /* Start locking stuff */
+ if (!PagingIo && !NoPreposting)
+ {
+ /* If it's already acquired, all fine */
+ if (RxContext->FcbResourceAcquired)
+ {
+ ASSERT(!IsPipe);
+ }
+ else
+ {
+ /* Otherwise, try to acquire shared (excepted for pipes) */
+ if (IsPipe)
+ {
+ Status = RxAcquireExclusiveFcb(RxContext, Fcb);
+ }
+ else if (CanWait ||
+ (!NoCache && RxWriteCacheingAllowed(Fcb, SrvOpen)))
+ {
+ Status = RxAcquireSharedFcb(RxContext, Fcb);
+ }
+ else
+ {
+ Status = RxAcquireSharedFcbWaitForEx(RxContext, Fcb);
+ }
+
+ /* We'll post IRP to retry */
+ if (Status == STATUS_LOCK_NOT_GRANTED)
+ {
+ PostIrp = TRUE;
+ DPRINT1("Failed to acquire lock!\n");
+ _SEH2_TRY_RETURN(Status);
+ }
+
+ /* We'll just fail */
+ if (Status != STATUS_SUCCESS)
+ {
+ _SEH2_TRY_RETURN(Status);
+ }
+
+ /* Resource acquired */
+ RxContext->FcbResourceAcquired = TRUE;
+ }
+
+ /* At that point, resource is acquired */
+ if (IsPipe)
+ {
+ ASSERT(RxContext->FcbResourceAcquired);
+ }
+ else
+ {
+ BOOLEAN IsDormant;
+
+ /* Now, check whether we have to promote shared lock */
+ if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL)
+ {
+ IsDormant = BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT);
+ }
+ else
+ {
+ IsDormant = FALSE;
+ }
+
+ /* We're writing beyond VDL, we'll need an exclusive lock if not dormant */
+ if (RxIsFcbAcquiredShared(Fcb) &&
+ ByteOffset.QuadPart + WriteLength > Fcb->Header.ValidDataLength.QuadPart)
+ {
+ if (!IsDormant)
+ {
+ RxReleaseFcb(RxContext, Fcb);
+ RxContext->FcbResourceAcquired = FALSE;
+
+ Status = RxAcquireExclusiveFcb(RxContext, Fcb);
+ if (Status == STATUS_LOCK_NOT_GRANTED)
+ {
+ PostIrp = TRUE;
+ DPRINT1("Failed to acquire lock!\n");
+ _SEH2_TRY_RETURN(Status);
+ }
+
+ if (Status != STATUS_SUCCESS)
+ {
+ _SEH2_TRY_RETURN(Status);
+ }
+
+ RxContext->FcbResourceAcquired = TRUE;
+ }
+ }
+
+ /* If we're writing in VDL, or if we're dormant, shared lock is enough */
+ if (ByteOffset.QuadPart + WriteLength <= Fcb->Header.ValidDataLength.QuadPart ||
+ IsDormant)
+ {
+ if (RxIsFcbAcquiredExclusive(Fcb))
+ {
+ RxConvertToSharedFcb(RxContext, Fcb);
+ }
+ }
+ else
+ {
+ /* We're extending file, disable collapsing */
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb));
+
+ DPRINT("Disabling collapsing\n");
+
+ if (NodeTypeCode == RDBSS_NTC_STORAGE_TYPE_FILE && Fobx != NULL)
+ {
+ SetFlag(Fobx->Flags, FOBX_FLAG_DISABLE_COLLAPSING);
+ }
+ }
+
+ ASSERT(RxContext->FcbResourceAcquired);
+ }
+
+ /* Keep track of the acquired resource */
+ LowIoContext->Resource = Fcb->Header.Resource;
+ }
+ else
+ {
+ /* Paging IO */
+ ASSERT(!IsPipe);
+
+ /* Lock the paging resource */
+ RxAcquirePagingIoResourceShared(RxContext, Fcb, TRUE);
+
+ /* Keep track of the acquired resource */
+ LowIoContext->Resource = Fcb->Header.PagingIoResource;
+ }
+
+ if (IsPipe)
+ {
+ UNIMPLEMENTED;
+ _SEH2_TRY_RETURN(Status = STATUS_NOT_IMPLEMENTED);
+ }
+
+ /* If it's a non cached write, or if caching is disallowed */
+ if (NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen))
+ {
+ /* If cache was previously enabled, we'll have to flush before writing */
+ if (!PagingIo && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL)
+ {
+ LARGE_INTEGER FlushOffset;
+
+ /* FCB is lock */
+ ASSERT(RxIsFcbAcquiredExclusive(Fcb) || RxIsFcbAcquiredShared(Fcb));
+
+ /* If shared, we'll have to relock exclusive */
+ if (!RxIsFcbAcquiredExclusive(Fcb))
+ {
+ /* Release and retry exclusive */
+ RxReleaseFcb(RxContext, Fcb);
+ RxContext->FcbResourceAcquired = FALSE;
+
+ Status = RxAcquireExclusiveFcb(RxContext, Fcb);
+ if (Status == STATUS_LOCK_NOT_GRANTED)
+ {
+ PostIrp = TRUE;
+ DPRINT1("Failed to acquire lock for flush!\n");
+ _SEH2_TRY_RETURN(Status);
+ }
+
+ if (Status != STATUS_SUCCESS)
+ {
+ _SEH2_TRY_RETURN(Status);
+ }
+
+ RxContext->FcbResourceAcquired = TRUE;
+ }
+
+ /* Get the length to flush */
+ if (WriteToEof)
+ {
+ RxGetFileSizeWithLock(Fcb, &FlushOffset.QuadPart);
+ }
+ else
+ {
+ FlushOffset.QuadPart = ByteOffset.QuadPart;
+ }
+
+ /* Perform the flushing */
+ RxAcquirePagingIoResource(RxContext, Fcb);
+ CcFlushCache(&Fcb->NonPaged->SectionObjectPointers, &FlushOffset,
+ WriteLength, &Irp->IoStatus);
+ RxReleasePagingIoResource(RxContext, Fcb);
+
+ /* Cannot continue if flushing failed */
+ if (!NT_SUCCESS(Irp->IoStatus.Status))
+ {
+ _SEH2_TRY_RETURN(Status = Irp->IoStatus.Status);
+ }
+
+ /* Synchronize */
+ RxAcquirePagingIoResource(RxContext, Fcb);
+ RxReleasePagingIoResource(RxContext, Fcb);
+
+ /* And purge */
+ CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers,
+ &FlushOffset, WriteLength, FALSE);
+ }
+ }
+
+ /* If not paging IO, check if write is allowed */
+ if (!PagingIo)
+ {
+ if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp))
+ {
+ _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
+ }
+ }
+
+ /* Get file sizes */
+ ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
+ RxGetFileSizeWithLock(Fcb, &FileSize);
+ ASSERT(ValidDataLength <= FileSize);
+
+ /* If paging IO, we cannot write past file size
+ * so fix write length if needed
+ */
+ if (PagingIo)
+ {
+ if (ByteOffset.QuadPart >= FileSize)
+ {
+ _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
+ }
+
+ if (WriteLength > FileSize - ByteOffset.QuadPart)
+ {
+ WriteLength = FileSize - ByteOffset.QuadPart;
+ }
+ }
+
+ /* If we're being called by the lazywrite */
+ if (Fcb->Specific.Fcb.LazyWriteThread == PsGetCurrentThread())
+ {
+ CalledByLazyWriter = TRUE;
+
+ /* Fail if we're beyong VDL */
+ if (BooleanFlagOn(Fcb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE))
+ {
+ if ((ByteOffset.QuadPart + WriteLength > ValidDataLength) &&
+ (ByteOffset.QuadPart < FileSize))
+ {
+ if (ByteOffset.QuadPart + WriteLength > ((ValidDataLength + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+ {
+ _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
+ }
+ }
+ }
+ }
+
+ /* If that's a recursive synchronous page write */
+ if (BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) &&
+ BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_RECURSIVE_CALL))
+ {
+ PIRP TopIrp;
+
+ /* Check the top level IRP on the FastIO path */
+ TopIrp = RxGetTopIrpIfRdbssIrp();
+ if (TopIrp != NULL && (ULONG_PTR)TopIrp > FSRTL_FAST_IO_TOP_LEVEL_IRP)
+ {
+ PIO_STACK_LOCATION IrpStack;
+
+ ASSERT(NodeType(TopIrp) == IO_TYPE_IRP);
+
+ /* If the top level IRP was a cached write for this file, keep track */
+ IrpStack = IoGetCurrentIrpStackLocation(TopIrp);
+ if (IrpStack->MajorFunction == IRP_MJ_WRITE &&
+ IrpStack->FileObject->FsContext == FileObject->FsContext)
+ {
+ RecursiveWriteThrough = TRUE;
+ SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WRITE_THROUGH);
+ }
+ }
+ }
+
+ /* Now, deal with file size and VDL */
+ if (!CalledByLazyWriter && !RecursiveWriteThrough &&
+ (WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength))
+ {
+ /* Not sync? Let's make it sync, just the time we extended */
+ if (!Sync)
+ {
+ CanWait = TRUE;
+ SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
+ ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
+ Sync = TRUE;
+
+ /* Keep track we'll have to switch back to async */
+ if (NoCache)
+ {
+ SwitchBackToAsync = TRUE;
+ }
+ }
+
+ /* Release all the locks */
+ RxWriteReleaseResources(RxContext, 0);
+
+ /* Acquire exclusive */
+ Status = RxAcquireExclusiveFcb(RxContext, Fcb);
+ if (Status == STATUS_LOCK_NOT_GRANTED)
+ {
+ PostIrp = TRUE;
+ DPRINT1("Failed to acquire lock for extension!\n");
+ _SEH2_TRY_RETURN(Status);
+ }
+
+ if (Status != STATUS_SUCCESS)
+ {
+ _SEH2_TRY_RETURN(Status);
+ }
+
+ RxContext->FcbResourceAcquired = TRUE;
+
+ RxItsTheSameContext();
+
+ /* Get the sizes again, to be sure they didn't change in the meantime */
+ ValidDataLength = Fcb->Header.ValidDataLength.QuadPart;
+ RxGetFileSizeWithLock(Fcb, &FileSize);
+ ASSERT(ValidDataLength <= FileSize);
+
+ /* Check we can switch back to async? */
+ if ((SwitchBackToAsync && Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) ||
+ (ByteOffset.QuadPart + WriteLength > FileSize) || RxNoAsync)
+ {
+ SwitchBackToAsync = FALSE;
+ }
+
+ /* If paging IO, check we don't try to extend the file */
+ if (PagingIo)
+ {
+ if (ByteOffset.QuadPart >= FileSize)
+ {
+ _SEH2_TRY_RETURN(Status = STATUS_SUCCESS);
+ }
+
+ if (WriteLength > FileSize - ByteOffset.QuadPart)
+ {
+ WriteLength = FileSize - ByteOffset.QuadPart;
+ }
+ }
+ }
+
+ /* Save our initial sizes for potential rollback */
+ InitialFileSize = FileSize;
+ InitialValidDataLength = ValidDataLength;
+ /* If writing to EOF, update byte offset with file size */
+ if (WriteToEof)
+ {
+ ByteOffset.QuadPart = FileSize;
+ }
+
+ /* Check again whether we're allowed to write */
+ if (!PagingIo)
+ {
+ if (!FsRtlCheckLockForWriteAccess(&Fcb->Specific.Fcb.FileLock, Irp ))
+ {
+ _SEH2_TRY_RETURN(Status = STATUS_FILE_LOCK_CONFLICT);
+ }
+
+ /* Do we have to extend? */
+ if (NormalFile && (ByteOffset.QuadPart + WriteLength > FileSize))
+ {
+ DPRINT("Need to extend file\n");
+ ExtendingFile = TRUE;
+ SetFlag(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE);
+ }
+ }
+
+ /* Let's start to extend */
+ if (ExtendingFile)
+ {
+ /* If we're past allocating, inform mini-rdr */
+ FileSize = ByteOffset.QuadPart + WriteLength;
+ if (FileSize > Fcb->Header.AllocationSize.QuadPart)
+ {
+ LARGE_INTEGER NewAllocationSize;
+
+ DPRINT("Extending %p\n", RxContext);
+
+ if (NoCache)
+ {
+ C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER));
+ MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForNonCache,
+ (RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize));
+ }
+ else
+ {
+ C_ASSERT(sizeof(LONGLONG) == sizeof(LARGE_INTEGER));
+ MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxExtendForCache,
+ (RxContext, (PLARGE_INTEGER)&FileSize, &NewAllocationSize));
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ _SEH2_TRY_RETURN(Status);
+ }
+
+ if (FileSize > NewAllocationSize.QuadPart)
+ {
+ NewAllocationSize.QuadPart = FileSize;
+ }
+
+ /* And update FCB */
+ Fcb->Header.AllocationSize.QuadPart = NewAllocationSize.QuadPart;
+ }
+
+ /* Set the new sizes */
+ RxSetFileSizeWithLock(Fcb, &FileSize);
+ RxAdjustAllocationSizeforCC(Fcb);
+
+ /* And inform Cc */
+ if (CcIsFileCached(FileObject))
+ {
+ CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
+ }
+ }
+
+ /* Do we have to extend VDL? */
+ if (!CalledByLazyWriter && !RecursiveWriteThrough)
+ {
+ if (WriteToEof || ByteOffset.QuadPart + WriteLength > ValidDataLength)
+ {
+ ExtendingValidData = TRUE;
+ SetFlag(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL);
+ }
+ }
+
+ /* If none cached write */
+ if (PagingIo || NoCache || !RxWriteCacheingAllowed(Fcb, SrvOpen))
+ {
+ /* Switch back to async, if asked to */
+ if (SwitchBackToAsync)
+ {
+ CanWait = FALSE;
+ Sync = FALSE;
+
+ ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
+ SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION);
+ }
+
+ /* If not synchronous, keep track of writes to be finished */
+ if (!Sync)
+ {
+ if (Fcb->NonPaged->OutstandingAsyncEvent == NULL)
+ {
+ Fcb->NonPaged->OutstandingAsyncEvent = &Fcb->NonPaged->TheActualEvent;
+ KeInitializeEvent(Fcb->NonPaged->OutstandingAsyncEvent,
+ NotificationEvent, FALSE);
+ }
+
+ if (ExInterlockedAddUlong(&Fcb->NonPaged->OutstandingAsyncWrites,
+ 1,
+ &RxStrucSupSpinLock) == 0)
+ {
+ KeResetEvent(Fcb->NonPaged->OutstandingAsyncEvent);
+ }
+
+ UnwindOutstandingAsync = TRUE;
+ LowIoContext->ParamsFor.ReadWrite.NonPagedFcb = Fcb->NonPaged;
+ }
+
+ /* Set our LOWIO_CONTEXT information */
+ LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
+ LowIoContext->ParamsFor.ReadWrite.ByteCount = WriteLength;
+
+ RxItsTheSameContext();
+
+ /* We have to be locked */
+ ASSERT(RxContext->FcbResourceAcquired || RxContext->FcbPagingIoResourceAcquired);
+
+ /* Update thread ID if we're in FSP */
+ if (InFsp)
+ {
+ LowIoContext->ResourceThreadId = (ULONG_PTR)RxContext | 3;
+
+ if (RxContext->FcbResourceAcquired)
+ {
+ ExSetResourceOwnerPointer(Fcb->Header.Resource, (PVOID)((ULONG_PTR)RxContext | 3));
+ }
+
+ if (RxContext->FcbPagingIoResourceAcquired)
+ {
+ ExSetResourceOwnerPointer(Fcb->Header.PagingIoResource, (PVOID)((ULONG_PTR)RxContext | 3));
+ }
+
+ ResourceOwnerSet = TRUE;
+ }
+
+ /* And perform the write */
+ Status = RxLowIoWriteShell(RxContext);
+
+ RxItsTheSameContext();
+
+ /* Not outstanding write anymore */
+ if (UnwindOutstandingAsync && Status == STATUS_PENDING)
+ {
+ UnwindOutstandingAsync = FALSE;
+ }
+ }
+ /* Cached write */
+ else
+ {
+ /* If cache wasn't enabled yet, do it */
+ if (FileObject->PrivateCacheMap == NULL)
+ {
+ if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
+ {
+ _SEH2_TRY_RETURN(Status = STATUS_FILE_CLOSED);
+ }
+
+ RxAdjustAllocationSizeforCC(Fcb);
+
+ CcInitializeCacheMap(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
+ FALSE, &RxData.CacheManagerCallbacks, Fcb);
+
+ CcSetReadAheadGranularity(FileObject, NetRoot->DiskParameters.ReadAheadGranularity);
+ }
+
+ /* If that's a MDL backed write */
+ if (BooleanFlagOn(RxContext->MinorFunction, IRP_MN_MDL))
+ {
+ /* Shouldn't happen */
+ ASSERT(FALSE);
+ ASSERT(CanWait);
+
+ /* Perform it, though */
+ CcPrepareMdlWrite(FileObject, &ByteOffset, WriteLength,
+ &Irp->MdlAddress, &Irp->IoStatus);
+
+ Status = Irp->IoStatus.Status;
+ }
+ else
+ {
+ PVOID SystemBuffer;
+ ULONG BreakpointsSave;
+
+ /* Map the user buffer */
+ SystemBuffer = RxNewMapUserBuffer(RxContext);
+ if (SystemBuffer == NULL)
+ {
+ _SEH2_TRY_RETURN(Status = STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ RxSaveAndSetExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
+
+ RxItsTheSameContext();
+
+ /* And deal with Cc */
+ if (!CcCopyWrite(FileObject, &ByteOffset, WriteLength, CanWait,
+ SystemBuffer))
+ {
+ RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
+
+ RxItsTheSameContext();
+
+ DPRINT1("CcCopyWrite failed for: %p %I64d %d %lx\n",
+ FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status);
+
+ PostIrp = TRUE;
+ }
+ else
+ {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = WriteLength;
+
+ RxRestoreExceptionNoBreakpointFlag(RxContext, BreakpointsSave);
+
+ RxItsTheSameContext();
+
+ DPRINT("CcCopyWrite succeed for: %p %I64d %d %lx\n",
+ FileObject, Fcb->Header.FileSize.QuadPart, WriteLength, Status);
+ }
+ }
+ }
+
+try_exit: NOTHING;
+
+ /* If we've to post the IRP */
+ if (PostIrp)
+ {
+ /* Reset the file size if required */
+ if (ExtendingFile && !IsPipe)
{
- LowIoContext->ParamsFor.ReadWrite.ByteCount = ReadLength;
- LowIoContext->ParamsFor.ReadWrite.ByteOffset = ByteOffset.QuadPart;
+ ASSERT(RxWriteCacheingAllowed(Fcb, SrvOpen));
+ ASSERT(Fcb->Header.PagingIoResource != NULL);
- RxItsTheSameContext();
+ RxAcquirePagingIoResource(RxContext, Fcb);
+ RxSetFileSizeWithLock(Fcb, &InitialFileSize);
+ RxReleasePagingIoResource(RxContext, Fcb);
- if (InFsp && ReadCachingDisabled)
+ if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
{
- ExSetResourceOwnerPointer((PagingIo ? Fcb->Header.PagingIoResource : Fcb->Header.Resource),
- (PVOID)((ULONG_PTR)RxContext | 3));
- OwnerSet = TRUE;
+ *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
}
+ }
- Status = RxLowIoReadShell(RxContext);
+ InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
+ ContextReferenced = TRUE;
- RxItsTheSameContext();
- }
- else
+ /* Release locks */
+ ASSERT(!ResourceOwnerSet);
+ RxWriteReleaseResources(RxContext, ResourceOwnerSet);
+
+#ifdef RDBSS_TRACKER
+ ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0);
+#endif
+
+ /* And post the request */
+ Status = RxFsdPostRequest(RxContext);
+ }
+ else
+ {
+ if (!IsPipe)
{
- if (ByteOffset.QuadPart > FileSize)
+ /* Update FILE_OBJECT if synchronous write succeed */
+ if (!PagingIo)
{
- ReadLength = 0;
- Irp->IoStatus.Information = ReadLength;
- _SEH2_LEAVE;
+ if (NT_SUCCESS(Status) && BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+ {
+ FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
+ }
}
- if (ByteOffset.QuadPart + ReadLength > FileSize)
+ /* If write succeed, ,also update FILE_OBJECT flags */
+ if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
{
- ReadLength = FileSize - ByteOffset.QuadPart;
- }
+ /* File was modified */
+ if (!PagingIo)
+ {
+ SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
+ }
- SystemBuffer = RxNewMapUserBuffer(RxContext);
- RtlZeroMemory(SystemBuffer, ReadLength);
- Irp->IoStatus.Information = ReadLength;
+ /* If was even extended */
+ if (ExtendingFile)
+ {
+ SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
+ }
+
+ /* If VDL was extended, update FCB and inform Cc */
+ if (ExtendingValidData)
+ {
+ LONGLONG LastOffset;
+
+ LastOffset = ByteOffset.QuadPart + Irp->IoStatus.Information;
+ if (FileSize < LastOffset)
+ {
+ LastOffset = FileSize;
+ }
+
+ Fcb->Header.ValidDataLength.QuadPart = LastOffset;
+
+ if (NoCache && CcIsFileCached(FileObject))
+ {
+ CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
+ }
+ }
+ }
}
}
}
_SEH2_FINALLY
{
- RxItsTheSameContext();
-
- /* Post if required */
- if (PostRequest)
- {
- InterlockedIncrement((volatile long *)&RxContext->ReferenceCount);
- Status = RxFsdPostRequest(RxContext);
- }
- else
+ /* Finally, if we failed while extension was required */
+ if (_SEH2_AbnormalTermination() && (ExtendingFile || ExtendingValidData))
{
- /* Update FO in case of sync IO */
- if (!IsPipe && !PagingIo)
+ /* Rollback! */
+ if (!IsPipe)
{
- if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+ ASSERT(Fcb->Header.PagingIoResource != NULL);
+
+ RxAcquirePagingIoResource(RxContext, Fcb);
+ RxSetFileSizeWithLock(Fcb, &InitialFileSize);
+ Fcb->Header.ValidDataLength.QuadPart = InitialValidDataLength;
+ RxReleasePagingIoResource(RxContext, Fcb);
+
+ if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
{
- FileObject->CurrentByteOffset.QuadPart = ByteOffset.QuadPart + Irp->IoStatus.Information;
+ *CcGetFileSizePointer(FileObject) = Fcb->Header.FileSize;
}
}
}
- /* Set FastIo if read was a success */
- if (NT_SUCCESS(Status) && Status != STATUS_PENDING)
+ /* One async write less */
+ if (UnwindOutstandingAsync)
{
- if (!IsPipe && !PagingIo)
- {
- SetFlag(FileObject->Flags, FO_FILE_FAST_IO_READ);
- }
+ ASSERT(!IsPipe);
+
+ ExInterlockedAddUlong(&Fcb->NonPaged->OutstandingAsyncWrites, -1, &RxStrucSupSpinLock);
+ KeSetEvent(Fcb->NonPaged->OutstandingAsyncEvent, IO_NO_INCREMENT, FALSE);
}
- /* In case we're done (not expected any further processing */
- if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostRequest)
+ /* And now, cleanup everything */
+ if (_SEH2_AbnormalTermination() || Status != STATUS_PENDING || PostIrp)
{
- /* Release everything that can be */
- if (ReadCachingDisabled)
+ /* If we didn't post, release every lock (for posting, it's already done) */
+ if (!PostIrp)
{
- if (PagingIo)
- {
- if (OwnerSet)
- {
- RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
- }
- else
- {
- RxReleasePagingIoResource(RxContext, Fcb);
- }
- }
- else
- {
- if (OwnerSet)
- {
- RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
- }
- else
- {
- RxReleaseFcb(RxContext, Fcb);
- }
- }
+ RxWriteReleaseResources(RxContext, ResourceOwnerSet);
}
- /* Dereference/Delete context */
- if (PostRequest)
+ /* If the context was referenced - posting, dereference it */
+ if (ContextReferenced)
{
RxDereferenceAndDeleteRxContext(RxContext);
}
- else
+
+ /* If that's a pipe operation, resume any blocked one */
+ if (!PostIrp)
{
if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
{
}
}
- /* We cannot return more than asked */
+ /* Sanity check for write */
if (Status == STATUS_SUCCESS)
{
- ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
+ ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length);
}
}
+ /* Just dereference our context */
else
{
ASSERT(!Sync);
-
RxDereferenceAndDeleteRxContext(RxContext);
}
}
_SEH2_END;
+#undef _SEH2_TRY_RETURN
+
return Status;
}
+/*
+ * @implemented
+ */
NTSTATUS
NTAPI
-RxCommonSetEa(
- PRX_CONTEXT Context)
+RxCompleteMdl(
+ IN PRX_CONTEXT RxContext)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
+ PIRP Irp;
+ PFILE_OBJECT FileObject;
+ PIO_STACK_LOCATION Stack;
-NTSTATUS
-NTAPI
-RxCommonSetInformation(
- PRX_CONTEXT Context)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
+#define BugCheckFileId RDBSS_BUG_CHECK_CACHESUP
-NTSTATUS
-NTAPI
-RxCommonSetQuotaInformation(
- PRX_CONTEXT Context)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
+ PAGED_CODE();
-NTSTATUS
-NTAPI
-RxCommonSetSecurity(
- PRX_CONTEXT Context)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
+ Irp = RxContext->CurrentIrp;
+ Stack = RxContext->CurrentIrpSp;
+ FileObject = Stack->FileObject;
-NTSTATUS
-NTAPI
-RxCommonSetVolumeInformation(
- PRX_CONTEXT Context)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
+ /* We can only complete for IRP_MJ_READ and IRP_MJ_WRITE */
+ switch (RxContext->MajorFunction)
+ {
+ /* Call the Cc function */
+ case IRP_MJ_READ:
+ CcMdlReadComplete(FileObject, Irp->MdlAddress);
+ break;
-NTSTATUS
-NTAPI
-RxCommonUnimplemented(
- PRX_CONTEXT Context)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
+ case IRP_MJ_WRITE:
+ /* If here, we can wait */
+ ASSERT(BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT));
-NTSTATUS
-NTAPI
-RxCommonWrite(
- PRX_CONTEXT Context)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
+ /* Call the Cc function */
+ CcMdlWriteComplete(FileObject, &Stack->Parameters.Write.ByteOffset, Irp->MdlAddress);
-NTSTATUS
-NTAPI
-RxCompleteMdl(
- IN PRX_CONTEXT RxContext)
-{
- PAGED_CODE();
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ default:
+ DPRINT1("Invalid major for RxCompleteMdl: %d\n", RxContext->MajorFunction);
+ RxBugCheck(RxContext->MajorFunction, 0, 0);
+ break;
+ }
+
+ /* MDL was freed */
+ Irp->MdlAddress = NULL;
+
+ /* And complete the IRP */
+ RxCompleteRequest(RxContext, STATUS_SUCCESS);
+
+#undef BugCheckFileId
+
+ return STATUS_SUCCESS;
}
/*
RxInitializeDispatcher();
- ExInitializeNPagedLookasideList(&RxContextLookasideList, ExAllocatePoolWithTag, ExFreePool, 0, sizeof(RX_CONTEXT), RX_IRPC_POOLTAG, 4);
+ ExInitializeNPagedLookasideList(&RxContextLookasideList, RxAllocatePoolWithTag, RxFreePool, 0, sizeof(RX_CONTEXT), RX_IRPC_POOLTAG, 4);
InitializeListHead(&RxIrpsList);
KeInitializeSpinLock(&RxIrpsListSpinLock);
#endif
}
+#if DBG
/*
* @implemented
*/
{
PAGED_CODE();
}
+#endif
+/*
+ * @implemented
+ */
BOOLEAN
NTAPI
RxFastIoCheckIfPossible(
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject)
{
- UNIMPLEMENTED;
- return FALSE;
+ PFCB Fcb;
+ PSRV_OPEN SrvOpen;
+ LARGE_INTEGER LargeLength;
+
+ PAGED_CODE();
+
+ /* Get the FCB to validate it */
+ Fcb = FileObject->FsContext;
+ if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE)
+ {
+ DPRINT1("Not a file, FastIO not possible!\n");
+ return FALSE;
+ }
+
+ if (FileObject->DeletePending)
+ {
+ DPRINT1("File delete pending\n");
+ return FALSE;
+ }
+
+ /* If there's a pending write operation, deny fast operation */
+ if (Fcb->NonPaged->OutstandingAsyncWrites != 0)
+ {
+ DPRINT1("Write operations to be completed\n");
+ return FALSE;
+ }
+
+ /* Deny read on orphaned node */
+ SrvOpen = (PSRV_OPEN)((PFOBX)FileObject->FsContext2)->pSrvOpen;
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_ORPHANED))
+ {
+ DPRINT1("SRV_OPEN orphaned\n");
+ return FALSE;
+ }
+
+ if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED))
+ {
+ DPRINT1("FCB orphaned\n");
+ return FALSE;
+ }
+
+ /* If there's a buffering state change pending, deny fast operation (it might change
+ * cache status)
+ */
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING))
+ {
+ DPRINT1("Buffering change pending\n");
+ return FALSE;
+ }
+
+ /* File got renamed/deleted, deny operation */
+ if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED) ||
+ BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED))
+ {
+ DPRINT1("File renamed/deleted\n");
+ return FALSE;
+ }
+
+ /* Process pending change buffering state operations */
+ FsRtlEnterFileSystem();
+ RxProcessChangeBufferingStateRequestsForSrvOpen(SrvOpen);
+ FsRtlExitFileSystem();
+
+ LargeLength.QuadPart = Length;
+
+ /* If operation to come is a read operation */
+ if (CheckForReadOperation)
+ {
+ /* Check that read cache is enabled */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_READCACHING_ENABLED))
+ {
+ DPRINT1("Read caching disabled\n");
+ return FALSE;
+ }
+
+ /* Check whether there's a lock conflict */
+ if (!FsRtlFastCheckLockForRead(&Fcb->Specific.Fcb.FileLock,
+ FileOffset,
+ &LargeLength,
+ LockKey,
+ FileObject,
+ PsGetCurrentProcess()))
+ {
+ DPRINT1("FsRtlFastCheckLockForRead failed\n");
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ /* Check that write cache is enabled */
+ if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_WRITECACHING_ENABLED))
+ {
+ DPRINT1("Write caching disabled\n");
+ return FALSE;
+ }
+
+ /* Check whether there's a lock conflict */
+ if (!FsRtlFastCheckLockForWrite(&Fcb->Specific.Fcb.FileLock,
+ FileOffset,
+ &LargeLength,
+ LockKey,
+ FileObject,
+ PsGetCurrentProcess()))
+ {
+ DPRINT1("FsRtlFastCheckLockForWrite failed\n");
+ return FALSE;
+ }
+
+ return TRUE;
}
BOOLEAN
}
}
+/*
+ * @implemented
+ */
BOOLEAN
NTAPI
RxFastIoRead(
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject)
{
- UNIMPLEMENTED;
- return FALSE;
+ BOOLEAN Ret;
+ RX_TOPLEVELIRP_CONTEXT TopLevelContext;
+
+ PAGED_CODE();
+
+ DPRINT("RxFastIoRead: %p (%p, %p)\n", FileObject, FileObject->FsContext,
+ FileObject->FsContext2);
+ DPRINT("Reading %ld at %I64x\n", Length, FileOffset->QuadPart);
+
+ /* Prepare a TLI context */
+ ASSERT(RxIsThisTheTopLevelIrp(NULL));
+ RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP,
+ (PRDBSS_DEVICE_OBJECT)DeviceObject);
+
+ Ret = FsRtlCopyRead2(FileObject, FileOffset, Length, Wait, LockKey, Buffer,
+ IoStatus, DeviceObject, &TopLevelContext);
+ if (Ret)
+ {
+ DPRINT("Read OK\n");
+ }
+ else
+ {
+ DPRINT1("Read failed!\n");
+ }
+
+ return Ret;
}
+/*
+ * @implemented
+ */
BOOLEAN
NTAPI
RxFastIoWrite(
PIO_STATUS_BLOCK IoStatus,
PDEVICE_OBJECT DeviceObject)
{
- UNIMPLEMENTED;
- return FALSE;
-}
+ PFOBX Fobx;
+ BOOLEAN Ret;
+ RX_TOPLEVELIRP_CONTEXT TopLevelContext;
-NTSTATUS
-NTAPI
-RxFinalizeConnection(
- IN OUT PNET_ROOT NetRoot,
- IN OUT PV_NET_ROOT VNetRoot OPTIONAL,
- IN LOGICAL ForceFilesClosed)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PAGED_CODE();
+
+ Fobx = (PFOBX)FileObject->FsContext2;
+ if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_BAD_HANDLE))
+ {
+ return FALSE;
+ }
+
+ DPRINT("RxFastIoWrite: %p (%p, %p)\n", FileObject, FileObject->FsContext,
+ FileObject->FsContext2);
+ DPRINT("Writing %ld at %I64x\n", Length, FileOffset->QuadPart);
+
+ /* Prepare a TLI context */
+ ASSERT(RxIsThisTheTopLevelIrp(NULL));
+ RxInitializeTopLevelIrpContext(&TopLevelContext, (PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP,
+ (PRDBSS_DEVICE_OBJECT)DeviceObject);
+
+ Ret = FsRtlCopyWrite2(FileObject, FileOffset, Length, Wait, LockKey, Buffer,
+ IoStatus, DeviceObject, &TopLevelContext);
+ if (Ret)
+ {
+ DPRINT("Write OK\n");
+ }
+ else
+ {
+ DPRINT1("Write failed!\n");
+ }
+
+ return Ret;
}
NTSTATUS
VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot;
ASSERT(NetRoot == VNetRoot->NetRoot);
- TableAcquired = FALSE;
Status = STATUS_SUCCESS;
AcquiredExclusive = FALSE;
/* If FCB was not found or is not covering full path, prepare for more work */
if (Fcb == NULL || Fcb->FcbTableEntry.Path.Length != NetRootName->Length)
{
+ if (Fcb != NULL)
+ {
+ DPRINT1("FCB was found and it's not covering the whole path: %wZ - %wZ\n", &Fcb->FcbTableEntry.Path, NetRootName);
+ }
+
if (!AcquiredExclusive)
{
RxReleaseFcbTableLock(&NetRoot->FcbTable);
if (Context->Create.CanonicalNameBuffer != NULL)
{
- ExFreePoolWithTag(Context->Create.CanonicalNameBuffer, RX_MISC_POOLTAG);
+ RxFreePoolWithTag(Context->Create.CanonicalNameBuffer, RX_MISC_POOLTAG);
Context->Create.CanonicalNameBuffer = NULL;
Context->AlsoCanonicalNameBuffer = NULL;
}
RxContext->LastExecutionThread = PsGetCurrentThread();
SetFlag(RxContext->Flags, (RX_CONTEXT_FLAG_IN_FSP | RX_CONTEXT_FLAG_WAIT));
- DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx", RxContext->MinorFunction,
+ DPRINT("Dispatch: MN: %d, Ctxt: %p, IRP: %p, THRD: %lx #%lx\n", RxContext->MinorFunction,
RxContext, RxContext->CurrentIrp, RxContext->LastExecutionThread,
RxContext->SerialNumber);
return TopDevice;
}
+/*
+ * @implemented
+ */
+PIRP
+RxGetTopIrpIfRdbssIrp(
+ VOID)
+{
+ PIRP Irp = NULL;
+ PRX_TOPLEVELIRP_CONTEXT TopLevel;
+
+ TopLevel = (PRX_TOPLEVELIRP_CONTEXT)IoGetTopLevelIrp();
+ if (RxIsThisAnRdbssTopLevelContext(TopLevel))
+ {
+ Irp = TopLevel->Irp;
+ }
+
+ return Irp;
+}
+
/*
* @implemented
*/
return STATUS_SUCCESS;
}
-NTSTATUS
-NTAPI
-RxInitializeRxTimer(
- VOID)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
/*
* @implemented
*/
return Found;
}
+/*
+ * @implemented
+ */
BOOLEAN
RxIsOkToPurgeFcb(
PFCB Fcb)
{
- UNIMPLEMENTED;
- return FALSE;
+ PLIST_ENTRY Entry;
+
+ /* No associated SRV_OPEN, it's OK to purge */
+ if (IsListEmpty(&Fcb->SrvOpenList))
+ {
+ return TRUE;
+ }
+
+ /* Only allow to purge if all the associated SRV_OPEN
+ * - have no outstanding opens ongoing
+ * - have only read attribute set
+ */
+ for (Entry = Fcb->SrvOpenList.Flink;
+ Entry != &Fcb->SrvOpenList;
+ Entry = Entry->Flink)
+ {
+ PSRV_OPEN SrvOpen;
+
+ SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenQLinks);
+
+ /* Failing previous needs, don't allow purge */
+ if (SrvOpen->UncleanFobxCount != 0 ||
+ (SrvOpen->DesiredAccess & 0xFFEFFFFF) != FILE_READ_ATTRIBUTES)
+ {
+ return FALSE;
+ }
+ }
+
+ /* All correct, allow purge */
+ return TRUE;
}
/*
return Status;
}
+NTSTATUS
+RxLowIoLockControlShell(
+ IN PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+RxLowIoNotifyChangeDirectoryCompletion(
+ PRX_CONTEXT RxContext)
+{
+ PAGED_CODE();
+
+ DPRINT("Completing NCD with: %lx, %lx\n", RxContext->IoStatusBlock.Status, RxContext->IoStatusBlock.Information);
+
+ /* Just copy back the IO_STATUS to the IRP */
+ RxSetIoStatusStatus(RxContext, RxContext->IoStatusBlock.Status);
+ RxSetIoStatusInfo(RxContext, RxContext->IoStatusBlock.Information);
+
+ return RxContext->IoStatusBlock.Status;
+}
+
/*
* @implemented
*/
}
else
{
- RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
+ RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
+ }
+ }
+
+ if (IsPipe)
+ {
+ UNIMPLEMENTED;
+ }
+
+ /* Final sanity checks */
+ ASSERT(Status != STATUS_RETRY);
+ ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
+ ASSERT(RxContext->MajorFunction == IRP_MJ_READ);
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxLowIoWriteShell(
+ IN PRX_CONTEXT RxContext)
+{
+ PFCB Fcb;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ DPRINT("RxLowIoWriteShell(%p)\n", RxContext);
+
+ Fcb = (PFCB)RxContext->pFcb;
+
+ ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) &&
+ !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED));
+
+ /* Always update stats for disks */
+ if (Fcb->CachedNetRootType == NET_ROOT_DISK)
+ {
+ ExInterlockedAddLargeStatistic(&RxContext->RxDeviceObject->NetworkWriteBytesRequested, RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount);
+ }
+
+ /* And forward the write to the mini-rdr */
+ Status = RxLowIoSubmit(RxContext, RxLowIoWriteShellCompletion);
+ DPRINT("RxLowIoWriteShell(%p), Status: %lx\n", RxContext, Status);
+
+ return Status;
+}
+
+NTSTATUS
+NTAPI
+RxLowIoWriteShellCompletion(
+ PRX_CONTEXT RxContext)
+{
+ PIRP Irp;
+ PFCB Fcb;
+ NTSTATUS Status;
+ BOOLEAN PagingIo;
+ PLOWIO_CONTEXT LowIoContext;
+
+ PAGED_CODE();
+
+ DPRINT("RxLowIoWriteShellCompletion(%p)\n", RxContext);
+
+ Status = RxContext->IoStatusBlock.Status;
+ DPRINT("In %p, Status: %lx, Information: %lx\n", RxContext, Status, RxContext->IoStatusBlock.Information);
+
+ Irp = RxContext->CurrentIrp;
+
+ /* Set IRP information from the RX_CONTEXT status block */
+ Irp->IoStatus.Information = RxContext->IoStatusBlock.Information;
+
+ LowIoContext = &RxContext->LowIoContext;
+ ASSERT(RxLowIoIsBufferLocked(LowIoContext));
+
+ /* Perform a few sanity checks */
+ Fcb = (PFCB)RxContext->pFcb;
+ if (Status == STATUS_SUCCESS)
+ {
+ if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_THIS_IO_BUFFERED))
+ {
+ ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_BUF_COMPRESSED) &&
+ !BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_DISK_COMPRESSED));
+ }
+
+ ASSERT(!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FILE_IS_SHADOWED));
+ }
+
+ PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
+ if (Status != STATUS_SUCCESS && PagingIo)
+ {
+ DPRINT1("Paging IO failed %p (%p) %lx\n", Fcb, Fcb->NetRoot, Status);
+ }
+
+ /* In case of async call, perform last bits not done in RxCommonWrite */
+ if (!BooleanFlagOn(LowIoContext->Flags, LOWIO_CONTEXT_FLAG_SYNCCALL))
+ {
+ PFILE_OBJECT FileObject;
+ PIO_STACK_LOCATION Stack;
+
+ /* We only succeed if we wrote what was asked for */
+ if (NT_SUCCESS(Status) && !BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION))
+ {
+ ASSERT(Irp->IoStatus.Information == LowIoContext->ParamsFor.ReadWrite.ByteCount);
+ }
+
+ /* If write succeed, ,also update FILE_OBJECT flags */
+ Stack = RxContext->CurrentIrpSp;
+ FileObject = Stack->FileObject;
+ if (!PagingIo)
+ {
+ SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
+ }
+
+ if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_FILESIZE))
+ {
+ SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);
+ }
+
+ /* If VDL was extended, fix attributes */
+ if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_EXTENDING_VDL))
+ {
+ LONGLONG LastOffset, FileSize;
+
+ LastOffset = LowIoContext->ParamsFor.ReadWrite.ByteOffset +
+ Irp->IoStatus.Information;
+ RxGetFileSizeWithLock(Fcb, &FileSize);
+
+ if (FileSize < LastOffset)
+ {
+ LastOffset = FileSize;
+ }
+
+ Fcb->Header.ValidDataLength.QuadPart = LastOffset;
+ }
+
+ /* One less outstanding write */
+ if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
+ {
+ PNON_PAGED_FCB NonPagedFcb;
+
+ NonPagedFcb = LowIoContext->ParamsFor.ReadWrite.NonPagedFcb;
+ if (NonPagedFcb != NULL)
+ {
+ if (ExInterlockedAddUlong(&NonPagedFcb->OutstandingAsyncWrites,
+ -1, &RxStrucSupSpinLock) == 1)
+ {
+ KeSetEvent(NonPagedFcb->OutstandingAsyncEvent, IO_NO_INCREMENT, FALSE);
+ }
+ }
+ }
+
+ /* Release paging resource if acquired */
+ if (RxContext->FcbPagingIoResourceAcquired)
+ {
+ RxReleasePagingIoResourceForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
+ }
+
+ /* Resume blocked operations for pipes */
+ if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION))
+ {
+ RxResumeBlockedOperations_Serially(RxContext,
+ &((PFOBX)RxContext->pFobx)->Specific.NamedPipe.WriteSerializationQueue);
+ }
+ else
+ {
+ /* And release FCB only for files */
+ if (RxContext->FcbResourceAcquired)
+ {
+ RxReleaseFcbForThread(RxContext, Fcb, LowIoContext->ResourceThreadId);
+ }
+ }
+
+ /* Final sanity checks */
+ ASSERT(Status != STATUS_RETRY);
+ ASSERT((Status != STATUS_SUCCESS) || (Irp->IoStatus.Information <= Stack->Parameters.Write.Length));
+ ASSERT(RxContext->MajorFunction == IRP_MJ_WRITE);
+
+ if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_OPERATION))
+ {
+ UNIMPLEMENTED;
+ }
+ }
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxNotifyChangeDirectory(
+ PRX_CONTEXT RxContext)
+{
+ PIRP Irp;
+ NTSTATUS Status;
+ PIO_STACK_LOCATION Stack;
+
+ PAGED_CODE();
+
+ /* The IRP can abviously wait */
+ SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
+
+ /* Initialize its lowio */
+ RxInitializeLowIoContext(&RxContext->LowIoContext, LOWIO_OP_NOTIFY_CHANGE_DIRECTORY);
+
+ _SEH2_TRY
+ {
+ /* Lock user buffer */
+ Stack = RxContext->CurrentIrpSp;
+ RxLockUserBuffer(RxContext, IoWriteAccess, Stack->Parameters.NotifyDirectory.Length);
+
+ /* Copy parameters from IO_STACK */
+ RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.WatchTree = BooleanFlagOn(Stack->Flags, SL_WATCH_TREE);
+ RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.CompletionFilter = Stack->Parameters.NotifyDirectory.CompletionFilter;
+ RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.NotificationBufferLength = Stack->Parameters.NotifyDirectory.Length;
+
+ /* If we have an associated MDL */
+ Irp = RxContext->CurrentIrp;
+ if (Irp->MdlAddress != NULL)
+ {
+ /* Then, call mini-rdr */
+ RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ if (RxContext->LowIoContext.ParamsFor.NotifyChangeDirectory.pNotificationBuffer != NULL)
+ {
+ Status = RxLowIoSubmit(RxContext, RxLowIoNotifyChangeDirectoryCompletion);
+ }
+ else
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ else
+ {
+ Status = STATUS_INVALID_PARAMETER;
}
}
-
- if (IsPipe)
+ _SEH2_FINALLY
{
- UNIMPLEMENTED;
+ /* All correct */
}
-
- /* Final sanity checks */
- ASSERT(Status != STATUS_RETRY);
- ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Read.Length);
- ASSERT(RxContext->MajorFunction == IRP_MJ_READ);
+ _SEH2_END;
return Status;
}
-NTSTATUS
-RxNotifyChangeDirectory(
- PRX_CONTEXT RxContext)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
NTSTATUS
RxPostStackOverflowRead (
IN PRX_CONTEXT RxContext)
Fcb = (PFCB)RxContext->pFcb;
/* Set the RX_CONTEXT */
- RxContext->Info.FsInformationClass = FileInfoClass;
+ RxContext->Info.FileInformationClass = FileInfoClass;
RxContext->Info.Buffer = Buffer;
/* Pass down */
RxContext->MajorFunction = IRP_MJ_CREATE;
/* Fake canon name */
- RxContext->PrefixClaim.SuppliedPathName.Buffer = ExAllocatePoolWithTag(NonPagedPool, QueryRequest->PathNameLength, RX_MISC_POOLTAG);
+ RxContext->PrefixClaim.SuppliedPathName.Buffer = RxAllocatePoolWithTag(NonPagedPool, QueryRequest->PathNameLength, RX_MISC_POOLTAG);
if (RxContext->PrefixClaim.SuppliedPathName.Buffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
{
if (RxContext->PrefixClaim.SuppliedPathName.Buffer != NULL)
{
- ExFreePoolWithTag(RxContext->PrefixClaim.SuppliedPathName.Buffer, RX_MISC_POOLTAG);
+ RxFreePoolWithTag(RxContext->PrefixClaim.SuppliedPathName.Buffer, RX_MISC_POOLTAG);
}
RxpPrepareCreateContextForReuse(RxContext);
return Status;
}
+/*
+ * @implemented
+ */
NTSTATUS
NTAPI
RxPrepareToReparseSymbolicLink(
BOOLEAN NewPathIsAbsolute,
PBOOLEAN ReparseRequired)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PWSTR NewBuffer;
+ USHORT NewLength;
+ PFILE_OBJECT FileObject;
+
+ /* Assume no reparse is required first */
+ *ReparseRequired = FALSE;
+
+ /* Only supported for IRP_MJ_CREATE */
+ if (RxContext->MajorFunction != IRP_MJ_CREATE)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* If symbolic link is not embedded, and DELETE is specified, fail */
+ if (!SymbolicLinkEmbeddedInOldPath)
+ {
+ /* Excepted if DELETE is the only flag specified, then, open has to succeed
+ * See: https://msdn.microsoft.com/en-us/library/windows/hardware/ff554649(v=vs.85).aspx (remarks)
+ */
+ if (BooleanFlagOn(RxContext->Create.NtCreateParameters.DesiredAccess, DELETE) &&
+ BooleanFlagOn(RxContext->Create.NtCreateParameters.DesiredAccess, ~DELETE))
+ {
+ return STATUS_ACCESS_DENIED;
+ }
+ }
+
+ /* At that point, assume reparse will be required */
+ *ReparseRequired = TRUE;
+
+ /* If new path isn't absolute, it's up to us to make it absolute */
+ if (!NewPathIsAbsolute)
+ {
+ /* The prefix will be \Device\Mup */
+ NewLength = NewPath->Length + (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL));
+ NewBuffer = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, NewLength,
+ RX_MISC_POOLTAG);
+ if (NewBuffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Copy data for the new path */
+ RtlMoveMemory(NewBuffer, L"\\Device\\Mup", (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL)));
+ RtlMoveMemory(Add2Ptr(NewBuffer, (sizeof(L"\\Device\\Mup") - sizeof(UNICODE_NULL))),
+ NewPath->Buffer, NewPath->Length);
+ }
+ /* Otherwise, use caller path as it */
+ else
+ {
+ NewLength = NewPath->Length;
+ NewBuffer = NewPath->Buffer;
+ }
+
+ /* Get the FILE_OBJECT we'll modify */
+ FileObject = RxContext->CurrentIrpSp->FileObject;
+
+ /* Free old path first */
+ ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
+ /* And setup new one */
+ FileObject->FileName.Length = NewLength;
+ FileObject->FileName.MaximumLength = NewLength;
+ FileObject->FileName.Buffer = NewBuffer;
+
+ /* And set reparse flag */
+ SetFlag(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_REPARSE);
+
+ /* Done! */
+ return STATUS_SUCCESS;
}
/*
IoMarkIrpPending(Irp);
}
+/*
+ * @implemented
+ */
+NTSTATUS
+RxpSetInfoMiniRdr(
+ PRX_CONTEXT RxContext,
+ FILE_INFORMATION_CLASS Class)
+{
+ PFCB Fcb;
+ NTSTATUS Status;
+
+ /* Initialize parameters in RX_CONTEXT */
+ RxContext->Info.FileInformationClass = Class;
+ RxContext->Info.Buffer = RxContext->CurrentIrp->AssociatedIrp.SystemBuffer;
+ RxContext->Info.Length = RxContext->CurrentIrpSp->Parameters.SetFile.Length;
+
+ /* And call mini-rdr */
+ Fcb = (PFCB)RxContext->pFcb;
+ MINIRDR_CALL(Status, RxContext, Fcb->MRxDispatch, MRxSetFileInfo, (RxContext));
+
+ return Status;
+}
+
VOID
NTAPI
RxpUnregisterMinirdr(
UNIMPLEMENTED;
}
+/*
+ * @implemented
+ */
+VOID
+RxPurgeNetFcb(
+ PFCB Fcb,
+ PRX_CONTEXT LocalContext)
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ /* First, flush */
+ MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite);
+
+ /* And force close */
+ RxReleaseFcb(NULL, Fcb);
+ MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE);
+ Status = RxAcquireExclusiveFcb(NULL, Fcb);
+ ASSERT(Status == STATUS_SUCCESS);
+}
+
NTSTATUS
RxQueryAlternateNameInfo(
PRX_CONTEXT RxContext,
{
Fobx->ContainsWildCards = FsRtlDoesNameContainWildCards(FileName);
- Fobx->UnicodeQueryTemplate.Buffer = RxAllocatePoolWithTag(PagedPool, FileName->Length, 'cDxR');
+ Fobx->UnicodeQueryTemplate.Buffer = RxAllocatePoolWithTag(PagedPool, FileName->Length, RX_DIRCTL_POOLTAG);
if (Fobx->UnicodeQueryTemplate.Buffer != NULL)
{
/* UNICODE_STRING; length has to be even */
if ((FileName->Length & 1) != 0)
{
Status = STATUS_INVALID_PARAMETER;
- RxFreePool(Fobx->UnicodeQueryTemplate.Buffer);
+ RxFreePoolWithTag(Fobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG);
}
else
{
Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
{
- DisableByteRangeLockingOnReadOnlyFiles = ((ULONG)PartialInfo->Data != 0);
+ DisableByteRangeLockingOnReadOnlyFiles = (*(PULONG)PartialInfo->Data != 0);
}
RtlInitUnicodeString(&ParamName, L"ReadAheadGranularity");
Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
{
- ULONG Granularity = (ULONG)PartialInfo->Data;
+ ULONG Granularity = *(PULONG)PartialInfo->Data;
if (Granularity > 16)
{
Status = ZwQueryValueKey(KeyHandle, &ParamName, KeyValuePartialInformation, PartialInfo, sizeof(Buffer), &ResultLength);
if (NT_SUCCESS(Status) && PartialInfo->Type == REG_DWORD)
{
- DisableFlushOnCleanup = ((ULONG)PartialInfo->Data != 0);
+ DisableFlushOnCleanup = (*(PULONG)PartialInfo->Data != 0);
}
ZwClose(KeyHandle);
RxInitializePrefixTable(RDBSSDevice->pRxNetNameTable, 0, FALSE);
RDBSSDevice->RxNetNameTableInDeviceObject.IsNetNameTable = TRUE;
ScavengerTimeLimit.QuadPart = MrdrDispatch->ScavengerTimeout * 10000000LL;
- RxInitializeRdbssScavenger(&RDBSSDevice->RdbssScavengerInDeviceObject, ScavengerTimeLimit);
+ RDBSSDevice->pRdbssScavenger = &RDBSSDevice->RdbssScavengerInDeviceObject;
+ RxInitializeRdbssScavenger(RDBSSDevice->pRdbssScavenger, ScavengerTimeLimit);
}
RDBSSDevice->pAsynchronousRequestsCompletionEvent = NULL;
return STATUS_SUCCESS;
}
-VOID
-NTAPI
-RxReleaseFcbFromLazyWrite(
- PVOID Context)
-{
- UNIMPLEMENTED;
-}
-
-VOID
-NTAPI
-RxReleaseFcbFromReadAhead(
- PVOID Context)
-{
- UNIMPLEMENTED;
-}
-
-VOID
-NTAPI
-RxReleaseFileForNtCreateSection(
- PFILE_OBJECT FileObject)
-{
- UNIMPLEMENTED;
-}
-
-NTSTATUS
-NTAPI
-RxReleaseForCcFlush(
- PFILE_OBJECT FileObject,
- PDEVICE_OBJECT DeviceObject)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
/*
* @implemented
*/
return Context;
}
+#if DBG
+/*
+ * @implemented
+ */
VOID
RxRemoveShareAccess(
_Inout_ PFILE_OBJECT FileObject,
_In_ PSZ where,
_In_ PSZ wherelogtag)
{
- UNIMPLEMENTED;
+ PAGED_CODE();
+
+ RxDumpCurrentAccess(where, "before", wherelogtag, ShareAccess);
+ IoRemoveShareAccess(FileObject, ShareAccess);
+ RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
+}
+#endif
+
+/*
+ * @implemented
+ */
+VOID
+RxRemoveShareAccessPerSrvOpens(
+ IN OUT PSRV_OPEN SrvOpen)
+{
+ ACCESS_MASK DesiredAccess;
+ BOOLEAN ReadAccess;
+ BOOLEAN WriteAccess;
+ BOOLEAN DeleteAccess;
+
+ PAGED_CODE();
+
+ /* Get access that were granted to SRV_OPEN */
+ DesiredAccess = SrvOpen->DesiredAccess;
+ ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
+ WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
+ DeleteAccess = (DesiredAccess & DELETE) != 0;
+
+ /* If any, drop them */
+ if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
+ {
+ BOOLEAN SharedRead;
+ BOOLEAN SharedWrite;
+ BOOLEAN SharedDelete;
+ ULONG DesiredShareAccess;
+ PSHARE_ACCESS ShareAccess;
+
+ ShareAccess = &((PFCB)SrvOpen->pFcb)->ShareAccessPerSrvOpens;
+ DesiredShareAccess = SrvOpen->ShareAccess;
+
+ ShareAccess->Readers -= ReadAccess;
+ ShareAccess->Writers -= WriteAccess;
+ ShareAccess->Deleters -= DeleteAccess;
+
+ ShareAccess->OpenCount--;
+
+ SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
+ SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
+ SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
+ ShareAccess->SharedRead -= SharedRead;
+ ShareAccess->SharedWrite -= SharedWrite;
+ ShareAccess->SharedDelete -= SharedDelete;
+ }
}
NTSTATUS
return Status;
}
+NTSTATUS
+RxSetAllocationInfo(
+ PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+RxSetBasicInfo(
+ PRX_CONTEXT RxContext)
+{
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+#define FILE_ATTRIBUTE_VOLUME 0x8
+#define VALID_FILE_ATTRIBUTES ( \
+ FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
+ FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_VOLUME | \
+ FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | \
+ FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | \
+ FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_COMPRESSED | \
+ FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | \
+ FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_INTEGRITY_STREAM)
+#define VALID_DIR_ATTRIBUTES (VALID_FILE_ATTRIBUTES | FILE_ATTRIBUTE_DIRECTORY)
+
+ /* First of all, call the mini-rdr */
+ Status = RxpSetInfoMiniRdr(RxContext, FileBasicInformation);
+ /* If it succeed, perform last bits */
+ if (NT_SUCCESS(Status))
+ {
+ PIRP Irp;
+ PFCB Fcb;
+ PFOBX Fobx;
+ PFILE_OBJECT FileObject;
+ ULONG Attributes, CleanAttr;
+ PFILE_BASIC_INFORMATION BasicInfo;
+
+ Fcb = (PFCB)RxContext->pFcb;
+ Fobx = (PFOBX)RxContext->pFobx;
+ Irp = RxContext->CurrentIrp;
+ BasicInfo = Irp->AssociatedIrp.SystemBuffer;
+ FileObject = RxContext->CurrentIrpSp->FileObject;
+
+ /* If caller provided flags, handle the change */
+ Attributes = BasicInfo->FileAttributes;
+ if (Attributes != 0)
+ {
+ /* Clean our flags first, with only stuff we support */
+ if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY)
+ {
+ CleanAttr = (Attributes & VALID_DIR_ATTRIBUTES) | FILE_ATTRIBUTE_DIRECTORY;
+ }
+ else
+ {
+ CleanAttr = Attributes & VALID_FILE_ATTRIBUTES;
+ }
+
+ /* Handle the temporary mark (set/unset depending on caller) */
+ if (BooleanFlagOn(Attributes, FILE_ATTRIBUTE_TEMPORARY))
+ {
+ SetFlag(Fcb->FcbState, FCB_STATE_TEMPORARY);
+ SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
+ }
+ else
+ {
+ ClearFlag(Fcb->FcbState, FCB_STATE_TEMPORARY);
+ ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE);
+ }
+
+ /* And set new attributes */
+ Fcb->Attributes = CleanAttr;
+ }
+
+ /* If caller provided a creation time, set it */
+ if (BasicInfo->CreationTime.QuadPart != 0LL)
+ {
+ Fcb->CreationTime.QuadPart = BasicInfo->CreationTime.QuadPart;
+ SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_CREATION);
+ }
+
+ /* If caller provided a last access time, set it */
+ if (BasicInfo->LastAccessTime.QuadPart != 0LL)
+ {
+ Fcb->LastAccessTime.QuadPart = BasicInfo->LastAccessTime.QuadPart;
+ SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_ACCESS);
+ }
+
+ /* If caller provided a last write time, set it */
+ if (BasicInfo->LastWriteTime.QuadPart != 0LL)
+ {
+ Fcb->LastWriteTime.QuadPart = BasicInfo->LastWriteTime.QuadPart;
+ SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_WRITE);
+ }
+
+ /* If caller provided a last change time, set it */
+ if (BasicInfo->ChangeTime.QuadPart != 0LL)
+ {
+ Fcb->LastChangeTime.QuadPart = BasicInfo->ChangeTime.QuadPart;
+ SetFlag(Fobx->Flags, FOBX_FLAG_USER_SET_LAST_CHANGE);
+ }
+ }
+
+ /* Done */
+ return Status;
+}
+
+NTSTATUS
+RxSetDispositionInfo(
+ PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+RxSetEndOfFileInfo(
+ PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+RxSetPipeInfo(
+ PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+RxSetPositionInfo(
+ PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+RxSetRenameInfo(
+ PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+#if DBG
/*
* @implemented
*/
IoSetShareAccess(DesiredAccess, DesiredShareAccess, FileObject, ShareAccess);
RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
}
+#endif
+
+NTSTATUS
+RxSetSimpleInfo(
+ PRX_CONTEXT RxContext)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
/*
* @implemented
/* If not TLC provider, allocate one */
if (TopLevelContext == NULL)
{
- TopLevelContext = RxAllocatePoolWithTag(NonPagedPool, sizeof(RX_TOPLEVELIRP_CONTEXT), '??xR');
+ TopLevelContext = RxAllocatePoolWithTag(NonPagedPool, sizeof(RX_TOPLEVELIRP_CONTEXT), RX_TLC_POOLTAG);
if (TopLevelContext == NULL)
{
return FALSE;
return TRUE;
}
+#if DBG
/*
* @implemented
*/
IoUpdateShareAccess(FileObject, ShareAccess);
RxDumpCurrentAccess(where, "after", wherelogtag, ShareAccess);
}
+#endif
/*
* @implemented
if (BooleanFlagOn(TopLevelContext->Flags, RX_TOPLEVELCTX_FLAG_FROM_POOL))
{
RxRemoveFromTopLevelIrpAllocatedContextsList(TopLevelContext);
- ExFreePool(TopLevelContext);
+ RxFreePoolWithTag(TopLevelContext, RX_TLC_POOLTAG);
}
}