/*++ Copyright (c) 1991 Microsoft Corporation Module Name: VolInfo.c Abstract: This module implements the set and query volume information routines for Ntfs called by the dispatch driver. Author: Your Name [Email] dd-Mon-Year Revision History: --*/ #include "NtfsProc.h" // // The local debug trace level // #define Dbg (DEBUG_TRACE_VOLINFO) // // Local procedure prototypes // NTSTATUS NtfsQueryFsVolumeInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_VOLUME_INFORMATION Buffer, IN OUT PULONG Length ); NTSTATUS NtfsQueryFsSizeInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_SIZE_INFORMATION Buffer, IN OUT PULONG Length ); NTSTATUS NtfsQueryFsDeviceInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_DEVICE_INFORMATION Buffer, IN OUT PULONG Length ); NTSTATUS NtfsQueryFsAttributeInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, IN OUT PULONG Length ); NTSTATUS NtfsQueryFsControlInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_CONTROL_INFORMATION Buffer, IN OUT PULONG Length ); NTSTATUS NtfsSetFsLabelInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_LABEL_INFORMATION Buffer ); NTSTATUS NtfsSetFsControlInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_CONTROL_INFORMATION Buffer ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, NtfsCommonQueryVolumeInfo) #pragma alloc_text(PAGE, NtfsCommonSetVolumeInfo) #pragma alloc_text(PAGE, NtfsFsdQueryVolumeInformation) #pragma alloc_text(PAGE, NtfsFsdSetVolumeInformation) #pragma alloc_text(PAGE, NtfsQueryFsAttributeInfo) #pragma alloc_text(PAGE, NtfsQueryFsDeviceInfo) #pragma alloc_text(PAGE, NtfsQueryFsSizeInfo) #pragma alloc_text(PAGE, NtfsQueryFsVolumeInfo) #pragma alloc_text(PAGE, NtfsQueryFsControlInfo) #pragma alloc_text(PAGE, NtfsSetFsLabelInfo) #pragma alloc_text(PAGE, NtfsSetFsControlInfo) #endif NTSTATUS NtfsFsdQueryVolumeInformation ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of query Volume Information. Arguments: VolumeDeviceObject - Supplies the volume device object where the file exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { TOP_LEVEL_CONTEXT TopLevelContext; PTOP_LEVEL_CONTEXT ThreadTopLevelContext; NTSTATUS Status = STATUS_SUCCESS; PIRP_CONTEXT IrpContext = NULL; UNREFERENCED_PARAMETER( VolumeDeviceObject ); ASSERT_IRP( Irp ); PAGED_CODE(); DebugTrace( +1, Dbg, ("NtfsFsdQueryVolumeInformation\n") ); // // Call the common query Volume Information routine // FsRtlEnterFileSystem(); ThreadTopLevelContext = NtfsSetTopLevelIrp( &TopLevelContext, FALSE, FALSE ); do { try { // // We are either initiating this request or retrying it. // if (IrpContext == NULL) { IrpContext = NtfsCreateIrpContext( Irp, CanFsdWait( Irp ) ); NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext ); } else if (Status == STATUS_LOG_FILE_FULL) { NtfsCheckpointForLogFileFull( IrpContext ); } Status = NtfsCommonQueryVolumeInfo( IrpContext, Irp ); break; } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() ); } } while (Status == STATUS_CANT_WAIT || Status == STATUS_LOG_FILE_FULL); if (ThreadTopLevelContext == &TopLevelContext) { NtfsRestoreTopLevelIrp( ThreadTopLevelContext ); } FsRtlExitFileSystem(); // // And return to our caller // DebugTrace( -1, Dbg, ("NtfsFsdQueryVolumeInformation -> %08lx\n", Status) ); return Status; } NTSTATUS NtfsFsdSetVolumeInformation ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of set Volume Information. Arguments: VolumeDeviceObject - Supplies the volume device object where the file exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { TOP_LEVEL_CONTEXT TopLevelContext; PTOP_LEVEL_CONTEXT ThreadTopLevelContext; NTSTATUS Status = STATUS_SUCCESS; PIRP_CONTEXT IrpContext = NULL; UNREFERENCED_PARAMETER( VolumeDeviceObject ); ASSERT_IRP( Irp ); PAGED_CODE(); DebugTrace( +1, Dbg, ("NtfsFsdSetVolumeInformation\n") ); // // Call the common set Volume Information routine // FsRtlEnterFileSystem(); ThreadTopLevelContext = NtfsSetTopLevelIrp( &TopLevelContext, FALSE, FALSE ); do { try { // // We are either initiating this request or retrying it. // if (IrpContext == NULL) { IrpContext = NtfsCreateIrpContext( Irp, CanFsdWait( Irp ) ); NtfsUpdateIrpContextWithTopLevel( IrpContext, ThreadTopLevelContext ); } else if (Status == STATUS_LOG_FILE_FULL) { NtfsCheckpointForLogFileFull( IrpContext ); } Status = NtfsCommonSetVolumeInfo( IrpContext, Irp ); break; } except(NtfsExceptionFilter( IrpContext, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code // Status = NtfsProcessException( IrpContext, Irp, GetExceptionCode() ); } } while (Status == STATUS_CANT_WAIT || Status == STATUS_LOG_FILE_FULL); if (ThreadTopLevelContext == &TopLevelContext) { NtfsRestoreTopLevelIrp( ThreadTopLevelContext ); } FsRtlExitFileSystem(); // // And return to our caller // DebugTrace( -1, Dbg, ("NtfsFsdSetVolumeInformation -> %08lx\n", Status) ); return Status; } NTSTATUS NtfsCommonQueryVolumeInfo ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for query Volume Information called by both the fsd and fsp threads. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfOpen; PVCB Vcb; PFCB Fcb; PSCB Scb; PCCB Ccb; ULONG Length; FS_INFORMATION_CLASS FsInformationClass; PVOID Buffer; ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_IRP( Irp ); PAGED_CODE(); // // Get the current stack location // IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace( +1, Dbg, ("NtfsCommonQueryVolumeInfo...\n") ); DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) ); DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) ); DebugTrace( 0, Dbg, ("Length = %08lx\n", IrpSp->Parameters.QueryVolume.Length) ); DebugTrace( 0, Dbg, ("FsInformationClass = %08lx\n", IrpSp->Parameters.QueryVolume.FsInformationClass) ); DebugTrace( 0, Dbg, ("Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer) ); // // Reference our input parameters to make things easier // Length = IrpSp->Parameters.QueryVolume.Length; FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass; Buffer = Irp->AssociatedIrp.SystemBuffer; // // Extract and decode the file object to get the Vcb, we don't really // care what the type of open is. // FileObject = IrpSp->FileObject; TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE ); // // We need exclusive access to the Vcb because we are going to verify // it. After we verify the vcb we'll convert our access to shared // NtfsAcquireSharedVcb( IrpContext, Vcb, FALSE ); try { // // Based on the information class we'll do different actions. Each // of the procedures that we're calling fills up the output buffer // if possible and returns true if it successfully filled the buffer // and false if it couldn't wait for any I/O to complete. // switch (FsInformationClass) { case FileFsVolumeInformation: Status = NtfsQueryFsVolumeInfo( IrpContext, Vcb, Buffer, &Length ); break; case FileFsSizeInformation: Status = NtfsQueryFsSizeInfo( IrpContext, Vcb, Buffer, &Length ); break; case FileFsDeviceInformation: Status = NtfsQueryFsDeviceInfo( IrpContext, Vcb, Buffer, &Length ); break; case FileFsAttributeInformation: Status = NtfsQueryFsAttributeInfo( IrpContext, Vcb, Buffer, &Length ); break; #ifdef _CAIRO_ case FileFsControlInformation: Status = NtfsQueryFsControlInfo( IrpContext, Vcb, Buffer, &Length ); break; case FileFsQuotaQueryInformation: Status = NtfsFsQuotaQueryInfo( IrpContext, Vcb, Buffer, &Length ); break; #endif // _CAIRO_ default: Status = STATUS_INVALID_PARAMETER; break; } // // Set the information field to the number of bytes actually filled in // Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length; // // Abort transaction on error by raising. // NtfsCleanupTransaction( IrpContext, Status, FALSE ); } finally { DebugUnwind( NtfsCommonQueryVolumeInfo ); NtfsReleaseVcb( IrpContext, Vcb ); if (!AbnormalTermination()) { NtfsCompleteRequest( &IrpContext, &Irp, Status ); } DebugTrace( -1, Dbg, ("NtfsCommonQueryVolumeInfo -> %08lx\n", Status) ); } return Status; } NTSTATUS NtfsCommonSetVolumeInfo ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for set Volume Information called by both the fsd and fsp threads. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfOpen; PVCB Vcb; PFCB Fcb; PSCB Scb; PCCB Ccb; ULONG Length; FS_INFORMATION_CLASS FsInformationClass; PVOID Buffer; ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_IRP( Irp ); PAGED_CODE(); // // Get the current Irp stack location // IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace( +1, Dbg, ("NtfsCommonSetVolumeInfo\n") ); DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) ); DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) ); DebugTrace( 0, Dbg, ("Length = %08lx\n", IrpSp->Parameters.SetVolume.Length) ); DebugTrace( 0, Dbg, ("FsInformationClass = %08lx\n", IrpSp->Parameters.SetVolume.FsInformationClass) ); DebugTrace( 0, Dbg, ("Buffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer) ); // // Reference our input parameters to make things easier // Length = IrpSp->Parameters.SetVolume.Length; FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass; Buffer = Irp->AssociatedIrp.SystemBuffer; // // Extract and decode the file object to get the Vcb, we don't really // care what the type of open is. // FileObject = IrpSp->FileObject; TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE ); if (TypeOfOpen != UserVolumeOpen) { NtfsCompleteRequest( &IrpContext, &Irp, STATUS_ACCESS_DENIED ); DebugTrace( -1, Dbg, ("NtfsCommonSetVolumeInfo -> STATUS_ACCESS_DENIED\n") ); return STATUS_ACCESS_DENIED; } // // Acquire exclusive access to the Vcb // NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE ); try { // // Proceed only if the volume is mounted. // if (FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) { // // Based on the information class we'll do different actions. Each // of the procedures that we're calling performs the action if // possible and returns true if it successful and false if it couldn't // wait for any I/O to complete. // switch (FsInformationClass) { case FileFsLabelInformation: Status = NtfsSetFsLabelInfo( IrpContext, Vcb, Buffer ); break; #ifdef _CAIRO_ case FileFsQuotaSetInformation: Status = NtfsFsQuotaSetInfo( IrpContext, Vcb, Buffer, Length ); break; case FileFsControlInformation: Status = NtfsSetFsControlInfo( IrpContext, Vcb, Buffer ); break; #endif // _CAIRO_ default: Status = STATUS_INVALID_PARAMETER; break; } } else { Status = STATUS_FILE_INVALID; } // // Abort transaction on error by raising. // NtfsCleanupTransaction( IrpContext, Status, FALSE ); } finally { DebugUnwind( NtfsCommonSetVolumeInfo ); NtfsReleaseVcb( IrpContext, Vcb ); if (!AbnormalTermination()) { NtfsCompleteRequest( &IrpContext, &Irp, Status ); } DebugTrace( -1, Dbg, ("NtfsCommonSetVolumeInfo -> %08lx\n", Status) ); } return Status; } // // Internal Support Routine // NTSTATUS NtfsQueryFsVolumeInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_VOLUME_INFORMATION Buffer, IN OUT PULONG Length ) /*++ Routine Description: This routine implements the query volume info call Arguments: Vcb - Supplies the Vcb being queried Buffer - Supplies a pointer to the output buffer where the information is to be returned Length - Supplies the length of the buffer in byte. This variable upon return recieves the remaining bytes free in the buffer Return Value: NTSTATUS - Returns the status for the query --*/ { NTSTATUS Status; ULONG BytesToCopy; ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_VCB( Vcb ); PAGED_CODE(); DebugTrace( 0, Dbg, ("NtfsQueryFsVolumeInfo...\n") ); // // Get the volume creation time from the Vcb. // Buffer->VolumeCreationTime.QuadPart = Vcb->VolumeCreationTime; // // Fill in the serial number and indicate that we support objects // Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber; Buffer->SupportsObjects = TRUE; Buffer->VolumeLabelLength = Vcb->Vpb->VolumeLabelLength; // // Update the length field with how much we have filled in so far. // *Length -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel[0]); // // See how many bytes of volume label we can copy // if (*Length >= (ULONG)Vcb->Vpb->VolumeLabelLength) { Status = STATUS_SUCCESS; BytesToCopy = Vcb->Vpb->VolumeLabelLength; } else { Status = STATUS_BUFFER_OVERFLOW; BytesToCopy = *Length; } // // Copy over the volume label (if there is one). // RtlCopyMemory( &Buffer->VolumeLabel[0], &Vcb->Vpb->VolumeLabel[0], BytesToCopy); // // Update the buffer length by the amount we copied. // *Length -= BytesToCopy; return Status; } // // Internal Support Routine // NTSTATUS NtfsQueryFsSizeInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_SIZE_INFORMATION Buffer, IN OUT PULONG Length ) /*++ Routine Description: This routine implements the query size information call Arguments: Vcb - Supplies the Vcb being queried Buffer - Supplies a pointer to the output buffer where the information is to be returned Length - Supplies the length of the buffer in byte. This variable upon return recieves the remaining bytes free in the buffer Return Value: NTSTATUS - Returns the status for the query --*/ { ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_VCB( Vcb ); PAGED_CODE(); DebugTrace( 0, Dbg, ("NtfsQueryFsSizeInfo...\n") ); // // Make sure the buffer is large enough and zero it out // if (*Length < sizeof(FILE_FS_SIZE_INFORMATION)) { return STATUS_BUFFER_OVERFLOW; } RtlZeroMemory( Buffer, sizeof(FILE_FS_SIZE_INFORMATION) ); // // Check if we need to rescan the bitmap. Don't try this // if we have started to teardown the volume. // if (FlagOn( Vcb->VcbState, VCB_STATE_RELOAD_FREE_CLUSTERS ) && FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) { // // Acquire the volume bitmap shared to rescan the bitmap. // NtfsAcquireExclusiveScb( IrpContext, Vcb->BitmapScb ); try { NtfsScanEntireBitmap( IrpContext, Vcb, TRUE ); } finally { NtfsReleaseScb( IrpContext, Vcb->BitmapScb ); } } // // Set the output buffer // Buffer->TotalAllocationUnits.QuadPart = Vcb->TotalClusters; Buffer->AvailableAllocationUnits.QuadPart = Vcb->FreeClusters; Buffer->SectorsPerAllocationUnit = Vcb->BytesPerCluster / Vcb->BytesPerSector; Buffer->BytesPerSector = Vcb->BytesPerSector; #ifdef _CAIRO_ // // If quota enforcement is enabled then the availalble allocation // units. must be reduced by the available quota. // if (FlagOn(Vcb->QuotaFlags, QUOTA_FLAG_TRACKING_ENABLED)) { PCCB Ccb; // // Go grab the ccb out of the Irp. // Ccb = (PCCB) (IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp)-> FileObject->FsContext2); if (Ccb != NULL && Ccb->OwnerId != 0) { ULONGLONG Quota; NtfsGetRemainingQuota( IrpContext, Ccb->OwnerId, &Quota, NULL ); Quota = LlClustersFromBytesTruncate( Vcb, Quota ); if (Quota < (ULONGLONG) Vcb->FreeClusters) { Buffer->AvailableAllocationUnits.QuadPart = Quota; } } } #endif // _CAIRO_ // // Adjust the length variable // *Length -= sizeof(FILE_FS_SIZE_INFORMATION); return STATUS_SUCCESS; } // // Internal Support Routine // NTSTATUS NtfsQueryFsDeviceInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_DEVICE_INFORMATION Buffer, IN OUT PULONG Length ) /*++ Routine Description: This routine implements the query device information call Arguments: Vcb - Supplies the Vcb being queried Buffer - Supplies a pointer to the output buffer where the information is to be returned Length - Supplies the length of the buffer in byte. This variable upon return recieves the remaining bytes free in the buffer Return Value: NTSTATUS - Returns the status for the query --*/ { ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_VCB( Vcb ); PAGED_CODE(); DebugTrace( 0, Dbg, ("NtfsQueryFsDeviceInfo...\n") ); // // Make sure the buffer is large enough and zero it out // if (*Length < sizeof(FILE_FS_DEVICE_INFORMATION)) { return STATUS_BUFFER_OVERFLOW; } RtlZeroMemory( Buffer, sizeof(FILE_FS_DEVICE_INFORMATION) ); // // Set the output buffer // Buffer->DeviceType = FILE_DEVICE_DISK; Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics; // // Adjust the length variable // *Length -= sizeof(FILE_FS_DEVICE_INFORMATION); return STATUS_SUCCESS; } // // Internal Support Routine // NTSTATUS NtfsQueryFsAttributeInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, IN OUT PULONG Length ) /*++ Routine Description: This routine implements the query attribute information call Arguments: Vcb - Supplies the Vcb being queried Buffer - Supplies a pointer to the output buffer where the information is to be returned Length - Supplies the length of the buffer in byte. This variable upon return recieves the remaining bytes free in the buffer Return Value: NTSTATUS - Returns the status for the query --*/ { NTSTATUS Status; ULONG BytesToCopy; ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_VCB( Vcb ); PAGED_CODE(); DebugTrace( 0, Dbg, ("NtfsQueryFsAttributeInfo...\n") ); // // See how many bytes of the name we can copy. // *Length -= FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[0]); if ( *Length >= 8 ) { Status = STATUS_SUCCESS; BytesToCopy = 8; } else { Status = STATUS_BUFFER_OVERFLOW; BytesToCopy = *Length; } // // Set the output buffer // Buffer->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_FILE_COMPRESSION | FILE_PERSISTENT_ACLS; // // Clear the compression flag if we don't allow compression on this drive // (i.e. large clusters) // if (!FlagOn( Vcb->AttributeFlagsMask, ATTRIBUTE_FLAG_COMPRESSION_MASK )) { ClearFlag( Buffer->FileSystemAttributes, FILE_FILE_COMPRESSION ); } Buffer->MaximumComponentNameLength = 255; Buffer->FileSystemNameLength = BytesToCopy;; RtlCopyMemory( &Buffer->FileSystemName[0], L"NTFS", BytesToCopy ); // // Adjust the length variable // *Length -= BytesToCopy; return Status; } #ifdef _CAIRO_ // // Internal Support Routine // NTSTATUS NtfsQueryFsControlInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_CONTROL_INFORMATION Buffer, IN OUT PULONG Length ) /*++ Routine Description: This routine implements the query control information call Arguments: Vcb - Supplies the Vcb being queried Buffer - Supplies a pointer to the output buffer where the information is to be returned Length - Supplies the length of the buffer in byte. This variable upon return recieves the remaining bytes free in the buffer Return Value: NTSTATUS - Returns the status for the query --*/ { INDEX_ROW IndexRow; INDEX_KEY IndexKey; QUOTA_USER_DATA QuotaBuffer; PQUOTA_USER_DATA UserData; ULONG OwnerId; ULONG Count = 1; PREAD_CONTEXT ReadContext = NULL; NTSTATUS Status = STATUS_SUCCESS; ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_VCB( Vcb ); PAGED_CODE(); DebugTrace( 0, Dbg, ("NtfsQueryFsControlInfo...\n") ); RtlZeroMemory( Buffer, sizeof( FILE_FS_CONTROL_INFORMATION )); PAGED_CODE(); try { // // Fill in the quota information if quotas are running. // if (Vcb->QuotaTableScb != NULL) { OwnerId = QUOTA_DEFAULTS_ID; IndexKey.KeyLength = sizeof( OwnerId ); IndexKey.Key = &OwnerId; Status = NtOfsReadRecords( IrpContext, Vcb->QuotaTableScb, &ReadContext, &IndexKey, NtOfsMatchUlongExact, &IndexKey, &Count, &IndexRow, sizeof( QuotaBuffer ), &QuotaBuffer ); if (NT_SUCCESS( Status )) { UserData = IndexRow.DataPart.Data; Buffer->DefaultQuotaThreshold.QuadPart = UserData->QuotaThreshold; Buffer->DefaultQuotaLimit.QuadPart = UserData->QuotaLimit; // // If the quota info is corrupt or has not been rebuilt // yet then indicate the information is incomplete. // if (FlagOn( Vcb->QuotaFlags, QUOTA_FLAG_OUT_OF_DATE | QUOTA_FLAG_CORRUPT )) { SetFlag( Buffer->FileSystemControlFlags, FILE_VC_QUOTAS_INCOMPLETE ); } if ((Vcb->QuotaState & VCB_QUOTA_REPAIR_RUNNING) > VCB_QUOTA_REPAIR_POSTED ) { SetFlag( Buffer->FileSystemControlFlags, FILE_VC_QUOTAS_REBUILDING ); } // // Set the quota information basied on where we want // to be rather than where we are. // if (FlagOn( UserData->QuotaFlags, QUOTA_FLAG_ENFORCEMENT_ENABLED )) { SetFlag( Buffer->FileSystemControlFlags, FILE_VC_QUOTA_ENFORCE ); } else if (FlagOn( UserData->QuotaFlags, QUOTA_FLAG_TRACKING_REQUESTED )) { SetFlag( Buffer->FileSystemControlFlags, FILE_VC_QUOTA_TRACK ); } if (FlagOn( UserData->QuotaFlags, QUOTA_FLAG_LOG_LIMIT)) { SetFlag( Buffer->FileSystemControlFlags, FILE_VC_LOG_QUOTA_LIMIT ); } if (FlagOn( UserData->QuotaFlags, QUOTA_FLAG_LOG_THRESHOLD)) { SetFlag( Buffer->FileSystemControlFlags, FILE_VC_LOG_QUOTA_THRESHOLD ); } } } } finally { if (ReadContext != NULL) { NtOfsFreeReadContext( ReadContext ); } } // // Adjust the length variable // *Length -= sizeof( FILE_FS_CONTROL_INFORMATION ); return Status; } // // Internal Support Routine // NTSTATUS NtfsSetFsControlInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_CONTROL_INFORMATION Buffer ) /*++ Routine Description: This routine implements the set label call Arguments: Vcb - Supplies the Vcb being altered Buffer - Supplies a pointer to the input buffer containing the new label Return Value: NTSTATUS - Returns the status for the operation --*/ { ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_VCB( Vcb ); PAGED_CODE(); if (Vcb->QuotaTableScb == NULL) { return( STATUS_INVALID_PARAMETER ); } // // Process the quota part of the control structure. // NtfsUpdateQuotaDefaults( IrpContext, Vcb, Buffer ); return STATUS_SUCCESS; } #endif // _CAIRO_ // // Internal Support Routine // NTSTATUS NtfsSetFsLabelInfo ( IN PIRP_CONTEXT IrpContext, IN PVCB Vcb, IN PFILE_FS_LABEL_INFORMATION Buffer ) /*++ Routine Description: This routine implements the set label call Arguments: Vcb - Supplies the Vcb being altered Buffer - Supplies a pointer to the input buffer containing the new label Return Value: NTSTATUS - Returns the status for the operation --*/ { ATTRIBUTE_ENUMERATION_CONTEXT AttributeContext; ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_VCB( Vcb ); PAGED_CODE(); DebugTrace( 0, Dbg, ("NtfsSetFsLabelInfo...\n") ); // // Check that the volume label length is supported by the system. // if (Buffer->VolumeLabelLength > MAXIMUM_VOLUME_LABEL_LENGTH) { return STATUS_INVALID_VOLUME_LABEL; } try { // // Initialize the attribute context and then lookup the volume name // attribute for on the volume dasd file // NtfsInitializeAttributeContext( &AttributeContext ); if (NtfsLookupAttributeByCode( IrpContext, Vcb->VolumeDasdScb->Fcb, &Vcb->VolumeDasdScb->Fcb->FileReference, $VOLUME_NAME, &AttributeContext )) { // // We found the volume name so now simply update the label // NtfsChangeAttributeValue( IrpContext, Vcb->VolumeDasdScb->Fcb, 0, &Buffer->VolumeLabel[0], Buffer->VolumeLabelLength, TRUE, FALSE, FALSE, FALSE, &AttributeContext ); } else { // // We didn't find the volume name so now create a new label // NtfsCleanupAttributeContext( &AttributeContext ); NtfsInitializeAttributeContext( &AttributeContext ); NtfsCreateAttributeWithValue( IrpContext, Vcb->VolumeDasdScb->Fcb, $VOLUME_NAME, NULL, &Buffer->VolumeLabel[0], Buffer->VolumeLabelLength, 0, // Attributeflags NULL, TRUE, &AttributeContext ); } Vcb->Vpb->VolumeLabelLength = (USHORT)Buffer->VolumeLabelLength; if ( Vcb->Vpb->VolumeLabelLength > MAXIMUM_VOLUME_LABEL_LENGTH) { Vcb->Vpb->VolumeLabelLength = MAXIMUM_VOLUME_LABEL_LENGTH; } RtlCopyMemory( &Vcb->Vpb->VolumeLabel[0], &Buffer->VolumeLabel[0], Vcb->Vpb->VolumeLabelLength ); } finally { DebugUnwind( NtfsSetFsLabelInfo ); NtfsCleanupAttributeContext( &AttributeContext ); } // // and return to our caller // return STATUS_SUCCESS; }