Reactos
at master 2703 lines 109 kB view raw
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*************************************************************************/ 44NTSTATUS 45NTAPI 46UDFFileInfo( 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*************************************************************************/ 113NTSTATUS 114UDFCommonFileInfo( 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_PTR)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 460try_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 */ 531NTSTATUS 532UDFGetBasicInformation( 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 597try_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 */ 613NTSTATUS 614UDFGetStandardInformation( 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 */ 675NTSTATUS 676UDFGetNetworkInformation( 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 731try_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 */ 746NTSTATUS 747UDFGetInternalInformation( 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 786try_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 */ 800NTSTATUS 801UDFGetEaInformation( 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 821try_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 */ 835NTSTATUS 836UDFGetFullNameInformation( 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 */ 868NTSTATUS 869UDFGetAltNameInformation( 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 */ 909NTSTATUS 910UDFGetPositionInformation( 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 */ 929NTSTATUS 930UDFGetFileStreamInformation( 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 994try_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 */ 1012NTSTATUS 1013UDFSetBasicInformation( 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 1129try_exit: NOTHING; 1130 } _SEH2_FINALLY { 1131 ; 1132 } _SEH2_END; 1133 return(RC); 1134} // end UDFSetBasicInformation() 1135 1136NTSTATUS 1137UDFMarkStreamsForDeletion( 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 1306try_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 */ 1339NTSTATUS 1340UDFSetDispositionInformation( 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 1441try_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 */ 1453NTSTATUS 1454UDFSetAllocationInformation( 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 1607try_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 */ 1626NTSTATUS 1627UDFSetEOF( 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 1847notify_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 1865try_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 1881NTSTATUS 1882UDFPrepareForRenameMoveLink( 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 */ 1960NTSTATUS 1961UDFRename( 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; 2076post_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)) { 2299insuf_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 2339try_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 2379LONG 2380UDFFindFileId( 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 2392LONG 2393UDFFindFreeFileId( 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 2416NTSTATUS 2417UDFStoreFileId( 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 2441NTSTATUS 2442UDFRemoveFileId( 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 2455VOID 2456UDFReleaseFileIdCache( 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 2471NTSTATUS 2472UDFGetOpenParamsByFileId( 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 */ 2493NTSTATUS 2494UDFHardLink( 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 2673try_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