1 //////////////////////////////////////////////////////////////////// 2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine 3 // All rights reserved 4 // This file was released under the GPLv2 on June 2015. 5 //////////////////////////////////////////////////////////////////// 6 /*++ 7 8 Module Name: 9 10 VolInfo.cpp 11 12 Abstract: 13 14 This module implements the volume information routines for UDF called by 15 the dispatch driver. 16 17 --*/ 18 19 #include "udffs.h" 20 21 // define the file specific bug-check id 22 #define UDF_BUG_CHECK_ID UDF_FILE_VOL_INFORMATION 23 24 // Local support routines 25 NTSTATUS 26 UDFQueryFsVolumeInfo ( 27 IN PtrUDFIrpContext PtrIrpContext, 28 IN PVCB Vcb, 29 IN PFILE_FS_VOLUME_INFORMATION Buffer, 30 IN OUT PULONG Length 31 ); 32 33 NTSTATUS 34 UDFQueryFsSizeInfo ( 35 IN PtrUDFIrpContext PtrIrpContext, 36 IN PVCB Vcb, 37 IN PFILE_FS_SIZE_INFORMATION Buffer, 38 IN OUT PULONG Length 39 ); 40 41 NTSTATUS 42 UDFQueryFsFullSizeInfo ( 43 IN PtrUDFIrpContext PtrIrpContext, 44 IN PVCB Vcb, 45 IN PFILE_FS_FULL_SIZE_INFORMATION Buffer, 46 IN OUT PULONG Length 47 ); 48 49 NTSTATUS 50 UDFQueryFsDeviceInfo ( 51 IN PtrUDFIrpContext PtrIrpContext, 52 IN PVCB Vcb, 53 IN PFILE_FS_DEVICE_INFORMATION Buffer, 54 IN OUT PULONG Length 55 ); 56 57 NTSTATUS 58 UDFQueryFsAttributeInfo ( 59 IN PtrUDFIrpContext PtrIrpContext, 60 IN PVCB Vcb, 61 IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, 62 IN OUT PULONG Length 63 ); 64 65 NTSTATUS 66 UDFSetLabelInfo ( 67 IN PtrUDFIrpContext PtrIrpContext, 68 IN PVCB Vcb, 69 IN PFILE_FS_LABEL_INFORMATION Buffer, 70 IN OUT PULONG Length); 71 72 /* 73 This is the routine for querying volume information 74 75 Arguments: 76 77 Irp - Supplies the Irp being processed 78 79 Return Value: 80 81 NTSTATUS - The return status for the operation 82 83 */ 84 NTSTATUS 85 NTAPI 86 UDFQueryVolInfo( 87 PDEVICE_OBJECT DeviceObject, // the logical volume device object 88 PIRP Irp // I/O Request Packet 89 ) 90 { 91 NTSTATUS RC = STATUS_SUCCESS; 92 PtrUDFIrpContext PtrIrpContext = NULL; 93 BOOLEAN AreWeTopLevel = FALSE; 94 95 UDFPrint(("UDFQueryVolInfo: \n")); 96 97 FsRtlEnterFileSystem(); 98 ASSERT(DeviceObject); 99 ASSERT(Irp); 100 101 // set the top level context 102 AreWeTopLevel = UDFIsIrpTopLevel(Irp); 103 ASSERT(!UDFIsFSDevObj(DeviceObject)); 104 105 _SEH2_TRY { 106 107 // get an IRP context structure and issue the request 108 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); 109 if(PtrIrpContext) { 110 RC = UDFCommonQueryVolInfo(PtrIrpContext, Irp); 111 } else { 112 RC = STATUS_INSUFFICIENT_RESOURCES; 113 Irp->IoStatus.Status = RC; 114 Irp->IoStatus.Information = 0; 115 // complete the IRP 116 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 117 } 118 119 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { 120 121 RC = UDFExceptionHandler(PtrIrpContext, Irp); 122 123 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); 124 } _SEH2_END; 125 126 if (AreWeTopLevel) { 127 IoSetTopLevelIrp(NULL); 128 } 129 130 FsRtlExitFileSystem(); 131 132 return(RC); 133 } // end UDFQueryVolInfo() 134 135 /* 136 This is the common routine for querying volume information called by both 137 the fsd and fsp threads. 138 139 Arguments: 140 141 Irp - Supplies the Irp being processed 142 143 Return Value: 144 145 NTSTATUS - The return status for the operation 146 147 */ 148 NTSTATUS 149 UDFCommonQueryVolInfo( 150 PtrUDFIrpContext PtrIrpContext, 151 PIRP Irp 152 ) 153 { 154 NTSTATUS RC = STATUS_INVALID_PARAMETER; 155 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 156 ULONG Length; 157 BOOLEAN CanWait = FALSE; 158 PVCB Vcb; 159 BOOLEAN PostRequest = FALSE; 160 BOOLEAN AcquiredVCB = FALSE; 161 PFILE_OBJECT FileObject = NULL; 162 // PtrUDFFCB Fcb = NULL; 163 PtrUDFCCB Ccb = NULL; 164 165 _SEH2_TRY { 166 167 UDFPrint(("UDFCommonQueryVolInfo: \n")); 168 169 ASSERT(PtrIrpContext); 170 ASSERT(Irp); 171 172 PAGED_CODE(); 173 174 FileObject = IrpSp->FileObject; 175 ASSERT(FileObject); 176 177 // Get the FCB and CCB pointers. 178 Ccb = (PtrUDFCCB)(FileObject->FsContext2); 179 ASSERT(Ccb); 180 181 Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension); 182 ASSERT(Vcb); 183 //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; 184 // Reference our input parameters to make things easier 185 Length = IrpSp->Parameters.QueryVolume.Length; 186 // Acquire the Vcb for this volume. 187 CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); 188 #ifdef UDF_ENABLE_SECURITY 189 RC = IoCheckFunctionAccess( 190 Ccb->PreviouslyGrantedAccess, 191 PtrIrpContext->MajorFunction, 192 PtrIrpContext->MinorFunction, 193 0, 194 NULL, 195 &(IrpSp->Parameters.QueryVolume.FsInformationClass)); 196 if(!NT_SUCCESS(RC)) { 197 try_return(RC); 198 } 199 #endif //UDF_ENABLE_SECURITY 200 switch (IrpSp->Parameters.QueryVolume.FsInformationClass) { 201 202 case FileFsVolumeInformation: 203 204 // This is the only routine we need the Vcb shared because of 205 // copying the volume label. All other routines copy fields that 206 // cannot change or are just manifest constants. 207 UDFFlushTryBreak(Vcb); 208 if (!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) { 209 PostRequest = TRUE; 210 try_return (RC = STATUS_PENDING); 211 } 212 AcquiredVCB = TRUE; 213 214 RC = UDFQueryFsVolumeInfo( PtrIrpContext, Vcb, (PFILE_FS_VOLUME_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); 215 break; 216 217 case FileFsSizeInformation: 218 219 RC = UDFQueryFsSizeInfo( PtrIrpContext, Vcb, (PFILE_FS_SIZE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); 220 break; 221 222 case FileFsDeviceInformation: 223 224 RC = UDFQueryFsDeviceInfo( PtrIrpContext, Vcb, (PFILE_FS_DEVICE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); 225 break; 226 227 case FileFsAttributeInformation: 228 229 RC = UDFQueryFsAttributeInfo( PtrIrpContext, Vcb, (PFILE_FS_ATTRIBUTE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); 230 break; 231 232 case FileFsFullSizeInformation: 233 234 RC = UDFQueryFsFullSizeInfo( PtrIrpContext, Vcb, (PFILE_FS_FULL_SIZE_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); 235 break; 236 237 default: 238 239 RC = STATUS_INVALID_DEVICE_REQUEST; 240 Irp->IoStatus.Information = 0; 241 break; 242 243 } 244 245 // Set the information field to the number of bytes actually filled in 246 Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length; 247 248 try_exit: NOTHING; 249 250 } _SEH2_FINALLY { 251 252 if (AcquiredVCB) { 253 UDFReleaseResource(&(Vcb->VCBResource)); 254 AcquiredVCB = FALSE; 255 } 256 257 // Post IRP if required 258 if (PostRequest) { 259 260 // Since, the I/O Manager gave us a system buffer, we do not 261 // need to "lock" anything. 262 263 // Perform the post operation which will mark the IRP pending 264 // and will return STATUS_PENDING back to us 265 RC = UDFPostRequest(PtrIrpContext, Irp); 266 267 } else 268 if(!_SEH2_AbnormalTermination()) { 269 270 Irp->IoStatus.Status = RC; 271 // Free up the Irp Context 272 UDFReleaseIrpContext(PtrIrpContext); 273 // complete the IRP 274 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 275 } // can we complete the IRP ? 276 277 } _SEH2_END; 278 279 return RC; 280 } // end UDFCommonQueryVolInfo() 281 282 283 // Local support routine 284 285 /* 286 This routine implements the query volume info call 287 288 Arguments: 289 290 Vcb - Vcb for this volume. 291 Buffer - Supplies a pointer to the output buffer where the information 292 is to be returned 293 Length - Supplies the length of the buffer in byte. This variable 294 upon return recieves the remaining bytes free in the buffer 295 */ 296 NTSTATUS 297 UDFQueryFsVolumeInfo( 298 IN PtrUDFIrpContext PtrIrpContext, 299 IN PVCB Vcb, 300 IN PFILE_FS_VOLUME_INFORMATION Buffer, 301 IN OUT PULONG Length 302 ) 303 { 304 ULONG BytesToCopy; 305 NTSTATUS Status; 306 307 PAGED_CODE(); 308 309 UDFPrint((" UDFQueryFsVolumeInfo: \n")); 310 // Fill in the data from the Vcb. 311 Buffer->VolumeCreationTime.QuadPart = Vcb->VolCreationTime; 312 Buffer->VolumeSerialNumber = Vcb->PhSerialNumber; 313 UDFPrint((" SN %x\n", Vcb->PhSerialNumber)); 314 315 Buffer->SupportsObjects = FALSE; 316 317 *Length -= FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel[0] ); 318 319 // Check if the buffer we're given is long enough 320 if (*Length >= (ULONG) Vcb->VolIdent.Length) { 321 BytesToCopy = Vcb->VolIdent.Length; 322 Status = STATUS_SUCCESS; 323 } else { 324 BytesToCopy = *Length; 325 Status = STATUS_BUFFER_OVERFLOW; 326 } 327 // Copy over what we can of the volume label, and adjust *Length 328 Buffer->VolumeLabelLength = BytesToCopy; 329 330 if (BytesToCopy) 331 RtlCopyMemory( &(Buffer->VolumeLabel[0]), Vcb->VolIdent.Buffer, BytesToCopy ); 332 *Length -= BytesToCopy; 333 334 return Status; 335 } // end UDFQueryFsVolumeInfo() 336 337 /* 338 This routine implements the query volume size call. 339 340 Arguments: 341 342 Vcb - Vcb for this volume. 343 Buffer - Supplies a pointer to the output buffer where the information 344 is to be returned 345 Length - Supplies the length of the buffer in byte. This variable 346 upon return recieves the remaining bytes free in the buffer 347 */ 348 NTSTATUS 349 UDFQueryFsSizeInfo( 350 IN PtrUDFIrpContext PtrIrpContext, 351 IN PVCB Vcb, 352 IN PFILE_FS_SIZE_INFORMATION Buffer, 353 IN OUT PULONG Length 354 ) 355 { 356 PAGED_CODE(); 357 358 UDFPrint((" UDFQueryFsSizeInfo: \n")); 359 // Fill in the output buffer. 360 if(Vcb->BitmapModified) { 361 Vcb->TotalAllocUnits = 362 Buffer->TotalAllocationUnits.QuadPart = UDFGetTotalSpace(Vcb); 363 Vcb->FreeAllocUnits = 364 Buffer->AvailableAllocationUnits.QuadPart = UDFGetFreeSpace(Vcb); 365 Vcb->BitmapModified = FALSE; 366 } else { 367 Buffer->TotalAllocationUnits.QuadPart = Vcb->TotalAllocUnits; 368 Buffer->AvailableAllocationUnits.QuadPart = Vcb->FreeAllocUnits; 369 } 370 Vcb->LowFreeSpace = (Vcb->FreeAllocUnits < max(Vcb->FECharge,UDF_DEFAULT_FE_CHARGE)*128); 371 if(!Buffer->TotalAllocationUnits.QuadPart) 372 Buffer->TotalAllocationUnits.QuadPart = max(1, Vcb->LastPossibleLBA); 373 Buffer->SectorsPerAllocationUnit = Vcb->LBlockSize / Vcb->BlockSize; 374 if(!Buffer->SectorsPerAllocationUnit) 375 Buffer->SectorsPerAllocationUnit = 1; 376 Buffer->BytesPerSector = Vcb->BlockSize; 377 if(!Buffer->BytesPerSector) 378 Buffer->BytesPerSector = 2048; 379 380 UDFPrint((" Space: Total %I64x, Free %I64x\n", 381 Buffer->TotalAllocationUnits.QuadPart, 382 Buffer->AvailableAllocationUnits.QuadPart)); 383 384 // Adjust the length variable 385 *Length -= sizeof( FILE_FS_SIZE_INFORMATION ); 386 return STATUS_SUCCESS; 387 } // UDFQueryFsSizeInfo() 388 389 /* 390 This routine implements the query volume full size call. 391 392 Arguments: 393 394 Vcb - Vcb for this volume. 395 Buffer - Supplies a pointer to the output buffer where the information 396 is to be returned 397 Length - Supplies the length of the buffer in byte. This variable 398 upon return recieves the remaining bytes free in the buffer 399 */ 400 NTSTATUS 401 UDFQueryFsFullSizeInfo( 402 IN PtrUDFIrpContext PtrIrpContext, 403 IN PVCB Vcb, 404 IN PFILE_FS_FULL_SIZE_INFORMATION Buffer, 405 IN OUT PULONG Length 406 ) 407 { 408 PAGED_CODE(); 409 410 UDFPrint((" UDFQueryFsFullSizeInfo: \n")); 411 // Fill in the output buffer. 412 if(Vcb->BitmapModified) { 413 Vcb->TotalAllocUnits = 414 Buffer->TotalAllocationUnits.QuadPart = UDFGetTotalSpace(Vcb); 415 Vcb->FreeAllocUnits = 416 Buffer->CallerAvailableAllocationUnits.QuadPart = 417 Buffer->ActualAvailableAllocationUnits.QuadPart = UDFGetFreeSpace(Vcb); 418 Vcb->BitmapModified = FALSE; 419 } else { 420 Buffer->TotalAllocationUnits.QuadPart = Vcb->TotalAllocUnits; 421 Buffer->CallerAvailableAllocationUnits.QuadPart = 422 Buffer->ActualAvailableAllocationUnits.QuadPart = Vcb->FreeAllocUnits; 423 } 424 if(!Buffer->TotalAllocationUnits.QuadPart) 425 Buffer->TotalAllocationUnits.QuadPart = max(1, Vcb->LastPossibleLBA); 426 Buffer->SectorsPerAllocationUnit = Vcb->LBlockSize / Vcb->BlockSize; 427 if(!Buffer->SectorsPerAllocationUnit) 428 Buffer->SectorsPerAllocationUnit = 1; 429 Buffer->BytesPerSector = Vcb->BlockSize; 430 if(!Buffer->BytesPerSector) 431 Buffer->BytesPerSector = 2048; 432 433 UDFPrint((" Space: Total %I64x, Free %I64x\n", 434 Buffer->TotalAllocationUnits.QuadPart, 435 Buffer->ActualAvailableAllocationUnits.QuadPart)); 436 437 // Adjust the length variable 438 *Length -= sizeof( FILE_FS_FULL_SIZE_INFORMATION ); 439 return STATUS_SUCCESS; 440 } // UDFQueryFsSizeInfo() 441 442 /* 443 This routine implements the query volume device call. 444 445 Arguments: 446 447 Vcb - Vcb for this volume. 448 Buffer - Supplies a pointer to the output buffer where the information 449 is to be returned 450 Length - Supplies the length of the buffer in byte. This variable 451 upon return recieves the remaining bytes free in the buffer 452 */ 453 NTSTATUS 454 UDFQueryFsDeviceInfo( 455 IN PtrUDFIrpContext PtrIrpContext, 456 IN PVCB Vcb, 457 IN PFILE_FS_DEVICE_INFORMATION Buffer, 458 IN OUT PULONG Length 459 ) 460 { 461 PAGED_CODE(); 462 463 UDFPrint((" UDFQueryFsDeviceInfo: \n")); 464 // Update the output buffer. 465 if (Vcb->TargetDeviceObject->DeviceType != FILE_DEVICE_CD_ROM && Vcb->TargetDeviceObject->DeviceType != FILE_DEVICE_DVD) 466 { 467 ASSERT(! (Vcb->TargetDeviceObject->Characteristics & (FILE_READ_ONLY_DEVICE | FILE_WRITE_ONCE_MEDIA))); 468 Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics & ~(FILE_READ_ONLY_DEVICE | FILE_WRITE_ONCE_MEDIA); 469 } 470 else 471 { 472 Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics; 473 } 474 Buffer->DeviceType = Vcb->TargetDeviceObject->DeviceType; 475 UDFPrint((" Characteristics %x, DeviceType %x\n", Buffer->Characteristics, Buffer->DeviceType)); 476 // Adjust the length variable 477 *Length -= sizeof( FILE_FS_DEVICE_INFORMATION ); 478 return STATUS_SUCCESS; 479 } // end UDFQueryFsDeviceInfo() 480 481 /* 482 This routine implements the query volume attribute call. 483 484 Arguments: 485 486 Vcb - Vcb for this volume. 487 Buffer - Supplies a pointer to the output buffer where the information 488 is to be returned 489 Length - Supplies the length of the buffer in byte. This variable 490 upon return recieves the remaining bytes free in the buffer 491 */ 492 NTSTATUS 493 UDFQueryFsAttributeInfo( 494 IN PtrUDFIrpContext PtrIrpContext, 495 IN PVCB Vcb, 496 IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, 497 IN OUT PULONG Length 498 ) 499 { 500 ULONG BytesToCopy; 501 502 NTSTATUS Status = STATUS_SUCCESS; 503 PCWSTR FsTypeTitle; 504 ULONG FsTypeTitleLen; 505 506 PAGED_CODE(); 507 UDFPrint((" UDFQueryFsAttributeInfo: \n")); 508 // Fill out the fixed portion of the buffer. 509 Buffer->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH | 510 FILE_CASE_PRESERVED_NAMES | 511 (UDFStreamsSupported(Vcb) ? FILE_NAMED_STREAMS : 0) | 512 #ifdef ALLOW_SPARSE 513 FILE_SUPPORTS_SPARSE_FILES | 514 #endif //ALLOW_SPARSE 515 #ifdef UDF_ENABLE_SECURITY 516 (UDFNtAclSupported(Vcb) ? FILE_PERSISTENT_ACLS : 0) | 517 #endif //UDF_ENABLE_SECURITY 518 ((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) ? FILE_READ_ONLY_VOLUME : 0) | 519 520 FILE_UNICODE_ON_DISK; 521 522 Buffer->MaximumComponentNameLength = UDF_X_NAME_LEN-1; 523 524 *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ); 525 // Make sure we can copy full unicode characters. 526 *Length &= ~1; 527 // Determine how much of the file system name will fit. 528 529 #define UDFSetFsTitle(tit) \ 530 FsTypeTitle = UDF_FS_TITLE_##tit; \ 531 FsTypeTitleLen = sizeof(UDF_FS_TITLE_##tit) - sizeof(WCHAR); 532 533 switch(Vcb->TargetDeviceObject->DeviceType) { 534 case FILE_DEVICE_CD_ROM: { 535 if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { 536 if(!Vcb->LastLBA) { 537 UDFSetFsTitle(BLANK); 538 } else { 539 UDFSetFsTitle(UNKNOWN); 540 } 541 } else 542 if(Vcb->CDR_Mode) { 543 if(Vcb->MediaClassEx == CdMediaClass_DVDR || 544 Vcb->MediaClassEx == CdMediaClass_DVDRW || 545 Vcb->MediaClassEx == CdMediaClass_DVDRAM) { 546 UDFSetFsTitle(DVDR); 547 } else 548 if(Vcb->MediaClassEx == CdMediaClass_DVDpR || 549 Vcb->MediaClassEx == CdMediaClass_DVDpRW) { 550 UDFSetFsTitle(DVDpR); 551 } else 552 if(Vcb->MediaClassEx == CdMediaClass_DVDROM) { 553 UDFSetFsTitle(DVDROM); 554 } else 555 if(Vcb->MediaClassEx == CdMediaClass_CDROM) { 556 UDFSetFsTitle(CDROM); 557 } else { 558 UDFSetFsTitle(CDR); 559 } 560 } else { 561 if(Vcb->MediaClassEx == CdMediaClass_DVDROM || 562 Vcb->MediaClassEx == CdMediaClass_DVDR || 563 Vcb->MediaClassEx == CdMediaClass_DVDpR) { 564 UDFSetFsTitle(DVDROM); 565 } else 566 if(Vcb->MediaClassEx == CdMediaClass_DVDR) { 567 UDFSetFsTitle(DVDR); 568 } else 569 if(Vcb->MediaClassEx == CdMediaClass_DVDRW) { 570 UDFSetFsTitle(DVDRW); 571 } else 572 if(Vcb->MediaClassEx == CdMediaClass_DVDpRW) { 573 UDFSetFsTitle(DVDpRW); 574 } else 575 if(Vcb->MediaClassEx == CdMediaClass_DVDRAM) { 576 UDFSetFsTitle(DVDRAM); 577 } else 578 if(Vcb->MediaClassEx == CdMediaClass_CDROM) { 579 UDFSetFsTitle(CDROM); 580 } else { 581 UDFSetFsTitle(CDRW); 582 } 583 } 584 break; 585 } 586 default: { 587 UDFSetFsTitle(HDD); 588 break; 589 } 590 } 591 592 #undef UDFSetFsTitle 593 594 if (*Length >= FsTypeTitleLen) { 595 BytesToCopy = FsTypeTitleLen; 596 } else { 597 BytesToCopy = *Length; 598 Status = STATUS_BUFFER_OVERFLOW; 599 } 600 601 *Length -= BytesToCopy; 602 // Do the file system name. 603 Buffer->FileSystemNameLength = BytesToCopy; 604 RtlCopyMemory( &Buffer->FileSystemName[0], FsTypeTitle, BytesToCopy ); 605 // And return to our caller 606 return Status; 607 } // end UDFQueryFsAttributeInfo() 608 609 610 #ifndef UDF_READ_ONLY_BUILD 611 612 NTSTATUS 613 NTAPI 614 UDFSetVolInfo( 615 PDEVICE_OBJECT DeviceObject, // the logical volume device object 616 PIRP Irp // I/O Request Packet 617 ) 618 { 619 NTSTATUS RC = STATUS_SUCCESS; 620 PtrUDFIrpContext PtrIrpContext = NULL; 621 BOOLEAN AreWeTopLevel = FALSE; 622 623 UDFPrint(("UDFSetVolInfo: \n")); 624 625 FsRtlEnterFileSystem(); 626 ASSERT(DeviceObject); 627 ASSERT(Irp); 628 629 // set the top level context 630 AreWeTopLevel = UDFIsIrpTopLevel(Irp); 631 ASSERT(!UDFIsFSDevObj(DeviceObject)); 632 633 _SEH2_TRY { 634 635 // get an IRP context structure and issue the request 636 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); 637 ASSERT(PtrIrpContext); 638 639 RC = UDFCommonSetVolInfo(PtrIrpContext, Irp); 640 641 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { 642 643 RC = UDFExceptionHandler(PtrIrpContext, Irp); 644 645 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); 646 } _SEH2_END; 647 648 if (AreWeTopLevel) { 649 IoSetTopLevelIrp(NULL); 650 } 651 652 FsRtlExitFileSystem(); 653 654 return(RC); 655 } // end UDFSetVolInfo() 656 657 658 /* 659 This is the common routine for setting volume information called by both 660 the fsd and fsp threads. 661 */ 662 NTSTATUS 663 UDFCommonSetVolInfo( 664 PtrUDFIrpContext PtrIrpContext, 665 PIRP Irp 666 ) 667 { 668 NTSTATUS RC = STATUS_INVALID_PARAMETER; 669 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 670 ULONG Length; 671 BOOLEAN CanWait = FALSE; 672 PVCB Vcb; 673 BOOLEAN PostRequest = FALSE; 674 BOOLEAN AcquiredVCB = FALSE; 675 PFILE_OBJECT FileObject = NULL; 676 // PtrUDFFCB Fcb = NULL; 677 PtrUDFCCB Ccb = NULL; 678 679 _SEH2_TRY { 680 681 UDFPrint(("UDFCommonSetVolInfo: \n")); 682 ASSERT(PtrIrpContext); 683 ASSERT(Irp); 684 685 PAGED_CODE(); 686 687 FileObject = IrpSp->FileObject; 688 ASSERT(FileObject); 689 690 // Get the FCB and CCB pointers. 691 Ccb = (PtrUDFCCB)(FileObject->FsContext2); 692 ASSERT(Ccb); 693 694 if(Ccb && Ccb->Fcb && (Ccb->Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB)) { 695 UDFPrint((" Can't change Label on Non-volume object\n")); 696 try_return(RC = STATUS_ACCESS_DENIED); 697 } 698 699 Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension); 700 ASSERT(Vcb); 701 Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; 702 // Reference our input parameters to make things easier 703 704 if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { 705 UDFPrint((" Can't change Label on blank volume ;)\n")); 706 try_return(RC = STATUS_ACCESS_DENIED); 707 } 708 709 Length = IrpSp->Parameters.SetVolume.Length; 710 // Acquire the Vcb for this volume. 711 CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); 712 if (!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) { 713 PostRequest = TRUE; 714 try_return (RC = STATUS_PENDING); 715 } 716 AcquiredVCB = TRUE; 717 #ifdef UDF_ENABLE_SECURITY 718 RC = IoCheckFunctionAccess( 719 Ccb->PreviouslyGrantedAccess, 720 PtrIrpContext->MajorFunction, 721 PtrIrpContext->MinorFunction, 722 0, 723 NULL, 724 &(IrpSp->Parameters.SetVolume.FsInformationClass)); 725 if(!NT_SUCCESS(RC)) { 726 try_return(RC); 727 } 728 #endif //UDF_ENABLE_SECURITY 729 switch (IrpSp->Parameters.SetVolume.FsInformationClass) { 730 731 case FileFsLabelInformation: 732 733 RC = UDFSetLabelInfo( PtrIrpContext, Vcb, (PFILE_FS_LABEL_INFORMATION)(Irp->AssociatedIrp.SystemBuffer), &Length ); 734 Irp->IoStatus.Information = 0; 735 break; 736 737 default: 738 739 RC = STATUS_INVALID_DEVICE_REQUEST; 740 Irp->IoStatus.Information = 0; 741 break; 742 743 } 744 745 // Set the information field to the number of bytes actually filled in 746 Irp->IoStatus.Information = IrpSp->Parameters.SetVolume.Length - Length; 747 748 try_exit: NOTHING; 749 750 } _SEH2_FINALLY { 751 752 if (AcquiredVCB) { 753 UDFReleaseResource(&(Vcb->VCBResource)); 754 AcquiredVCB = FALSE; 755 } 756 757 // Post IRP if required 758 if (PostRequest) { 759 760 // Since, the I/O Manager gave us a system buffer, we do not 761 // need to "lock" anything. 762 763 // Perform the post operation which will mark the IRP pending 764 // and will return STATUS_PENDING back to us 765 RC = UDFPostRequest(PtrIrpContext, Irp); 766 767 } else { 768 769 // Can complete the IRP here if no exception was encountered 770 if (!_SEH2_AbnormalTermination()) { 771 Irp->IoStatus.Status = RC; 772 773 // Free up the Irp Context 774 UDFReleaseIrpContext(PtrIrpContext); 775 // complete the IRP 776 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 777 } 778 } // can we complete the IRP ? 779 780 } _SEH2_END; 781 782 return RC; 783 } // end UDFCommonSetVolInfo() 784 785 /* 786 This sets Volume Label 787 */ 788 NTSTATUS 789 UDFSetLabelInfo ( 790 IN PtrUDFIrpContext PtrIrpContext, 791 IN PVCB Vcb, 792 IN PFILE_FS_LABEL_INFORMATION Buffer, 793 IN OUT PULONG Length 794 ) 795 { 796 PAGED_CODE(); 797 798 UDFPrint((" UDFSetLabelInfo: \n")); 799 if(Buffer->VolumeLabelLength > UDF_VOL_LABEL_LEN*sizeof(WCHAR)) { 800 // Too long Volume Label... NT doesn't like it 801 UDFPrint((" UDFSetLabelInfo: STATUS_INVALID_VOLUME_LABEL\n")); 802 return STATUS_INVALID_VOLUME_LABEL; 803 } 804 805 if(Vcb->VolIdent.Buffer) MyFreePool__(Vcb->VolIdent.Buffer); 806 Vcb->VolIdent.Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Buffer->VolumeLabelLength+sizeof(WCHAR)); 807 if(!Vcb->VolIdent.Buffer) return STATUS_INSUFFICIENT_RESOURCES; 808 809 Vcb->VolIdent.Length = (USHORT)Buffer->VolumeLabelLength; 810 Vcb->VolIdent.MaximumLength = (USHORT)Buffer->VolumeLabelLength+sizeof(WCHAR); 811 RtlCopyMemory(Vcb->VolIdent.Buffer, &(Buffer->VolumeLabel), Buffer->VolumeLabelLength); 812 Vcb->VolIdent.Buffer[Buffer->VolumeLabelLength/sizeof(WCHAR)] = 0; 813 UDFSetModified(Vcb); 814 815 UDFPrint((" UDFSetLabelInfo: OK\n")); 816 return STATUS_SUCCESS; 817 } // end UDFSetLabelInfo () 818 819 #endif //UDF_READ_ONLY_BUILD 820