summaryrefslogtreecommitdiffstats
path: root/private/ntos/cntfs/vattrsup.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/cntfs/vattrsup.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/cntfs/vattrsup.c')
-rw-r--r--private/ntos/cntfs/vattrsup.c627
1 files changed, 627 insertions, 0 deletions
diff --git a/private/ntos/cntfs/vattrsup.c b/private/ntos/cntfs/vattrsup.c
new file mode 100644
index 000000000..b5d51cc11
--- /dev/null
+++ b/private/ntos/cntfs/vattrsup.c
@@ -0,0 +1,627 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ VAttrSup.c
+
+Abstract:
+
+ This module implements the attribute routines for NtOfs
+
+Author:
+
+ Tom Miller [TomM] 10-Apr-1996
+
+Revision History:
+
+--*/
+
+#include "NtfsProc.h"
+
+//
+// Define a tag for general pool allocations from this module
+//
+
+#undef MODULE_POOL_TAG
+#define MODULE_POOL_TAG ('vFtN')
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, NtOfsCreateAttribute)
+#endif
+
+
+NTFSAPI
+NTSTATUS
+NtOfsCreateAttribute (
+ IN PIRP_CONTEXT IrpContext,
+ IN PFCB Fcb,
+ IN UNICODE_STRING Name,
+ IN CREATE_OPTIONS CreateOptions,
+ IN ULONG LogNonresidentToo,
+ OUT PSCB *ReturnScb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine may be called to create / open a named data attribute
+ within a given file, which may or may not be recoverable.
+
+Arguments:
+
+ Fcb - File in which the attribute is to be created. It is acquired exclusive
+
+ Name - Name of the attribute for all related Scbs and attributes on disk.
+
+ CreateOptions - Standard create flags.
+
+ LogNonresidentToo - Supplies nonzero if updates to the attribute should
+ be logged.
+
+ ReturnScb - Returns an Scb as handle for the attribute.
+
+Return Value:
+
+ STATUS_OBJECT_NAME_COLLISION -- if CreateNew and attribute already exists
+ STATUS_OBJECT_NAME_NOT_FOUND -- if OpenExisting and attribute does not exist
+
+--*/
+
+{
+ ATTRIBUTE_ENUMERATION_CONTEXT LocalContext;
+ BOOLEAN FoundAttribute;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PSCB Scb = NULL;
+
+ ASSERT_IRP_CONTEXT( IrpContext );
+ ASSERT( NtfsIsExclusiveFcb( Fcb ));
+
+ PAGED_CODE();
+
+ //
+ // Now, just create the Data Attribute.
+ //
+
+ NtfsInitializeAttributeContext( &LocalContext );
+
+ try {
+
+ //
+ // First see if the attribute already exists, by searching for the root
+ // attribute.
+ //
+
+ FoundAttribute = NtfsLookupAttributeByName( IrpContext,
+ Fcb,
+ &Fcb->FileReference,
+ $DATA,
+ &Name,
+ NULL,
+ TRUE,
+ &LocalContext );
+
+ //
+ // If it is not there, and the CreateOptions allow, then let's create
+ // the attribute root now. (First cleaning up the attribute context from
+ // the lookup).
+ //
+
+ if (!FoundAttribute && (CreateOptions <= CREATE_OR_OPEN)) {
+
+ NtfsCleanupAttributeContext( &LocalContext );
+
+ NtfsCreateAttributeWithValue( IrpContext,
+ Fcb,
+ $DATA,
+ &Name,
+ NULL,
+ 0,
+ 0,
+ NULL,
+ TRUE,
+ &LocalContext );
+
+ //
+ // If the attribute is already there, and we were asked to create it, then
+ // return an error.
+ //
+
+ } else if (FoundAttribute && (CreateOptions == CREATE_NEW)) {
+
+ Status = STATUS_OBJECT_NAME_COLLISION;
+ leave;
+
+ //
+ // If the attribute is not there, and we were supposed to open existing, then
+ // return an error.
+ //
+
+ } else if (!FoundAttribute) {
+
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ leave;
+ }
+
+ //
+ // Otherwise create/find the Scb and reference it.
+ //
+
+ Scb = NtfsCreateScb( IrpContext, Fcb, $DATA, &Name, FALSE, &FoundAttribute );
+
+ //
+ // Make sure things are correctly reference counted
+ //
+
+ NtfsIncrementCloseCounts( Scb, TRUE, FALSE );
+
+ //
+ // Make sure the stream can be mapped internally
+ //
+
+ if (Scb->FileObject == NULL) {
+ NtfsCreateInternalAttributeStream( IrpContext, Scb, TRUE );
+ }
+
+ //
+ // If we created the Scb, then get the no modified write set correctly.
+ //
+
+ ASSERT( !FoundAttribute ||
+ (LogNonresidentToo == BooleanFlagOn(Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE)) );
+
+ if (!FoundAttribute && LogNonresidentToo) {
+ SetFlag( Scb->ScbState, SCB_STATE_MODIFIED_NO_WRITE );
+ }
+
+ NtfsUpdateScbFromAttribute( IrpContext, Scb, NtfsFoundAttribute(&LocalContext) );
+
+ NtfsExpandQuotaToAllocationSize( IrpContext, Scb );
+
+ } finally {
+
+ if (AbnormalTermination( )) {
+ if (Scb != NULL) {
+ NtOfsCloseAttribute( IrpContext, Scb );
+ }
+ }
+
+ NtfsCleanupAttributeContext( &LocalContext );
+ }
+
+ *ReturnScb = Scb;
+
+ return Status;
+}
+
+
+NTFSAPI
+VOID
+NtOfsCloseAttribute (
+ IN PIRP_CONTEXT IrpContext,
+ IN PSCB Scb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine may be called to close a previously returned handle on an attribute.
+
+Arguments:
+
+ Scb - Supplies an Scb as the previously returned handle for this attribute.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ASSERT( NtfsIsExclusiveFcb( Scb->Fcb ));
+
+ NtfsDecrementCloseCounts( IrpContext, Scb, NULL, TRUE, FALSE, TRUE );
+}
+
+
+NTFSAPI
+VOID
+NtOfsDeleteAttribute (
+ IN PIRP_CONTEXT IrpContext,
+ IN PFCB Fcb,
+ IN PSCB Scb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine may be called to delete an attribute.
+
+Arguments:
+
+ Fcb - Supplies an Fcb as the previously returned object handle for the file
+
+ Scb - Supplies an Scb as the previously returned handle for this attribute.
+
+Return Value:
+
+ None (Deleting a nonexistant index is benign).
+
+--*/
+
+{
+ ATTRIBUTE_ENUMERATION_CONTEXT LocalContext;
+ BOOLEAN FoundAttribute;
+
+ ASSERT_IRP_CONTEXT( IrpContext );
+
+ PAGED_CODE();
+
+ ASSERT( NtfsIsExclusiveFcb( Fcb ));
+
+ try {
+
+ //
+ // First see if there is some attribute allocation, and if so truncate it
+ // away allowing this operation to be broken up.
+ //
+
+ NtfsInitializeAttributeContext( &LocalContext );
+
+ if (NtfsLookupAttributeByName( IrpContext,
+ Fcb,
+ &Fcb->FileReference,
+ $DATA,
+ &Scb->AttributeName,
+ NULL,
+ FALSE,
+ &LocalContext )
+
+ &&
+
+ !NtfsIsAttributeResident(NtfsFoundAttribute(&LocalContext))) {
+
+ ASSERT(Scb->FileObject != NULL);
+
+ NtfsDeleteAllocation( IrpContext, NULL, Scb, 0, MAXLONGLONG, TRUE, TRUE );
+ }
+
+ NtfsCleanupAttributeContext( &LocalContext );
+
+ //
+ // Initialize the attribute context on each trip through the loop.
+ //
+
+ NtfsInitializeAttributeContext( &LocalContext );
+
+ //
+ // Now there should be a single attribute record, so look it up and delete it.
+ //
+
+ FoundAttribute = NtfsLookupAttributeByName( IrpContext,
+ Fcb,
+ &Fcb->FileReference,
+ $DATA,
+ &Scb->AttributeName,
+ NULL,
+ TRUE,
+ &LocalContext );
+
+ ASSERT(FlagOn( Scb->ScbState, SCB_STATE_QUOTA_ENLARGED ));
+
+ NtfsDeleteAttributeRecord( IrpContext, Fcb, TRUE, FALSE, &LocalContext );
+
+ SetFlag( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED );
+
+ } finally {
+
+ NtfsCleanupAttributeContext( &LocalContext );
+
+ }
+}
+
+
+NTFSAPI
+LONGLONG
+NtOfsQueryLength (
+ IN PSCB Scb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine may be called to query the Length (FileSize) of an attribute.
+
+Arguments:
+
+ Scb - Supplies an Scb as the previously returned handle for this attribute.
+
+ Length - Returns the current Length of the attribute.
+
+Return Value:
+
+ None (Deleting a nonexistant index is benign).
+
+--*/
+
+{
+ LONGLONG Length;
+
+ ExAcquireFastMutex( Scb->Header.FastMutex );
+ Length = Scb->Header.FileSize.QuadPart;
+ ExReleaseFastMutex( Scb->Header.FastMutex );
+ return Length;
+}
+
+NTFSAPI
+VOID
+NtOfsSetLength (
+ IN PIRP_CONTEXT IrpContext,
+ IN PSCB Scb,
+ IN LONGLONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine may be called to set the Length (FileSize) of an attribute.
+
+Arguments:
+
+ Scb - Supplies an Scb as the previously returned handle for this attribute.
+
+ Length - Supplies the new Length for the attribute.
+
+Return Value:
+
+ None (Deleting a nonexistant index is benign).
+
+--*/
+
+{
+ ATTRIBUTE_ENUMERATION_CONTEXT AttrContext;
+
+ EOF_WAIT_BLOCK EofWaitBlock;
+ PFILE_OBJECT FileObject = Scb->FileObject;
+ PFCB Fcb = Scb->Fcb;
+ BOOLEAN DoingIoAtEof = FALSE;
+ BOOLEAN Truncating = FALSE;
+ BOOLEAN CleanupAttrContext = FALSE;
+
+ ASSERT_IRP_CONTEXT( IrpContext );
+ ASSERT_SCB( Scb );
+ ASSERT( NtfsIsExclusiveScb( Scb ));
+
+ ASSERT(FileObject != NULL);
+
+ PAGED_CODE();
+
+ try {
+
+ //
+ // If this is a resident attribute we will try to keep it resident.
+ //
+
+ if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
+
+ //
+ // If the new file size is larger than a file record then convert
+ // to non-resident and use the non-resident code below. Otherwise
+ // call ChangeAttributeValue which may also convert to nonresident.
+ //
+
+ NtfsInitializeAttributeContext( &AttrContext );
+ CleanupAttrContext = TRUE;
+
+ NtfsLookupAttributeForScb( IrpContext,
+ Scb,
+ NULL,
+ &AttrContext );
+
+ //
+ // Either convert or change the attribute value.
+ //
+
+ if (Length >= Scb->Vcb->BytesPerFileRecordSegment) {
+
+ NtfsConvertToNonresident( IrpContext,
+ Fcb,
+ NtfsFoundAttribute( &AttrContext ),
+ FALSE,
+ &AttrContext );
+
+ } else {
+
+ ULONG AttributeOffset;
+
+ //
+ // We are sometimes called by MM during a create section, so
+ // for right now the best way we have of detecting a create
+ // section is whether or not the requestor mode is kernel.
+ //
+
+ if ((ULONG)Length > Scb->Header.FileSize.LowPart) {
+
+ AttributeOffset = Scb->Header.ValidDataLength.LowPart;
+
+ } else {
+
+ AttributeOffset = (ULONG) Length;
+ }
+
+ //
+ // ****TEMP Ideally we would do this simple case by hand.
+ //
+
+ NtfsChangeAttributeValue( IrpContext,
+ Fcb,
+ AttributeOffset,
+ NULL,
+ (ULONG)Length - AttributeOffset,
+ TRUE,
+ FALSE,
+ FALSE,
+ FALSE,
+ &AttrContext );
+
+ ExAcquireFastMutex( Scb->Header.FastMutex );
+
+ Scb->Header.FileSize.QuadPart = Length;
+
+ //
+ // If the file went non-resident, then the allocation size in
+ // the Scb is correct. Otherwise we quad-align the new file size.
+ //
+
+ if (FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_RESIDENT )) {
+
+ Scb->Header.AllocationSize.LowPart = QuadAlign( Scb->Header.FileSize.LowPart );
+ Scb->Header.ValidDataLength.QuadPart = Length;
+
+ Scb->TotalAllocated = Scb->Header.AllocationSize.QuadPart;
+
+ } else {
+
+ SetFlag( Scb->ScbState, SCB_STATE_CHECK_ATTRIBUTE_SIZE );
+ }
+
+ ExReleaseFastMutex( Scb->Header.FastMutex );
+
+ //
+ // Now update Cc.
+ //
+
+ CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Scb->Header.AllocationSize );
+
+ //
+ // ****TEMP**** This hack is awaiting our actually doing this change
+ // in CcSetFileSizes.
+ //
+
+ *((PLONGLONG)(Scb->NonpagedScb->SegmentObject.SharedCacheMap) + 5) = Length;
+
+ leave;
+ }
+ }
+
+ //
+ // Nonresident path
+ //
+ // Now determine where the new file size lines up with the
+ // current file layout. The two cases we need to consider are
+ // where the new file size is less than the current file size and
+ // valid data length, in which case we need to shrink them.
+ // Or we new file size is greater than the current allocation,
+ // in which case we need to extend the allocation to match the
+ // new file size.
+ //
+
+ if (Length > Scb->Header.AllocationSize.QuadPart) {
+
+ //
+ // Add the allocation.
+ //
+
+ NtfsAddAllocation( IrpContext,
+ FileObject,
+ Scb,
+ LlClustersFromBytes( Scb->Vcb, Scb->Header.AllocationSize.QuadPart ),
+ LlClustersFromBytes(Scb->Vcb, (Length - Scb->Header.AllocationSize.QuadPart)),
+ FALSE );
+
+
+ ExAcquireFastMutex( Scb->Header.FastMutex );
+ Scb->Header.FileSize.QuadPart = Length;
+ ExReleaseFastMutex( Scb->Header.FastMutex );
+
+ //
+ // Otherwise see if we have to knock these numbers down...
+ //
+
+ } else {
+
+ ExAcquireFastMutex( Scb->Header.FastMutex );
+ if (Length < Scb->Header.ValidDataLength.QuadPart) {
+
+ Scb->Header.ValidDataLength.QuadPart = Length;
+ }
+
+ if (Length < Scb->ValidDataToDisk) {
+
+ Scb->ValidDataToDisk = Length;
+ }
+ Scb->Header.FileSize.QuadPart = Length;
+ ExReleaseFastMutex( Scb->Header.FastMutex );
+ }
+
+
+ //
+ // Call our common routine to modify the file sizes. We are now
+ // done with Length and NewValidDataLength, and we have
+ // PagingIo + main exclusive (so no one can be working on this Scb).
+ // NtfsWriteFileSizes uses the sizes in the Scb, and this is the
+ // one place where in Ntfs where we wish to use a different value
+ // for ValidDataLength. Therefore, we save the current ValidData
+ // and plug it with our desired value and restore on return.
+ //
+
+ NtfsWriteFileSizes( IrpContext,
+ Scb,
+ &Scb->Header.ValidDataLength.QuadPart,
+ FALSE,
+ TRUE );
+
+ //
+ // Now update Cc.
+ //
+
+ CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&Scb->Header.AllocationSize );
+
+ } finally {
+
+ if (CleanupAttrContext) {
+ NtfsCleanupAttributeContext( &AttrContext );
+ }
+
+ }
+}
+
+NTFSAPI
+VOID
+NtOfsFlushAttribute (
+ IN PIRP_CONTEXT IrpContext,
+ IN PSCB Scb,
+ IN ULONG Purge
+ )
+
+/*++
+
+Routine Description:
+
+ This routine flushes the specified attribute, and optionally purges it from the cache.
+
+Arguments:
+
+ Scb - Supplies an Scb as the previously returned handle for this attribute.
+
+ Purge - Supplies TRUE if the attribute is to be purged.
+
+Return Value:
+
+ None (Deleting a nonexistant index is benign).
+
+--*/
+
+{
+ if (Purge) {
+ NtfsFlushAndPurgeScb( IrpContext, Scb, NULL );
+ } else {
+ NtfsFlushUserStream( IrpContext, Scb, NULL, 0 );
+ }
+}