reactos/drivers/filesystems/udfs/volinfo.cpp

820 lines
24 KiB
C++

////////////////////////////////////////////////////////////////////
// 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
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