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 * File: Fileinfo.cpp 9 * 10 * Module: UDF File System Driver (Kernel mode execution only) 11 * 12 * Description: 13 * Contains code to handle the "set/query file information" dispatch 14 * entry points. 15 * 16 *************************************************************************/ 17 18 #include "udffs.h" 19 20 // define the file specific bug-check id 21 #define UDF_BUG_CHECK_ID UDF_FILE_INFORMATION 22 23 #define MEM_USREN_TAG "US_Ren" 24 #define MEM_USREN2_TAG "US_Ren2" 25 #define MEM_USFIDC_TAG "US_FIDC" 26 #define MEM_USHL_TAG "US_HL" 27 28 /************************************************************************* 29 * 30 * Function: UDFFileInfo() 31 * 32 * Description: 33 * The I/O Manager will invoke this routine to handle a set/query file 34 * information request 35 * 36 * Expected Interrupt Level (for execution) : 37 * 38 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution 39 * to be deferred to a worker thread context) 40 * 41 * Return Value: STATUS_SUCCESS/Error 42 * 43 *************************************************************************/ 44 NTSTATUS 45 NTAPI 46 UDFFileInfo( 47 PDEVICE_OBJECT DeviceObject, // the logical volume device object 48 PIRP Irp // I/O Request Packet 49 ) 50 { 51 NTSTATUS RC = STATUS_SUCCESS; 52 PtrUDFIrpContext PtrIrpContext = NULL; 53 BOOLEAN AreWeTopLevel = FALSE; 54 55 TmPrint(("UDFFileInfo: \n")); 56 57 FsRtlEnterFileSystem(); 58 ASSERT(DeviceObject); 59 ASSERT(Irp); 60 61 // set the top level context 62 AreWeTopLevel = UDFIsIrpTopLevel(Irp); 63 ASSERT(!UDFIsFSDevObj(DeviceObject)); 64 65 _SEH2_TRY { 66 67 // get an IRP context structure and issue the request 68 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); 69 if(PtrIrpContext) { 70 RC = UDFCommonFileInfo(PtrIrpContext, Irp); 71 } else { 72 RC = STATUS_INSUFFICIENT_RESOURCES; 73 Irp->IoStatus.Status = RC; 74 Irp->IoStatus.Information = 0; 75 // complete the IRP 76 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 77 } 78 79 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { 80 81 RC = UDFExceptionHandler(PtrIrpContext, Irp); 82 83 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); 84 } _SEH2_END; 85 86 if(AreWeTopLevel) { 87 IoSetTopLevelIrp(NULL); 88 } 89 90 FsRtlExitFileSystem(); 91 92 return(RC); 93 } // end UDFFileInfo() 94 95 96 /************************************************************************* 97 * 98 * Function: UDFCommonFileInfo() 99 * 100 * Description: 101 * The actual work is performed here. This routine may be invoked in one' 102 * of the two possible contexts: 103 * (a) in the context of a system worker thread 104 * (b) in the context of the original caller 105 * 106 * Expected Interrupt Level (for execution) : 107 * 108 * IRQL_PASSIVE_LEVEL 109 * 110 * Return Value: STATUS_SUCCESS/Error 111 * 112 *************************************************************************/ 113 NTSTATUS 114 UDFCommonFileInfo( 115 PtrUDFIrpContext PtrIrpContext, 116 PIRP Irp 117 ) 118 { 119 NTSTATUS RC = STATUS_SUCCESS; 120 PIO_STACK_LOCATION IrpSp = NULL; 121 PFILE_OBJECT FileObject = NULL; 122 PtrUDFFCB Fcb = NULL; 123 PtrUDFCCB Ccb = NULL; 124 PVCB Vcb = NULL; 125 PtrUDFNTRequiredFCB NtReqFcb = NULL; 126 BOOLEAN MainResourceAcquired = FALSE; 127 BOOLEAN ParentResourceAcquired = FALSE; 128 BOOLEAN PagingIoResourceAcquired = FALSE; 129 PVOID PtrSystemBuffer = NULL; 130 LONG BufferLength = 0; 131 FILE_INFORMATION_CLASS FunctionalityRequested; 132 BOOLEAN CanWait = FALSE; 133 BOOLEAN PostRequest = FALSE; 134 BOOLEAN AcquiredVcb = FALSE; 135 PIRP TopIrp; 136 137 TmPrint(("UDFCommonFileInfo: irp %x\n", Irp)); 138 139 TopIrp = IoGetTopLevelIrp(); 140 switch((ULONG)TopIrp) { 141 case FSRTL_FSP_TOP_LEVEL_IRP: 142 UDFPrint((" FSRTL_FSP_TOP_LEVEL_IRP\n")); 143 break; 144 case FSRTL_CACHE_TOP_LEVEL_IRP: 145 UDFPrint((" FSRTL_CACHE_TOP_LEVEL_IRP\n")); 146 break; 147 case FSRTL_MOD_WRITE_TOP_LEVEL_IRP: 148 UDFPrint((" FSRTL_MOD_WRITE_TOP_LEVEL_IRP\n")); 149 break; 150 case FSRTL_FAST_IO_TOP_LEVEL_IRP: 151 UDFPrint((" FSRTL_FAST_IO_TOP_LEVEL_IRP\n")); 152 BrutePoint() 153 break; 154 case NULL: 155 UDFPrint((" NULL TOP_LEVEL_IRP\n")); 156 break; 157 default: 158 if(TopIrp == Irp) { 159 UDFPrint((" TOP_LEVEL_IRP\n")); 160 } else { 161 UDFPrint((" RECURSIVE_IRP, TOP = %x\n", TopIrp)); 162 } 163 } 164 165 _SEH2_TRY { 166 // First, get a pointer to the current I/O stack location. 167 IrpSp = IoGetCurrentIrpStackLocation(Irp); 168 ASSERT(IrpSp); 169 170 FileObject = IrpSp->FileObject; 171 ASSERT(FileObject); 172 173 // Get the FCB and CCB pointers. 174 Ccb = (PtrUDFCCB)(FileObject->FsContext2); 175 ASSERT(Ccb); 176 if(!Ccb) { 177 // some applications sends us FO without Ccb 178 // This is not allowed... 179 RC = STATUS_INVALID_PARAMETER; 180 try_return(RC); 181 } 182 Fcb = Ccb->Fcb; 183 ASSERT(Fcb); 184 185 NtReqFcb = Fcb->NTRequiredFCB; 186 187 CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE; 188 189 // If the caller has opened a logical volume and is attempting to 190 // query information for it as a file stream, return an error. 191 if(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) { 192 // This is not allowed. Caller must use get/set volume information instead. 193 RC = STATUS_INVALID_PARAMETER; 194 try_return(RC); 195 } 196 197 198 Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension); 199 ASSERT(Vcb); 200 ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB); 201 //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; 202 203 // The NT I/O Manager always allocates and supplies a system 204 // buffer for query and set file information calls. 205 // Copying information to/from the user buffer and the system 206 // buffer is performed by the I/O Manager and the FSD need not worry about it. 207 PtrSystemBuffer = Irp->AssociatedIrp.SystemBuffer; 208 209 UDFFlushTryBreak(Vcb); 210 if(!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) { 211 PostRequest = TRUE; 212 try_return(RC = STATUS_PENDING); 213 } 214 AcquiredVcb = TRUE; 215 216 if(IrpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION) { 217 // Now, obtain some parameters. 218 BufferLength = IrpSp->Parameters.QueryFile.Length; 219 FunctionalityRequested = IrpSp->Parameters.QueryFile.FileInformationClass; 220 #ifdef UDF_ENABLE_SECURITY 221 RC = IoCheckFunctionAccess( 222 Ccb->PreviouslyGrantedAccess, 223 PtrIrpContext->MajorFunction, 224 PtrIrpContext->MinorFunction, 225 0, 226 &FunctionalityRequested, 227 NULL); 228 if(!NT_SUCCESS(RC)) { 229 try_return(RC); 230 } 231 #endif //UDF_ENABLE_SECURITY 232 // Acquire the MainResource shared (NOTE: for paging-IO on a 233 // page file, we should avoid acquiring any resources and simply 234 // trust the VMM to do the right thing, else we could possibly 235 // run into deadlocks). 236 if(!(Fcb->FCBFlags & UDF_FCB_PAGE_FILE)) { 237 // Acquire the MainResource shared. 238 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 239 UDFAcquireResourceShared(&(NtReqFcb->MainResource), TRUE); 240 MainResourceAcquired = TRUE; 241 } 242 243 // Do whatever the caller asked us to do 244 switch (FunctionalityRequested) { 245 case FileBasicInformation: 246 RC = UDFGetBasicInformation(FileObject, Fcb, (PFILE_BASIC_INFORMATION)PtrSystemBuffer, &BufferLength); 247 break; 248 case FileStandardInformation: 249 RC = UDFGetStandardInformation(Fcb, (PFILE_STANDARD_INFORMATION) PtrSystemBuffer, &BufferLength); 250 break; 251 #if(_WIN32_WINNT >= 0x0400) 252 case FileNetworkOpenInformation: 253 RC = UDFGetNetworkInformation(Fcb, (PFILE_NETWORK_OPEN_INFORMATION)PtrSystemBuffer, &BufferLength); 254 break; 255 #endif // _WIN32_WINNT >= 0x0400 256 case FileInternalInformation: 257 RC = UDFGetInternalInformation(PtrIrpContext, Fcb, Ccb, (PFILE_INTERNAL_INFORMATION) PtrSystemBuffer, &BufferLength); 258 break; 259 case FileEaInformation: 260 RC = UDFGetEaInformation(PtrIrpContext, Fcb, (PFILE_EA_INFORMATION) PtrSystemBuffer, &BufferLength); 261 break; 262 case FileNameInformation: 263 RC = UDFGetFullNameInformation(FileObject, (PFILE_NAME_INFORMATION) PtrSystemBuffer, &BufferLength); 264 break; 265 case FileAlternateNameInformation: 266 RC = UDFGetAltNameInformation(Fcb, (PFILE_NAME_INFORMATION) PtrSystemBuffer, &BufferLength); 267 break; 268 // case FileCompressionInformation: 269 // // RC = UDFGetCompressionInformation(...); 270 // break; 271 case FilePositionInformation: 272 RC = UDFGetPositionInformation(FileObject, (PFILE_POSITION_INFORMATION)PtrSystemBuffer, &BufferLength); 273 break; 274 case FileStreamInformation: 275 RC = UDFGetFileStreamInformation(Fcb, (PFILE_STREAM_INFORMATION) PtrSystemBuffer, &BufferLength); 276 break; 277 case FileAllInformation: 278 // The I/O Manager supplies the Mode, Access, and Alignment 279 // information. The rest is up to us to provide. 280 // Therefore, decrement the BufferLength appropriately (assuming 281 // that the above 3 types on information are already in the 282 // buffer) 283 { 284 PFILE_ALL_INFORMATION PtrAllInfo = (PFILE_ALL_INFORMATION)PtrSystemBuffer; 285 286 BufferLength -= (sizeof(FILE_MODE_INFORMATION) + 287 sizeof(FILE_ACCESS_INFORMATION) + 288 sizeof(FILE_ALIGNMENT_INFORMATION)); 289 290 // Get the remaining stuff. 291 if(!NT_SUCCESS(RC = UDFGetBasicInformation(FileObject, Fcb, &(PtrAllInfo->BasicInformation), &BufferLength)) || 292 !NT_SUCCESS(RC = UDFGetStandardInformation(Fcb, &(PtrAllInfo->StandardInformation), &BufferLength)) || 293 !NT_SUCCESS(RC = UDFGetInternalInformation(PtrIrpContext, Fcb, Ccb, &(PtrAllInfo->InternalInformation), &BufferLength)) || 294 !NT_SUCCESS(RC = UDFGetEaInformation(PtrIrpContext, Fcb, &(PtrAllInfo->EaInformation), &BufferLength)) || 295 !NT_SUCCESS(RC = UDFGetPositionInformation(FileObject, &(PtrAllInfo->PositionInformation), &BufferLength)) || 296 !NT_SUCCESS(RC = UDFGetFullNameInformation(FileObject, &(PtrAllInfo->NameInformation), &BufferLength)) 297 ) 298 try_return(RC); 299 } 300 break; 301 default: 302 RC = STATUS_INVALID_PARAMETER; 303 try_return(RC); 304 } 305 306 #ifndef UDF_READ_ONLY_BUILD 307 } else { 308 // if(IrpSp->MajorFunction == IRP_MJ_SET_INFORMATION) { 309 Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; 310 ASSERT(IrpSp->MajorFunction == IRP_MJ_SET_INFORMATION); 311 // Now, obtain some parameters. 312 FunctionalityRequested = IrpSp->Parameters.SetFile.FileInformationClass; 313 if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) && 314 (FunctionalityRequested != FilePositionInformation)) { 315 try_return(RC = STATUS_ACCESS_DENIED); 316 } 317 #ifdef UDF_ENABLE_SECURITY 318 RC = IoCheckFunctionAccess( 319 Ccb->PreviouslyGrantedAccess, 320 PtrIrpContext->MajorFunction, 321 PtrIrpContext->MinorFunction, 322 0, 323 &FunctionalityRequested, 324 NULL); 325 if(!NT_SUCCESS(RC)) { 326 try_return(RC); 327 } 328 #endif //UDF_ENABLE_SECURITY 329 // If the FSD supports opportunistic locking, 330 // then we should check whether the oplock state 331 // allows the caller to proceed. 332 333 // Rename, and link operations require creation of a directory 334 // entry and possibly deletion of another directory entry. 335 336 // Unless this is an operation on a page file, we should go ahead and 337 // acquire the FCB exclusively at this time. Note that we will pretty 338 // much block out anything being done to the FCB from this point on. 339 if(!(Fcb->FCBFlags & UDF_FCB_PAGE_FILE) && 340 (FunctionalityRequested != FilePositionInformation) && 341 (FunctionalityRequested != FileRenameInformation) && 342 (FunctionalityRequested != FileLinkInformation)) { 343 // Acquire the Parent & Main Resources exclusive. 344 if(Fcb->FileInfo->ParentFile) { 345 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB); 346 if(!UDFAcquireResourceExclusive(&(Fcb->ParentFcb->NTRequiredFCB->MainResource), CanWait)) { 347 PostRequest = TRUE; 348 try_return(RC = STATUS_PENDING); 349 } 350 ParentResourceAcquired = TRUE; 351 } 352 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 353 if(!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) { 354 PostRequest = TRUE; 355 try_return(RC = STATUS_PENDING); 356 } 357 MainResourceAcquired = TRUE; 358 } else 359 // The only operations that could conceivably proceed from this point 360 // on are paging-IO read/write operations. For delete, link (rename), 361 // set allocation size, and set EOF, should also acquire the paging-IO 362 // resource, thereby synchronizing with paging-IO requests. 363 if((Fcb->FCBFlags & UDF_FCB_PAGE_FILE) && 364 ((FunctionalityRequested == FileDispositionInformation) || 365 (FunctionalityRequested == FileAllocationInformation) || 366 (FunctionalityRequested == FileEndOfFileInformation)) ) { 367 368 // Acquire the MainResource shared. 369 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 370 if(!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) { 371 PostRequest = TRUE; 372 try_return(RC = STATUS_PENDING); 373 } 374 MainResourceAcquired = TRUE; 375 // Acquire the PagingResource exclusive. 376 if(!UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), CanWait)) { 377 PostRequest = TRUE; 378 try_return(RC = STATUS_PENDING); 379 } 380 PagingIoResourceAcquired = TRUE; 381 } else if((FunctionalityRequested != FileRenameInformation) && 382 (FunctionalityRequested != FileLinkInformation)) { 383 // Acquire the MainResource shared. 384 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 385 if(!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) { 386 PostRequest = TRUE; 387 try_return(RC = STATUS_PENDING); 388 } 389 MainResourceAcquired = TRUE; 390 } 391 392 if((Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && 393 (FunctionalityRequested != FilePositionInformation)) { 394 AdPrint((" Can't change File Information on blank volume ;)\n")); 395 try_return(RC = STATUS_ACCESS_DENIED); 396 } 397 398 // Do whatever the caller asked us to do 399 switch (FunctionalityRequested) { 400 case FileBasicInformation: 401 RC = UDFSetBasicInformation(Fcb, Ccb, FileObject, (PFILE_BASIC_INFORMATION)PtrSystemBuffer); 402 break; 403 case FilePositionInformation: { 404 // Check if no intermediate buffering has been specified. 405 // If it was specified, do not allow non-aligned set file 406 // position requests to succeed. 407 PFILE_POSITION_INFORMATION PtrFileInfoBuffer; 408 409 PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)PtrSystemBuffer; 410 411 if(FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) { 412 if(PtrFileInfoBuffer->CurrentByteOffset.LowPart & IrpSp->DeviceObject->AlignmentRequirement) { 413 // Invalid alignment. 414 try_return(RC = STATUS_INVALID_PARAMETER); 415 } 416 } 417 418 FileObject->CurrentByteOffset = PtrFileInfoBuffer->CurrentByteOffset; 419 break; 420 } 421 case FileDispositionInformation: 422 RC = UDFSetDispositionInformation(Fcb, Ccb, Vcb, FileObject, 423 ((PFILE_DISPOSITION_INFORMATION)PtrSystemBuffer)->DeleteFile ? TRUE : FALSE); 424 break; 425 case FileRenameInformation: 426 if(!CanWait) { 427 PostRequest = TRUE; 428 try_return(RC = STATUS_PENDING); 429 } 430 RC = UDFRename(IrpSp, Fcb, Ccb, FileObject, (PFILE_RENAME_INFORMATION)PtrSystemBuffer); 431 if(RC == STATUS_PENDING) { 432 PostRequest = TRUE; 433 try_return(RC); 434 } 435 break; 436 #ifdef UDF_ALLOW_HARD_LINKS 437 case FileLinkInformation: 438 if(!CanWait) { 439 PostRequest = TRUE; 440 try_return(RC = STATUS_PENDING); 441 } 442 RC = UDFHardLink(IrpSp, Fcb, Ccb, FileObject, (PFILE_LINK_INFORMATION)PtrSystemBuffer); 443 break; 444 #endif //UDF_ALLOW_HARD_LINKS 445 case FileAllocationInformation: 446 RC = UDFSetAllocationInformation(Fcb, Ccb, Vcb, FileObject, 447 PtrIrpContext, Irp, 448 (PFILE_ALLOCATION_INFORMATION)PtrSystemBuffer); 449 break; 450 case FileEndOfFileInformation: 451 RC = UDFSetEOF(IrpSp, Fcb, Ccb, Vcb, FileObject, Irp, (PFILE_END_OF_FILE_INFORMATION)PtrSystemBuffer); 452 break; 453 default: 454 RC = STATUS_INVALID_PARAMETER; 455 try_return(RC); 456 } 457 #endif //UDF_READ_ONLY_BUILD 458 } 459 460 try_exit: NOTHING; 461 462 } _SEH2_FINALLY { 463 464 if(PagingIoResourceAcquired) { 465 UDFReleaseResource(&(NtReqFcb->PagingIoResource)); 466 PagingIoResourceAcquired = FALSE; 467 } 468 469 if(MainResourceAcquired) { 470 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 471 UDFReleaseResource(&(NtReqFcb->MainResource)); 472 MainResourceAcquired = FALSE; 473 } 474 475 if(ParentResourceAcquired) { 476 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB); 477 UDFReleaseResource(&(Fcb->ParentFcb->NTRequiredFCB->MainResource)); 478 ParentResourceAcquired = FALSE; 479 } 480 481 // Post IRP if required 482 if(PostRequest) { 483 484 // Since, the I/O Manager gave us a system buffer, we do not 485 // need to "lock" anything. 486 487 // Perform the post operation which will mark the IRP pending 488 // and will return STATUS_PENDING back to us 489 RC = UDFPostRequest(PtrIrpContext, Irp); 490 491 } else { 492 493 if (!_SEH2_AbnormalTermination()) { 494 Irp->IoStatus.Status = RC; 495 // Set status for "query" requests 496 if(IrpSp->MajorFunction == IRP_MJ_QUERY_INFORMATION) { 497 // Return the amount of information transferred. 498 Irp->IoStatus.Information = IrpSp->Parameters.QueryFile.Length - BufferLength; 499 #ifndef UDF_READ_ONLY_BUILD 500 #ifdef UDF_DELAYED_CLOSE 501 } else 502 if(NT_SUCCESS(RC)) { 503 if(FunctionalityRequested == FileDispositionInformation) { 504 if(AcquiredVcb) { 505 AcquiredVcb = FALSE; 506 UDFReleaseResource(&(Vcb->VCBResource)); 507 } 508 UDFRemoveFromDelayedQueue(Fcb); 509 } 510 #endif //UDF_DELAYED_CLOSE 511 #endif //UDF_READ_ONLY_BUILD 512 } 513 // complete the IRP 514 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 515 // Free up the Irp Context 516 UDFReleaseIrpContext(PtrIrpContext); 517 } // can we complete the IRP ? 518 519 } 520 if(AcquiredVcb) { 521 UDFReleaseResource(&(Vcb->VCBResource)); 522 } 523 } _SEH2_END;// end of "__finally" processing 524 525 return(RC); 526 } // end UDFCommonFileInfo() 527 528 /* 529 Return some time-stamps and file attributes to the caller. 530 */ 531 NTSTATUS 532 UDFGetBasicInformation( 533 IN PFILE_OBJECT FileObject, 534 IN PtrUDFFCB Fcb, 535 IN PFILE_BASIC_INFORMATION PtrBuffer, 536 IN OUT LONG* PtrReturnedLength 537 ) 538 { 539 NTSTATUS RC = STATUS_SUCCESS; 540 PUDF_FILE_INFO FileInfo; 541 PDIR_INDEX_ITEM DirNdx; 542 543 AdPrint(("UDFGetBasicInformation: \n")); 544 545 _SEH2_TRY { 546 547 if(*PtrReturnedLength < (LONG)sizeof(FILE_BASIC_INFORMATION)) { 548 try_return(RC = STATUS_BUFFER_OVERFLOW); 549 } 550 551 // Zero out the supplied buffer. 552 RtlZeroMemory(PtrBuffer, sizeof(FILE_BASIC_INFORMATION)); 553 554 // Get information from the FCB and update TimesCache in DirIndex 555 FileInfo = Fcb->FileInfo; 556 557 if(!FileInfo) { 558 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n")); 559 AdPrint(("!!!! GetBasicInfo to unopened file !!!!\n")); 560 try_return(RC = STATUS_INVALID_PARAMETER); 561 } 562 563 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index); 564 565 PtrBuffer->CreationTime = Fcb->NTRequiredFCB->CreationTime; 566 DirNdx->CreationTime = PtrBuffer->CreationTime.QuadPart; 567 568 PtrBuffer->LastAccessTime = Fcb->NTRequiredFCB->LastAccessTime; 569 DirNdx->LastAccessTime = PtrBuffer->LastAccessTime.QuadPart; 570 571 PtrBuffer->LastWriteTime = Fcb->NTRequiredFCB->LastWriteTime; 572 DirNdx->LastWriteTime = PtrBuffer->LastWriteTime.QuadPart; 573 574 PtrBuffer->ChangeTime = Fcb->NTRequiredFCB->ChangeTime; 575 DirNdx->ChangeTime = PtrBuffer->ChangeTime.QuadPart; 576 577 // Now fill in the attributes. 578 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { 579 PtrBuffer->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; 580 #ifdef UDF_DBG 581 if(!FileInfo->Dloc->DirIndex) AdPrint(("*****!!!!! Directory has no DirIndex !!!!!*****\n")); 582 #endif 583 } 584 // Similarly, fill in attributes indicating a hidden file, system 585 // file, compressed file, temporary file, etc. if the FSD supports 586 // such file attribute values. 587 PtrBuffer->FileAttributes |= UDFAttributesToNT(DirNdx,NULL); 588 if(FileObject->Flags & FO_TEMPORARY_FILE) { 589 PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_TEMPORARY; 590 } else { 591 PtrBuffer->FileAttributes &= ~FILE_ATTRIBUTE_TEMPORARY; 592 } 593 if(!PtrBuffer->FileAttributes) { 594 PtrBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL; 595 } 596 597 try_exit: NOTHING; 598 599 } _SEH2_FINALLY { 600 601 if(NT_SUCCESS(RC)) { 602 // Return the amount of information filled in. 603 (*PtrReturnedLength) -= sizeof(FILE_BASIC_INFORMATION); 604 } 605 } _SEH2_END; 606 return(RC); 607 } // end UDFGetBasicInformation() 608 609 610 /* 611 Return file sizes to the caller. 612 */ 613 NTSTATUS 614 UDFGetStandardInformation( 615 IN PtrUDFFCB Fcb, 616 IN PFILE_STANDARD_INFORMATION PtrBuffer, 617 IN OUT LONG* PtrReturnedLength 618 ) 619 { 620 NTSTATUS RC = STATUS_SUCCESS; 621 PUDF_FILE_INFO FileInfo; 622 // PVCB Vcb; 623 624 AdPrint(("UDFGetStandardInformation: \n")); 625 626 _SEH2_TRY { 627 628 if(*PtrReturnedLength < (LONG)sizeof(FILE_STANDARD_INFORMATION)) { 629 try_return(RC = STATUS_BUFFER_OVERFLOW); 630 } 631 632 // Zero out the supplied buffer. 633 RtlZeroMemory(PtrBuffer, sizeof(FILE_STANDARD_INFORMATION)); 634 635 FileInfo = Fcb->FileInfo; 636 637 if(!FileInfo) { 638 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n")); 639 AdPrint(("!!!! GetStandardInfo to unopened file !!!!\n")); 640 try_return(RC = STATUS_INVALID_PARAMETER); 641 } 642 // Vcb = Fcb->Vcb; 643 PtrBuffer->NumberOfLinks = UDFGetFileLinkCount(FileInfo); 644 PtrBuffer->DeletePending = (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) ? TRUE : FALSE; 645 646 // Case on whether this is a file or a directory, and extract 647 // the information and fill in the fcb/dcb specific parts 648 // of the output buffer 649 if(UDFIsADirectory(Fcb->FileInfo)) { 650 PtrBuffer->Directory = TRUE; 651 } else { 652 if(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.LowPart == 0xffffffff) { 653 Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart = 654 UDFSysGetAllocSize(Fcb->Vcb, UDFGetFileSize(FileInfo)); 655 } 656 PtrBuffer->AllocationSize = Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize; 657 PtrBuffer->EndOfFile = Fcb->NTRequiredFCB->CommonFCBHeader.FileSize; 658 659 PtrBuffer->Directory = FALSE; 660 } 661 662 try_exit: NOTHING; 663 } _SEH2_FINALLY { 664 if(NT_SUCCESS(RC)) { 665 // Return the amount of information filled in. 666 *PtrReturnedLength -= sizeof(FILE_STANDARD_INFORMATION); 667 } 668 } _SEH2_END; 669 return(RC); 670 } // end UDFGetStandardInformation() 671 672 /* 673 Return some time-stamps and file attributes to the caller. 674 */ 675 NTSTATUS 676 UDFGetNetworkInformation( 677 IN PtrUDFFCB Fcb, 678 IN PFILE_NETWORK_OPEN_INFORMATION PtrBuffer, 679 IN OUT PLONG PtrReturnedLength 680 ) 681 { 682 NTSTATUS RC = STATUS_SUCCESS; 683 PUDF_FILE_INFO FileInfo; 684 685 AdPrint(("UDFGetNetworkInformation: \n")); 686 687 _SEH2_TRY { 688 689 if(*PtrReturnedLength < (LONG)sizeof(FILE_NETWORK_OPEN_INFORMATION)) { 690 try_return(RC = STATUS_BUFFER_OVERFLOW); 691 } 692 693 // Zero out the supplied buffer. 694 RtlZeroMemory(PtrBuffer, sizeof(FILE_NETWORK_OPEN_INFORMATION)); 695 696 // Get information from the FCB. 697 PtrBuffer->CreationTime = Fcb->NTRequiredFCB->CreationTime; 698 PtrBuffer->LastAccessTime = Fcb->NTRequiredFCB->LastAccessTime; 699 PtrBuffer->LastWriteTime = Fcb->NTRequiredFCB->LastWriteTime; 700 PtrBuffer->ChangeTime = Fcb->NTRequiredFCB->ChangeTime; 701 702 FileInfo = Fcb->FileInfo; 703 704 if(!FileInfo) { 705 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n")); 706 AdPrint(("!!!! UDFGetNetworkInformation to unopened file !!!!\n")); 707 try_return(RC = STATUS_INVALID_PARAMETER); 708 } 709 // Now fill in the attributes. 710 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { 711 PtrBuffer->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; 712 #ifdef UDF_DBG 713 if(!FileInfo->Dloc->DirIndex) AdPrint(("*****!!!!! Directory has no DirIndex !!!!!*****\n")); 714 #endif 715 } else { 716 if(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.LowPart == 0xffffffff) { 717 Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart = 718 UDFSysGetAllocSize(Fcb->Vcb, UDFGetFileSize(FileInfo)); 719 } 720 PtrBuffer->AllocationSize = Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize; 721 PtrBuffer->EndOfFile = Fcb->NTRequiredFCB->CommonFCBHeader.FileSize; 722 } 723 // Similarly, fill in attributes indicating a hidden file, system 724 // file, compressed file, temporary file, etc. if the FSD supports 725 // such file attribute values. 726 PtrBuffer->FileAttributes |= UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index),NULL); 727 if(!PtrBuffer->FileAttributes) { 728 PtrBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL; 729 } 730 731 try_exit: NOTHING; 732 733 } _SEH2_FINALLY { 734 if(NT_SUCCESS(RC)) { 735 // Return the amount of information filled in. 736 (*PtrReturnedLength) -= sizeof(FILE_NETWORK_OPEN_INFORMATION); 737 } 738 } _SEH2_END; 739 return(RC); 740 } // end UDFGetNetworkInformation() 741 742 743 /* 744 Return some time-stamps and file attributes to the caller. 745 */ 746 NTSTATUS 747 UDFGetInternalInformation( 748 PtrUDFIrpContext PtrIrpContext, 749 IN PtrUDFFCB Fcb, 750 IN PtrUDFCCB Ccb, 751 IN PFILE_INTERNAL_INFORMATION PtrBuffer, 752 IN OUT PLONG PtrReturnedLength 753 ) 754 { 755 NTSTATUS RC = STATUS_SUCCESS; 756 PUDF_FILE_INFO FileInfo; 757 PVCB Vcb; 758 759 AdPrint(("UDFGetInternalInformation\n")); 760 761 _SEH2_TRY { 762 763 if(*PtrReturnedLength < (LONG)sizeof(FILE_INTERNAL_INFORMATION)) { 764 try_return(RC = STATUS_BUFFER_OVERFLOW); 765 } 766 767 // Zero out the supplied buffer. 768 RtlZeroMemory(PtrBuffer, sizeof(FILE_INTERNAL_INFORMATION)); 769 770 FileInfo = Fcb->FileInfo; 771 772 if(!FileInfo) { 773 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n")); 774 AdPrint(("!!!! UDFGetInternalInformation to unopened file !!!!\n")); 775 try_return(RC = STATUS_INVALID_PARAMETER); 776 } 777 778 Vcb = Fcb->Vcb; 779 PtrBuffer->IndexNumber.QuadPart = UDFGetNTFileId(Vcb, FileInfo, &(Fcb->FCBName->ObjectName)); 780 781 UDFAcquireResourceExclusive(&(Fcb->Vcb->FileIdResource), TRUE); 782 // remember File Id & full path 783 UDFStoreFileId(Fcb->Vcb, Ccb, FileInfo, PtrBuffer->IndexNumber.QuadPart); 784 UDFReleaseResource(&(Fcb->Vcb->FileIdResource)); 785 786 try_exit: NOTHING; 787 788 } _SEH2_FINALLY { 789 if(NT_SUCCESS(RC)) { 790 // Return the amount of information filled in. 791 *PtrReturnedLength -= sizeof(FILE_INTERNAL_INFORMATION); 792 } 793 } _SEH2_END; 794 return(RC); 795 } // end UDFGetInternalInformation() 796 797 /* 798 Return zero-filled EAs to the caller. 799 */ 800 NTSTATUS 801 UDFGetEaInformation( 802 PtrUDFIrpContext PtrIrpContext, 803 IN PtrUDFFCB Fcb, 804 IN PFILE_EA_INFORMATION PtrBuffer, 805 IN OUT PLONG PtrReturnedLength 806 ) 807 { 808 NTSTATUS RC = STATUS_SUCCESS; 809 810 AdPrint(("UDFGetEaInformation\n")); 811 812 _SEH2_TRY { 813 814 if(*PtrReturnedLength < (LONG)sizeof(FILE_EA_INFORMATION)) { 815 try_return(RC = STATUS_BUFFER_OVERFLOW); 816 } 817 818 // Zero out the supplied buffer. 819 PtrBuffer->EaSize = 0; 820 821 try_exit: NOTHING; 822 823 } _SEH2_FINALLY { 824 if(NT_SUCCESS(RC)) { 825 // Return the amount of information filled in. 826 *PtrReturnedLength -= sizeof(FILE_EA_INFORMATION); 827 } 828 } _SEH2_END; 829 return(RC); 830 } // end UDFGetEaInformation() 831 832 /* 833 Return file's long name to the caller. 834 */ 835 NTSTATUS 836 UDFGetFullNameInformation( 837 IN PFILE_OBJECT FileObject, 838 IN PFILE_NAME_INFORMATION PtrBuffer, 839 IN OUT PLONG PtrReturnedLength 840 ) 841 { 842 ULONG BytesToCopy; 843 NTSTATUS RC = STATUS_SUCCESS; 844 845 846 AdPrint(("UDFGetFullNameInformation\n")); 847 848 PtrBuffer->FileNameLength = FileObject->FileName.Length; 849 BytesToCopy = FileObject->FileName.Length; 850 851 if (PtrBuffer->FileNameLength + sizeof( ULONG ) > (ULONG)(*PtrReturnedLength)) { 852 853 BytesToCopy = *PtrReturnedLength - sizeof( ULONG ); 854 RC = STATUS_BUFFER_OVERFLOW; 855 } 856 857 RtlCopyMemory( PtrBuffer->FileName, FileObject->FileName.Buffer, BytesToCopy ); 858 859 // Reduce the available bytes by the amount stored into this buffer. 860 *PtrReturnedLength -= sizeof( ULONG ) + PtrBuffer->FileNameLength; 861 862 return RC; 863 } // end UDFGetFullNameInformation() 864 865 /* 866 Return file short(8.3) name to the caller. 867 */ 868 NTSTATUS 869 UDFGetAltNameInformation( 870 IN PtrUDFFCB Fcb, 871 IN PFILE_NAME_INFORMATION PtrBuffer, 872 IN OUT PLONG PtrReturnedLength 873 ) 874 { 875 PDIR_INDEX_ITEM DirNdx; 876 ULONG BytesToCopy; 877 UNICODE_STRING ShortName; 878 WCHAR ShortNameBuffer[13]; 879 880 AdPrint(("UDFGetAltNameInformation: \n")); 881 882 *PtrReturnedLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]); 883 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index); 884 885 ShortName.MaximumLength = 13 * sizeof(WCHAR); 886 ShortName.Buffer = (PWCHAR)&ShortNameBuffer; 887 888 UDFDOSName__(Fcb->Vcb, &ShortName, &(DirNdx->FName), Fcb->FileInfo); 889 890 if(*PtrReturnedLength < ShortName.Length) { 891 return(STATUS_BUFFER_OVERFLOW); 892 } else { 893 BytesToCopy = ShortName.Length; 894 *PtrReturnedLength -= ShortName.Length; 895 } 896 897 RtlCopyMemory( &(PtrBuffer->FileName), 898 ShortName.Buffer, 899 BytesToCopy ); 900 901 PtrBuffer->FileNameLength = ShortName.Length; 902 903 return(STATUS_SUCCESS); 904 } // end UDFGetAltNameInformation() 905 906 /* 907 Get file position information 908 */ 909 NTSTATUS 910 UDFGetPositionInformation( 911 IN PFILE_OBJECT FileObject, 912 IN PFILE_POSITION_INFORMATION PtrBuffer, 913 IN OUT PLONG PtrReturnedLength 914 ) 915 { 916 if(*PtrReturnedLength < (LONG)sizeof(FILE_POSITION_INFORMATION)) { 917 return(STATUS_BUFFER_OVERFLOW); 918 } 919 PtrBuffer->CurrentByteOffset = FileObject->CurrentByteOffset; 920 // Modify the local variable for BufferLength appropriately. 921 *PtrReturnedLength -= sizeof(FILE_POSITION_INFORMATION); 922 923 return(STATUS_SUCCESS); 924 } // end UDFGetAltNameInformation() 925 926 /* 927 Get file file stream(s) information 928 */ 929 NTSTATUS 930 UDFGetFileStreamInformation( 931 IN PtrUDFFCB Fcb, 932 IN PFILE_STREAM_INFORMATION PtrBuffer, 933 IN OUT PLONG PtrReturnedLength 934 ) 935 { 936 NTSTATUS RC = STATUS_SUCCESS; 937 PUDF_FILE_INFO FileInfo; 938 PUDF_FILE_INFO SDirInfo; 939 PVCB Vcb; 940 BOOLEAN FcbAcquired = FALSE; 941 uint_di i; 942 LONG l; 943 PDIR_INDEX_HDR hSDirIndex; 944 PDIR_INDEX_ITEM SDirIndex; 945 PFILE_BOTH_DIR_INFORMATION NTFileInfo = NULL; 946 947 AdPrint(("UDFGetFileStreamInformation\n")); 948 949 _SEH2_TRY { 950 951 UDFAcquireResourceExclusive(&(Fcb->Vcb->FileIdResource), TRUE); 952 FcbAcquired = TRUE; 953 954 FileInfo = Fcb->FileInfo; 955 if(!FileInfo) { 956 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n")); 957 AdPrint(("!!!! UDFGetFileStreamInformation to unopened file !!!!\n")); 958 try_return(RC = STATUS_INVALID_PARAMETER); 959 } 960 Vcb = Fcb->Vcb; 961 // Zero out the supplied buffer. 962 RtlZeroMemory(PtrBuffer, *PtrReturnedLength); 963 if(!(SDirInfo = FileInfo->Dloc->SDirInfo) || 964 UDFIsSDirDeleted(SDirInfo) ) { 965 (*PtrReturnedLength) -= (sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR)); 966 try_return(RC = STATUS_SUCCESS); 967 } 968 969 hSDirIndex = SDirInfo->Dloc->DirIndex; 970 NTFileInfo = (PFILE_BOTH_DIR_INFORMATION)MyAllocatePool__(NonPagedPool, sizeof(FILE_BOTH_DIR_INFORMATION)+UDF_NAME_LEN*sizeof(WCHAR)); 971 if(!NTFileInfo) try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 972 973 for(i=2; (SDirIndex = UDFDirIndex(hSDirIndex,i)); i++) { 974 if((SDirIndex->FI_Flags & UDF_FI_FLAG_FI_INTERNAL) || 975 UDFIsDeleted(SDirIndex) || 976 !SDirIndex->FName.Buffer ) 977 continue; 978 // copy data to buffer 979 if(*PtrReturnedLength < (l = ((sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR)) + 980 SDirIndex->FName.Length + 3) & (~3)) ) { 981 try_return(RC = STATUS_BUFFER_OVERFLOW); 982 } 983 RC = UDFFileDirInfoToNT(Vcb, SDirIndex, NTFileInfo); 984 985 PtrBuffer->NextEntryOffset = l; 986 PtrBuffer->StreamNameLength = SDirIndex->FName.Length; 987 PtrBuffer->StreamSize = NTFileInfo->EndOfFile; 988 PtrBuffer->StreamAllocationSize = NTFileInfo->AllocationSize; 989 RtlCopyMemory(&(PtrBuffer->StreamName), SDirIndex->FName.Buffer, SDirIndex->FName.Length); 990 *PtrReturnedLength -= l; 991 *((PCHAR*)(&PtrBuffer)) += l; 992 } 993 994 try_exit: NOTHING; 995 996 } _SEH2_FINALLY { 997 if(FcbAcquired) 998 UDFReleaseResource(&(Fcb->Vcb->FileIdResource)); 999 if(NTFileInfo) 1000 MyFreePool__(NTFileInfo); 1001 } _SEH2_END; 1002 return(RC); 1003 } // end UDFGetFileStreamInformation() 1004 1005 //******************************************************************* 1006 1007 #ifndef UDF_READ_ONLY_BUILD 1008 1009 /* 1010 Set some time-stamps and file attributes supplied by the caller. 1011 */ 1012 NTSTATUS 1013 UDFSetBasicInformation( 1014 IN PtrUDFFCB Fcb, 1015 IN PtrUDFCCB Ccb, 1016 IN PFILE_OBJECT FileObject, 1017 IN PFILE_BASIC_INFORMATION PtrBuffer) 1018 { 1019 NTSTATUS RC = STATUS_SUCCESS; 1020 ULONG NotifyFilter = 0; 1021 1022 AdPrint(("UDFSetBasicInformation\n")); 1023 1024 _SEH2_TRY { 1025 1026 // Obtain a pointer to the directory entry associated with 1027 // the FCB being modifed. The directory entry is obviously 1028 // part of the data associated with the parent directory that 1029 // contains this particular file stream. 1030 if(PtrBuffer->FileAttributes) { 1031 UDFUpdateAttrTime(Fcb->Vcb, Fcb->FileInfo); 1032 } else 1033 if( UDFIsADirectory(Fcb->FileInfo) && 1034 !(Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME) && 1035 ((Fcb->FileInfo->Dloc->DataLoc.Modified || 1036 Fcb->FileInfo->Dloc->AllocLoc.Modified || 1037 (Fcb->FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) || 1038 Fcb->FileInfo->Dloc->FELoc.Modified)) 1039 ) { 1040 // ignore Access Time Modification for unchanged Dir 1041 if(!PtrBuffer->CreationTime.QuadPart && 1042 PtrBuffer->LastAccessTime.QuadPart && 1043 !PtrBuffer->ChangeTime.QuadPart && 1044 !PtrBuffer->LastWriteTime.QuadPart) 1045 try_return(RC); 1046 } 1047 1048 UDFSetFileXTime(Fcb->FileInfo, 1049 &(PtrBuffer->CreationTime.QuadPart), 1050 &(PtrBuffer->LastAccessTime.QuadPart), 1051 &(PtrBuffer->ChangeTime.QuadPart), 1052 &(PtrBuffer->LastWriteTime.QuadPart) ); 1053 1054 if(PtrBuffer->CreationTime.QuadPart) { 1055 // The interesting thing here is that the user has set certain time 1056 // fields. However, before doing this, the user may have performed 1057 // I/O which in turn would have caused FSD to mark the fact that 1058 // write/access time should be modifed at cleanup. 1059 // We'll mark the fact that such updates are no longer 1060 // required since the user has explicitly specified the values he 1061 // wishes to see associated with the file stream. 1062 Fcb->NTRequiredFCB->CreationTime = PtrBuffer->CreationTime; 1063 Ccb->CCBFlags |= UDF_CCB_CREATE_TIME_SET; 1064 NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION; 1065 } 1066 if(PtrBuffer->LastAccessTime.QuadPart) { 1067 Fcb->NTRequiredFCB->LastAccessTime = PtrBuffer->LastAccessTime; 1068 Ccb->CCBFlags |= UDF_CCB_ACCESS_TIME_SET; 1069 NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS; 1070 } 1071 if(PtrBuffer->ChangeTime.QuadPart) { 1072 Fcb->NTRequiredFCB->ChangeTime = PtrBuffer->ChangeTime; 1073 Ccb->CCBFlags |= UDF_CCB_MODIFY_TIME_SET; 1074 } 1075 if(PtrBuffer->LastWriteTime.QuadPart) { 1076 Fcb->NTRequiredFCB->LastWriteTime = PtrBuffer->LastWriteTime; 1077 Ccb->CCBFlags |= UDF_CCB_WRITE_TIME_SET; 1078 NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE; 1079 } 1080 1081 // Now come the attributes. 1082 if(PtrBuffer->FileAttributes) { 1083 // We have a non-zero attribute value. 1084 // The presence of a particular attribute indicates that the 1085 // user wishes to set the attribute value. The absence indicates 1086 // the user wishes to clear the particular attribute. 1087 1088 // Our routine ignores unsupported flags 1089 PtrBuffer->FileAttributes &= ~(FILE_ATTRIBUTE_NORMAL); 1090 1091 // Similarly, we should pick out other invalid flag values. 1092 if( (PtrBuffer->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) && 1093 !(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) 1094 try_return(RC = STATUS_INVALID_PARAMETER); 1095 1096 if(PtrBuffer->FileAttributes & FILE_ATTRIBUTE_TEMPORARY) { 1097 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) 1098 try_return(RC = STATUS_INVALID_PARAMETER); 1099 FileObject->Flags |= FO_TEMPORARY_FILE; 1100 } else { 1101 FileObject->Flags &= ~FO_TEMPORARY_FILE; 1102 } 1103 1104 if(PtrBuffer->FileAttributes & FILE_ATTRIBUTE_READONLY) { 1105 Fcb->FCBFlags |= UDF_FCB_READ_ONLY; 1106 } else { 1107 Fcb->FCBFlags &= ~UDF_FCB_READ_ONLY; 1108 } 1109 1110 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index), 1111 NULL, PtrBuffer->FileAttributes); 1112 1113 (UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index)) 1114 ->FI_Flags |= UDF_FI_FLAG_SYS_ATTR; 1115 // If the FSD supports file compression, we may wish to 1116 // note the user's preferences for compressing/not compressing 1117 // the file at this time. 1118 Ccb->CCBFlags |= UDF_CCB_ATTRIBUTES_SET; 1119 NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; 1120 } 1121 1122 if(NotifyFilter) { 1123 UDFNotifyFullReportChange( Fcb->Vcb, Fcb->FileInfo, 1124 NotifyFilter, FILE_ACTION_MODIFIED); 1125 UDFSetFileSizeInDirNdx(Fcb->Vcb, Fcb->FileInfo, NULL); 1126 Fcb->FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 1127 } 1128 1129 try_exit: NOTHING; 1130 } _SEH2_FINALLY { 1131 ; 1132 } _SEH2_END; 1133 return(RC); 1134 } // end UDFSetBasicInformation() 1135 1136 NTSTATUS 1137 UDFMarkStreamsForDeletion( 1138 IN PVCB Vcb, 1139 IN PtrUDFFCB Fcb, 1140 IN BOOLEAN ForDel 1141 ) 1142 { 1143 NTSTATUS RC = STATUS_SUCCESS; 1144 PUDF_FILE_INFO SDirInfo = NULL; 1145 PUDF_FILE_INFO FileInfo = NULL; 1146 ULONG lc; 1147 BOOLEAN SDirAcq = FALSE; 1148 BOOLEAN StrAcq = FALSE; 1149 uint_di d,i; 1150 1151 _SEH2_TRY { 1152 1153 // In some cases we needn't marking Streams for deleteion 1154 // (Not opened or Don't exist) 1155 if(UDFIsAStream(Fcb->FileInfo) || 1156 UDFIsAStreamDir(Fcb->FileInfo) || 1157 !UDFHasAStreamDir(Fcb->FileInfo) || 1158 !Fcb->FileInfo->Dloc->SDirInfo || 1159 UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo) || 1160 (UDFGetFileLinkCount(Fcb->FileInfo) > 1) ) 1161 try_return (RC /*=STATUS_SUCCESS*/); 1162 1163 // We shall mark Streams for deletion if there is no 1164 // Links to the file. Otherwise we'll delete only the file. 1165 // If we are asked to unmark Streams, we'll precess the whole Tree 1166 RC = UDFOpenStreamDir__(Vcb, Fcb->FileInfo, &SDirInfo); 1167 if(!NT_SUCCESS(RC)) 1168 try_return(RC); 1169 1170 if(SDirInfo->Fcb && 1171 SDirInfo->Fcb->NTRequiredFCB) { 1172 UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB); 1173 UDFAcquireResourceExclusive(&(SDirInfo->Fcb->NTRequiredFCB->MainResource),TRUE); 1174 SDirAcq = TRUE; 1175 } 1176 1177 if(!ForDel || ((lc = UDFGetFileLinkCount(Fcb->FileInfo)) < 2)) { 1178 1179 UDF_DIR_SCAN_CONTEXT ScanContext; 1180 PDIR_INDEX_ITEM DirNdx; 1181 1182 // It is not worth checking whether the Stream can be deleted if 1183 // Undelete requested 1184 if(ForDel && 1185 // scan DirIndex 1186 UDFDirIndexInitScan(SDirInfo, &ScanContext, 2)) { 1187 1188 // Check if we can delete Streams 1189 while((DirNdx = UDFDirIndexScan(&ScanContext, &FileInfo))) { 1190 if(!FileInfo) 1191 continue; 1192 if(FileInfo->Fcb) { 1193 FileInfo->Fcb->NTRequiredFCB->AcqFlushCount++; 1194 MmPrint((" MmFlushImageSection() for Stream\n")); 1195 if(!MmFlushImageSection(&(FileInfo->Fcb->NTRequiredFCB->SectionObject), MmFlushForDelete)) { 1196 FileInfo->Fcb->NTRequiredFCB->AcqFlushCount--; 1197 try_return(RC = STATUS_CANNOT_DELETE); 1198 } 1199 FileInfo->Fcb->NTRequiredFCB->AcqFlushCount--; 1200 } 1201 } 1202 } 1203 // (Un)Mark Streams for deletion 1204 1205 // Perform sequencial Open for Streams & mark 'em 1206 // for deletion. We should not get FileInfo pointers directly 1207 // from DirNdx[i] to prevent great troubles with linked 1208 // files. We should mark for deletion FI with proper ParentFile 1209 // pointer. 1210 d = UDFDirIndexGetLastIndex(SDirInfo->Dloc->DirIndex); 1211 for(i=2; i<d; i++) { 1212 RC = UDFOpenFile__(Vcb, 1213 FALSE,TRUE,NULL, 1214 SDirInfo,&FileInfo,&i); 1215 ASSERT(NT_SUCCESS(RC) || (RC == STATUS_FILE_DELETED)); 1216 if(NT_SUCCESS(RC)) { 1217 if(FileInfo->Fcb) { 1218 if(FileInfo->Fcb->NTRequiredFCB) { 1219 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb->NTRequiredFCB); 1220 UDFAcquireResourceExclusive(&(FileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); 1221 StrAcq = TRUE; 1222 } 1223 #ifndef UDF_ALLOW_LINKS_TO_STREAMS 1224 if(UDFGetFileLinkCount(FileInfo) >= 2) { 1225 // Currently, UDF_INFO package doesn't 1226 // support this case, so we'll inform developer 1227 // about this to prevent on-disk space leaks... 1228 BrutePoint(); 1229 try_return(RC = STATUS_CANNOT_DELETE); 1230 } 1231 #endif //UDF_ALLOW_LINKS_TO_STREAMS 1232 if(ForDel) { 1233 AdPrint((" SET stream DeleteOnClose\n")); 1234 #ifdef UDF_DBG 1235 ASSERT(!(FileInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 1236 if(FileInfo->ParentFile && 1237 FileInfo->ParentFile->Fcb) { 1238 ASSERT(!(FileInfo->ParentFile->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 1239 } 1240 #endif // UDF_DBG 1241 FileInfo->Fcb->FCBFlags |= (UDF_FCB_DELETE_ON_CLOSE | 1242 UDF_FCB_DELETE_PARENT); 1243 } else { 1244 AdPrint((" CLEAR stream DeleteOnClose\n")); 1245 FileInfo->Fcb->FCBFlags &= ~(UDF_FCB_DELETE_ON_CLOSE | 1246 UDF_FCB_DELETE_PARENT); 1247 } 1248 } 1249 UDFCloseFile__(Vcb, FileInfo); 1250 } else 1251 if(RC == STATUS_FILE_DELETED) { 1252 // That's OK if STATUS_FILE_DELETED returned... 1253 RC = STATUS_SUCCESS; 1254 } 1255 if(FileInfo) { 1256 if(UDFCleanUpFile__(Vcb, FileInfo)) { 1257 ASSERT(!StrAcq && !(FileInfo->Fcb)); 1258 MyFreePool__(FileInfo); 1259 } 1260 if(StrAcq) { 1261 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb->NTRequiredFCB); 1262 UDFReleaseResource(&(FileInfo->Fcb->NTRequiredFCB->MainResource)); 1263 StrAcq = FALSE; 1264 } 1265 } 1266 FileInfo = NULL; 1267 } 1268 // Mark SDir for deletion 1269 if(SDirInfo->Fcb) { 1270 if(ForDel) { 1271 #ifdef UDF_DBG 1272 ASSERT(!(SDirInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 1273 if(SDirInfo->ParentFile && 1274 SDirInfo->ParentFile->Fcb) { 1275 ASSERT(!(SDirInfo->ParentFile->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 1276 } 1277 #endif // UDF_DBG 1278 AdPrint((" SET stream dir DeleteOnClose\n")); 1279 SDirInfo->Fcb->FCBFlags |= (UDF_FCB_DELETE_ON_CLOSE | 1280 UDF_FCB_DELETE_PARENT); 1281 } else { 1282 AdPrint((" CLEAR stream dir DeleteOnClose\n")); 1283 SDirInfo->Fcb->FCBFlags &= ~(UDF_FCB_DELETE_ON_CLOSE | 1284 UDF_FCB_DELETE_PARENT); 1285 } 1286 } 1287 } else 1288 if(lc >= 2) { 1289 // if caller wants us to perform DelTree for Streams, but 1290 // someone keeps Stream opened and there is a Link to this 1291 // file, we can't delete it immediately (on Cleanup) & should 1292 // not delete the whole Tree. Instead, we'll set DELETE_PARENT 1293 // flag in SDir to kill this file later, when all the Handles 1294 // to Streams, opened via this file, would be closed 1295 #ifdef UDF_DBG 1296 ASSERT(!(SDirInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 1297 if(SDirInfo->ParentFile && 1298 SDirInfo->ParentFile->Fcb) { 1299 ASSERT(!(SDirInfo->ParentFile->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 1300 } 1301 #endif // UDF_DBG 1302 if(SDirInfo->Fcb) 1303 SDirInfo->Fcb->FCBFlags |= UDF_FCB_DELETE_PARENT; 1304 } 1305 1306 try_exit: NOTHING; 1307 1308 } _SEH2_FINALLY { 1309 if(FileInfo) { 1310 UDFCloseFile__(Vcb, FileInfo); 1311 if(UDFCleanUpFile__(Vcb, FileInfo)) { 1312 ASSERT(!StrAcq && !(FileInfo->Fcb)); 1313 MyFreePool__(FileInfo); 1314 } 1315 if(StrAcq) { 1316 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb->NTRequiredFCB); 1317 UDFReleaseResource(&(FileInfo->Fcb->NTRequiredFCB->MainResource)); 1318 } 1319 SDirInfo = NULL; 1320 } 1321 if(SDirInfo) { 1322 UDFCloseFile__(Vcb, SDirInfo); 1323 if(SDirAcq) { 1324 UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB); 1325 UDFReleaseResource(&(SDirInfo->Fcb->NTRequiredFCB->MainResource)); 1326 } 1327 if(UDFCleanUpFile__(Vcb, SDirInfo)) { 1328 MyFreePool__(SDirInfo); 1329 } 1330 SDirInfo = NULL; 1331 } 1332 } _SEH2_END; 1333 return RC; 1334 } // end UDFMarkStreamsForDeletion() 1335 1336 /* 1337 (Un)Mark file for deletion. 1338 */ 1339 NTSTATUS 1340 UDFSetDispositionInformation( 1341 IN PtrUDFFCB Fcb, 1342 IN PtrUDFCCB Ccb, 1343 IN PVCB Vcb, 1344 IN PFILE_OBJECT FileObject, 1345 IN BOOLEAN Delete 1346 ) 1347 { 1348 NTSTATUS RC = STATUS_SUCCESS; 1349 // PUDF_FILE_INFO SDirInfo = NULL; 1350 // PUDF_FILE_INFO FileInfo = NULL; 1351 ULONG lc; 1352 1353 AdPrint(("UDFSetDispositionInformation\n")); 1354 1355 _SEH2_TRY { 1356 1357 if(!Delete) { 1358 AdPrint((" CLEAR DeleteOnClose\n")); 1359 // "un-delete" the file. 1360 Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE; 1361 if(FileObject) 1362 FileObject->DeletePending = FALSE; 1363 RC = UDFMarkStreamsForDeletion(Vcb, Fcb, FALSE); // Undelete 1364 try_return(RC); 1365 } 1366 AdPrint((" SET DeleteOnClose\n")); 1367 1368 // The easy part is over. Now, we know that the user wishes to 1369 // delete the corresponding directory entry (of course, if this 1370 // is the only link to the file stream, any on-disk storage space 1371 // associated with the file stream will also be released when the 1372 // (only) link is deleted!) 1373 1374 // Do some checking to see if the file can even be deleted. 1375 if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) { 1376 // All done! 1377 try_return(RC); 1378 } 1379 1380 if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) { 1381 try_return(RC = STATUS_CANNOT_DELETE); 1382 } 1383 1384 if(Fcb->FCBFlags & UDF_FCB_READ_ONLY) { 1385 RC = UDFCheckAccessRights(NULL, NULL, Fcb->ParentFcb, NULL, FILE_DELETE_CHILD, 0); 1386 if(!NT_SUCCESS(RC)) { 1387 try_return (RC = STATUS_CANNOT_DELETE); 1388 } 1389 } 1390 1391 // It would not be prudent to allow deletion of either a root 1392 // directory or a directory that is not empty. 1393 if(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) 1394 try_return(RC = STATUS_CANNOT_DELETE); 1395 1396 lc = UDFGetFileLinkCount(Fcb->FileInfo); 1397 1398 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { 1399 // Perform check to determine whether the directory 1400 // is empty or not. 1401 if(!UDFIsDirEmpty__(Fcb->FileInfo)) { 1402 try_return(RC = STATUS_DIRECTORY_NOT_EMPTY); 1403 } 1404 1405 } else { 1406 // An important step is to check if the file stream has been 1407 // mapped by any process. The delete cannot be allowed to proceed 1408 // in this case. 1409 MmPrint((" MmFlushImageSection()\n")); 1410 Fcb->NTRequiredFCB->AcqFlushCount++; 1411 if(!MmFlushImageSection(&(Fcb->NTRequiredFCB->SectionObject), 1412 (lc > 1) ? MmFlushForWrite : MmFlushForDelete)) { 1413 Fcb->NTRequiredFCB->AcqFlushCount--; 1414 try_return(RC = STATUS_CANNOT_DELETE); 1415 } 1416 Fcb->NTRequiredFCB->AcqFlushCount--; 1417 } 1418 // We should also mark Streams for deletion if there are no 1419 // Links to the file. Otherwise we'll delete only the file 1420 1421 if(lc > 1) { 1422 RC = STATUS_SUCCESS; 1423 } else { 1424 RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete 1425 if(!NT_SUCCESS(RC)) 1426 try_return(RC); 1427 } 1428 1429 // Set a flag to indicate that this directory entry will become history 1430 // at cleanup. 1431 Fcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE; 1432 if(FileObject) 1433 FileObject->DeletePending = TRUE; 1434 1435 if((Fcb->FCBFlags & UDF_FCB_DIRECTORY) && Ccb) { 1436 FsRtlNotifyFullChangeDirectory( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), 1437 (PVOID)Ccb, NULL, FALSE, FALSE, 1438 0, NULL, NULL, NULL ); 1439 } 1440 1441 try_exit: NOTHING; 1442 1443 } _SEH2_FINALLY { 1444 ; 1445 } _SEH2_END; 1446 return(RC); 1447 } // end UDFSetDispositionInformation() 1448 1449 1450 /* 1451 Change file allocation length. 1452 */ 1453 NTSTATUS 1454 UDFSetAllocationInformation( 1455 IN PtrUDFFCB Fcb, 1456 IN PtrUDFCCB Ccb, 1457 IN PVCB Vcb, 1458 IN PFILE_OBJECT FileObject, 1459 IN PtrUDFIrpContext PtrIrpContext, 1460 IN PIRP Irp, 1461 IN PFILE_ALLOCATION_INFORMATION PtrBuffer 1462 ) 1463 { 1464 NTSTATUS RC = STATUS_SUCCESS; 1465 BOOLEAN TruncatedFile = FALSE; 1466 BOOLEAN ModifiedAllocSize = FALSE; 1467 BOOLEAN CacheMapInitialized = FALSE; 1468 BOOLEAN AcquiredPagingIo = FALSE; 1469 1470 AdPrint(("UDFSetAllocationInformation\n")); 1471 1472 _SEH2_TRY { 1473 // Increasing the allocation size associated with a file stream 1474 // is relatively easy. All we have to do is execute some FSD 1475 // specific code to check whether we have enough space available 1476 // (and if the FSD supports user/volume quotas, whether the user 1477 // is not exceeding quota), and then increase the file size in the 1478 // corresponding on-disk and in-memory structures. 1479 // Then, all we should do is inform the Cache Manager about the 1480 // increased allocation size. 1481 1482 // First, do whatever error checking is appropriate here (e.g. whether 1483 // the caller is trying the change size for a directory, etc.). 1484 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) 1485 try_return(RC = STATUS_INVALID_PARAMETER); 1486 1487 Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); 1488 1489 if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) && 1490 (FileObject->SectionObjectPointer->SharedCacheMap == NULL) && 1491 !FlagOn(Irp->Flags, IRP_PAGING_IO)) { 1492 ASSERT( !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) ); 1493 // Now initialize the cache map. 1494 MmPrint((" CcInitializeCacheMap()\n")); 1495 CcInitializeCacheMap( FileObject, 1496 (PCC_FILE_SIZES)&Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize, 1497 FALSE, 1498 &(UDFGlobalData.CacheMgrCallBacks), 1499 Fcb->NTRequiredFCB ); 1500 1501 CacheMapInitialized = TRUE; 1502 } 1503 1504 // Are we increasing the allocation size? 1505 if(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart < 1506 PtrBuffer->AllocationSize.QuadPart) { 1507 1508 // Yes. Do the FSD specific stuff i.e. increase reserved 1509 // space on disk. 1510 if(((LONGLONG)UDFGetFreeSpace(Vcb) << Vcb->LBlockSizeBits) < PtrBuffer->AllocationSize.QuadPart) { 1511 try_return(RC = STATUS_DISK_FULL); 1512 } 1513 // RC = STATUS_SUCCESS; 1514 ModifiedAllocSize = TRUE; 1515 1516 } else if(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart > 1517 PtrBuffer->AllocationSize.QuadPart) { 1518 // This is the painful part. See if the VMM will allow us to proceed. 1519 // The VMM will deny the request if: 1520 // (a) any image section exists OR 1521 // (b) a data section exists and the size of the user mapped view 1522 // is greater than the new size 1523 // Otherwise, the VMM should allow the request to proceed. 1524 MmPrint((" MmCanFileBeTruncated()\n")); 1525 if(!MmCanFileBeTruncated(&(Fcb->NTRequiredFCB->SectionObject), &(PtrBuffer->AllocationSize))) { 1526 // VMM said no way! 1527 try_return(RC = STATUS_USER_MAPPED_FILE); 1528 } 1529 1530 // Perform our directory entry modifications. Release any on-disk 1531 // space we may need to in the process. 1532 ModifiedAllocSize = TRUE; 1533 TruncatedFile = TRUE; 1534 } 1535 1536 ASSERT(NT_SUCCESS(RC)); 1537 // This is a good place to check if we have performed a truncate 1538 // operation. If we have perform a truncate (whether we extended 1539 // or reduced file size or even leave it intact), we should update 1540 // file time stamps. 1541 FileObject->Flags |= FO_FILE_MODIFIED; 1542 1543 // Last, but not the lease, we must inform the Cache Manager of file size changes. 1544 if(ModifiedAllocSize) { 1545 1546 // If we decreased the allocation size to less than the 1547 // current file size, modify the file size value. 1548 // Similarly, if we decreased the value to less than the 1549 // current valid data length, modify that value as well. 1550 1551 AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&(Fcb->NTRequiredFCB->PagingIoResource)); 1552 // Update the FCB Header with the new allocation size. 1553 if(TruncatedFile) { 1554 if(Fcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength.QuadPart > 1555 PtrBuffer->AllocationSize.QuadPart) { 1556 // Decrease the valid data length value. 1557 Fcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength = 1558 PtrBuffer->AllocationSize; 1559 } 1560 if(Fcb->NTRequiredFCB->CommonFCBHeader.FileSize.QuadPart > 1561 PtrBuffer->AllocationSize.QuadPart) { 1562 // Decrease the file size value. 1563 Fcb->NTRequiredFCB->CommonFCBHeader.FileSize = 1564 PtrBuffer->AllocationSize; 1565 RC = UDFResizeFile__(Vcb, Fcb->FileInfo, PtrBuffer->AllocationSize.QuadPart); 1566 // UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, NULL); 1567 } 1568 } else { 1569 Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize = PtrBuffer->AllocationSize; 1570 // UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, 1571 // &(PtrBuffer->AllocationSize.QuadPart)); 1572 } 1573 if(AcquiredPagingIo) { 1574 UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource)); 1575 AcquiredPagingIo = FALSE; 1576 } 1577 // If the FCB has not had caching initiated, it is still valid 1578 // for us to invoke the NT Cache Manager. It is possible in such 1579 // situations for the call to be no'oped (unless some user has 1580 // mapped in the file) 1581 1582 // NOTE: The invocation to CcSetFileSizes() will quite possibly 1583 // result in a recursive call back into the file system. 1584 // This is because the NT Cache Manager will typically 1585 // perform a flush before telling the VMM to purge pages 1586 // especially when caching has not been initiated on the 1587 // file stream, but the user has mapped the file into 1588 // the process' virtual address space. 1589 MmPrint((" CcSetFileSizes()\n")); 1590 Fcb->NTRequiredFCB->AcqFlushCount++; 1591 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize)); 1592 Fcb->NTRequiredFCB->AcqFlushCount--; 1593 Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; 1594 1595 // Inform any pending IRPs (notify change directory). 1596 if(UDFIsAStream(Fcb->FileInfo)) { 1597 UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, 1598 FILE_NOTIFY_CHANGE_STREAM_SIZE, 1599 FILE_ACTION_MODIFIED_STREAM); 1600 } else { 1601 UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, 1602 FILE_NOTIFY_CHANGE_SIZE, 1603 FILE_ACTION_MODIFIED); 1604 } 1605 } 1606 1607 try_exit: NOTHING; 1608 1609 } _SEH2_FINALLY { 1610 if(AcquiredPagingIo) { 1611 UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource)); 1612 AcquiredPagingIo = FALSE; 1613 } 1614 if (CacheMapInitialized) { 1615 1616 MmPrint((" CcUninitializeCacheMap()\n")); 1617 CcUninitializeCacheMap( FileObject, NULL, NULL ); 1618 } 1619 } _SEH2_END; 1620 return(RC); 1621 } // end UDFSetAllocationInformation() 1622 1623 /* 1624 Set end of file (resize). 1625 */ 1626 NTSTATUS 1627 UDFSetEOF( 1628 IN PIO_STACK_LOCATION PtrSp, 1629 IN PtrUDFFCB Fcb, 1630 IN PtrUDFCCB Ccb, 1631 IN PVCB Vcb, 1632 IN PFILE_OBJECT FileObject, 1633 IN PIRP Irp, 1634 IN PFILE_END_OF_FILE_INFORMATION PtrBuffer 1635 ) 1636 { 1637 NTSTATUS RC = STATUS_SUCCESS; 1638 BOOLEAN TruncatedFile = FALSE; 1639 BOOLEAN ModifiedAllocSize = FALSE; 1640 ULONG Attr; 1641 PDIR_INDEX_ITEM DirNdx; 1642 PtrUDFNTRequiredFCB NtReqFcb = NULL; 1643 LONGLONG OldFileSize; 1644 // BOOLEAN ZeroBlock; 1645 BOOLEAN CacheMapInitialized = FALSE; 1646 BOOLEAN AcquiredPagingIo = FALSE; 1647 1648 AdPrint(("UDFSetEOF\n")); 1649 1650 _SEH2_TRY { 1651 // Increasing the allocation size associated with a file stream 1652 // is relatively easy. All we have to do is execute some FSD 1653 // specific code to check whether we have enough space available 1654 // (and if the FSD supports user/volume quotas, whether the user 1655 // is not exceeding quota), and then increase the file size in the 1656 // corresponding on-disk and in-memory structures. 1657 // Then, all we should do is inform the Cache Manager about the 1658 // increased allocation size. 1659 1660 // First, do whatever error checking is appropriate here (e.g. whether 1661 // the caller is trying the change size for a directory, etc.). 1662 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) 1663 try_return(RC = STATUS_INVALID_PARAMETER); 1664 1665 NtReqFcb = Fcb->NTRequiredFCB; 1666 1667 if((Fcb->FCBFlags & UDF_FCB_DELETED) || 1668 (NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED)) { 1669 #ifdef UDF_DBG 1670 if(UDFGetFileLinkCount(Fcb->FileInfo) < 1) { 1671 BrutePoint(); 1672 try_return(RC = STATUS_SUCCESS); 1673 } else 1674 #endif // UDF_DBG 1675 try_return(RC = STATUS_SUCCESS); 1676 } 1677 1678 NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb); 1679 1680 if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) && 1681 (FileObject->SectionObjectPointer->SharedCacheMap == NULL) && 1682 !(Irp->Flags & IRP_PAGING_IO)) { 1683 ASSERT( !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) ); 1684 // Now initialize the cache map. 1685 MmPrint((" CcInitializeCacheMap()\n")); 1686 CcInitializeCacheMap( FileObject, 1687 (PCC_FILE_SIZES)&Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize, 1688 FALSE, 1689 &(UDFGlobalData.CacheMgrCallBacks), 1690 Fcb->NTRequiredFCB ); 1691 1692 CacheMapInitialized = TRUE; 1693 } 1694 1695 AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&(Fcb->NTRequiredFCB->PagingIoResource)); 1696 // Do a special case here for the lazy write of file sizes. 1697 if(PtrSp->Parameters.SetFile.AdvanceOnly) { 1698 // Never have the dirent filesize larger than the fcb filesize 1699 PtrBuffer->EndOfFile.QuadPart = 1700 min(PtrBuffer->EndOfFile.QuadPart, 1701 NtReqFcb->CommonFCBHeader.FileSize.QuadPart); 1702 // Only advance the file size, never reduce it with this call 1703 RC = STATUS_SUCCESS; 1704 if(UDFGetFileSizeFromDirNdx(Vcb, Fcb->FileInfo) >= 1705 PtrBuffer->EndOfFile.QuadPart) 1706 try_return(RC); 1707 1708 UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, &(PtrBuffer->EndOfFile.QuadPart)); 1709 goto notify_size_changes; 1710 } 1711 1712 // !!! IMPORTANT !!! 1713 1714 // We can get here after all Handles to the file are closed 1715 // To prevent allocation size incoherency we should 1716 // reference FileInfo _before_ call to UDFResizeFile__() 1717 // and use UDFCloseFile__() _after_ that 1718 1719 // Are we increasing the allocation size? 1720 OldFileSize = NtReqFcb->CommonFCBHeader.FileSize.QuadPart; 1721 if(OldFileSize < PtrBuffer->EndOfFile.QuadPart) { 1722 1723 // Yes. Do the FSD specific stuff i.e. increase reserved 1724 // space on disk. 1725 /* 1726 if (FileObject->PrivateCacheMap) 1727 ZeroBlock = TRUE; 1728 */ 1729 1730 // reference file to pretend that it is opened 1731 UDFReferenceFile__(Fcb->FileInfo); 1732 UDFInterlockedIncrement((PLONG)&(Fcb->ReferenceCount)); 1733 UDFInterlockedIncrement((PLONG)&(NtReqFcb->CommonRefCount)); 1734 // perform resize operation 1735 RC = UDFResizeFile__(Vcb, Fcb->FileInfo, PtrBuffer->EndOfFile.QuadPart); 1736 // dereference file 1737 UDFCloseFile__(Vcb, Fcb->FileInfo); 1738 UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); 1739 UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount)); 1740 // update values in NtReqFcb 1741 NtReqFcb->CommonFCBHeader.FileSize.QuadPart = 1742 // NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = 1743 PtrBuffer->EndOfFile.QuadPart; 1744 ModifiedAllocSize = TRUE; 1745 1746 } else if(NtReqFcb->CommonFCBHeader.FileSize.QuadPart > 1747 PtrBuffer->EndOfFile.QuadPart) { 1748 1749 // This is the painful part. See if the VMM will allow us to proceed. 1750 // The VMM will deny the request if: 1751 // (a) any image section exists OR 1752 // (b) a data section exists and the size of the user mapped view 1753 // is greater than the new size 1754 // Otherwise, the VMM should allow the request to proceed. 1755 1756 MmPrint((" MmCanFileBeTruncated()\n")); 1757 if(!MmCanFileBeTruncated(&(NtReqFcb->SectionObject), &(PtrBuffer->EndOfFile))) { 1758 // VMM said no way! 1759 try_return(RC = STATUS_USER_MAPPED_FILE); 1760 } 1761 1762 // Perform directory entry modifications. Release any on-disk 1763 // space we may need to in the process. 1764 UDFReferenceFile__(Fcb->FileInfo); 1765 UDFInterlockedIncrement((PLONG)&(Fcb->ReferenceCount)); 1766 UDFInterlockedIncrement((PLONG)&(NtReqFcb->CommonRefCount)); 1767 // perform resize operation 1768 RC = UDFResizeFile__(Vcb, Fcb->FileInfo, PtrBuffer->EndOfFile.QuadPart); 1769 // dereference file 1770 UDFCloseFile__(Vcb, Fcb->FileInfo); 1771 UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); 1772 UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount)); 1773 1774 ModifiedAllocSize = TRUE; 1775 TruncatedFile = TRUE; 1776 } 1777 1778 // This is a good place to check if we have performed a truncate 1779 // operation. If we have perform a truncate (whether we extended 1780 // or reduced file size), we should update file time stamps. 1781 1782 // Last, but not the least, we must inform the Cache Manager of file size changes. 1783 if(ModifiedAllocSize && NT_SUCCESS(RC)) { 1784 // If we decreased the allocation size to less than the 1785 // current file size, modify the file size value. 1786 // Similarly, if we decreased the value to less than the 1787 // current valid data length, modify that value as well. 1788 if(TruncatedFile) { 1789 if(NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart > 1790 PtrBuffer->EndOfFile.QuadPart) { 1791 // Decrease the valid data length value. 1792 NtReqFcb->CommonFCBHeader.ValidDataLength = 1793 PtrBuffer->EndOfFile; 1794 } 1795 if(NtReqFcb->CommonFCBHeader.FileSize.QuadPart > 1796 PtrBuffer->EndOfFile.QuadPart) { 1797 // Decrease the file size value. 1798 NtReqFcb->CommonFCBHeader.FileSize = 1799 PtrBuffer->EndOfFile; 1800 } 1801 UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, NULL); 1802 } else { 1803 // Update the FCB Header with the new allocation size. 1804 // NT expects AllocationSize to be decreased on Close only 1805 NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = 1806 PtrBuffer->EndOfFile.QuadPart; 1807 // UDFSysGetAllocSize(Vcb, UDFGetFileSize(Fcb->FileInfo)); 1808 UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, &(PtrBuffer->EndOfFile.QuadPart)); 1809 } 1810 1811 FileObject->Flags |= FO_FILE_MODIFIED; 1812 // UDFGetFileAllocationSize(Vcb, Fcb->FileInfo); 1813 1814 // If the FCB has not had caching initiated, it is still valid 1815 // for us to invoke the NT Cache Manager. It is possible in such 1816 // situations for the call to be no'oped (unless some user has 1817 // mapped in the file) 1818 1819 // Archive bit 1820 if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT) { 1821 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index); 1822 Ccb->CCBFlags &= ~UDF_CCB_ATTRIBUTES_SET; 1823 Attr = UDFAttributesToNT(DirNdx, Fcb->FileInfo->Dloc->FileEntry); 1824 if(!(Attr & FILE_ATTRIBUTE_ARCHIVE)) 1825 UDFAttributesToUDF(DirNdx, Fcb->FileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE); 1826 } 1827 1828 // NOTE: The invocation to CcSetFileSizes() will quite possibly 1829 // result in a recursive call back into the file system. 1830 // This is because the NT Cache Manager will typically 1831 // perform a flush before telling the VMM to purge pages 1832 // especially when caching has not been initiated on the 1833 // file stream, but the user has mapped the file into 1834 // the process' virtual address space. 1835 MmPrint((" CcSetFileSizes(), thrd:%8.8x\n",PsGetCurrentThread())); 1836 Fcb->NTRequiredFCB->AcqFlushCount++; 1837 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize)); 1838 Fcb->NTRequiredFCB->AcqFlushCount--; 1839 /* if(ZeroBlock) { 1840 UDFZeroDataEx(NtReqFcb, 1841 OldFileSize, 1842 PtrBuffer->EndOfFile.QuadPart - OldFileSize, 1843 TRUE // CanWait, Vcb, FileObject); 1844 }*/ 1845 Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; 1846 1847 notify_size_changes: 1848 if(AcquiredPagingIo) { 1849 UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource)); 1850 AcquiredPagingIo = FALSE; 1851 } 1852 1853 // Inform any pending IRPs (notify change directory). 1854 if(UDFIsAStream(Fcb->FileInfo)) { 1855 UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, 1856 FILE_NOTIFY_CHANGE_STREAM_SIZE, 1857 FILE_ACTION_MODIFIED_STREAM); 1858 } else { 1859 UDFNotifyFullReportChange( Vcb, Fcb->FileInfo, 1860 FILE_NOTIFY_CHANGE_SIZE, 1861 FILE_ACTION_MODIFIED); 1862 } 1863 } 1864 1865 try_exit: NOTHING; 1866 1867 } _SEH2_FINALLY { 1868 if(AcquiredPagingIo) { 1869 UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource)); 1870 AcquiredPagingIo = FALSE; 1871 } 1872 if (CacheMapInitialized) { 1873 1874 MmPrint((" CcUninitializeCacheMap()\n")); 1875 CcUninitializeCacheMap( FileObject, NULL, NULL ); 1876 } 1877 } _SEH2_END; 1878 return(RC); 1879 } // end UDFSetEOF() 1880 1881 NTSTATUS 1882 UDFPrepareForRenameMoveLink( 1883 PVCB Vcb, 1884 PBOOLEAN AcquiredVcb, 1885 PBOOLEAN AcquiredVcbEx, 1886 PBOOLEAN SingleDir, 1887 PBOOLEAN AcquiredDir1, 1888 PBOOLEAN AcquiredFcb1, 1889 IN PtrUDFCCB Ccb1, 1890 PUDF_FILE_INFO File1, 1891 PUDF_FILE_INFO Dir1, 1892 PUDF_FILE_INFO Dir2, 1893 BOOLEAN HardLink 1894 ) 1895 { 1896 // convert acquisition to Exclusive 1897 // this will prevent us from the following situation: 1898 // There is a pair of objects among input dirs & 1899 // one of them is a parent of another. Sequential resource 1900 // acquisition may lead to deadlock due to concurrent 1901 // CleanUpFcbChain() or UDFCloseFileInfoChain() 1902 UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); 1903 UDFReleaseResource(&(Vcb->VCBResource)); 1904 (*AcquiredVcb) = FALSE; 1905 1906 // At first, make system to issue last Close request 1907 // for our Source & Target ... 1908 // we needn't flush/purge for Source on HLink 1909 UDFRemoveFromSystemDelayedQueue(Dir2->Fcb); 1910 if(!HardLink && (Dir2 != Dir1)) 1911 UDFRemoveFromSystemDelayedQueue(File1->Fcb); 1912 1913 #ifdef UDF_DELAYED_CLOSE 1914 _SEH2_TRY { 1915 // Do actual close for all "delayed close" calls 1916 1917 // ... and now remove the rest from our queue 1918 if(!HardLink) { 1919 UDFCloseAllDelayedInDir(Vcb, Dir1); 1920 if(Dir2 != Dir1) 1921 UDFCloseAllDelayedInDir(Vcb, Dir2); 1922 } else { 1923 UDFCloseAllDelayedInDir(Vcb, Dir2); 1924 } 1925 1926 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 1927 BrutePoint(); 1928 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); 1929 return (STATUS_DRIVER_INTERNAL_ERROR); 1930 } _SEH2_END; 1931 #endif //UDF_DELAYED_CLOSE 1932 1933 (*SingleDir) = ((Dir1 == Dir2) && (Dir1->Fcb)); 1934 1935 if(!(*SingleDir) || 1936 (UDFGetFileLinkCount(File1) != 1)) { 1937 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 1938 (*AcquiredVcb) = TRUE; 1939 (*AcquiredVcbEx) = TRUE; 1940 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); 1941 } else { 1942 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); 1943 (*AcquiredVcb) = TRUE; 1944 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); 1945 1946 UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB); 1947 UDFAcquireResourceExclusive(&(Dir1->Fcb->NTRequiredFCB->MainResource),TRUE); 1948 (*AcquiredDir1) = TRUE; 1949 1950 UDF_CHECK_PAGING_IO_RESOURCE(File1->Fcb->NTRequiredFCB); 1951 UDFAcquireResourceExclusive(&(File1->Fcb->NTRequiredFCB->MainResource),TRUE); 1952 (*AcquiredFcb1) = TRUE; 1953 } 1954 return STATUS_SUCCESS; 1955 } // end UDFPrepareForRenameMoveLink() 1956 1957 /* 1958 Rename or move file 1959 */ 1960 NTSTATUS 1961 UDFRename( 1962 IN PIO_STACK_LOCATION PtrSp, 1963 IN PtrUDFFCB Fcb1, 1964 IN PtrUDFCCB Ccb1, 1965 IN PFILE_OBJECT FileObject1, // Source File 1966 IN PFILE_RENAME_INFORMATION PtrBuffer 1967 ) 1968 { 1969 // Source Directory 1970 PFILE_OBJECT DirObject1 = FileObject1->RelatedFileObject; 1971 // Target Directory 1972 PFILE_OBJECT DirObject2 = PtrSp->Parameters.SetFile.FileObject; 1973 // Overwite Flag 1974 BOOLEAN Replace = PtrSp->Parameters.SetFile.ReplaceIfExists && 1975 PtrBuffer->ReplaceIfExists; 1976 NTSTATUS RC; 1977 PVCB Vcb = Fcb1->Vcb; 1978 PtrUDFFCB Fcb2; 1979 BOOLEAN ic; 1980 BOOLEAN AcquiredVcb = TRUE; 1981 BOOLEAN AcquiredVcbEx = FALSE; 1982 BOOLEAN AcquiredDir1 = FALSE; 1983 BOOLEAN AcquiredFcb1 = FALSE; 1984 BOOLEAN SingleDir = TRUE; 1985 BOOLEAN UseClose; 1986 1987 PUDF_FILE_INFO File1; 1988 PUDF_FILE_INFO Dir1; 1989 PUDF_FILE_INFO Dir2; 1990 PUDF_FILE_INFO NextFileInfo, fi; 1991 1992 UNICODE_STRING NewName; 1993 UNICODE_STRING LocalPath; 1994 PtrUDFCCB CurCcb = NULL; 1995 PLIST_ENTRY Link; 1996 ULONG i; 1997 ULONG DirRefCount; 1998 ULONG FileInfoRefCount; 1999 ULONG Attr; 2000 PDIR_INDEX_ITEM DirNdx; 2001 2002 AdPrint(("UDFRename %8.8x\n", DirObject2)); 2003 2004 LocalPath.Buffer = NULL; 2005 2006 _SEH2_TRY { 2007 // do we try to rename Volume ? 2008 #ifdef UDF_ALLOW_RENAME_MOVE 2009 if(!(File1 = Fcb1->FileInfo)) 2010 #endif //UDF_ALLOW_RENAME_MOVE 2011 try_return (RC = STATUS_ACCESS_DENIED); 2012 2013 // do we try to rename RootDir ? 2014 if(!(Dir1 = File1->ParentFile)) 2015 try_return (RC = STATUS_ACCESS_DENIED); 2016 2017 // do we try to rename to RootDir or Volume ? 2018 if(!DirObject2) { 2019 Dir2 = File1->ParentFile; 2020 DirObject2 = DirObject1; 2021 } else 2022 if(DirObject2->FsContext2 && 2023 (Fcb2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb)) { 2024 Dir2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb->FileInfo; 2025 } else { 2026 try_return (RC = STATUS_INVALID_PARAMETER); 2027 } 2028 // invalid destination ? 2029 if(!Dir2) try_return (RC = STATUS_ACCESS_DENIED); 2030 2031 // Stream can't be a Dir or have StreamDir 2032 if(UDFIsAStreamDir(Dir2)) { 2033 #ifdef UDF_ENABLE_SECURITY 2034 if(UDFIsADirectory(File1)) { 2035 try_return (RC = STATUS_ACCESS_DENIED); 2036 } 2037 // We should check whether File1 has only Internal 2038 // (or Deleted) streams. In this case SDir should be 2039 // removed (in UDFRenameMoveFile__()). Otherwise 2040 // return STATUS_ACCESS_DENIED 2041 if(UDFHasAStreamDir(File1)) { 2042 UDFPrint(("TODO: We should remove Streams from source file\n")); 2043 try_return (RC = STATUS_ACCESS_DENIED); 2044 } 2045 #else //UDF_ENABLE_SECURITY 2046 if(UDFIsADirectory(File1) || 2047 UDFHasAStreamDir(File1)) { 2048 try_return (RC = STATUS_ACCESS_DENIED); 2049 } 2050 #endif //UDF_ENABLE_SECURITY 2051 } 2052 2053 RC = UDFPrepareForRenameMoveLink(Vcb, &AcquiredVcb, &AcquiredVcbEx, 2054 &SingleDir, 2055 &AcquiredDir1, &AcquiredFcb1, 2056 Ccb1, File1, 2057 Dir1, Dir2, 2058 FALSE); // it is Rename operation 2059 if(!NT_SUCCESS(RC)) 2060 try_return(RC); 2061 2062 // check if the source file is in use 2063 if(Fcb1->OpenHandleCount > 1) 2064 try_return (RC = STATUS_ACCESS_DENIED); 2065 ASSERT(Fcb1->OpenHandleCount); 2066 ASSERT(!Fcb1->IrpContextLite); 2067 if(Fcb1->IrpContextLite) { 2068 try_return (RC = STATUS_ACCESS_DENIED); 2069 } 2070 // Check if we have parallel/pending Close threads 2071 if(Fcb1->CcbCount && !SingleDir) { 2072 // if this is the 1st attempt, we'll try to 2073 // synchronize with Close requests 2074 // otherwise fail request 2075 RC = STATUS_ACCESS_DENIED; 2076 post_rename: 2077 if(Fcb1->FCBFlags & UDF_FCB_POSTED_RENAME) { 2078 Fcb1->FCBFlags &= ~UDF_FCB_POSTED_RENAME; 2079 try_return (RC); 2080 } 2081 Fcb1->FCBFlags |= UDF_FCB_POSTED_RENAME; 2082 try_return (RC = STATUS_PENDING); 2083 } 2084 2085 if(!DirObject2) { 2086 // Make sure the name is of legal length. 2087 if(PtrBuffer->FileNameLength > UDF_NAME_LEN*sizeof(WCHAR)) { 2088 try_return(RC = STATUS_OBJECT_NAME_INVALID); 2089 } 2090 NewName.Length = NewName.MaximumLength = (USHORT)(PtrBuffer->FileNameLength); 2091 NewName.Buffer = (PWCHAR)&(PtrBuffer->FileName); 2092 } else { 2093 // This name is by definition legal. 2094 NewName = *((PUNICODE_STRING)&DirObject2->FileName); 2095 } 2096 2097 ic = (Ccb1->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? FALSE : TRUE; 2098 2099 AdPrint((" %ws ->\n %ws\n", 2100 Fcb1->FCBName->ObjectName.Buffer, 2101 NewName.Buffer)); 2102 2103 if(UDFIsDirOpened__(File1)) { 2104 // We can't rename file because of unclean references. 2105 // UDF_INFO package can safely do it, but NT side cannot. 2106 // In this case NT requires STATUS_OBJECT_NAME_COLLISION 2107 // rather than STATUS_ACCESS_DENIED 2108 if(NT_SUCCESS(UDFFindFile__(Vcb, ic, &NewName, Dir2))) 2109 try_return(RC = STATUS_OBJECT_NAME_COLLISION); 2110 try_return (RC = STATUS_ACCESS_DENIED); 2111 } else { 2112 // Last check before Moving. 2113 // We can't move across Dir referenced (even internally) file 2114 if(!SingleDir) { 2115 RC = UDFDoesOSAllowFileToBeMoved__(File1); 2116 if(!NT_SUCCESS(RC)) { 2117 // try_return(RC); 2118 goto post_rename; 2119 } 2120 } 2121 2122 ASSERT_REF(Fcb1->ReferenceCount >= File1->RefCount); 2123 ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount); 2124 ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount); 2125 2126 RC = UDFRenameMoveFile__(Vcb, ic, &Replace, &NewName, Dir1, Dir2, File1); 2127 } 2128 if(!NT_SUCCESS(RC)) 2129 try_return (RC); 2130 2131 ASSERT(UDFDirIndex(File1->ParentFile->Dloc->DirIndex, File1->Index)->FileInfo == File1); 2132 2133 RC = MyCloneUnicodeString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 2134 &UDFGlobalData.UnicodeStrRoot : 2135 &(Dir2->Fcb->FCBName->ObjectName) ); 2136 if(!NT_SUCCESS(RC)) try_return (RC); 2137 // RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName)); 2138 // if(!NT_SUCCESS(RC)) try_return (RC); 2139 if(Dir2->ParentFile) { 2140 RC = MyAppendUnicodeToString(&LocalPath, L"\\"); 2141 if(!NT_SUCCESS(RC)) try_return (RC); 2142 } 2143 RC = MyAppendUnicodeStringToStringTag(&LocalPath, &NewName, MEM_USREN_TAG); 2144 if(!NT_SUCCESS(RC)) try_return (RC); 2145 2146 // Set Archive bit 2147 DirNdx = UDFDirIndex(File1->ParentFile->Dloc->DirIndex, File1->Index); 2148 if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT) { 2149 Attr = UDFAttributesToNT(DirNdx, File1->Dloc->FileEntry); 2150 if(!(Attr & FILE_ATTRIBUTE_ARCHIVE)) 2151 UDFAttributesToUDF(DirNdx, File1->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE); 2152 } 2153 // Update Parent Objects (mark 'em as modified) 2154 if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) { 2155 if(DirObject1) 2156 DirObject1->Flags |= FO_FILE_MODIFIED; 2157 if(DirObject2) { 2158 DirObject2->Flags |= FO_FILE_MODIFIED; 2159 if(!Replace) 2160 DirObject2->Flags |= FO_FILE_SIZE_CHANGED; 2161 } 2162 } 2163 // report changes 2164 if(SingleDir && !Replace) { 2165 UDFNotifyFullReportChange( Vcb, File1, 2166 UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 2167 FILE_ACTION_RENAMED_OLD_NAME); 2168 /* UDFNotifyFullReportChange( Vcb, File2, 2169 UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 2170 FILE_ACTION_RENAMED_NEW_NAME );*/ 2171 FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), 2172 (PSTRING)&LocalPath, 2173 ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), 2174 NULL,NULL, 2175 UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 2176 FILE_ACTION_RENAMED_NEW_NAME, 2177 NULL); 2178 } else { 2179 UDFNotifyFullReportChange( Vcb, File1, 2180 UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 2181 FILE_ACTION_REMOVED); 2182 if(Replace) { 2183 /* UDFNotifyFullReportChange( Vcb, File2, 2184 FILE_NOTIFY_CHANGE_ATTRIBUTES | 2185 FILE_NOTIFY_CHANGE_SIZE | 2186 FILE_NOTIFY_CHANGE_LAST_WRITE | 2187 FILE_NOTIFY_CHANGE_LAST_ACCESS | 2188 FILE_NOTIFY_CHANGE_CREATION | 2189 FILE_NOTIFY_CHANGE_EA, 2190 FILE_ACTION_MODIFIED );*/ 2191 FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), 2192 (PSTRING)&LocalPath, 2193 ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 2194 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), 2195 NULL,NULL, 2196 FILE_NOTIFY_CHANGE_ATTRIBUTES | 2197 FILE_NOTIFY_CHANGE_SIZE | 2198 FILE_NOTIFY_CHANGE_LAST_WRITE | 2199 FILE_NOTIFY_CHANGE_LAST_ACCESS | 2200 FILE_NOTIFY_CHANGE_CREATION | 2201 FILE_NOTIFY_CHANGE_EA, 2202 FILE_ACTION_MODIFIED, 2203 NULL); 2204 } else { 2205 /* UDFNotifyFullReportChange( Vcb, File2, 2206 UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 2207 FILE_ACTION_ADDED );*/ 2208 FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), 2209 (PSTRING)&LocalPath, 2210 ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 2211 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), 2212 NULL,NULL, 2213 UDFIsADirectory(File1) ? 2214 FILE_NOTIFY_CHANGE_DIR_NAME : 2215 FILE_NOTIFY_CHANGE_FILE_NAME, 2216 FILE_ACTION_ADDED, 2217 NULL); 2218 } 2219 } 2220 2221 // this will prevent structutre release before call to 2222 // UDFCleanUpFcbChain() 2223 UDFInterlockedIncrement((PLONG)&(Dir1->Fcb->ReferenceCount)); 2224 UDFInterlockedIncrement((PLONG)&(Dir1->Fcb->NTRequiredFCB->CommonRefCount)); 2225 ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount); 2226 2227 // Look through Ccb list & decrement OpenHandleCounter(s) 2228 // acquire CcbList 2229 if(!SingleDir) { 2230 UDFAcquireResourceExclusive(&(Fcb1->CcbListResource),TRUE); 2231 Link = Fcb1->NextCCB.Flink; 2232 DirRefCount = 0; 2233 FileInfoRefCount = 0; 2234 ASSERT(Link != &(Fcb1->NextCCB)); 2235 while (Link != &(Fcb1->NextCCB)) { 2236 NextFileInfo = Dir1; 2237 CurCcb = CONTAINING_RECORD(Link, UDFCCB, NextCCB); 2238 ASSERT(CurCcb->TreeLength); 2239 i = (CurCcb->TreeLength) ? (CurCcb->TreeLength - 1) : 0; 2240 Link = Link->Flink; 2241 UseClose = (CurCcb->CCBFlags & UDF_CCB_CLEANED) ? FALSE : TRUE; 2242 2243 AdPrint((" Ccb:%x:%s:i:%x\n", CurCcb, UseClose ? "Close" : "",i)); 2244 // cleanup old parent chain 2245 for(; i && NextFileInfo; i--) { 2246 // remember parent file now 2247 // it will prevent us from data losses 2248 // due to eventual structure release 2249 fi = NextFileInfo->ParentFile; 2250 if(UseClose) { 2251 ASSERT_REF(NextFileInfo->Fcb->ReferenceCount >= NextFileInfo->RefCount); 2252 UDFCloseFile__(Vcb, NextFileInfo); 2253 } 2254 ASSERT_REF(NextFileInfo->Fcb->ReferenceCount > NextFileInfo->RefCount); 2255 ASSERT_REF(NextFileInfo->Fcb->ReferenceCount); 2256 ASSERT_REF(NextFileInfo->Fcb->NTRequiredFCB->CommonRefCount); 2257 UDFInterlockedDecrement((PLONG)&(NextFileInfo->Fcb->ReferenceCount)); 2258 UDFInterlockedDecrement((PLONG)&(NextFileInfo->Fcb->NTRequiredFCB->CommonRefCount)); 2259 ASSERT_REF(NextFileInfo->Fcb->ReferenceCount >= NextFileInfo->RefCount); 2260 NextFileInfo = fi; 2261 } 2262 2263 if(CurCcb->TreeLength > 1) { 2264 DirRefCount++; 2265 if(UseClose) 2266 FileInfoRefCount++; 2267 CurCcb->TreeLength = 2; 2268 #ifdef UDF_DBG 2269 } else { 2270 BrutePoint(); 2271 #endif // UDF_DBG 2272 } 2273 } 2274 UDFReleaseResource(&(Fcb1->CcbListResource)); 2275 2276 ASSERT_REF(DirRefCount >= FileInfoRefCount); 2277 // update counters & pointers 2278 Fcb1->ParentFcb = Dir2->Fcb; 2279 // move references to Dir2 2280 UDFInterlockedExchangeAdd((PLONG)&(Dir2->Fcb->ReferenceCount), DirRefCount); 2281 UDFInterlockedExchangeAdd((PLONG)&(Dir2->Fcb->NTRequiredFCB->CommonRefCount), DirRefCount); 2282 ASSERT_REF(Dir2->Fcb->ReferenceCount > Dir2->RefCount); 2283 UDFReferenceFileEx__(Dir2,FileInfoRefCount); 2284 ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount); 2285 } 2286 ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount); 2287 ASSERT_REF(Dir2->RefCount); 2288 2289 ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount); 2290 // Modify name in Fcb1 2291 if(Fcb1->FCBName) { 2292 if(Fcb1->FCBName->ObjectName.Buffer) { 2293 MyFreePool__(Fcb1->FCBName->ObjectName.Buffer); 2294 } 2295 UDFReleaseObjectName(Fcb1->FCBName); 2296 } 2297 Fcb1->FCBName = UDFAllocateObjectName(); 2298 if(!(Fcb1->FCBName)) { 2299 insuf_res: 2300 BrutePoint(); 2301 // UDFCleanUpFcbChain()... 2302 if(AcquiredFcb1) { 2303 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1->NTRequiredFCB); 2304 UDFReleaseResource(&(Fcb1->NTRequiredFCB->MainResource)); 2305 AcquiredDir1 = FALSE; 2306 } 2307 if(AcquiredDir1) { 2308 UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB); 2309 UDFReleaseResource(&(Dir1->Fcb->NTRequiredFCB->MainResource)); 2310 AcquiredDir1 = FALSE; 2311 } 2312 UDFCleanUpFcbChain(Vcb, Dir1, 1, TRUE); 2313 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 2314 } 2315 2316 RC = MyCloneUnicodeString(&(Fcb1->FCBName->ObjectName), &(Fcb2->FCBName->ObjectName)); 2317 if(!NT_SUCCESS(RC)) 2318 goto insuf_res; 2319 /* RC = MyAppendUnicodeStringToString(&(Fcb1->FCBName->ObjectName), &(Fcb2->FCBName->ObjectName)); 2320 if(!NT_SUCCESS(RC)) 2321 goto insuf_res;*/ 2322 // if Dir2 is a RootDir, we shoud not append '\\' because 2323 // uit will be the 2nd '\\' character (RootDir's name is also '\\') 2324 if(Dir2->ParentFile) { 2325 RC = MyAppendUnicodeToString(&(Fcb1->FCBName->ObjectName), L"\\"); 2326 if(!NT_SUCCESS(RC)) 2327 goto insuf_res; 2328 } 2329 RC = MyAppendUnicodeStringToStringTag(&(Fcb1->FCBName->ObjectName), &NewName, MEM_USREN2_TAG); 2330 if(!NT_SUCCESS(RC)) 2331 goto insuf_res; 2332 2333 ASSERT_REF(Fcb1->ReferenceCount >= File1->RefCount); 2334 ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount); 2335 ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount); 2336 2337 RC = STATUS_SUCCESS; 2338 2339 try_exit: NOTHING; 2340 2341 } _SEH2_FINALLY { 2342 2343 if(AcquiredFcb1) { 2344 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1->NTRequiredFCB); 2345 UDFReleaseResource(&(Fcb1->NTRequiredFCB->MainResource)); 2346 } 2347 if(AcquiredDir1) { 2348 UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB); 2349 UDFReleaseResource(&(Dir1->Fcb->NTRequiredFCB->MainResource)); 2350 } 2351 // perform protected structure release 2352 if(NT_SUCCESS(RC) && 2353 (RC != STATUS_PENDING)) { 2354 ASSERT(AcquiredVcb); 2355 UDFCleanUpFcbChain(Vcb, Dir1, 1, TRUE); 2356 ASSERT_REF(Fcb1->ReferenceCount >= File1->RefCount); 2357 ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount); 2358 } 2359 2360 if(AcquiredVcb) { 2361 if(AcquiredVcbEx) 2362 UDFConvertExclusiveToSharedLite(&(Vcb->VCBResource)); 2363 } else { 2364 // caller assumes Vcb to be acquired shared 2365 BrutePoint(); 2366 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); 2367 } 2368 2369 if(LocalPath.Buffer) { 2370 MyFreePool__(LocalPath.Buffer); 2371 } 2372 } _SEH2_END; 2373 2374 return RC; 2375 } // end UDFRename() 2376 2377 #endif //UDF_READ_ONLY_BUILD 2378 2379 LONG 2380 UDFFindFileId( 2381 IN PVCB Vcb, 2382 IN LONGLONG Id 2383 ) 2384 { 2385 if(!Vcb->FileIdCache) return (-1); 2386 for(ULONG i=0; i<Vcb->FileIdCount; i++) { 2387 if(Vcb->FileIdCache[i].Id == Id) return i; 2388 } 2389 return (-1); 2390 } // end UDFFindFileId() 2391 2392 LONG 2393 UDFFindFreeFileId( 2394 IN PVCB Vcb, 2395 IN LONGLONG Id 2396 ) 2397 { 2398 if(!Vcb->FileIdCache) { 2399 if(!(Vcb->FileIdCache = (PUDFFileIDCacheItem)MyAllocatePool__(NonPagedPool, sizeof(UDFFileIDCacheItem)*FILE_ID_CACHE_GRANULARITY))) 2400 return (-1); 2401 RtlZeroMemory(Vcb->FileIdCache, FILE_ID_CACHE_GRANULARITY*sizeof(UDFFileIDCacheItem)); 2402 Vcb->FileIdCount = FILE_ID_CACHE_GRANULARITY; 2403 } 2404 for(ULONG i=0; i<Vcb->FileIdCount; i++) { 2405 if(!Vcb->FileIdCache[i].FullName.Buffer) return i; 2406 } 2407 if(!MyReallocPool__((PCHAR)(Vcb->FileIdCache), Vcb->FileIdCount*sizeof(UDFFileIDCacheItem), 2408 (PCHAR*)&(Vcb->FileIdCache), (Vcb->FileIdCount+FILE_ID_CACHE_GRANULARITY)*sizeof(UDFFileIDCacheItem))) { 2409 return (-1); 2410 } 2411 RtlZeroMemory(&(Vcb->FileIdCache[Vcb->FileIdCount]), FILE_ID_CACHE_GRANULARITY*sizeof(UDFFileIDCacheItem)); 2412 Vcb->FileIdCount += FILE_ID_CACHE_GRANULARITY; 2413 return (Vcb->FileIdCount - FILE_ID_CACHE_GRANULARITY); 2414 } // end UDFFindFreeFileId() 2415 2416 NTSTATUS 2417 UDFStoreFileId( 2418 IN PVCB Vcb, 2419 IN PtrUDFCCB Ccb, 2420 IN PUDF_FILE_INFO fi, 2421 IN LONGLONG Id 2422 ) 2423 { 2424 LONG i; 2425 NTSTATUS RC = STATUS_SUCCESS; 2426 2427 if((i = UDFFindFileId(Vcb, Id)) == (-1)) { 2428 if((i = UDFFindFreeFileId(Vcb, Id)) == (-1)) return STATUS_INSUFFICIENT_RESOURCES; 2429 } else { 2430 return STATUS_SUCCESS; 2431 } 2432 Vcb->FileIdCache[i].Id = Id; 2433 Vcb->FileIdCache[i].CaseSens = (Ccb->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? TRUE : FALSE; 2434 RC = MyCloneUnicodeString(&(Vcb->FileIdCache[i].FullName), &(Ccb->Fcb->FCBName->ObjectName)); 2435 /* if(NT_SUCCESS(RC)) { 2436 RC = MyAppendUnicodeStringToStringTag(&(Vcb->FileIdCache[i].FullName), &(Ccb->Fcb->FCBName->ObjectName), MEM_USFIDC_TAG); 2437 }*/ 2438 return RC; 2439 } // end UDFStoreFileId() 2440 2441 NTSTATUS 2442 UDFRemoveFileId( 2443 IN PVCB Vcb, 2444 IN LONGLONG Id 2445 ) 2446 { 2447 LONG i; 2448 2449 if((i = UDFFindFileId(Vcb, Id)) == (-1)) return STATUS_INVALID_PARAMETER; 2450 MyFreePool__(Vcb->FileIdCache[i].FullName.Buffer); 2451 RtlZeroMemory(&(Vcb->FileIdCache[i]), sizeof(UDFFileIDCacheItem)); 2452 return STATUS_SUCCESS; 2453 } // end UDFRemoveFileId() 2454 2455 VOID 2456 UDFReleaseFileIdCache( 2457 IN PVCB Vcb 2458 ) 2459 { 2460 if(!Vcb->FileIdCache) return; 2461 for(ULONG i=0; i<Vcb->FileIdCount; i++) { 2462 if(Vcb->FileIdCache[i].FullName.Buffer) { 2463 MyFreePool__(Vcb->FileIdCache[i].FullName.Buffer); 2464 } 2465 } 2466 MyFreePool__(Vcb->FileIdCache); 2467 Vcb->FileIdCache = NULL; 2468 Vcb->FileIdCount = 0; 2469 } // end UDFReleaseFileIdCache() 2470 2471 NTSTATUS 2472 UDFGetOpenParamsByFileId( 2473 IN PVCB Vcb, 2474 IN LONGLONG Id, 2475 OUT PUNICODE_STRING* FName, 2476 OUT BOOLEAN* CaseSens 2477 ) 2478 { 2479 LONG i; 2480 2481 if((i = UDFFindFileId(Vcb, Id)) == (-1)) return STATUS_NOT_FOUND; 2482 (*FName) = &(Vcb->FileIdCache[i].FullName); 2483 (*CaseSens) = !(Vcb->FileIdCache[i].CaseSens); 2484 return STATUS_SUCCESS; 2485 } // end UDFGetOpenParamsByFileId() 2486 2487 #ifndef UDF_READ_ONLY_BUILD 2488 2489 #ifdef UDF_ALLOW_HARD_LINKS 2490 /* 2491 create hard link for the file 2492 */ 2493 NTSTATUS 2494 UDFHardLink( 2495 IN PIO_STACK_LOCATION PtrSp, 2496 IN PtrUDFFCB Fcb1, 2497 IN PtrUDFCCB Ccb1, 2498 IN PFILE_OBJECT FileObject1, // Source File 2499 IN PFILE_LINK_INFORMATION PtrBuffer 2500 ) 2501 { 2502 // Target Directory 2503 PFILE_OBJECT DirObject2 = PtrSp->Parameters.SetFile.FileObject; 2504 // Overwite Flag 2505 BOOLEAN Replace = PtrSp->Parameters.SetFile.ReplaceIfExists && 2506 PtrBuffer->ReplaceIfExists; 2507 NTSTATUS RC; 2508 PVCB Vcb = Fcb1->Vcb; 2509 PtrUDFFCB Fcb2; 2510 BOOLEAN ic; 2511 BOOLEAN AcquiredVcb = TRUE; 2512 BOOLEAN AcquiredVcbEx = FALSE; 2513 BOOLEAN AcquiredDir1 = FALSE; 2514 BOOLEAN AcquiredFcb1 = FALSE; 2515 BOOLEAN SingleDir = TRUE; 2516 2517 PUDF_FILE_INFO File1; 2518 PUDF_FILE_INFO Dir1 = NULL; 2519 PUDF_FILE_INFO Dir2; 2520 2521 UNICODE_STRING NewName; 2522 UNICODE_STRING LocalPath; 2523 // PtrUDFCCB CurCcb = NULL; 2524 2525 AdPrint(("UDFHardLink\n")); 2526 2527 LocalPath.Buffer = NULL; 2528 2529 _SEH2_TRY { 2530 2531 // do we try to link Volume ? 2532 if(!(File1 = Fcb1->FileInfo)) 2533 try_return (RC = STATUS_ACCESS_DENIED); 2534 2535 // do we try to link RootDir ? 2536 if(!(Dir1 = File1->ParentFile)) 2537 try_return (RC = STATUS_ACCESS_DENIED); 2538 2539 // do we try to link Stream / Stream Dir ? 2540 #ifdef UDF_ALLOW_LINKS_TO_STREAMS 2541 if(UDFIsAStreamDir(File1)) 2542 try_return (RC = STATUS_ACCESS_DENIED); 2543 #else //UDF_ALLOW_LINKS_TO_STREAMS 2544 if(UDFIsAStream(File1) || UDFIsAStreamDir(File1) /*|| 2545 UDFIsADirectory(File1) || UDFHasAStreamDir(File1)*/) 2546 try_return (RC = STATUS_ACCESS_DENIED); 2547 #endif // UDF_ALLOW_LINKS_TO_STREAMS 2548 2549 // do we try to link to RootDir or Volume ? 2550 if(!DirObject2) { 2551 Dir2 = File1->ParentFile; 2552 DirObject2 = FileObject1->RelatedFileObject; 2553 } else 2554 if(DirObject2->FsContext2 && 2555 (Fcb2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb)) { 2556 Dir2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb->FileInfo; 2557 } else { 2558 try_return (RC = STATUS_INVALID_PARAMETER); 2559 } 2560 2561 // check target dir 2562 if(!Dir2) try_return (RC = STATUS_ACCESS_DENIED); 2563 2564 // Stream can't be a Dir or have Streams 2565 if(UDFIsAStreamDir(Dir2)) { 2566 try_return (RC = STATUS_ACCESS_DENIED); 2567 /* if(UDFIsADirectory(File1) || 2568 UDFHasAStreamDir(File1)) { 2569 BrutePoint(); 2570 try_return (RC = STATUS_ACCESS_DENIED); 2571 }*/ 2572 } 2573 2574 /* if(UDFIsAStreamDir(Dir2)) 2575 try_return (RC = STATUS_ACCESS_DENIED);*/ 2576 2577 RC = UDFPrepareForRenameMoveLink(Vcb, &AcquiredVcb, &AcquiredVcbEx, 2578 &SingleDir, 2579 &AcquiredDir1, &AcquiredFcb1, 2580 Ccb1, File1, 2581 Dir1, Dir2, 2582 TRUE); // it is HLink operation 2583 if(!NT_SUCCESS(RC)) 2584 try_return(RC); 2585 2586 // check if the source file is used 2587 if(!DirObject2) { 2588 // Make sure the name is of legal length. 2589 if(PtrBuffer->FileNameLength > UDF_NAME_LEN*sizeof(WCHAR)) { 2590 try_return(RC = STATUS_OBJECT_NAME_INVALID); 2591 } 2592 NewName.Length = NewName.MaximumLength = (USHORT)(PtrBuffer->FileNameLength); 2593 NewName.Buffer = (PWCHAR)&(PtrBuffer->FileName); 2594 } else { 2595 // This name is by definition legal. 2596 NewName = *((PUNICODE_STRING)&DirObject2->FileName); 2597 } 2598 2599 ic = (Ccb1->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? FALSE : TRUE; 2600 2601 AdPrint((" %ws ->\n %ws\n", 2602 Fcb1->FCBName->ObjectName.Buffer, 2603 NewName.Buffer)); 2604 2605 RC = UDFHardLinkFile__(Vcb, ic, &Replace, &NewName, Dir1, Dir2, File1); 2606 if(!NT_SUCCESS(RC)) try_return (RC); 2607 2608 // Update Parent Objects (mark 'em as modified) 2609 if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) { 2610 if(DirObject2) { 2611 DirObject2->Flags |= FO_FILE_MODIFIED; 2612 if(!Replace) 2613 DirObject2->Flags |= FO_FILE_SIZE_CHANGED; 2614 } 2615 } 2616 // report changes 2617 UDFNotifyFullReportChange( Vcb, File1, 2618 FILE_NOTIFY_CHANGE_LAST_WRITE | 2619 FILE_NOTIFY_CHANGE_LAST_ACCESS, 2620 FILE_ACTION_MODIFIED ); 2621 2622 RC = MyCloneUnicodeString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 2623 &UDFGlobalData.UnicodeStrRoot : 2624 &(Dir2->Fcb->FCBName->ObjectName)); 2625 if(!NT_SUCCESS(RC)) try_return (RC); 2626 /* RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName)); 2627 if(!NT_SUCCESS(RC)) try_return (RC);*/ 2628 // if Dir2 is a RootDir, we shoud not append '\\' because 2629 // it will be the 2nd '\\' character (RootDir's name is also '\\') 2630 if(Dir2->ParentFile) { 2631 RC = MyAppendUnicodeToString(&LocalPath, L"\\"); 2632 if(!NT_SUCCESS(RC)) try_return (RC); 2633 } 2634 RC = MyAppendUnicodeStringToStringTag(&LocalPath, &NewName, MEM_USHL_TAG); 2635 if(!NT_SUCCESS(RC)) try_return (RC); 2636 2637 if(!Replace) { 2638 /* UDFNotifyFullReportChange( Vcb, File2, 2639 UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 2640 FILE_ACTION_ADDED );*/ 2641 FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), 2642 (PSTRING)&LocalPath, 2643 ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), 2644 NULL,NULL, 2645 UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 2646 FILE_ACTION_ADDED, 2647 NULL); 2648 } else { 2649 /* UDFNotifyFullReportChange( Vcb, File2, 2650 FILE_NOTIFY_CHANGE_ATTRIBUTES | 2651 FILE_NOTIFY_CHANGE_SIZE | 2652 FILE_NOTIFY_CHANGE_LAST_WRITE | 2653 FILE_NOTIFY_CHANGE_LAST_ACCESS | 2654 FILE_NOTIFY_CHANGE_CREATION | 2655 FILE_NOTIFY_CHANGE_EA, 2656 FILE_ACTION_MODIFIED );*/ 2657 FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), 2658 (PSTRING)&LocalPath, 2659 ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR), 2660 NULL,NULL, 2661 UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 2662 FILE_NOTIFY_CHANGE_ATTRIBUTES | 2663 FILE_NOTIFY_CHANGE_SIZE | 2664 FILE_NOTIFY_CHANGE_LAST_WRITE | 2665 FILE_NOTIFY_CHANGE_LAST_ACCESS | 2666 FILE_NOTIFY_CHANGE_CREATION | 2667 FILE_NOTIFY_CHANGE_EA, 2668 NULL); 2669 } 2670 2671 RC = STATUS_SUCCESS; 2672 2673 try_exit: NOTHING; 2674 2675 } _SEH2_FINALLY { 2676 2677 if(AcquiredFcb1) { 2678 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1->NTRequiredFCB); 2679 UDFReleaseResource(&(Fcb1->NTRequiredFCB->MainResource)); 2680 } 2681 if(AcquiredDir1) { 2682 UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB); 2683 UDFReleaseResource(&(Dir1->Fcb->NTRequiredFCB->MainResource)); 2684 } 2685 if(AcquiredVcb) { 2686 if(AcquiredVcbEx) 2687 UDFConvertExclusiveToSharedLite(&(Vcb->VCBResource)); 2688 } else { 2689 // caller assumes Vcb to be acquired shared 2690 BrutePoint(); 2691 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); 2692 } 2693 2694 if(LocalPath.Buffer) { 2695 MyFreePool__(LocalPath.Buffer); 2696 } 2697 } _SEH2_END; 2698 2699 return RC; 2700 } // end UDFHardLink() 2701 #endif //UDF_ALLOW_HARD_LINKS 2702 2703 #endif //UDF_READ_ONLY_BUILD 2704