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