mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
822 lines
24 KiB
C++
822 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
|
|
|
|
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
|