//////////////////////////////////////////////////////////////////// // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine // All rights reserved // This file was released under the GPLv2 on June 2015. //////////////////////////////////////////////////////////////////// /*++ Module Name: VolInfo.cpp Abstract: This module implements the volume information routines for UDF called by the dispatch driver. --*/ #include "udffs.h" // define the file specific bug-check id #define UDF_BUG_CHECK_ID UDF_FILE_VOL_INFORMATION // Local support routines NTSTATUS UDFQueryFsVolumeInfo ( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_VOLUME_INFORMATION Buffer, IN OUT PULONG Length ); NTSTATUS UDFQueryFsSizeInfo ( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_SIZE_INFORMATION Buffer, IN OUT PULONG Length ); NTSTATUS UDFQueryFsFullSizeInfo ( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_FULL_SIZE_INFORMATION Buffer, IN OUT PULONG Length ); NTSTATUS UDFQueryFsDeviceInfo ( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_DEVICE_INFORMATION Buffer, IN OUT PULONG Length ); NTSTATUS UDFQueryFsAttributeInfo ( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, IN OUT PULONG Length ); NTSTATUS UDFSetLabelInfo ( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_LABEL_INFORMATION Buffer, IN OUT PULONG Length); /* This is the routine for querying volume information Arguments: Irp - Supplies the Irp being processed Return Value: NTSTATUS - The return status for the operation */ NTSTATUS NTAPI UDFQueryVolInfo( PDEVICE_OBJECT DeviceObject, // the logical volume device object PIRP Irp // I/O Request Packet ) { NTSTATUS RC = STATUS_SUCCESS; PtrUDFIrpContext PtrIrpContext = NULL; BOOLEAN AreWeTopLevel = FALSE; UDFPrint(("UDFQueryVolInfo: \n")); FsRtlEnterFileSystem(); ASSERT(DeviceObject); ASSERT(Irp); // set the top level context AreWeTopLevel = UDFIsIrpTopLevel(Irp); ASSERT(!UDFIsFSDevObj(DeviceObject)); _SEH2_TRY { // get an IRP context structure and issue the request PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); if(PtrIrpContext) { RC = UDFCommonQueryVolInfo(PtrIrpContext, Irp); } else { RC = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Status = RC; Irp->IoStatus.Information = 0; // complete the IRP IoCompleteRequest(Irp, IO_DISK_INCREMENT); } } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { RC = UDFExceptionHandler(PtrIrpContext, Irp); UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); } _SEH2_END; if (AreWeTopLevel) { IoSetTopLevelIrp(NULL); } FsRtlExitFileSystem(); return(RC); } // end UDFQueryVolInfo() /* This is the common routine for querying volume information called by both the fsd and fsp threads. Arguments: Irp - Supplies the Irp being processed Return Value: NTSTATUS - The return status for the operation */ NTSTATUS UDFCommonQueryVolInfo( PtrUDFIrpContext PtrIrpContext, PIRP Irp ) { NTSTATUS RC = STATUS_INVALID_PARAMETER; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); ULONG Length; BOOLEAN CanWait = FALSE; PVCB Vcb; BOOLEAN PostRequest = FALSE; BOOLEAN AcquiredVCB = FALSE; PFILE_OBJECT FileObject = NULL; // PtrUDFFCB Fcb = NULL; PtrUDFCCB Ccb = NULL; _SEH2_TRY { UDFPrint(("UDFCommonQueryVolInfo: \n")); ASSERT(PtrIrpContext); ASSERT(Irp); PAGED_CODE(); FileObject = IrpSp->FileObject; ASSERT(FileObject); // Get the FCB and CCB pointers. Ccb = (PtrUDFCCB)(FileObject->FsContext2); ASSERT(Ccb); Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension); ASSERT(Vcb); //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; // Reference our input parameters to make things easier Length = IrpSp->Parameters.QueryVolume.Length; // Acquire the Vcb for this volume. CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); #ifdef UDF_ENABLE_SECURITY RC = IoCheckFunctionAccess( Ccb->PreviouslyGrantedAccess, PtrIrpContext->MajorFunction, PtrIrpContext->MinorFunction, 0, NULL, &(IrpSp->Parameters.QueryVolume.FsInformationClass)); if(!NT_SUCCESS(RC)) { try_return(RC); } #endif //UDF_ENABLE_SECURITY RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, Length); switch (IrpSp->Parameters.QueryVolume.FsInformationClass) { case FileFsVolumeInformation: // This is the only routine we need the Vcb shared because of // copying the volume label. All other routines copy fields that // cannot change or are just manifest constants. UDFFlushTryBreak(Vcb); if (!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) { PostRequest = TRUE; try_return (RC = STATUS_PENDING); } AcquiredVCB = TRUE; RC = UDFQueryFsVolumeInfo( PtrIrpContext, Vcb, (PFILE_FS_VOLUME_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); break; case FileFsSizeInformation: RC = UDFQueryFsSizeInfo( PtrIrpContext, Vcb, (PFILE_FS_SIZE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); break; case FileFsDeviceInformation: RC = UDFQueryFsDeviceInfo( PtrIrpContext, Vcb, (PFILE_FS_DEVICE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); break; case FileFsAttributeInformation: RC = UDFQueryFsAttributeInfo( PtrIrpContext, Vcb, (PFILE_FS_ATTRIBUTE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); break; case FileFsFullSizeInformation: RC = UDFQueryFsFullSizeInfo( PtrIrpContext, Vcb, (PFILE_FS_FULL_SIZE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); break; default: RC = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Information = 0; break; } // Set the information field to the number of bytes actually filled in Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length; try_exit: NOTHING; } _SEH2_FINALLY { if (AcquiredVCB) { UDFReleaseResource(&(Vcb->VCBResource)); AcquiredVCB = FALSE; } // Post IRP if required if (PostRequest) { // Since, the I/O Manager gave us a system buffer, we do not // need to "lock" anything. // Perform the post operation which will mark the IRP pending // and will return STATUS_PENDING back to us RC = UDFPostRequest(PtrIrpContext, Irp); } else if(!_SEH2_AbnormalTermination()) { Irp->IoStatus.Status = RC; // Free up the Irp Context UDFReleaseIrpContext(PtrIrpContext); // complete the IRP IoCompleteRequest(Irp, IO_DISK_INCREMENT); } // can we complete the IRP ? } _SEH2_END; return RC; } // end UDFCommonQueryVolInfo() // Local support routine /* This routine implements the query volume info call Arguments: Vcb - Vcb for this volume. 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 */ NTSTATUS UDFQueryFsVolumeInfo( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_VOLUME_INFORMATION Buffer, IN OUT PULONG Length ) { ULONG BytesToCopy; NTSTATUS Status; PAGED_CODE(); UDFPrint((" UDFQueryFsVolumeInfo: \n")); // Fill in the data from the Vcb. Buffer->VolumeCreationTime.QuadPart = Vcb->VolCreationTime; Buffer->VolumeSerialNumber = Vcb->PhSerialNumber; UDFPrint((" SN %x\n", Vcb->PhSerialNumber)); Buffer->SupportsObjects = FALSE; *Length -= FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel[0] ); // Check if the buffer we're given is long enough if (*Length >= (ULONG) Vcb->VolIdent.Length) { BytesToCopy = Vcb->VolIdent.Length; Status = STATUS_SUCCESS; } else { BytesToCopy = *Length; Status = STATUS_BUFFER_OVERFLOW; } // Copy over what we can of the volume label, and adjust *Length Buffer->VolumeLabelLength = BytesToCopy; if (BytesToCopy) RtlCopyMemory( &(Buffer->VolumeLabel[0]), Vcb->VolIdent.Buffer, BytesToCopy ); *Length -= BytesToCopy; return Status; } // end UDFQueryFsVolumeInfo() /* This routine implements the query volume size call. Arguments: Vcb - Vcb for this volume. 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 */ NTSTATUS UDFQueryFsSizeInfo( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_SIZE_INFORMATION Buffer, IN OUT PULONG Length ) { PAGED_CODE(); UDFPrint((" UDFQueryFsSizeInfo: \n")); // Fill in the output buffer. if(Vcb->BitmapModified) { Vcb->TotalAllocUnits = Buffer->TotalAllocationUnits.QuadPart = UDFGetTotalSpace(Vcb); Vcb->FreeAllocUnits = Buffer->AvailableAllocationUnits.QuadPart = UDFGetFreeSpace(Vcb); Vcb->BitmapModified = FALSE; } else { Buffer->TotalAllocationUnits.QuadPart = Vcb->TotalAllocUnits; Buffer->AvailableAllocationUnits.QuadPart = Vcb->FreeAllocUnits; } Vcb->LowFreeSpace = (Vcb->FreeAllocUnits < max(Vcb->FECharge,UDF_DEFAULT_FE_CHARGE)*128); if(!Buffer->TotalAllocationUnits.QuadPart) Buffer->TotalAllocationUnits.QuadPart = max(1, Vcb->LastPossibleLBA); Buffer->SectorsPerAllocationUnit = Vcb->LBlockSize / Vcb->BlockSize; if(!Buffer->SectorsPerAllocationUnit) Buffer->SectorsPerAllocationUnit = 1; Buffer->BytesPerSector = Vcb->BlockSize; if(!Buffer->BytesPerSector) Buffer->BytesPerSector = 2048; UDFPrint((" Space: Total %I64x, Free %I64x\n", Buffer->TotalAllocationUnits.QuadPart, Buffer->AvailableAllocationUnits.QuadPart)); // Adjust the length variable *Length -= sizeof( FILE_FS_SIZE_INFORMATION ); return STATUS_SUCCESS; } // UDFQueryFsSizeInfo() /* This routine implements the query volume full size call. Arguments: Vcb - Vcb for this volume. 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 */ NTSTATUS UDFQueryFsFullSizeInfo( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_FULL_SIZE_INFORMATION Buffer, IN OUT PULONG Length ) { PAGED_CODE(); UDFPrint((" UDFQueryFsFullSizeInfo: \n")); // Fill in the output buffer. if(Vcb->BitmapModified) { Vcb->TotalAllocUnits = Buffer->TotalAllocationUnits.QuadPart = UDFGetTotalSpace(Vcb); Vcb->FreeAllocUnits = Buffer->CallerAvailableAllocationUnits.QuadPart = Buffer->ActualAvailableAllocationUnits.QuadPart = UDFGetFreeSpace(Vcb); Vcb->BitmapModified = FALSE; } else { Buffer->TotalAllocationUnits.QuadPart = Vcb->TotalAllocUnits; Buffer->CallerAvailableAllocationUnits.QuadPart = Buffer->ActualAvailableAllocationUnits.QuadPart = Vcb->FreeAllocUnits; } if(!Buffer->TotalAllocationUnits.QuadPart) Buffer->TotalAllocationUnits.QuadPart = max(1, Vcb->LastPossibleLBA); Buffer->SectorsPerAllocationUnit = Vcb->LBlockSize / Vcb->BlockSize; if(!Buffer->SectorsPerAllocationUnit) Buffer->SectorsPerAllocationUnit = 1; Buffer->BytesPerSector = Vcb->BlockSize; if(!Buffer->BytesPerSector) Buffer->BytesPerSector = 2048; UDFPrint((" Space: Total %I64x, Free %I64x\n", Buffer->TotalAllocationUnits.QuadPart, Buffer->ActualAvailableAllocationUnits.QuadPart)); // Adjust the length variable *Length -= sizeof( FILE_FS_FULL_SIZE_INFORMATION ); return STATUS_SUCCESS; } // UDFQueryFsSizeInfo() /* This routine implements the query volume device call. Arguments: Vcb - Vcb for this volume. 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 */ NTSTATUS UDFQueryFsDeviceInfo( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_DEVICE_INFORMATION Buffer, IN OUT PULONG Length ) { PAGED_CODE(); UDFPrint((" UDFQueryFsDeviceInfo: \n")); // Update the output buffer. if (Vcb->TargetDeviceObject->DeviceType != FILE_DEVICE_CD_ROM && Vcb->TargetDeviceObject->DeviceType != FILE_DEVICE_DVD) { ASSERT(! (Vcb->TargetDeviceObject->Characteristics & (FILE_READ_ONLY_DEVICE | FILE_WRITE_ONCE_MEDIA))); Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics & ~(FILE_READ_ONLY_DEVICE | FILE_WRITE_ONCE_MEDIA); } else { Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics; } Buffer->DeviceType = Vcb->TargetDeviceObject->DeviceType; UDFPrint((" Characteristics %x, DeviceType %x\n", Buffer->Characteristics, Buffer->DeviceType)); // Adjust the length variable *Length -= sizeof( FILE_FS_DEVICE_INFORMATION ); return STATUS_SUCCESS; } // end UDFQueryFsDeviceInfo() /* This routine implements the query volume attribute call. Arguments: Vcb - Vcb for this volume. 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 */ NTSTATUS UDFQueryFsAttributeInfo( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, IN OUT PULONG Length ) { ULONG BytesToCopy; NTSTATUS Status = STATUS_SUCCESS; PCWSTR FsTypeTitle; ULONG FsTypeTitleLen; PAGED_CODE(); UDFPrint((" UDFQueryFsAttributeInfo: \n")); // Fill out the fixed portion of the buffer. Buffer->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES | (UDFStreamsSupported(Vcb) ? FILE_NAMED_STREAMS : 0) | #ifdef ALLOW_SPARSE FILE_SUPPORTS_SPARSE_FILES | #endif //ALLOW_SPARSE #ifdef UDF_ENABLE_SECURITY (UDFNtAclSupported(Vcb) ? FILE_PERSISTENT_ACLS : 0) | #endif //UDF_ENABLE_SECURITY ((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) ? FILE_READ_ONLY_VOLUME : 0) | FILE_UNICODE_ON_DISK; Buffer->MaximumComponentNameLength = UDF_X_NAME_LEN-1; *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ); // Make sure we can copy full unicode characters. *Length &= ~1; // Determine how much of the file system name will fit. #define UDFSetFsTitle(tit) \ FsTypeTitle = UDF_FS_TITLE_##tit; \ FsTypeTitleLen = sizeof(UDF_FS_TITLE_##tit) - sizeof(WCHAR); switch(Vcb->TargetDeviceObject->DeviceType) { case FILE_DEVICE_CD_ROM: { if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { if(!Vcb->LastLBA) { UDFSetFsTitle(BLANK); } else { UDFSetFsTitle(UNKNOWN); } } else if(Vcb->CDR_Mode) { if(Vcb->MediaClassEx == CdMediaClass_DVDR || Vcb->MediaClassEx == CdMediaClass_DVDRW || Vcb->MediaClassEx == CdMediaClass_DVDRAM) { UDFSetFsTitle(DVDR); } else if(Vcb->MediaClassEx == CdMediaClass_DVDpR || Vcb->MediaClassEx == CdMediaClass_DVDpRW) { UDFSetFsTitle(DVDpR); } else if(Vcb->MediaClassEx == CdMediaClass_DVDROM) { UDFSetFsTitle(DVDROM); } else if(Vcb->MediaClassEx == CdMediaClass_CDROM) { UDFSetFsTitle(CDROM); } else { UDFSetFsTitle(CDR); } } else { if(Vcb->MediaClassEx == CdMediaClass_DVDROM || Vcb->MediaClassEx == CdMediaClass_DVDR || Vcb->MediaClassEx == CdMediaClass_DVDpR) { UDFSetFsTitle(DVDROM); } else if(Vcb->MediaClassEx == CdMediaClass_DVDR) { UDFSetFsTitle(DVDR); } else if(Vcb->MediaClassEx == CdMediaClass_DVDRW) { UDFSetFsTitle(DVDRW); } else if(Vcb->MediaClassEx == CdMediaClass_DVDpRW) { UDFSetFsTitle(DVDpRW); } else if(Vcb->MediaClassEx == CdMediaClass_DVDRAM) { UDFSetFsTitle(DVDRAM); } else if(Vcb->MediaClassEx == CdMediaClass_CDROM) { UDFSetFsTitle(CDROM); } else { UDFSetFsTitle(CDRW); } } break; } default: { UDFSetFsTitle(HDD); break; } } #undef UDFSetFsTitle if (*Length >= FsTypeTitleLen) { BytesToCopy = FsTypeTitleLen; } else { BytesToCopy = *Length; Status = STATUS_BUFFER_OVERFLOW; } *Length -= BytesToCopy; // Do the file system name. Buffer->FileSystemNameLength = BytesToCopy; RtlCopyMemory( &Buffer->FileSystemName[0], FsTypeTitle, BytesToCopy ); // And return to our caller return Status; } // end UDFQueryFsAttributeInfo() #ifndef UDF_READ_ONLY_BUILD NTSTATUS NTAPI UDFSetVolInfo( PDEVICE_OBJECT DeviceObject, // the logical volume device object PIRP Irp // I/O Request Packet ) { NTSTATUS RC = STATUS_SUCCESS; PtrUDFIrpContext PtrIrpContext = NULL; BOOLEAN AreWeTopLevel = FALSE; UDFPrint(("UDFSetVolInfo: \n")); FsRtlEnterFileSystem(); ASSERT(DeviceObject); ASSERT(Irp); // set the top level context AreWeTopLevel = UDFIsIrpTopLevel(Irp); ASSERT(!UDFIsFSDevObj(DeviceObject)); _SEH2_TRY { // get an IRP context structure and issue the request PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); ASSERT(PtrIrpContext); RC = UDFCommonSetVolInfo(PtrIrpContext, Irp); } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { RC = UDFExceptionHandler(PtrIrpContext, Irp); UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); } _SEH2_END; if (AreWeTopLevel) { IoSetTopLevelIrp(NULL); } FsRtlExitFileSystem(); return(RC); } // end UDFSetVolInfo() /* This is the common routine for setting volume information called by both the fsd and fsp threads. */ NTSTATUS UDFCommonSetVolInfo( PtrUDFIrpContext PtrIrpContext, PIRP Irp ) { NTSTATUS RC = STATUS_INVALID_PARAMETER; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); ULONG Length; BOOLEAN CanWait = FALSE; PVCB Vcb; BOOLEAN PostRequest = FALSE; BOOLEAN AcquiredVCB = FALSE; PFILE_OBJECT FileObject = NULL; // PtrUDFFCB Fcb = NULL; PtrUDFCCB Ccb = NULL; _SEH2_TRY { UDFPrint(("UDFCommonSetVolInfo: \n")); ASSERT(PtrIrpContext); ASSERT(Irp); PAGED_CODE(); FileObject = IrpSp->FileObject; ASSERT(FileObject); // Get the FCB and CCB pointers. Ccb = (PtrUDFCCB)(FileObject->FsContext2); ASSERT(Ccb); if(Ccb && Ccb->Fcb && (Ccb->Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB)) { UDFPrint((" Can't change Label on Non-volume object\n")); try_return(RC = STATUS_ACCESS_DENIED); } Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension); ASSERT(Vcb); Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; // Reference our input parameters to make things easier if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { UDFPrint((" Can't change Label on blank volume ;)\n")); try_return(RC = STATUS_ACCESS_DENIED); } Length = IrpSp->Parameters.SetVolume.Length; // Acquire the Vcb for this volume. CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); if (!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) { PostRequest = TRUE; try_return (RC = STATUS_PENDING); } AcquiredVCB = TRUE; #ifdef UDF_ENABLE_SECURITY RC = IoCheckFunctionAccess( Ccb->PreviouslyGrantedAccess, PtrIrpContext->MajorFunction, PtrIrpContext->MinorFunction, 0, NULL, &(IrpSp->Parameters.SetVolume.FsInformationClass)); if(!NT_SUCCESS(RC)) { try_return(RC); } #endif //UDF_ENABLE_SECURITY switch (IrpSp->Parameters.SetVolume.FsInformationClass) { case FileFsLabelInformation: RC = UDFSetLabelInfo( PtrIrpContext, Vcb, (PFILE_FS_LABEL_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); Irp->IoStatus.Information = 0; break; default: RC = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Information = 0; break; } // Set the information field to the number of bytes actually filled in Irp->IoStatus.Information = IrpSp->Parameters.SetVolume.Length - Length; try_exit: NOTHING; } _SEH2_FINALLY { if (AcquiredVCB) { UDFReleaseResource(&(Vcb->VCBResource)); AcquiredVCB = FALSE; } // Post IRP if required if (PostRequest) { // Since, the I/O Manager gave us a system buffer, we do not // need to "lock" anything. // Perform the post operation which will mark the IRP pending // and will return STATUS_PENDING back to us RC = UDFPostRequest(PtrIrpContext, Irp); } else { // Can complete the IRP here if no exception was encountered if (!_SEH2_AbnormalTermination()) { Irp->IoStatus.Status = RC; // Free up the Irp Context UDFReleaseIrpContext(PtrIrpContext); // complete the IRP IoCompleteRequest(Irp, IO_DISK_INCREMENT); } } // can we complete the IRP ? } _SEH2_END; return RC; } // end UDFCommonSetVolInfo() /* This sets Volume Label */ NTSTATUS UDFSetLabelInfo ( IN PtrUDFIrpContext PtrIrpContext, IN PVCB Vcb, IN PFILE_FS_LABEL_INFORMATION Buffer, IN OUT PULONG Length ) { PAGED_CODE(); UDFPrint((" UDFSetLabelInfo: \n")); if(Buffer->VolumeLabelLength > UDF_VOL_LABEL_LEN*sizeof(WCHAR)) { // Too long Volume Label... NT doesn't like it UDFPrint((" UDFSetLabelInfo: STATUS_INVALID_VOLUME_LABEL\n")); return STATUS_INVALID_VOLUME_LABEL; } if(Vcb->VolIdent.Buffer) MyFreePool__(Vcb->VolIdent.Buffer); Vcb->VolIdent.Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Buffer->VolumeLabelLength+sizeof(WCHAR)); if(!Vcb->VolIdent.Buffer) return STATUS_INSUFFICIENT_RESOURCES; Vcb->VolIdent.Length = (USHORT)Buffer->VolumeLabelLength; Vcb->VolIdent.MaximumLength = (USHORT)Buffer->VolumeLabelLength+sizeof(WCHAR); RtlCopyMemory(Vcb->VolIdent.Buffer, &(Buffer->VolumeLabel), Buffer->VolumeLabelLength); Vcb->VolIdent.Buffer[Buffer->VolumeLabelLength/sizeof(WCHAR)] = 0; UDFSetModified(Vcb); UDFPrint((" UDFSetLabelInfo: OK\n")); return STATUS_SUCCESS; } // end UDFSetLabelInfo () #endif //UDF_READ_ONLY_BUILD