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: Create.cpp 9 * 10 * Module: UDF File System Driver (Kernel mode execution only) 11 * 12 * Description: 13 * Contains code to handle the "Create"/"Open" dispatch entry point. 14 * 15 *************************************************************************/ 16 17 #include "udffs.h" 18 19 #define IsFileObjectReadOnly(FO) (!((FO)->WriteAccess | (FO)->DeleteAccess)) 20 21 // define the file specific bug-check id 22 #define UDF_BUG_CHECK_ID UDF_FILE_CREATE 23 24 #define MEM_USABS_TAG "US_Abs" 25 #define MEM_USLOC_TAG "US_Loc" 26 #define MEM_USOBJ_TAG "US_Obj" 27 28 #define UDF_LOG_CREATE_DISPOSITION 29 30 /************************************************************************* 31 * 32 * Function: UDFCreate() 33 * 34 * Description: 35 * The I/O Manager will invoke this routine to handle a create/open 36 * request 37 * 38 * Expected Interrupt Level (for execution) : 39 * 40 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution 41 * to be deferred to a worker thread context) 42 * 43 * Return Value: STATUS_SUCCESS/Error 44 * 45 *************************************************************************/ 46 NTSTATUS 47 NTAPI 48 UDFCreate( 49 PDEVICE_OBJECT DeviceObject, // the logical volume device object 50 PIRP Irp) // I/O Request Packet 51 { 52 NTSTATUS RC = STATUS_SUCCESS; 53 PtrUDFIrpContext PtrIrpContext; 54 BOOLEAN AreWeTopLevel = FALSE; 55 56 TmPrint(("UDFCreate:\n")); 57 58 FsRtlEnterFileSystem(); 59 ASSERT(DeviceObject); 60 ASSERT(Irp); 61 62 // sometimes, we may be called here with the device object representing 63 // the file system (instead of the device object created for a logical 64 // volume. In this case, there is not much we wish to do (this create 65 // typically will happen 'cause some process has to open the FSD device 66 // object so as to be able to send an IOCTL to the FSD) 67 68 // All of the logical volume device objects we create have a device 69 // extension whereas the device object representing the FSD has no 70 // device extension. This seems like a good enough method to identify 71 // between the two device objects ... 72 if (UDFIsFSDevObj(DeviceObject)) { 73 // this is an open of the FSD itself 74 Irp->IoStatus.Status = RC; 75 Irp->IoStatus.Information = FILE_OPENED; 76 77 IoCompleteRequest(Irp, IO_NO_INCREMENT); 78 FsRtlExitFileSystem(); 79 return(RC); 80 } 81 82 // set the top level context 83 AreWeTopLevel = UDFIsIrpTopLevel(Irp); 84 85 _SEH2_TRY { 86 87 // get an IRP context structure and issue the request 88 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); 89 if(PtrIrpContext) { 90 RC = UDFCommonCreate(PtrIrpContext, Irp); 91 } else { 92 RC = STATUS_INSUFFICIENT_RESOURCES; 93 Irp->IoStatus.Status = RC; 94 Irp->IoStatus.Information = 0; 95 // complete the IRP 96 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 97 } 98 99 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { 100 101 RC = UDFExceptionHandler(PtrIrpContext, Irp); 102 103 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); 104 } _SEH2_END; 105 106 if (AreWeTopLevel) { 107 IoSetTopLevelIrp(NULL); 108 } 109 110 AdPrint(("UDFCreate: %x\n", RC)); 111 112 FsRtlExitFileSystem(); 113 114 return(RC); 115 116 } // end UDFCreate() 117 118 /* 119 */ 120 VOID 121 __fastcall 122 UDFReleaseResFromCreate( 123 IN PERESOURCE* PagingIoRes, 124 IN PERESOURCE* Res1, 125 IN PERESOURCE* Res2 126 ) 127 { 128 if(*PagingIoRes) { 129 UDFReleaseResource(*PagingIoRes); 130 (*PagingIoRes) = NULL; 131 } 132 if(*Res1) { 133 UDFReleaseResource(*Res1); 134 (*Res1) = NULL; 135 } 136 if(*Res2) { 137 UDFReleaseResource(*Res2); 138 (*Res2) = NULL; 139 } 140 } // end UDFReleaseResFromCreate() 141 142 /* 143 */ 144 VOID 145 __fastcall 146 UDFAcquireParent( 147 IN PUDF_FILE_INFO RelatedFileInfo, 148 IN PERESOURCE* Res1, 149 IN PERESOURCE* Res2 150 ) 151 { 152 if(RelatedFileInfo->Fcb && 153 RelatedFileInfo->Fcb->ParentFcb) { 154 155 UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->ParentFcb->NTRequiredFCB); 156 UDFAcquireResourceExclusive((*Res2) = &(RelatedFileInfo->Fcb->ParentFcb->NTRequiredFCB->MainResource),TRUE); 157 } 158 159 UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->NTRequiredFCB); 160 UDFAcquireResourceExclusive((*Res1) = &(RelatedFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); 161 162 UDFInterlockedIncrement((PLONG)&(RelatedFileInfo->Fcb->ReferenceCount)); 163 UDFInterlockedIncrement((PLONG)&(RelatedFileInfo->Dloc->CommonFcb->CommonRefCount)); 164 UDFReferenceFile__(RelatedFileInfo); 165 ASSERT_REF(RelatedFileInfo->Fcb->ReferenceCount >= RelatedFileInfo->RefCount); 166 } // end UDFAcquireParent() 167 168 /************************************************************************* 169 * 170 * Function: UDFCommonCreate() 171 * 172 * Description: 173 * The actual work is performed here. This routine may be invoked in one' 174 * of the two possible contexts: 175 * (a) in the context of a system worker thread 176 * (b) in the context of the original caller 177 * 178 * Expected Interrupt Level (for execution) : 179 * 180 * IRQL_PASSIVE_LEVEL 181 * 182 * Return Value: STATUS_SUCCESS/Error 183 * 184 *************************************************************************/ 185 NTSTATUS 186 UDFCommonCreate( 187 PtrUDFIrpContext PtrIrpContext, 188 PIRP Irp 189 ) 190 { 191 NTSTATUS RC = STATUS_SUCCESS; 192 PIO_STACK_LOCATION IrpSp = NULL; 193 PIO_SECURITY_CONTEXT PtrSecurityContext = NULL; 194 PFILE_OBJECT PtrNewFileObject = NULL; 195 PFILE_OBJECT PtrRelatedFileObject = NULL; 196 LONGLONG AllocationSize; // if we create a new file 197 PFILE_FULL_EA_INFORMATION PtrExtAttrBuffer = NULL; 198 ULONG RequestedOptions; 199 ULONG RequestedDisposition; 200 USHORT FileAttributes; 201 USHORT TmpFileAttributes; 202 USHORT ShareAccess; 203 ULONG ExtAttrLength = 0; 204 ACCESS_MASK DesiredAccess; 205 PACCESS_STATE AccessState; 206 207 PVCB Vcb = NULL; 208 _SEH2_VOLATILE BOOLEAN AcquiredVcb = FALSE; 209 BOOLEAN OpenExisting = FALSE; 210 PERESOURCE Res1 = NULL; 211 PERESOURCE Res2 = NULL; 212 PERESOURCE PagingIoRes = NULL; 213 214 // BOOLEAN DirectoryOnlyRequested; 215 // BOOLEAN FileOnlyRequested; 216 // BOOLEAN NoBufferingSpecified; 217 BOOLEAN WriteThroughRequested; 218 BOOLEAN DeleteOnCloseSpecified; 219 // BOOLEAN NoExtAttrKnowledge; 220 // BOOLEAN CreateTreeConnection = FALSE; 221 // BOOLEAN OpenByFileId; 222 223 // Are we dealing with a page file? 224 BOOLEAN PageFileManipulation; 225 // Is this open for a target directory (used in rename operations)? 226 BOOLEAN OpenTargetDirectory; 227 // Should we ignore case when attempting to locate the object? 228 BOOLEAN IgnoreCase; 229 230 PtrUDFCCB PtrRelatedCCB = NULL, PtrNewCcb = NULL; 231 PtrUDFFCB PtrRelatedFCB = NULL, PtrNewFcb = NULL; 232 PtrUDFNTRequiredFCB NtReqFcb; 233 234 ULONG ReturnedInformation = 0; 235 236 UNICODE_STRING TargetObjectName; 237 UNICODE_STRING RelatedObjectName; 238 239 UNICODE_STRING AbsolutePathName; // '\aaa\cdf\fff\rrrr.tre:s' 240 UNICODE_STRING LocalPath; // '\aaa\cdf' 241 UNICODE_STRING CurName; // 'cdf' 242 UNICODE_STRING TailName; // 'fff\rrrr.tre:s' 243 UNICODE_STRING LastGoodName; // it depends... 244 UNICODE_STRING LastGoodTail; // it depends... 245 UNICODE_STRING StreamName; // ':s' 246 247 PUDF_FILE_INFO RelatedFileInfo; 248 PUDF_FILE_INFO OldRelatedFileInfo = NULL; 249 PUDF_FILE_INFO NewFileInfo = NULL; 250 PUDF_FILE_INFO LastGoodFileInfo = NULL; 251 PWCHAR TmpBuffer; 252 ULONG TreeLength = 0; 253 // ULONG i = 0; 254 255 BOOLEAN StreamOpen = FALSE; 256 BOOLEAN StreamExists = FALSE; 257 BOOLEAN RestoreVCBOpenCounter = FALSE; 258 BOOLEAN RestoreShareAccess = FALSE; 259 PWCHAR TailNameBuffer = NULL; 260 ULONG SNameIndex = 0; 261 262 TmPrint(("UDFCommonCreate:\n")); 263 264 ASSERT(PtrIrpContext); 265 ASSERT(Irp); 266 267 _SEH2_TRY { 268 269 AbsolutePathName.Buffer = 270 LocalPath.Buffer = NULL; 271 // If we were called with our file system device object instead of a 272 // volume device object, just complete this request with STATUS_SUCCESS. 273 if (!(PtrIrpContext->TargetDeviceObject->DeviceExtension)) { 274 275 ReturnedInformation = FILE_OPENED; 276 try_return(RC = STATUS_SUCCESS); 277 } 278 279 AbsolutePathName.Length = AbsolutePathName.MaximumLength = 280 LocalPath.Length = LocalPath.MaximumLength = 0; 281 // First, get a pointer to the current I/O stack location 282 IrpSp = IoGetCurrentIrpStackLocation(Irp); 283 ASSERT(IrpSp); 284 285 // If the caller cannot block, post the request to be handled 286 // asynchronously 287 if (!(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK)) { 288 // We must defer processing of this request since we could 289 // block anytime while performing the create/open ... 290 ASSERT(FALSE); 291 RC = UDFPostRequest(PtrIrpContext, Irp); 292 try_return(RC); 293 } 294 295 // Now, we can obtain the parameters specified by the user. 296 // Note that the file object is the new object created by the 297 // I/O Manager in anticipation that this create/open request 298 // will succeed. 299 PtrNewFileObject = IrpSp->FileObject; 300 TargetObjectName = PtrNewFileObject->FileName; 301 PtrRelatedFileObject = PtrNewFileObject->RelatedFileObject; 302 303 // If a related file object is present, get the pointers 304 // to the CCB and the FCB for the related file object 305 if (PtrRelatedFileObject) { 306 PtrRelatedCCB = (PtrUDFCCB)(PtrRelatedFileObject->FsContext2); 307 ASSERT(PtrRelatedCCB); 308 ASSERT(PtrRelatedCCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_CCB); 309 // each CCB in turn points to a FCB 310 PtrRelatedFCB = PtrRelatedCCB->Fcb; 311 ASSERT(PtrRelatedFCB); 312 ASSERT((PtrRelatedFCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB) 313 ||(PtrRelatedFCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB)); 314 RelatedObjectName = PtrRelatedFileObject->FileName; 315 if (!(RelatedObjectName.Length) || (RelatedObjectName.Buffer[0] != L'\\')) { 316 if(PtrRelatedFCB->FCBName) 317 RelatedObjectName = PtrRelatedFCB->FCBName->ObjectName; 318 } 319 } 320 321 // Allocation size is only used if a new file is created 322 // or a file is superseded. 323 AllocationSize = Irp->Overlay.AllocationSize.QuadPart; 324 325 // Get a ptr to the supplied security context 326 PtrSecurityContext = IrpSp->Parameters.Create.SecurityContext; 327 AccessState = PtrSecurityContext->AccessState; 328 329 // The desired access can be obtained from the SecurityContext 330 DesiredAccess = PtrSecurityContext->DesiredAccess; 331 332 // Two values are supplied in the Create.Options field: 333 // (a) the actual user supplied options 334 // (b) the create disposition 335 RequestedOptions = (IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS); 336 337 // The file disposition is packed with the user options ... 338 // Disposition includes FILE_SUPERSEDE, FILE_OPEN_IF, etc. 339 RequestedDisposition = (IrpSp->Parameters.Create.Options >> 24);// & 0xFF; 340 341 //#ifdef UDF_LOG_CREATE_DISPOSITION 342 switch(RequestedDisposition) { 343 case FILE_SUPERSEDE: 344 AdPrint((" Dispos: FILE_SUPERSEDE\n")); 345 break; 346 case FILE_OPEN: 347 AdPrint((" Dispos: FILE_OPEN\n")); 348 break; 349 case FILE_CREATE: 350 AdPrint((" Dispos: FILE_CREATE\n")); 351 break; 352 case FILE_OPEN_IF: 353 AdPrint((" Dispos: FILE_OPEN_IF\n")); 354 break; 355 case FILE_OVERWRITE: 356 AdPrint((" Dispos: FILE_OVERWRITE\n")); 357 break; 358 case FILE_OVERWRITE_IF: 359 AdPrint((" Dispos: FILE_OVERWRITE_IF\n")); 360 break; 361 default: 362 AdPrint((" Dispos: *** Unknown ***\n")); 363 break; 364 } 365 //#endif // UDF_LOG_CREATE_DISPOSITION 366 367 FileAttributes = (USHORT)(IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS); 368 ShareAccess = IrpSp->Parameters.Create.ShareAccess; 369 370 // If the FSD does not support EA manipulation, we might return 371 // invalid parameter if the following are supplied. 372 // EA arguments are only used if a new file is created or a file is 373 // superseded 374 375 // But some applications _require_ EA support 376 // (Notepad... rather strange, isn't it ?) 377 378 // So, for such stupid ones 379 // !!! We shall ignore these parameters !!! 380 381 // PtrExtAttrBuffer = (struct _FILE_FULL_EA_INFORMATION *) Irp->AssociatedIrp.SystemBuffer; 382 // ExtAttrLength = IrpSp->Parameters.Create.EaLength; 383 384 // Get the options supplied by the user 385 386 #define OpenForBackup (RequestedOptions & FILE_OPEN_FOR_BACKUP_INTENT) 387 // User specifies that returned object MUST be a directory. 388 // Lack of presence of this flag does not mean it *cannot* be a 389 // directory *unless* FileOnlyRequested is set (see below) 390 391 // Presence of the flag however, does require that the returned object be 392 // a directory (container) object. 393 #define DirectoryOnlyRequested (RequestedOptions & FILE_DIRECTORY_FILE) 394 395 // User specifies that returned object MUST NOT be a directory. 396 // Lack of presence of this flag does not mean it *cannot* be a 397 // file *unless* DirectoryOnlyRequested is set (see above). 398 399 // Presence of the flag however does require that the returned object be 400 // a simple file (non-container) object. 401 #define FileOnlyRequested (RequestedOptions & FILE_NON_DIRECTORY_FILE) 402 403 // We cannot cache the file if the following flag is set. 404 // However, things do get a little bit interesting if caching 405 // has been already initiated due to a previous open ... 406 // (maintaining consistency then becomes a little bit more 407 // of a headache - see read/write file descriptions) 408 #define NoBufferingSpecified (RequestedOptions & FILE_NO_INTERMEDIATE_BUFFERING) 409 410 // Write-through simply means that the FSD must *not* return from 411 // a user write request until the data has been flushed to secondary 412 // storage (either to disks directly connected to the node or across 413 // the network in the case of a redirector) 414 WriteThroughRequested = (RequestedOptions & FILE_WRITE_THROUGH) ? TRUE : FALSE; 415 416 #define SequentialIoRequested (RequestedOptions & FILE_SEQUENTIAL_ONLY ? TRUE : FALSE) 417 418 // Not all of the native file system implementations support 419 // the delete-on-close option. All this means is that after the 420 // last close on the FCB has been performed, the FSD should 421 // delete the file. It simply saves the caller from issuing a 422 // separate delete request. Also, some FSD implementations might choose 423 // to implement a Windows NT idiosyncratic behavior wherein we 424 // could create such "delete-on-close" marked files under directories 425 // marked for deletion. Ordinarily, a FSD will not allow us to create 426 // a new file under a directory that has been marked for deletion. 427 DeleteOnCloseSpecified = (IrpSp->Parameters.Create.Options & FILE_DELETE_ON_CLOSE) ? TRUE : FALSE; 428 429 if(DeleteOnCloseSpecified) { 430 AdPrint((" DeleteOnClose\n")); 431 } 432 433 #define NoExtAttrKnowledge /*(RequestedOptions & FILE_NO_EA_KNOWLEDGE) ?*/ TRUE /*: FALSE*/ 434 435 // The following flag is only used by the LAN Manager redirector 436 // to initiate a "new mapping" to a remote share. Typically, 437 // a FSD will not see this flag (especially disk based FSD's) 438 // CreateTreeConnection = (RequestedOptions & FILE_CREATE_TREE_CONNECTION) ? TRUE : FALSE; 439 440 // The NTFS file system for exmaple supports the OpenByFileId option. 441 // The FSD may also be able to associate a unique numerical ID with 442 // an on-disk object. The caller would get this ID in a "query file 443 // information" call. 444 445 // Later, the caller might decide to reopen the object, this time 446 // though it may supply the FSD with the file identifier instead of 447 // a file/path name. 448 #define OpenByFileId (RequestedOptions & FILE_OPEN_BY_FILE_ID) 449 450 // Are we dealing with a page file? 451 PageFileManipulation = (IrpSp->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE; 452 453 // The open target directory flag is used as part of the sequence of 454 // operations performed by the I/O Manager is response to a file/dir 455 // rename operation. See the explanation in the book for details. 456 OpenTargetDirectory = (IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE; 457 458 // If the FSD supports case-sensitive file name checks, we may 459 // choose to honor the following flag ... 460 IgnoreCase = (IrpSp->Flags & SL_CASE_SENSITIVE) ? FALSE : TRUE; 461 462 // Ensure that the operation has been directed to a valid VCB ... 463 Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); 464 ASSERT(Vcb); 465 ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); 466 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; 467 468 WriteThroughRequested = WriteThroughRequested || 469 (Vcb->CompatFlags & UDF_VCB_IC_FORCE_WRITE_THROUGH); 470 471 // Do some preliminary checks to make sure the operation is supported. 472 // We fail in the following cases immediately. 473 // - Open a paging file. 474 // - Open a file with Eas. 475 if(PageFileManipulation) { 476 ReturnedInformation = 0; 477 AdPrint(("Can't create a page file\n")); 478 try_return(RC = STATUS_ACCESS_DENIED); 479 } 480 if(ExtAttrLength) { 481 ReturnedInformation = 0; 482 AdPrint(("Can't create file with EAs\n")); 483 try_return(RC = STATUS_EAS_NOT_SUPPORTED); 484 } 485 486 UDFFlushTryBreak(Vcb); 487 488 if (Vcb->SoftEjectReq) { 489 AdPrint((" Eject requested\n")); 490 ReturnedInformation = FILE_DOES_NOT_EXIST; 491 try_return(RC = STATUS_FILE_INVALID); 492 } 493 494 // If the volume has been locked, fail the request 495 if ((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) && 496 (Vcb->VolumeLockPID != GetCurrentPID())) { 497 AdPrint((" Volume is locked\n")); 498 RC = STATUS_ACCESS_DENIED; 499 try_return(RC); 500 } 501 // We need EXCLUSIVE access to Vcb to avoid parallel calls to UDFVerifyVcb() 502 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 503 AcquiredVcb = TRUE; 504 505 // Disk based file systems might decide to verify the logical volume 506 // (if required and only if removable media are supported) at this time 507 RC = UDFVerifyVcb(PtrIrpContext,Vcb); 508 if(!NT_SUCCESS(RC)) 509 try_return(RC); 510 511 UDFConvertExclusiveToSharedLite(&(Vcb->VCBResource)); 512 513 ASSERT(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED); 514 515 // We fail in the following cases for Read-Only volumes 516 // - Open a target directory. 517 // - Create a file. 518 if( 519 ( 520 ((Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) && 521 (Vcb->CompatFlags & UDF_VCB_IC_DIRTY_RO)) 522 #ifndef UDF_READ_ONLY_BUILD 523 || (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) 524 #endif //UDF_READ_ONLY_BUILD 525 ) && 526 (DeleteOnCloseSpecified || 527 OpenTargetDirectory || 528 (RequestedDisposition == FILE_CREATE) || 529 (RequestedDisposition == FILE_OVERWRITE) || 530 (RequestedDisposition == FILE_OVERWRITE_IF) || 531 (RequestedDisposition == FILE_SUPERSEDE) || 532 AllocationSize) ) { 533 ReturnedInformation = 0; 534 AdPrint((" Write protected or dirty\n")); 535 try_return(RC = STATUS_MEDIA_WRITE_PROTECTED); 536 } 537 538 /* if(DesiredAccess & (FILE_READ_EA | FILE_WRITE_EA)) { 539 ReturnedInformation = 0; 540 AdPrint((" EAs not supported\n")); 541 try_return(RC = STATUS_ACCESS_DENIED); 542 }*/ 543 544 // **************** 545 // If a Volume open is requested, satisfy it now 546 // **************** 547 if (!(PtrNewFileObject->FileName.Length) && (!PtrRelatedFileObject || 548 (PtrRelatedFCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB))) { 549 550 BOOLEAN UndoLock = FALSE; 551 552 AdPrint((" Opening Volume\n")); 553 // If the supplied file name is NULL *and* either there exists 554 // no related file object *or* if a related file object was supplied 555 // but it too refers to a previously opened instance of a logical 556 // volume, this open must be for a logical volume. 557 558 // Note: the FSD might decide to do "special" things (whatever they 559 // might be) in response to an open request for the logical volume. 560 561 // Logical volume open requests are done primarily to get/set volume 562 // information, lock the volume, dismount the volume (using the IOCTL 563 // FSCTL_DISMOUNT_VOLUME) etc. 564 565 // If a volume open is requested, perform checks to ensure that 566 // invalid options have not also been specified ... 567 if ((OpenTargetDirectory) || (PtrExtAttrBuffer)) { 568 try_return(RC = STATUS_INVALID_PARAMETER); 569 } 570 571 if (DirectoryOnlyRequested) { 572 // a volume is not a directory 573 try_return(RC = STATUS_NOT_A_DIRECTORY); 574 } 575 576 #ifndef UDF_READ_ONLY_BUILD 577 if (DeleteOnCloseSpecified) { 578 // delete volume.... hmm 579 try_return(RC = STATUS_CANNOT_DELETE); 580 } 581 582 if ((RequestedDisposition != FILE_OPEN) && (RequestedDisposition != FILE_OPEN_IF)) { 583 // cannot create a new volume, I'm afraid ... 584 ReturnedInformation = FILE_DOES_NOT_EXIST; 585 try_return(RC = STATUS_ACCESS_DENIED); 586 } 587 #endif //UDF_READ_ONLY_BUILD 588 589 UDFPrint((" ShareAccess %x, DesiredAccess %x\n", ShareAccess, DesiredAccess)); 590 /* 591 if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE)) && 592 !(DesiredAccess & (FILE_GENERIC_WRITE & ~SYNCHRONIZE)) && 593 (ShareAccess & FILE_SHARE_READ) ) { 594 */ 595 if(!(DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) && 596 (ShareAccess & FILE_SHARE_READ) ) { 597 UDFPrint((" R/O volume open\n")); 598 } else { 599 600 UDFPrint((" R/W volume open\n")); 601 if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) { 602 UDFPrint((" media-ro\n")); 603 try_return(RC = STATUS_MEDIA_WRITE_PROTECTED); 604 } 605 } 606 607 if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE)) && 608 !(DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) && 609 (ShareAccess & FILE_SHARE_READ) ) { 610 // do nothing 611 } else { 612 613 if(!(ShareAccess & FILE_SHARE_READ) || 614 (DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) ) { 615 // As soon as OpenVolume flushes the volume 616 // we should complete all pending requests (Close) 617 618 UDFPrint((" set UDF_IRP_CONTEXT_FLUSH2_REQUIRED\n")); 619 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FLUSH2_REQUIRED; 620 621 /* 622 UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); 623 UDFReleaseResource(&(Vcb->VCBResource)); 624 AcquiredVcb = FALSE; 625 626 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) { 627 UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); 628 } 629 #ifdef UDF_DELAYED_CLOSE 630 UDFCloseAllDelayed(Vcb); 631 #endif //UDF_DELAYED_CLOSE 632 633 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 634 AcquiredVcb = TRUE; 635 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); 636 */ 637 } 638 } 639 640 // If the user does not want to share write or delete then we will try 641 // and take out a lock on the volume. 642 if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE))) { 643 // Do a quick check here for handles on exclusive open. 644 if ((Vcb->VCBHandleCount) && 645 !(ShareAccess & FILE_SHARE_READ)) { 646 // Sharing violation 647 UDFPrint((" !FILE_SHARE_READ + open handles (%d)\n", Vcb->VCBHandleCount)); 648 try_return(RC = STATUS_SHARING_VIOLATION); 649 } 650 if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_FLUSH2_REQUIRED) { 651 652 UDFPrint((" perform flush\n")); 653 PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_FLUSH2_REQUIRED; 654 655 UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); 656 UDFReleaseResource(&(Vcb->VCBResource)); 657 AcquiredVcb = FALSE; 658 659 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) { 660 UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); 661 } 662 #ifdef UDF_DELAYED_CLOSE 663 UDFCloseAllDelayed(Vcb); 664 #endif //UDF_DELAYED_CLOSE 665 666 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 667 AcquiredVcb = TRUE; 668 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); 669 670 UDFFlushLogicalVolume(NULL, NULL, Vcb); 671 672 if((ShareAccess & FILE_SHARE_READ) && 673 ((Vcb->VCBOpenCount - UDF_RESIDUAL_REFERENCE) != (Vcb->VCBOpenCountRO))) { 674 UDFPrint((" FILE_SHARE_READ + R/W handles: %d(%d) -> STATUS_SHARING_VIOLATION ?\n", 675 Vcb->VCBOpenCount - UDF_RESIDUAL_REFERENCE, 676 Vcb->VCBOpenCountRO)); 677 /* we shall not check it here, let System do it in IoCheckShareAccess() */ 678 //try_return(RC = STATUS_SHARING_VIOLATION); 679 } 680 } 681 // Lock the volume 682 if(!(ShareAccess & FILE_SHARE_READ)) { 683 UDFPrint((" set Lock\n")); 684 Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_LOCKED; 685 Vcb->VolumeLockFileObject = PtrNewFileObject; 686 UndoLock = TRUE; 687 } else 688 if(DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) { 689 UDFPrint((" set UDF_IRP_CONTEXT_FLUSH_REQUIRED\n")); 690 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FLUSH_REQUIRED; 691 } 692 } 693 694 PtrNewFcb = (PtrUDFFCB)Vcb; 695 ASSERT(!(PtrNewFcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE)); 696 697 RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); 698 if (!NT_SUCCESS(RC)) 699 goto op_vol_accs_dnd; 700 701 PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); 702 if(PtrNewCcb) PtrNewCcb->CCBFlags |= UDF_CCB_VOLUME_OPEN; 703 // Check _Security_ 704 RC = UDFCheckAccessRights(NULL, AccessState, Vcb->RootDirFCB, PtrNewCcb, DesiredAccess, ShareAccess); 705 if (!NT_SUCCESS(RC)) { 706 AdPrint((" Access violation (Volume)\n")); 707 goto op_vol_accs_dnd; 708 } 709 // Check _ShareAccess_ 710 RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); 711 if(!NT_SUCCESS(RC)) { 712 AdPrint((" Sharing violation (Volume)\n")); 713 op_vol_accs_dnd: 714 if(UndoLock) { 715 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED; 716 Vcb->VolumeLockFileObject = NULL; 717 } 718 try_return(RC); 719 } 720 721 // NoBufferingSpecified = TRUE; See #define above 722 RequestedOptions |= FILE_NO_INTERMEDIATE_BUFFERING; 723 724 ReturnedInformation = FILE_OPENED; 725 UDFNotifyVolumeEvent(PtrNewFileObject, FSRTL_VOLUME_LOCK); 726 try_return(RC); 727 } 728 729 if((Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && 730 (!(Vcb->CompatFlags & UDF_VCB_IC_SHOW_BLANK_CD) || UDFGlobalData.AutoFormatCount)) { 731 ReturnedInformation = 0; 732 AdPrint((" Can't open anything on blank volume ;)\n")); 733 try_return(RC = STATUS_OBJECT_NAME_NOT_FOUND); 734 } 735 736 if(UdfIllegalFcbAccess(Vcb,DesiredAccess)) { 737 ReturnedInformation = 0; 738 AdPrint((" Illegal share access\n")); 739 try_return(RC = STATUS_ACCESS_DENIED); 740 } 741 // we could mount blank R/RW media in order to allow 742 // user-mode applications to get access with Write privileges 743 ASSERT(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED); 744 745 // we should check appropriate privilege if OpenForBackup requested 746 if(OpenForBackup) { 747 if (!SeSinglePrivilegeCheck(SeExports->SeBackupPrivilege, UserMode)) { 748 try_return(RC = STATUS_PRIVILEGE_NOT_HELD); 749 } 750 } 751 752 // The FSD might wish to implement the open-by-id option. The "id" 753 // is some unique numerical representation of the on-disk object. 754 // The caller then therefore give us this file id and the FSD 755 // should be completely capable of "opening" the object (it must 756 // exist since the caller received an id for the object from the 757 // FSD in a "query file" call ... 758 759 // If the file has been deleted in the meantime, we'll return 760 // "not found" 761 762 // **************** 763 // Open by FileID 764 // **************** 765 if (OpenByFileId) { 766 // perform the open ... 767 PUNICODE_STRING TmpPath; 768 LONGLONG Id; 769 770 UDFPrint((" open by File ID\n")); 771 if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { 772 ReturnedInformation = 0; 773 AdPrint((" Can't open by FileID on blank volume ;)\n")); 774 try_return(RC = STATUS_OBJECT_NAME_NOT_FOUND); 775 } 776 777 if (TargetObjectName.Length != sizeof(FILE_ID)) { 778 AdPrint((" Invalid file ID\n")); 779 try_return(RC = STATUS_INVALID_PARAMETER); 780 } 781 Id = *((FILE_ID*)(TargetObjectName.Buffer)); 782 AdPrint((" Opening by ID %8.8x%8.8x\n", (ULONG)(Id>>32), (ULONG)Id)); 783 if ((RequestedDisposition != FILE_OPEN) && 784 (RequestedDisposition != FILE_OPEN_IF)) { 785 AdPrint((" Illegal disposition for ID open\n")); 786 try_return(RC = STATUS_ACCESS_DENIED); 787 } 788 789 RC = UDFGetOpenParamsByFileId(Vcb, Id, &TmpPath, &IgnoreCase); 790 if(!NT_SUCCESS(RC)) { 791 AdPrint((" ID open failed\n")); 792 try_return(RC); 793 } 794 // simulate absolute path open 795 /* if(!NT_SUCCESS(RC = MyInitUnicodeString(&TargetObjectName, L"")) || 796 !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&TargetObjectName, TmpPath, MEM_USABS_TAG))) {*/ 797 if(!NT_SUCCESS(RC = MyCloneUnicodeString(&TargetObjectName, TmpPath))) { 798 AdPrint((" Init String failed\n")); 799 try_return(RC); 800 } 801 //ASSERT(TargetObjectName.Buffer); 802 AbsolutePathName = TargetObjectName; 803 PtrRelatedFileObject = NULL; 804 } else 805 // **************** 806 // Relative open 807 // **************** 808 // Now determine the starting point from which to begin the parsing 809 if (PtrRelatedFileObject) { 810 // We have a user supplied related file object. 811 // This implies a "relative" open i.e. relative to the directory 812 // represented by the related file object ... 813 814 UDFPrint((" PtrRelatedFileObject %x, FCB %x\n", PtrRelatedFileObject, PtrRelatedFCB)); 815 // Note: The only purpose FSD implementations ever have for 816 // the related file object is to determine whether this 817 // is a relative open or not. At all other times (including 818 // during I/O operations), this field is meaningless from 819 // the FSD's perspective. 820 if (!(PtrRelatedFCB->FCBFlags & UDF_FCB_DIRECTORY)) { 821 // we must have a directory as the "related" object 822 RC = STATUS_INVALID_PARAMETER; 823 AdPrint((" Related object must be a directory\n")); 824 AdPrint((" Flags %x\n", PtrRelatedFCB->FCBFlags)); 825 _SEH2_TRY { 826 AdPrint((" ObjName %x, ", PtrRelatedFCB->FCBName->ObjectName)); 827 AdPrint((" Name %S\n", PtrRelatedFCB->FCBName->ObjectName.Buffer)); 828 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 829 AdPrint((" exception when printing name\n")); 830 } _SEH2_END; 831 try_return(RC); 832 } 833 834 // So we have a directory, ensure that the name begins with 835 // a "\" i.e. begins at the root and does *not* begin with a "\\" 836 // NOTE: This is just an example of the kind of path-name string 837 // validation that a FSD must do. Although the remainder of 838 // the code may not include such checks, any commercial 839 // FSD *must* include such checking (no one else, including 840 // the I/O Manager will perform checks on the FSD's behalf) 841 if (!(RelatedObjectName.Length) || (RelatedObjectName.Buffer[0] != L'\\')) { 842 AdPrint((" Wrong pathname (1)\n")); 843 RC = STATUS_INVALID_PARAMETER; 844 try_return(RC); 845 } 846 // similarly, if the target file name starts with a "\", it 847 // is wrong since the target file name can no longer be absolute 848 ASSERT(TargetObjectName.Buffer || !TargetObjectName.Length); 849 if (TargetObjectName.Length && (TargetObjectName.Buffer[0] == L'\\')) { 850 AdPrint((" Wrong pathname (2)\n")); 851 RC = STATUS_INVALID_PARAMETER; 852 try_return(RC); 853 } 854 // Create an absolute path-name. We could potentially use 855 // the absolute path-name if we cache previously opened 856 // file/directory object names. 857 /* if(!NT_SUCCESS(RC = MyInitUnicodeString(&AbsolutePathName, L"")) || 858 !NT_SUCCESS(RC MyAppendUnicodeStringToStringTag(&AbsolutePathName, &RelatedObjectName, MEM_USABS_TAG)))*/ 859 if(!NT_SUCCESS(RC = MyCloneUnicodeString(&AbsolutePathName, &RelatedObjectName))) 860 try_return(RC); 861 if(RelatedObjectName.Length && 862 (RelatedObjectName.Buffer[ (RelatedObjectName.Length/sizeof(WCHAR)) - 1 ] != L'\\')) { 863 RC = MyAppendUnicodeToString(&AbsolutePathName, L"\\"); 864 if(!NT_SUCCESS(RC)) try_return(RC); 865 } 866 if(!AbsolutePathName.Length || 867 (AbsolutePathName.Buffer[ (AbsolutePathName.Length/sizeof(WCHAR)) - 1 ] != L'\\')) { 868 ASSERT(TargetObjectName.Buffer); 869 if(TargetObjectName.Length && TargetObjectName.Buffer[0] != L'\\') { 870 RC = MyAppendUnicodeToString(&AbsolutePathName, L"\\"); 871 if(!NT_SUCCESS(RC)) try_return(RC); 872 } 873 } 874 //ASSERT(TargetObjectName.Buffer); 875 RC = MyAppendUnicodeStringToStringTag(&AbsolutePathName, &TargetObjectName, MEM_USABS_TAG); 876 if(!NT_SUCCESS(RC)) 877 try_return(RC); 878 879 } else { 880 // **************** 881 // Absolute open 882 // **************** 883 // The suplied path-name must be an absolute path-name i.e. 884 // starting at the root of the file system tree 885 UDFPrint((" Absolute open\n")); 886 ASSERT(TargetObjectName.Buffer); 887 if (!TargetObjectName.Length || TargetObjectName.Buffer[0] != L'\\') { 888 AdPrint((" Wrong target name (1)\n")); 889 try_return(RC = STATUS_INVALID_PARAMETER); 890 } 891 /* if(!NT_SUCCESS(RC = MyInitUnicodeString(&AbsolutePathName, L"")) || 892 !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&AbsolutePathName, &TargetObjectName, MEM_USABS_TAG)))*/ 893 ASSERT(TargetObjectName.Buffer); 894 if(!NT_SUCCESS(RC = MyCloneUnicodeString(&AbsolutePathName, &TargetObjectName))) 895 try_return(RC); 896 } 897 // Win 32 protection :) 898 if ((AbsolutePathName.Length >= sizeof(WCHAR)*2) && 899 (AbsolutePathName.Buffer[1] == L'\\') && 900 (AbsolutePathName.Buffer[0] == L'\\')) { 901 902 // If there are still two beginning backslashes, the name is bogus. 903 if ((AbsolutePathName.Length > 2*sizeof(WCHAR)) && 904 (AbsolutePathName.Buffer[2] == L'\\')) { 905 AdPrint((" Wrong target name (2)\n")); 906 try_return (RC = STATUS_OBJECT_NAME_INVALID); 907 } 908 // Slide the name down in the buffer. 909 RtlMoveMemory( AbsolutePathName.Buffer, 910 AbsolutePathName.Buffer + 1, 911 AbsolutePathName.Length ); // .Length includes 912 // NULL-terminator 913 AbsolutePathName.Length -= sizeof(WCHAR); 914 } 915 if ( (AbsolutePathName.Length > sizeof(WCHAR) ) && 916 (AbsolutePathName.Buffer[ (AbsolutePathName.Length/sizeof(WCHAR)) - 1 ] == L'\\') ) { 917 918 AbsolutePathName.Length -= sizeof(WCHAR); 919 } 920 // TERMINATOR (2) ;) 921 AbsolutePathName.Buffer[AbsolutePathName.Length/sizeof(WCHAR)] = 0; 922 923 // Sometimes W2000 decides to duplicate handle of 924 // already opened File/Dir. In this case it sends us 925 // RelatedFileObject & specifies zero-filled RelativePath 926 if(!TargetObjectName.Length) { 927 TargetObjectName = AbsolutePathName; 928 OpenExisting = TRUE; 929 } 930 //ASSERT(TargetObjectName.Buffer); 931 932 // **************** 933 // First, check if the caller simply wishes to open the Root 934 // of the file system tree. 935 // **************** 936 if (AbsolutePathName.Length == sizeof(WCHAR)) { 937 AdPrint((" Opening RootDir\n")); 938 // this is an open of the root directory, ensure that the caller 939 // has not requested a file only 940 if (FileOnlyRequested || (RequestedDisposition == FILE_SUPERSEDE) || 941 (RequestedDisposition == FILE_OVERWRITE) || 942 (RequestedDisposition == FILE_OVERWRITE_IF)) { 943 AdPrint((" Can't overwrite RootDir\n")); 944 RC = STATUS_FILE_IS_A_DIRECTORY; 945 try_return(RC); 946 } 947 948 #if 0 949 CollectStatistics(Vcb, MetaDataReads); 950 #endif 951 952 if (DeleteOnCloseSpecified) { 953 // delete RootDir.... rather strange idea... I dislike it 954 AdPrint((" Can't delete RootDir\n")); 955 try_return(RC = STATUS_CANNOT_DELETE); 956 } 957 958 PtrNewFcb = Vcb->RootDirFCB; 959 RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); 960 if(!NT_SUCCESS(RC)) try_return(RC); 961 // DbgPrint("UDF: Open/Create RootDir : ReferenceCount %x\n",PtrNewFcb->ReferenceCount); 962 UDFReferenceFile__(PtrNewFcb->FileInfo); 963 PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); 964 TreeLength = 1; 965 966 RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); 967 if(!NT_SUCCESS(RC)) { 968 AdPrint((" Access/Sharing violation (RootDir)\n")); 969 try_return(RC); 970 } 971 972 ReturnedInformation = FILE_OPENED; 973 974 try_return(RC); 975 } // end of OpenRootDir 976 977 _SEH2_TRY { 978 AdPrint((" Opening file %ws %8.8x\n",AbsolutePathName.Buffer, PtrNewFileObject)); 979 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 980 AdPrint((" Exception when printing FN\n")); 981 } _SEH2_END; 982 // **************** 983 // Check if we have DuplicateHandle (or Reopen) request 984 // **************** 985 if(OpenExisting) { 986 987 // BrutePoint(); 988 // We don't handle OpenTargetDirectory in this case 989 if(OpenTargetDirectory) 990 try_return(RC = STATUS_INVALID_PARAMETER); 991 992 // Init environment to simulate normal open procedure behavior 993 /* if(!NT_SUCCESS(RC = MyInitUnicodeString(&LocalPath, L"")) || 994 !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&LocalPath, &TargetObjectName, MEM_USLOC_TAG)))*/ 995 ASSERT(TargetObjectName.Buffer); 996 if(!NT_SUCCESS(RC = MyCloneUnicodeString(&LocalPath, &TargetObjectName))) 997 try_return(RC); 998 999 ASSERT(PtrRelatedFCB); 1000 RelatedFileInfo = PtrRelatedFCB->FileInfo; 1001 1002 RC = STATUS_SUCCESS; 1003 NewFileInfo = 1004 LastGoodFileInfo = RelatedFileInfo; 1005 1006 RelatedFileInfo = 1007 OldRelatedFileInfo = RelatedFileInfo->ParentFile; 1008 PtrRelatedFCB = PtrRelatedFCB->ParentFcb; 1009 // prevent releasing parent structures 1010 UDFAcquireParent(RelatedFileInfo, &Res1, &Res2); 1011 TreeLength++; 1012 1013 if(Res1) UDFReleaseResource(Res1); 1014 if(Res2) UDFReleaseResource(Res2); 1015 1016 UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->NTRequiredFCB); 1017 UDFAcquireResourceExclusive(Res2 = &(RelatedFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); 1018 PtrNewFcb = NewFileInfo->Fcb; 1019 1020 UDF_CHECK_PAGING_IO_RESOURCE(PtrNewFcb->NTRequiredFCB); 1021 UDFAcquireResourceExclusive(Res1 = &(PtrNewFcb->NTRequiredFCB->MainResource),TRUE); 1022 UDFReferenceFile__(NewFileInfo); 1023 TreeLength++; 1024 1025 goto AlreadyOpened; 1026 } 1027 1028 if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { 1029 ReturnedInformation = 0; 1030 AdPrint((" Can't open File on blank volume ;)\n")); 1031 ReturnedInformation = FILE_DOES_NOT_EXIST; 1032 try_return(RC = STATUS_OBJECT_NAME_NOT_FOUND); 1033 } 1034 1035 //AdPrint((" Opening file %ws %8.8x\n",AbsolutePathName.Buffer, PtrNewFileObject)); 1036 1037 if(AbsolutePathName.Length > UDF_X_PATH_LEN*sizeof(WCHAR)) { 1038 try_return(RC = STATUS_OBJECT_NAME_INVALID); 1039 } 1040 1041 // validate path specified 1042 // (sometimes we can see here very strange characters ;) 1043 if(!UDFIsNameValid(&AbsolutePathName, &StreamOpen, &SNameIndex)) { 1044 AdPrint((" Absolute path is not valid\n")); 1045 try_return(RC = STATUS_OBJECT_NAME_INVALID); 1046 } 1047 if(StreamOpen && !UDFStreamsSupported(Vcb)) { 1048 ReturnedInformation = FILE_DOES_NOT_EXIST; 1049 try_return(RC = STATUS_OBJECT_NAME_INVALID); 1050 } 1051 1052 RC = MyInitUnicodeString(&LocalPath, L""); 1053 if(!NT_SUCCESS(RC)) 1054 try_return(RC); 1055 if (PtrRelatedFileObject) { 1056 // Our "start directory" is the one identified 1057 // by the related file object 1058 RelatedFileInfo = PtrRelatedFCB->FileInfo; 1059 if(RelatedFileInfo != Vcb->RootDirFCB->FileInfo) { 1060 RC = MyAppendUnicodeStringToStringTag(&LocalPath, &(PtrRelatedFCB->FCBName->ObjectName), MEM_USLOC_TAG); 1061 if(!NT_SUCCESS(RC)) 1062 try_return(RC); 1063 } 1064 if(TargetObjectName.Buffer != AbsolutePathName.Buffer) { 1065 ASSERT(TargetObjectName.Buffer); 1066 if(!NT_SUCCESS(RC = MyCloneUnicodeString(&TailName, &TargetObjectName))) { 1067 AdPrint((" Init String 'TargetObjectName' failed\n")); 1068 try_return(RC); 1069 } 1070 TailNameBuffer = TailName.Buffer; 1071 } else { 1072 TailName = AbsolutePathName; 1073 } 1074 } else { 1075 // Start at the root of the file system 1076 RelatedFileInfo = Vcb->RootDirFCB->FileInfo; 1077 TailName = AbsolutePathName; 1078 } 1079 1080 if(StreamOpen) { 1081 StreamName = AbsolutePathName; 1082 StreamName.Buffer += SNameIndex; 1083 StreamName.Length -= (USHORT)SNameIndex*sizeof(WCHAR); 1084 // if StreamOpen specified & stream name starts with NULL character 1085 // we should create Stream Dir at first 1086 TailName.Length -= (AbsolutePathName.Length - (USHORT)SNameIndex*sizeof(WCHAR)); 1087 AbsolutePathName.Length = (USHORT)SNameIndex*sizeof(WCHAR); 1088 } 1089 CurName.MaximumLength = TailName.MaximumLength; 1090 1091 RC = STATUS_SUCCESS; 1092 LastGoodName.Length = 0; 1093 LastGoodFileInfo = RelatedFileInfo; 1094 // reference RelatedObject to prevent releasing parent structures 1095 UDFAcquireParent(RelatedFileInfo, &Res1, &Res2); 1096 TreeLength++; 1097 1098 // go into a loop parsing the supplied name 1099 1100 // Note that we may have to "open" intermediate directory objects 1101 // while traversing the path. We should __try to reuse existing code 1102 // whenever possible therefore we should consider using a common 1103 // open routine regardless of whether the open is on behalf of the 1104 // caller or an intermediate (internal) open performed by the driver. 1105 1106 // **************** 1107 // now we'll parse path to desired file 1108 // **************** 1109 1110 while (TRUE) { 1111 1112 // remember last 'good' ('good' means NO ERRORS before) path tail 1113 if(NT_SUCCESS(RC)) { 1114 LastGoodTail = TailName; 1115 while(LastGoodTail.Buffer[0] == L'\\') { 1116 LastGoodTail.Buffer++; 1117 LastGoodTail.Length -= sizeof(WCHAR); 1118 } 1119 } 1120 // get next path part... 1121 TmpBuffer = TailName.Buffer; 1122 TailName.Buffer = UDFDissectName(TailName.Buffer,&(CurName.Length) ); 1123 TailName.Length -= (USHORT)((ULONG_PTR)(TailName.Buffer) - (ULONG_PTR)TmpBuffer); 1124 CurName.Buffer = TailName.Buffer - CurName.Length; 1125 CurName.Length *= sizeof(WCHAR); 1126 CurName.MaximumLength = CurName.Length + sizeof(WCHAR); 1127 // check if we have already opened the component before last one 1128 // in this case OpenTargetDir request will be served in a special 1129 // way... 1130 if(OpenTargetDirectory && NT_SUCCESS(RC) && !TailName.Length) { 1131 // check if we should open SDir.. 1132 if(!StreamOpen || 1133 (TailName.Buffer[0]!=L':')) { 1134 // no, we should not. Continue with OpenTargetDir 1135 break; 1136 } 1137 } 1138 1139 if( CurName.Length && 1140 (NT_SUCCESS(RC) || !StreamOpen)) { 1141 // ...wow! non-zero! try to open! 1142 if(!NT_SUCCESS(RC)) { 1143 AdPrint((" Error opening path component\n")); 1144 // we haven't reached last name part... hm.. 1145 // probably, the path specified is invalid.. 1146 // or we had a hard error... What else can we do ? 1147 // Only say ..CK OFF !!!! 1148 if(RC == STATUS_OBJECT_NAME_NOT_FOUND) 1149 RC = STATUS_OBJECT_PATH_NOT_FOUND; 1150 ReturnedInformation = FILE_DOES_NOT_EXIST; 1151 try_return(RC); 1152 } 1153 1154 ASSERT_REF(RelatedFileInfo->Fcb->ReferenceCount >= RelatedFileInfo->RefCount); 1155 1156 if(RelatedFileInfo && (TreeLength>1)) { 1157 // it was an internal Open operation. Thus, assume 1158 // RelatedFileInfo's Fcb to be valid 1159 RelatedFileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; 1160 RelatedFileInfo->Fcb->FCBFlags |= UDF_FCB_VALID; 1161 } 1162 // check path fragment size 1163 if(CurName.Length > UDF_X_NAME_LEN * sizeof(WCHAR)) { 1164 AdPrint((" Path component is too long\n")); 1165 try_return(RC = STATUS_OBJECT_NAME_INVALID); 1166 } 1167 // ...and now release previously acquired objects, 1168 if(Res1) UDFReleaseResource(Res1); 1169 if(Res2) { 1170 UDFReleaseResource(Res2); 1171 Res2 = NULL; 1172 } 1173 // acquire new _parent_ directory & try to open what 1174 // we want. 1175 1176 UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->NTRequiredFCB); 1177 UDFAcquireResourceExclusive(Res1 = &(RelatedFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); 1178 1179 // check traverse rights 1180 RC = UDFCheckAccessRights(NULL, NULL, RelatedFileInfo->Fcb, PtrRelatedCCB, FILE_TRAVERSE, 0); 1181 if(!NT_SUCCESS(RC)) { 1182 NewFileInfo = NULL; 1183 AdPrint((" Traverse check failed\n")); 1184 goto Skip_open_attempt; 1185 } 1186 // check if we should open normal File/Dir or SDir 1187 if(CurName.Buffer[0] != ':') { 1188 // standard open, nothing interesting.... 1189 RC = UDFOpenFile__(Vcb, 1190 IgnoreCase,TRUE,&CurName, 1191 RelatedFileInfo,&NewFileInfo,NULL); 1192 if(RC == STATUS_FILE_DELETED) { 1193 // file has gone, but system still remembers it... 1194 NewFileInfo = NULL; 1195 AdPrint((" File deleted\n")); 1196 RC = STATUS_ACCESS_DENIED; 1197 #ifdef UDF_DBG 1198 } else 1199 if(RC == STATUS_NOT_A_DIRECTORY) { 1200 AdPrint((" Not a directory\n")); 1201 #endif // UDF_DBG 1202 } else 1203 if(RC == STATUS_SHARING_PAUSED) { 1204 AdPrint((" Dloc is being initialized\n")); 1205 BrutePoint(); 1206 RC = STATUS_SHARING_VIOLATION; 1207 } 1208 } else { 1209 // And here we should open Stream Dir (if any, of cource) 1210 RC = UDFOpenStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo); 1211 if(NT_SUCCESS(RC)) { 1212 SuccessOpen_SDir: 1213 // this indicates that we needn't Stream Dir creation 1214 StreamExists = TRUE; 1215 StreamName.Buffer++; 1216 StreamName.Length-=sizeof(WCHAR); 1217 // update TailName 1218 TailName = StreamName; 1219 } else 1220 if(RC == STATUS_NOT_FOUND) { 1221 #ifndef UDF_READ_ONLY_BUILD 1222 // Stream Dir doesn't exist, but caller wants it to be 1223 // created. Lets try to help him... 1224 if((RequestedDisposition == FILE_CREATE) || 1225 (RequestedDisposition == FILE_OPEN_IF) || 1226 (RequestedDisposition == FILE_OVERWRITE_IF) || 1227 OpenTargetDirectory ) { 1228 RC = UDFCreateStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo); 1229 if(NT_SUCCESS(RC)) 1230 goto SuccessOpen_SDir; 1231 } 1232 #endif //UDF_READ_ONLY_BUILD 1233 } 1234 /* } else { 1235 AdPrint((" File deleted (2)\n")); 1236 RC = STATUS_ACCESS_DENIED;*/ 1237 } 1238 #if 0 1239 CollectStatistics(Vcb, MetaDataReads); 1240 #endif 1241 1242 Skip_open_attempt: 1243 1244 // check if we have successfully opened path component 1245 if(NT_SUCCESS(RC)) { 1246 // Yesss !!! 1247 if (!(PtrNewFcb = NewFileInfo->Fcb)) { 1248 // It is a first open operation 1249 // Allocate new FCB 1250 // Here we set FileObject pointer to NULL to avoid 1251 // new CCB allocation 1252 RC = UDFFirstOpenFile(Vcb, 1253 NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo, 1254 &LocalPath, &CurName); 1255 1256 if(!NT_SUCCESS(RC)) { 1257 BrutePoint(); 1258 AdPrint((" Can't perform FirstOpen\n")); 1259 UDFCloseFile__(Vcb, NewFileInfo); 1260 if(PtrNewFcb) UDFCleanUpFCB(PtrNewFcb); 1261 PtrNewFcb = NULL; 1262 NewFileInfo->Fcb = NULL; 1263 if(UDFCleanUpFile__(Vcb, NewFileInfo)) { 1264 MyFreePool__(NewFileInfo); 1265 NewFileInfo = NULL; 1266 } 1267 try_return(RC); 1268 } 1269 } else { 1270 // It is not a first open operation 1271 // Validate Fcb. It is possible to get 1272 // not completly initialized Fcb here. 1273 if(!(PtrNewFcb->FCBFlags & UDF_FCB_VALID)) { 1274 BrutePoint(); 1275 AdPrint((" Fcb not valid\n")); 1276 UDFCloseFile__(Vcb, NewFileInfo); 1277 PtrNewFcb = NULL; 1278 if(UDFCleanUpFile__(Vcb, NewFileInfo)) { 1279 MyFreePool__(NewFileInfo); 1280 NewFileInfo = NULL; 1281 } 1282 try_return(RC = STATUS_ACCESS_DENIED); 1283 } 1284 } 1285 // Acquire newly opened File... 1286 Res2 = Res1; 1287 UDF_CHECK_PAGING_IO_RESOURCE(NewFileInfo->Fcb->NTRequiredFCB); 1288 UDFAcquireResourceExclusive(Res1 = &(NewFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); 1289 // ...and reference it 1290 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); 1291 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); 1292 1293 ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); 1294 // update unwind information 1295 LastGoodFileInfo = NewFileInfo; 1296 LastGoodName = CurName; 1297 TreeLength++; 1298 // update current path 1299 if(!StreamOpen || 1300 ((CurName.Buffer[0] != L':') && 1301 (!LocalPath.Length || (LocalPath.Buffer[LocalPath.Length/sizeof(WCHAR)-1] != L':'))) ) { 1302 // we should not insert '\' before or after ':' 1303 ASSERT(!LocalPath.Length || 1304 (LocalPath.Buffer[LocalPath.Length/2-1] != L'\\')); 1305 RC = MyAppendUnicodeToString(&LocalPath, L"\\"); 1306 if(!NT_SUCCESS(RC)) try_return(RC); 1307 } 1308 RC = MyAppendUnicodeStringToStringTag(&LocalPath, &CurName, MEM_USLOC_TAG); 1309 if(!NT_SUCCESS(RC)) 1310 try_return(RC); 1311 // DbgPrint("UDF: Open/Create File %ws : ReferenceCount %x\n",CurName.Buffer,PtrNewFcb->ReferenceCount); 1312 } else { 1313 AdPrint((" Can't open file\n")); 1314 // We have failed durring last Open attempt 1315 // Roll back to last good state 1316 PtrUDFNTRequiredFCB NtReqFcb = NULL; 1317 // Cleanup FileInfo if any 1318 if(NewFileInfo) { 1319 PtrNewFcb = NewFileInfo->Fcb; 1320 // acquire appropriate resource if possible 1321 if(PtrNewFcb && 1322 PtrNewFcb->NTRequiredFCB) { 1323 NtReqFcb = PtrNewFcb->NTRequiredFCB; 1324 Res2 = Res1; 1325 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 1326 UDFAcquireResourceExclusive(Res1 = &(NtReqFcb->MainResource),TRUE); 1327 } 1328 // cleanup pointer to Fcb in FileInfo to allow 1329 // UDF_INFO package release FileInfo if there are 1330 // no more references 1331 if(PtrNewFcb && 1332 !PtrNewFcb->ReferenceCount && 1333 !PtrNewFcb->OpenHandleCount) { 1334 NewFileInfo->Fcb = NULL; 1335 } 1336 // cleanup pointer to CommonFcb in Dloc to allow 1337 // UDF_INFO package release Dloc if there are 1338 // no more references 1339 if(NewFileInfo->Dloc && 1340 !NewFileInfo->Dloc->LinkRefCount && 1341 (!PtrNewFcb || !PtrNewFcb->ReferenceCount)) { 1342 NewFileInfo->Dloc->CommonFcb = NULL; 1343 } 1344 // try to release FileInfo 1345 if(UDFCleanUpFile__(Vcb, NewFileInfo)) { 1346 ASSERT(!PtrNewFcb); 1347 if(PtrNewFcb) { 1348 BrutePoint(); 1349 UDFCleanUpFCB(PtrNewFcb); 1350 } 1351 MyFreePool__(NewFileInfo); 1352 } else { 1353 // if we can't release FileInfo 1354 // restore pointers to Fcb & CommonFcb in 1355 // FileInfo & Dloc 1356 NewFileInfo->Fcb = PtrNewFcb; 1357 if(NtReqFcb) 1358 NewFileInfo->Dloc->CommonFcb = NtReqFcb; 1359 } 1360 // forget about last FileInfo & Fcb, 1361 // further unwind staff needs only last good 1362 // structures 1363 PtrNewFcb = NULL; 1364 NewFileInfo = NULL; 1365 } 1366 } 1367 1368 // should return error if 'delete in progress' 1369 if(LastGoodFileInfo->Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE | 1370 UDF_FCB_DELETED | 1371 UDF_FCB_POSTED_RENAME)) { 1372 AdPrint((" Return DeletePending (no err)\n")); 1373 try_return(RC = STATUS_DELETE_PENDING); 1374 } 1375 // update last good state information... 1376 OldRelatedFileInfo = RelatedFileInfo; 1377 RelatedFileInfo = NewFileInfo; 1378 // ...and go to the next open cycle 1379 } else { 1380 // ************ 1381 if(StreamOpen && (RC == STATUS_NOT_FOUND)) 1382 // handle SDir return code 1383 RC = STATUS_OBJECT_NAME_NOT_FOUND; 1384 if(RC == STATUS_OBJECT_NAME_NOT_FOUND) { 1385 // good path, but no such file.... Amen 1386 // break open loop and continue with Create 1387 break; 1388 } 1389 if (!NT_SUCCESS(RC)) { 1390 // Hard error or damaged data structures ... 1391 #ifdef UDF_DBG 1392 if((RC != STATUS_OBJECT_PATH_NOT_FOUND) && 1393 (RC != STATUS_ACCESS_DENIED) && 1394 (RC != STATUS_NOT_A_DIRECTORY)) { 1395 AdPrint((" Hard error or damaged data structures\n")); 1396 } 1397 #endif // UDF_DBG 1398 // ... and exit with error 1399 try_return(RC); 1400 } 1401 // discard changes for last successfully opened file 1402 UDFInterlockedDecrement((PLONG)&(PtrNewFcb->ReferenceCount)); 1403 UDFInterlockedDecrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); 1404 RC = STATUS_SUCCESS; 1405 ASSERT(!OpenTargetDirectory); 1406 // break open loop and continue with Open 1407 // (Create will be skipped) 1408 break; 1409 } 1410 } // end of while(TRUE) 1411 1412 // **************** 1413 // If "open target directory" was specified 1414 // **************** 1415 if(OpenTargetDirectory) { 1416 1417 if(!UDFIsADirectory(LastGoodFileInfo)) { 1418 AdPrint((" Not a directory (2)\n")); 1419 RC = STATUS_NOT_A_DIRECTORY; 1420 } 1421 if(!NT_SUCCESS(RC) || 1422 TailName.Length) { 1423 AdPrint((" Target name should not contain (back)slashes\n")); 1424 NewFileInfo = NULL; 1425 try_return(RC = STATUS_OBJECT_NAME_INVALID); 1426 } 1427 1428 NewFileInfo = LastGoodFileInfo; 1429 RtlCopyUnicodeString(&(PtrNewFileObject->FileName), &CurName); 1430 1431 // now we have to check if last component exists... 1432 if(NT_SUCCESS(RC = UDFFindFile__(Vcb, IgnoreCase, 1433 &CurName, RelatedFileInfo))) { 1434 // file exists, set this information in the Information field 1435 ReturnedInformation = FILE_EXISTS; 1436 AdPrint((" Open Target: FILE_EXISTS\n")); 1437 } else 1438 if(RC == STATUS_OBJECT_NAME_NOT_FOUND) { 1439 #ifdef UDF_DBG 1440 // check name. If there are '\\'s in TailName, some 1441 // directories in path specified do not exist 1442 for(TmpBuffer = LastGoodTail.Buffer; *TmpBuffer; TmpBuffer++) { 1443 if((*TmpBuffer) == L'\\') { 1444 ASSERT(FALSE); 1445 AdPrint((" Target name should not contain (back)slashes\n")); 1446 try_return(RC = STATUS_OBJECT_NAME_INVALID); 1447 } 1448 } 1449 #endif // UDF_DBG 1450 // Tell the I/O Manager that file does not exit 1451 ReturnedInformation = FILE_DOES_NOT_EXIST; 1452 AdPrint((" Open Target: FILE_DOES_NOT_EXIST\n")); 1453 RC = STATUS_SUCCESS; // is already set here 1454 } else { 1455 AdPrint((" Open Target: unexpected error\n")); 1456 NewFileInfo = NULL; 1457 ReturnedInformation = FILE_DOES_NOT_EXIST; 1458 try_return(RC = STATUS_OBJECT_NAME_INVALID); 1459 } 1460 1461 // RC = STATUS_SUCCESS; // is already set here 1462 1463 // Update the file object FsContext and FsContext2 fields 1464 // to reflect the fact that the parent directory of the 1465 // target has been opened 1466 PtrNewFcb = NewFileInfo->Fcb; 1467 UDFInterlockedDecrement((PLONG)&(PtrNewFcb->ReferenceCount)); 1468 UDFInterlockedDecrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); 1469 RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); 1470 ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); 1471 if (!NT_SUCCESS(RC)) { 1472 AdPrint((" Can't perform OpenFile operation for target\n")); 1473 try_return(RC); 1474 } 1475 PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); 1476 1477 ASSERT(Res1); 1478 RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); 1479 if(!NT_SUCCESS(RC)) { 1480 AdPrint((" Access/Share access check failed (Open Target)\n")); 1481 } 1482 1483 try_return(RC); 1484 } 1485 1486 // **************** 1487 // should we CREATE a new file ? 1488 // **************** 1489 if (!NT_SUCCESS(RC)) { 1490 if (RC == STATUS_OBJECT_NAME_NOT_FOUND || 1491 RC == STATUS_OBJECT_PATH_NOT_FOUND) { 1492 if( ((RequestedDisposition == FILE_OPEN) || 1493 (RequestedDisposition == FILE_OVERWRITE)) /*&& 1494 (!StreamOpen || !StreamExists)*/ ){ 1495 ReturnedInformation = FILE_DOES_NOT_EXIST; 1496 AdPrint((" File doesn't exist\n")); 1497 try_return(RC); 1498 } 1499 } else { 1500 // Any other operation return STATUS_ACCESS_DENIED. 1501 AdPrint((" Can't create due to unexpected error\n")); 1502 try_return(RC); 1503 } 1504 // Object was not found, create if requested 1505 if ((RequestedDisposition != FILE_CREATE) && (RequestedDisposition != FILE_OPEN_IF) && 1506 (RequestedDisposition != FILE_OVERWRITE_IF) && (RequestedDisposition != FILE_SUPERSEDE)) { 1507 AdPrint((" File doesn't exist (2)\n")); 1508 ReturnedInformation = FILE_DOES_NOT_EXIST; 1509 try_return(RC); 1510 } 1511 // Check Volume ReadOnly attr 1512 #ifndef UDF_READ_ONLY_BUILD 1513 if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) { 1514 #endif //UDF_READ_ONLY_BUILD 1515 ReturnedInformation = 0; 1516 AdPrint((" Write protected\n")); 1517 try_return(RC = STATUS_MEDIA_WRITE_PROTECTED); 1518 #ifndef UDF_READ_ONLY_BUILD 1519 } 1520 // Check r/o + delete on close 1521 if(DeleteOnCloseSpecified && 1522 (FileAttributes & FILE_ATTRIBUTE_READONLY)) { 1523 AdPrint((" Can't create r/o file marked for deletion\n")); 1524 try_return(RC = STATUS_CANNOT_DELETE); 1525 } 1526 1527 // Create a new file/directory here ... 1528 if(StreamOpen) 1529 StreamName.Buffer[StreamName.Length/sizeof(WCHAR)] = 0; 1530 for(TmpBuffer = LastGoodTail.Buffer; *TmpBuffer; TmpBuffer++) { 1531 if((*TmpBuffer) == L'\\') { 1532 AdPrint((" Target name should not contain (back)slashes\n")); 1533 try_return(RC = STATUS_OBJECT_NAME_INVALID); 1534 } 1535 } 1536 if( DirectoryOnlyRequested && 1537 ((IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_TEMPORARY) || 1538 StreamOpen || FALSE)) { 1539 AdPrint((" Creation of _temporary_ directory not permited\n")); 1540 try_return(RC = STATUS_INVALID_PARAMETER); 1541 } 1542 // check access rights 1543 ASSERT(Res1); 1544 RC = UDFCheckAccessRights(NULL, NULL, OldRelatedFileInfo->Fcb, PtrRelatedCCB, DirectoryOnlyRequested ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0); 1545 if(!NT_SUCCESS(RC)) { 1546 AdPrint((" Creation of File/Dir not permitted\n")); 1547 try_return(RC); 1548 } 1549 // Note that a FCB structure will be allocated at this time 1550 // and so will a CCB structure. Assume that these are called 1551 // PtrNewFcb and PtrNewCcb respectively. 1552 // Further, note that since the file is being created, no other 1553 // thread can have the file stream open at this time. 1554 RelatedFileInfo = OldRelatedFileInfo; 1555 1556 RC = UDFCreateFile__(Vcb, IgnoreCase, &LastGoodTail, 0, 0, 1557 Vcb->UseExtendedFE || (StreamOpen && !StreamExists), 1558 (RequestedDisposition == FILE_CREATE), RelatedFileInfo, &NewFileInfo); 1559 if(!NT_SUCCESS(RC)) { 1560 AdPrint((" Creation error\n")); 1561 Creation_Err_1: 1562 if(NewFileInfo) { 1563 PtrNewFcb = NewFileInfo->Fcb; 1564 ASSERT(!PtrNewFcb); 1565 if(PtrNewFcb && 1566 !PtrNewFcb->ReferenceCount && 1567 !PtrNewFcb->OpenHandleCount) { 1568 NewFileInfo->Fcb = NULL; 1569 } 1570 if(NewFileInfo->Dloc && 1571 !NewFileInfo->Dloc->LinkRefCount) { 1572 NewFileInfo->Dloc->CommonFcb = NULL; 1573 } 1574 if(UDFCleanUpFile__(Vcb, NewFileInfo)) { 1575 if(PtrNewFcb) { 1576 BrutePoint(); 1577 UDFCleanUpFCB(PtrNewFcb); 1578 } 1579 MyFreePool__(NewFileInfo); 1580 PtrNewFcb = PtrNewFcb; 1581 } else { 1582 NewFileInfo->Fcb = PtrNewFcb; 1583 } 1584 PtrNewFcb = NULL; 1585 } 1586 try_return(RC); 1587 } 1588 // Update parent object 1589 if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) && 1590 PtrRelatedFCB && 1591 PtrRelatedFileObject && 1592 (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) { 1593 PtrRelatedFileObject->Flags |= (FO_FILE_MODIFIED | FO_FILE_SIZE_CHANGED); 1594 } 1595 #if 0 1596 CollectStatistics(Vcb, MetaDataWrites); 1597 #endif 1598 1599 if(DirectoryOnlyRequested) { 1600 // user wants the directory to be created 1601 RC = UDFRecordDirectory__(Vcb, NewFileInfo); 1602 if(!NT_SUCCESS(RC)) { 1603 AdPrint((" Can't transform to directory\n")); 1604 Undo_Create_1: 1605 if((RC != STATUS_FILE_IS_A_DIRECTORY) && 1606 (RC != STATUS_NOT_A_DIRECTORY) && 1607 (RC != STATUS_ACCESS_DENIED)) { 1608 UDFFlushFile__(Vcb, NewFileInfo); 1609 UDFUnlinkFile__(Vcb, NewFileInfo, TRUE); 1610 } 1611 UDFCloseFile__(Vcb, NewFileInfo); 1612 BrutePoint(); 1613 goto Creation_Err_1; 1614 } 1615 #if 0 1616 CollectStatistics(Vcb, MetaDataWrites); 1617 #endif 1618 } else if(AllocationSize) { 1619 // set initial file size 1620 /* if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) { 1621 AdPrint((" Can't set initial file size\n")); 1622 goto Undo_Create_1; 1623 } 1624 CollectStatistics(Vcb, MetaDataWrites);*/ 1625 } 1626 1627 if(StreamOpen && !StreamExists) { 1628 1629 // PHASE 0 1630 1631 // Open the newly created object (file) 1632 if (!(PtrNewFcb = NewFileInfo->Fcb)) { 1633 // It is a first open operation 1634 // Allocate new FCB 1635 // Here we set FileObject pointer to NULL to avoid 1636 // new CCB allocation 1637 RC = UDFFirstOpenFile(Vcb, 1638 NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo, 1639 &LocalPath, &LastGoodTail); 1640 if(!NT_SUCCESS(RC)) { 1641 AdPrint((" Can't perform FirstOpenFile operation for file to contain stream\n")); 1642 BrutePoint(); 1643 UDFCleanUpFCB(NewFileInfo->Fcb); 1644 NewFileInfo->Fcb = NULL; 1645 goto Creation_Err_1; 1646 } 1647 } else { 1648 BrutePoint(); 1649 } 1650 1651 // Update unwind information 1652 TreeLength++; 1653 LastGoodFileInfo = NewFileInfo; 1654 // update FCB tree 1655 RC = MyAppendUnicodeToString(&LocalPath, L"\\"); 1656 if(!NT_SUCCESS(RC)) try_return(RC); 1657 RC = MyAppendUnicodeStringToStringTag(&LocalPath, &LastGoodTail, MEM_USLOC_TAG); 1658 if(!NT_SUCCESS(RC)) 1659 goto Creation_Err_1; 1660 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); 1661 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); 1662 ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); 1663 PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; 1664 PtrNewFcb->FCBFlags |= UDF_FCB_VALID; 1665 1666 UDFNotifyFullReportChange( Vcb, NewFileInfo, 1667 UDFIsADirectory(NewFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 1668 FILE_ACTION_ADDED); 1669 1670 // PHASE 1 1671 1672 // we need to create Stream Dir 1673 RelatedFileInfo = NewFileInfo; 1674 RC = UDFCreateStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo); 1675 if(!NT_SUCCESS(RC)) { 1676 AdPrint((" Can't create SDir\n")); 1677 BrutePoint(); 1678 goto Creation_Err_1; 1679 } 1680 #if 0 1681 CollectStatistics(Vcb, MetaDataWrites); 1682 #endif 1683 1684 // normalize stream name 1685 StreamName.Buffer++; 1686 StreamName.Length-=sizeof(WCHAR); 1687 // Open the newly created object 1688 if (!(PtrNewFcb = NewFileInfo->Fcb)) { 1689 // It is a first open operation 1690 // Allocate new FCB 1691 // Here we set FileObject pointer to NULL to avoid 1692 // new CCB allocation 1693 RC = UDFFirstOpenFile(Vcb, 1694 NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo, 1695 &LocalPath, &(UDFGlobalData.UnicodeStrSDir)); 1696 } else { 1697 BrutePoint(); 1698 } 1699 if(!NT_SUCCESS(RC)) { 1700 AdPrint((" Can't perform OpenFile operation for SDir\n")); 1701 BrutePoint(); 1702 goto Creation_Err_1; 1703 } 1704 1705 // Update unwind information 1706 TreeLength++; 1707 LastGoodFileInfo = NewFileInfo; 1708 // update FCB tree 1709 RC = MyAppendUnicodeStringToStringTag(&LocalPath, &(UDFGlobalData.UnicodeStrSDir), MEM_USLOC_TAG); 1710 if(!NT_SUCCESS(RC)) { 1711 AdPrint((" Can't append UNC str\n")); 1712 BrutePoint(); 1713 goto Creation_Err_1; 1714 } 1715 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); 1716 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); 1717 ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); 1718 PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; 1719 PtrNewFcb->FCBFlags |= UDF_FCB_VALID; 1720 1721 // PHASE 2 1722 1723 // create stream 1724 RelatedFileInfo = NewFileInfo; 1725 RC = UDFCreateFile__(Vcb, IgnoreCase, &StreamName, 0, 0, 1726 Vcb->UseExtendedFE, (RequestedDisposition == FILE_CREATE), 1727 RelatedFileInfo, &NewFileInfo); 1728 if(!NT_SUCCESS(RC)) { 1729 AdPrint((" Can't create Stream\n")); 1730 BrutePoint(); 1731 goto Creation_Err_1; 1732 } 1733 #if 0 1734 CollectStatistics(Vcb, MetaDataWrites); 1735 #endif 1736 1737 // Update unwind information 1738 LastGoodTail = StreamName; 1739 } 1740 // NT wants ARCHIVE bit to be set on Files 1741 if(!DirectoryOnlyRequested) 1742 FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; 1743 // Open the newly created object 1744 if (!(PtrNewFcb = NewFileInfo->Fcb)) { 1745 // It is a first open operation 1746 #ifndef IFS_40 1747 // Set attributes for the file ... 1748 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo),NewFileInfo->Index), 1749 NewFileInfo->Dloc->FileEntry, FileAttributes); 1750 #endif //IFS_40 1751 // Allocate new FCB 1752 // Here we set FileObject pointer to NULL to avoid 1753 // new CCB allocation 1754 RC = UDFFirstOpenFile(Vcb, 1755 PtrNewFileObject, &PtrNewFcb, RelatedFileInfo, NewFileInfo, 1756 &LocalPath, &LastGoodTail); 1757 } else { 1758 BrutePoint(); 1759 } 1760 1761 if(!NT_SUCCESS(RC)) { 1762 AdPrint((" Can't perform OpenFile operation for file or stream\n")); 1763 BrutePoint(); 1764 goto Undo_Create_1; 1765 } 1766 1767 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.FileSize.QuadPart = 1768 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength.QuadPart = 0; 1769 if(AllocationSize) { 1770 // inform NT about size changes 1771 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart = AllocationSize; 1772 MmPrint((" CcIsFileCached()\n")); 1773 if(CcIsFileCached(PtrNewFileObject)) { 1774 MmPrint((" CcSetFileSizes()\n")); 1775 BrutePoint(); 1776 CcSetFileSizes(PtrNewFileObject, (PCC_FILE_SIZES)&(PtrNewFcb->NTRequiredFCB->CommonFCBHeader.AllocationSize)); 1777 PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; 1778 } 1779 } 1780 1781 // Update unwind information 1782 TreeLength++; 1783 LastGoodFileInfo = NewFileInfo; 1784 1785 // Set the Share Access for the file stream. 1786 // The FCBShareAccess field will be set by the I/O Manager. 1787 PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); 1788 RC = UDFSetAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); 1789 1790 if(!NT_SUCCESS(RC)) { 1791 AdPrint((" Can't set Access Rights on Create\n")); 1792 BrutePoint(); 1793 UDFFlushFile__(Vcb, NewFileInfo); 1794 UDFUnlinkFile__(Vcb, NewFileInfo, TRUE); 1795 try_return(RC); 1796 } 1797 1798 #ifdef IFS_40 1799 // Set attributes for the file ... 1800 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo),NewFileInfo->Index), 1801 NewFileInfo->Dloc->FileEntry, FileAttributes); 1802 // It is rather strange for me, but NT requires us to allow 1803 // Create operation for r/o + WriteAccess, but denies all 1804 // the rest operations in this case. Thus, we should update 1805 // r/o flag in Fcb _after_ Access check :-/ 1806 if(FileAttributes & FILE_ATTRIBUTE_READONLY) 1807 PtrNewFcb->FCBFlags |= UDF_FCB_READ_ONLY; 1808 #endif //IFS_40 1809 // We call the notify package to report that the 1810 // we have added a stream. 1811 if(UDFIsAStream(NewFileInfo)) { 1812 UDFNotifyFullReportChange( Vcb, NewFileInfo, 1813 FILE_NOTIFY_CHANGE_STREAM_NAME, 1814 FILE_ACTION_ADDED_STREAM ); 1815 } else { 1816 UDFNotifyFullReportChange( Vcb, NewFileInfo, 1817 UDFIsADirectory(NewFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 1818 FILE_ACTION_ADDED); 1819 } 1820 /*#ifdef UDF_DBG 1821 { 1822 ULONG i; 1823 PDIR_INDEX_HDR hDirIndex = NewFileInfo->ParentFile->Dloc->DirIndex; 1824 1825 for(i=0;DirIndex[i].FName.Buffer;i++) { 1826 AdPrint(("%ws\n", DirIndex[i].FName.Buffer)); 1827 } 1828 } 1829 #endif*/ 1830 ReturnedInformation = FILE_CREATED; 1831 1832 try_return(RC); 1833 #endif //UDF_READ_ONLY_BUILD 1834 1835 } 1836 1837 AlreadyOpened: 1838 1839 // **************** 1840 // we have always STATUS_SUCCESS here 1841 // **************** 1842 1843 ASSERT(NewFileInfo != OldRelatedFileInfo); 1844 // A new CCB will be allocated. 1845 // Assume that this structure named PtrNewCcb 1846 RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); 1847 if (!NT_SUCCESS(RC)) try_return(RC); 1848 PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); 1849 1850 if(RequestedDisposition == FILE_CREATE) { 1851 ReturnedInformation = FILE_EXISTS; 1852 AdPrint((" Object name collision\n")); 1853 try_return(RC = STATUS_OBJECT_NAME_COLLISION); 1854 } 1855 1856 NtReqFcb = PtrNewFcb->NTRequiredFCB; 1857 NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(PtrNewFcb); 1858 1859 // Check if caller wanted a directory only and target object 1860 // is not a directory, or caller wanted a file only and target 1861 // object is not a file ... 1862 if((PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY) && ((RequestedDisposition == FILE_SUPERSEDE) || 1863 (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF) || 1864 FileOnlyRequested)) { 1865 if(FileOnlyRequested) { 1866 AdPrint((" Can't open directory as a plain file\n")); 1867 } else { 1868 AdPrint((" Can't supersede directory\n")); 1869 } 1870 RC = STATUS_FILE_IS_A_DIRECTORY; 1871 try_return(RC); 1872 } 1873 1874 if(DirectoryOnlyRequested && !(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)) { 1875 AdPrint((" This is not a directory\n")); 1876 RC = STATUS_NOT_A_DIRECTORY; 1877 try_return(RC); 1878 } 1879 1880 if(DeleteOnCloseSpecified && (PtrNewFcb->FCBFlags & UDF_FCB_READ_ONLY)) { 1881 AdPrint((" Can't delete Read-Only file\n")); 1882 RC = STATUS_CANNOT_DELETE; 1883 try_return(RC); 1884 } 1885 // Check share access and fail if the share conflicts with an existing 1886 // open. 1887 ASSERT(Res1 != NULL); 1888 ASSERT(Res2 != NULL); 1889 RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); 1890 if(!NT_SUCCESS(RC)) { 1891 AdPrint((" Access/Share access check failed\n")); 1892 try_return(RC); 1893 } 1894 1895 RestoreShareAccess = TRUE; 1896 1897 if(FileOnlyRequested) { 1898 // If the user wants 'write access' access to the file make sure there 1899 // is not a process mapping this file as an image. Any attempt to 1900 // delete the file will be stopped in fileinfo.cpp 1901 // 1902 // If the user wants to delete on close, we must check at this 1903 // point though. 1904 if( (DesiredAccess & FILE_WRITE_DATA) || DeleteOnCloseSpecified ) { 1905 MmPrint((" MmFlushImageSection();\n")); 1906 NtReqFcb->AcqFlushCount++; 1907 if(!MmFlushImageSection( &(NtReqFcb->SectionObject), 1908 MmFlushForWrite )) { 1909 1910 NtReqFcb->AcqFlushCount--; 1911 RC = DeleteOnCloseSpecified ? STATUS_CANNOT_DELETE : 1912 STATUS_SHARING_VIOLATION; 1913 AdPrint((" File is mapped or deletion in progress\n")); 1914 try_return (RC); 1915 } 1916 NtReqFcb->AcqFlushCount--; 1917 } 1918 if( NoBufferingSpecified && 1919 /* (PtrNewFileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) &&*/ 1920 !(PtrNewFcb->CachedOpenHandleCount) && 1921 (NtReqFcb->SectionObject.DataSectionObject) ) { 1922 // If this is a non-cached open, and there are no open cached 1923 // handles, but there is still a data section, attempt a flush 1924 // and purge operation to avoid cache coherency overhead later. 1925 // We ignore any I/O errors from the flush. 1926 MmPrint((" CcFlushCache()\n")); 1927 CcFlushCache( &(NtReqFcb->SectionObject), NULL, 0, NULL ); 1928 MmPrint((" CcPurgeCacheSection()\n")); 1929 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE ); 1930 } 1931 } 1932 1933 if(DeleteOnCloseSpecified && UDFIsADirectory(NewFileInfo) && !UDFIsDirEmpty__(NewFileInfo)) { 1934 AdPrint((" Directory in not empry\n")); 1935 try_return (RC = STATUS_DIRECTORY_NOT_EMPTY); 1936 } 1937 1938 // Get attributes for the file ... 1939 TmpFileAttributes = 1940 (USHORT)UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index), 1941 NewFileInfo->Dloc->FileEntry); 1942 1943 if(DeleteOnCloseSpecified && 1944 (TmpFileAttributes & FILE_ATTRIBUTE_READONLY)) { 1945 ASSERT(Res1 != NULL); 1946 ASSERT(Res2 != NULL); 1947 RC = UDFCheckAccessRights(NULL, NULL, OldRelatedFileInfo->Fcb, PtrRelatedCCB, FILE_DELETE_CHILD, 0); 1948 if(!NT_SUCCESS(RC)) { 1949 AdPrint((" Read-only. DeleteOnClose attempt failed\n")); 1950 try_return (RC = STATUS_CANNOT_DELETE); 1951 } 1952 } 1953 1954 // If a supersede or overwrite was requested, do so now ... 1955 if((RequestedDisposition == FILE_SUPERSEDE) || 1956 (RequestedDisposition == FILE_OVERWRITE) || 1957 (RequestedDisposition == FILE_OVERWRITE_IF)) { 1958 // Attempt the operation here ... 1959 1960 #ifndef UDF_READ_ONLY_BUILD 1961 ASSERT(!UDFIsADirectory(NewFileInfo)); 1962 1963 if(RequestedDisposition == FILE_SUPERSEDE) { 1964 BOOLEAN RestoreRO = FALSE; 1965 1966 ASSERT(Res1 != NULL); 1967 ASSERT(Res2 != NULL); 1968 // NT wants us to allow Supersede on RO files 1969 if(PtrNewFcb->FCBFlags & UDF_FCB_READ_ONLY) { 1970 // Imagine, that file is not RO and check other permissions 1971 RestoreRO = TRUE; 1972 PtrNewFcb->FCBFlags &= ~UDF_FCB_READ_ONLY; 1973 } 1974 RC = UDFCheckAccessRights(NULL, NULL, PtrNewFcb, PtrNewCcb, DELETE, 0); 1975 if(RestoreRO) { 1976 // Restore RO state if changed 1977 PtrNewFcb->FCBFlags |= UDF_FCB_READ_ONLY; 1978 } 1979 if(!NT_SUCCESS(RC)) { 1980 AdPrint((" Can't supersede. DELETE permission required\n")); 1981 try_return (RC); 1982 } 1983 } else { 1984 ASSERT(Res1 != NULL); 1985 ASSERT(Res2 != NULL); 1986 RC = UDFCheckAccessRights(NULL, NULL, PtrNewFcb, PtrNewCcb, 1987 FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES, 0); 1988 if(!NT_SUCCESS(RC)) { 1989 AdPrint((" Can't overwrite. Permission denied\n")); 1990 try_return (RC); 1991 } 1992 } 1993 // Existing & requested System and Hidden bits must match 1994 if( (TmpFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) & 1995 (FileAttributes ^ (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) ) { 1996 AdPrint((" The Hidden and/or System bits do not match\n")); 1997 try_return(RC = STATUS_ACCESS_DENIED); 1998 } 1999 2000 // Before we actually truncate, check to see if the purge 2001 // is going to fail. 2002 MmPrint((" MmCanFileBeTruncated()\n")); 2003 if (!MmCanFileBeTruncated( &NtReqFcb->SectionObject, 2004 &(UDFGlobalData.UDFLargeZero) )) { 2005 AdPrint((" Can't truncate. File is mapped\n")); 2006 try_return(RC = STATUS_USER_MAPPED_FILE); 2007 } 2008 2009 ASSERT(Res1 != NULL); 2010 ASSERT(Res2 != NULL); 2011 2012 #if 0 2013 CollectStatistics(Vcb, MetaDataWrites); 2014 #endif 2015 // Synchronize with PagingIo 2016 UDFAcquireResourceExclusive(PagingIoRes = &(NtReqFcb->PagingIoResource),TRUE); 2017 // Set file sizes 2018 if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, 0))) { 2019 AdPrint((" Error during resize operation\n")); 2020 try_return(RC); 2021 } 2022 /* if(AllocationSize) { 2023 if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) { 2024 AdPrint((" Error during resize operation (2)\n")); 2025 try_return(RC); 2026 } 2027 }*/ 2028 NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = UDFSysGetAllocSize(Vcb, AllocationSize); 2029 NtReqFcb->CommonFCBHeader.FileSize.QuadPart = 2030 NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = 0 /*AllocationSize*/; 2031 PtrNewFcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE; 2032 MmPrint((" CcSetFileSizes()\n")); 2033 CcSetFileSizes(PtrNewFileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize)); 2034 NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; 2035 // Release PagingIoResource 2036 UDFReleaseResource(PagingIoRes); 2037 PagingIoRes = NULL; 2038 2039 if(NT_SUCCESS(RC)) { 2040 FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; 2041 if (RequestedDisposition == FILE_SUPERSEDE) { 2042 // Set attributes for the file ... 2043 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index), 2044 NewFileInfo->Dloc->FileEntry, FileAttributes); 2045 ReturnedInformation = FILE_SUPERSEDED; 2046 } else { 2047 // Get attributes for the file ... 2048 FileAttributes |= TmpFileAttributes; 2049 // Set attributes for the file ... 2050 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index), 2051 NewFileInfo->Dloc->FileEntry, FileAttributes); 2052 ReturnedInformation = FILE_OVERWRITTEN; 2053 } 2054 } 2055 // notify changes 2056 UDFNotifyFullReportChange( Vcb, NewFileInfo, 2057 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE, 2058 FILE_ACTION_MODIFIED); 2059 2060 // Update parent object 2061 if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) && 2062 PtrRelatedFCB && 2063 PtrRelatedFileObject && 2064 (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) { 2065 PtrRelatedFileObject->Flags |= (FO_FILE_MODIFIED | FO_FILE_SIZE_CHANGED); 2066 } 2067 #else //UDF_READ_ONLY_BUILD 2068 try_return(RC = STATUS_ACCESS_DENIED); 2069 #endif //UDF_READ_ONLY_BUILD 2070 } else { 2071 ReturnedInformation = FILE_OPENED; 2072 } 2073 2074 // Update parent object 2075 if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_READ) && 2076 PtrRelatedFCB && 2077 PtrRelatedFileObject && 2078 (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) { 2079 PtrRelatedFileObject->Flags |= FO_FILE_FAST_IO_READ; 2080 } 2081 2082 try_exit: NOTHING; 2083 2084 } _SEH2_FINALLY { 2085 // Complete the request unless we are here as part of unwinding 2086 // when an exception condition was encountered, OR 2087 // if the request has been deferred (i.e. posted for later handling) 2088 2089 if(RestoreVCBOpenCounter) { 2090 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); 2091 RestoreVCBOpenCounter = FALSE; 2092 } 2093 2094 if (RC != STATUS_PENDING) { 2095 // If any intermediate (directory) open operations were performed, 2096 // implement the corresponding close (do *not* however close 2097 // the target we have opened on behalf of the caller ...). 2098 2099 #if 0 2100 if(NT_SUCCESS(RC)) { 2101 CollectStatistics2(Vcb, SuccessfulCreates); 2102 } else { 2103 CollectStatistics2(Vcb, FailedCreates); 2104 } 2105 #endif 2106 2107 if (NT_SUCCESS(RC) && PtrNewFcb) { 2108 // Update the file object such that: 2109 // (a) the FsContext field points to the NTRequiredFCB field 2110 // in the FCB 2111 // (b) the FsContext2 field points to the CCB created as a 2112 // result of the open operation 2113 2114 // If write-through was requested, then mark the file object 2115 // appropriately 2116 2117 // directories are not cached 2118 // so we should prevent flush attepmts on cleanup 2119 if(!(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)) { 2120 #ifndef UDF_READ_ONLY_BUILD 2121 if(WriteThroughRequested) { 2122 PtrNewFileObject->Flags |= FO_WRITE_THROUGH; 2123 PtrNewFcb->FCBFlags |= UDF_FCB_WRITE_THROUGH; 2124 MmPrint((" FO_WRITE_THROUGH\n")); 2125 } 2126 #endif //UDF_READ_ONLY_BUILD 2127 if(SequentialIoRequested && 2128 !(Vcb->CompatFlags & UDF_VCB_IC_IGNORE_SEQUENTIAL_IO)) { 2129 PtrNewFileObject->Flags |= FO_SEQUENTIAL_ONLY; 2130 MmPrint((" FO_SEQUENTIAL_ONLY\n")); 2131 #ifndef UDF_READ_ONLY_BUILD 2132 if(Vcb->TargetDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 2133 PtrNewFileObject->Flags &= ~FO_WRITE_THROUGH; 2134 PtrNewFcb->FCBFlags &= ~UDF_FCB_WRITE_THROUGH; 2135 MmPrint((" FILE_REMOVABLE_MEDIA + FO_SEQUENTIAL_ONLY => ~FO_WRITE_THROUGH\n")); 2136 } 2137 #endif //UDF_READ_ONLY_BUILD 2138 if(PtrNewFcb->FileInfo) { 2139 UDFSetFileAllocMode__(PtrNewFcb->FileInfo, EXTENT_FLAG_ALLOC_SEQUENTIAL); 2140 } 2141 } 2142 if(NoBufferingSpecified) { 2143 PtrNewFileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; 2144 MmPrint((" FO_NO_INTERMEDIATE_BUFFERING\n")); 2145 } else { 2146 PtrNewFileObject->Flags |= FO_CACHE_SUPPORTED; 2147 MmPrint((" FO_CACHE_SUPPORTED\n")); 2148 } 2149 } 2150 2151 if((DesiredAccess & FILE_EXECUTE) /*&& 2152 !(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)*/) { 2153 MmPrint((" FO_FILE_FAST_IO_READ\n")); 2154 PtrNewFileObject->Flags |= FO_FILE_FAST_IO_READ; 2155 } 2156 // All right. Now we can safely increment OpenHandleCount 2157 UDFInterlockedIncrement((PLONG)&(Vcb->VCBHandleCount)); 2158 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->OpenHandleCount)); 2159 2160 if(PtrNewFileObject->Flags & FO_CACHE_SUPPORTED) 2161 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->CachedOpenHandleCount)); 2162 // Store some flags in CCB 2163 if(PtrNewCcb) { 2164 PtrNewCcb->TreeLength = TreeLength; 2165 // delete on close 2166 #ifndef UDF_READ_ONLY_BUILD 2167 if(DeleteOnCloseSpecified) { 2168 ASSERT(!(PtrNewFcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); 2169 PtrNewCcb->CCBFlags |= UDF_CCB_DELETE_ON_CLOSE; 2170 } 2171 #endif //UDF_READ_ONLY_BUILD 2172 // case sensetivity 2173 if(!IgnoreCase) { 2174 // remember this for possible Rename/Move operation 2175 PtrNewCcb->CCBFlags |= UDF_CCB_CASE_SENSETIVE; 2176 PtrNewFileObject->Flags |= FO_OPENED_CASE_SENSITIVE; 2177 } 2178 if(IsFileObjectReadOnly(PtrNewFileObject)) { 2179 UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCountRO)); 2180 PtrNewCcb->CCBFlags |= UDF_CCB_READ_ONLY; 2181 } 2182 } else { 2183 BrutePoint(); 2184 } 2185 // it was a stream... 2186 if(StreamOpen) 2187 PtrNewFileObject->Flags |= FO_STREAM_FILE; 2188 // PtrNewCcb->CCBFlags |= UDF_CCB_VALID; 2189 // increment the number of outstanding open operations on this 2190 // logical volume (i.e. volume cannot be dismounted) 2191 UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); 2192 PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; 2193 PtrNewFcb->FCBFlags |= UDF_FCB_VALID; 2194 #ifdef UDF_DBG 2195 // We have no FileInfo for Volume 2196 if(PtrNewFcb->FileInfo) { 2197 ASSERT_REF(PtrNewFcb->ReferenceCount >= PtrNewFcb->FileInfo->RefCount); 2198 } 2199 #endif // UDF_DBG 2200 AdPrint((" FCB %x, CCB %x, FO %x, Flags %x\n", PtrNewFcb, PtrNewCcb, PtrNewFileObject, PtrNewFcb->FCBFlags)); 2201 2202 UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); 2203 2204 } else if(!NT_SUCCESS(RC)) { 2205 // Perform failure related post-processing now 2206 if(RestoreShareAccess && NtReqFcb && PtrNewFileObject) { 2207 IoRemoveShareAccess(PtrNewFileObject, &(NtReqFcb->FCBShareAccess)); 2208 } 2209 UDFCleanUpCCB(PtrNewCcb); 2210 if(PtrNewFileObject) { 2211 PtrNewFileObject->FsContext2 = NULL; 2212 } 2213 // We have successfully opened LastGoodFileInfo, 2214 // so mark it as VALID to avoid future troubles... 2215 if(LastGoodFileInfo && LastGoodFileInfo->Fcb) { 2216 LastGoodFileInfo->Fcb->FCBFlags |= UDF_FCB_VALID; 2217 if(LastGoodFileInfo->Fcb->NTRequiredFCB) { 2218 LastGoodFileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; 2219 } 2220 } 2221 // Release resources... 2222 UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); 2223 ASSERT(AcquiredVcb); 2224 // close the chain 2225 UDFCloseFileInfoChain(Vcb, LastGoodFileInfo, TreeLength, TRUE); 2226 // cleanup FCBs (if any) 2227 if( Vcb && (PtrNewFcb != Vcb->RootDirFCB) && 2228 LastGoodFileInfo ) { 2229 UDFCleanUpFcbChain(Vcb, LastGoodFileInfo, TreeLength, TRUE); 2230 } else { 2231 ASSERT(!LastGoodFileInfo); 2232 } 2233 } else { 2234 UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); 2235 } 2236 // As long as this unwinding is not being performed as a result of 2237 // an exception condition, complete the IRP ... 2238 if (!_SEH2_AbnormalTermination()) { 2239 Irp->IoStatus.Status = RC; 2240 Irp->IoStatus.Information = ReturnedInformation; 2241 2242 // complete the IRP 2243 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 2244 // Free up the Irp Context 2245 UDFReleaseIrpContext(PtrIrpContext); 2246 } 2247 } else { 2248 UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); 2249 } 2250 2251 if(AcquiredVcb) { 2252 UDFReleaseResource(&(Vcb->VCBResource)); 2253 } 2254 // free allocated tmp buffers (if any) 2255 if(AbsolutePathName.Buffer) 2256 MyFreePool__(AbsolutePathName.Buffer); 2257 if(LocalPath.Buffer) 2258 MyFreePool__(LocalPath.Buffer); 2259 if(TailNameBuffer) 2260 MyFreePool__(TailNameBuffer); 2261 } _SEH2_END; 2262 2263 return(RC); 2264 } // end UDFCommonCreate() 2265 2266 /************************************************************************* 2267 * 2268 * Function: UDFFirstOpenFile() 2269 * 2270 * Description: 2271 * Perform first Open/Create initialization. 2272 * 2273 * Expected Interrupt Level (for execution) : 2274 * 2275 * IRQL_PASSIVE_LEVEL 2276 * 2277 * Return Value: STATUS_SUCCESS/Error 2278 * 2279 *************************************************************************/ 2280 NTSTATUS 2281 UDFFirstOpenFile( 2282 IN PVCB Vcb, // volume control block 2283 IN PFILE_OBJECT PtrNewFileObject, // I/O Mgr. created file object 2284 OUT PtrUDFFCB* PtrNewFcb, 2285 IN PUDF_FILE_INFO RelatedFileInfo, 2286 IN PUDF_FILE_INFO NewFileInfo, 2287 IN PUNICODE_STRING LocalPath, 2288 IN PUNICODE_STRING CurName 2289 ) 2290 { 2291 // DIR_INDEX NewFileIndex; 2292 PtrUDFObjectName NewFCBName; 2293 PtrUDFNTRequiredFCB NtReqFcb; 2294 NTSTATUS RC; 2295 BOOLEAN Linked = TRUE; 2296 PDIR_INDEX_HDR hDirIndex; 2297 PDIR_INDEX_ITEM DirIndex; 2298 2299 AdPrint(("UDFFirstOpenFile\n")); 2300 2301 if(!((*PtrNewFcb) = UDFAllocateFCB())) { 2302 AdPrint(("Can't allocate FCB\n")); 2303 return STATUS_INSUFFICIENT_RESOURCES; 2304 } 2305 2306 // Allocate and set new FCB unique name (equal to absolute path name) 2307 if(!(NewFCBName = UDFAllocateObjectName())) return STATUS_INSUFFICIENT_RESOURCES; 2308 2309 if(RelatedFileInfo && RelatedFileInfo->Fcb && 2310 !(RelatedFileInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)) { 2311 RC = MyCloneUnicodeString(&(NewFCBName->ObjectName), &(RelatedFileInfo->Fcb->FCBName->ObjectName)); 2312 } else { 2313 RC = MyInitUnicodeString(&(NewFCBName->ObjectName), L""); 2314 } 2315 if(!NT_SUCCESS(RC)) 2316 return STATUS_INSUFFICIENT_RESOURCES; 2317 if( (CurName->Buffer[0] != L':') && 2318 (!LocalPath->Length || 2319 ((LocalPath->Buffer[LocalPath->Length/sizeof(WCHAR)-1] != L':') /*&& 2320 (LocalPath->Buffer[LocalPath->Length/sizeof(WCHAR)-1] != L'\\')*/) )) { 2321 RC = MyAppendUnicodeToString(&(NewFCBName->ObjectName), L"\\"); 2322 if(!NT_SUCCESS(RC)) { 2323 UDFReleaseObjectName(NewFCBName); 2324 return STATUS_INSUFFICIENT_RESOURCES; 2325 } 2326 } 2327 2328 // Make link between Fcb and FileInfo 2329 (*PtrNewFcb)->FileInfo = NewFileInfo; 2330 NewFileInfo->Fcb = (*PtrNewFcb); 2331 (*PtrNewFcb)->ParentFcb = RelatedFileInfo->Fcb; 2332 2333 if(!((*PtrNewFcb)->NTRequiredFCB = NewFileInfo->Dloc->CommonFcb)) { 2334 (*PtrNewFcb)->NTRequiredFCB = (PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB))); 2335 if(!((*PtrNewFcb)->NTRequiredFCB)) { 2336 UDFReleaseObjectName(NewFCBName); 2337 return STATUS_INSUFFICIENT_RESOURCES; 2338 } 2339 2340 UDFPrint(("UDFAllocateNtReqFCB: %x\n", (*PtrNewFcb)->NTRequiredFCB)); 2341 RtlZeroMemory((*PtrNewFcb)->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB))); 2342 (*PtrNewFcb)->FileInfo->Dloc->CommonFcb = (*PtrNewFcb)->NTRequiredFCB; 2343 Linked = FALSE; 2344 } else { 2345 if(!(NewFileInfo->Dloc->CommonFcb->NtReqFCBFlags & UDF_NTREQ_FCB_VALID)) { 2346 (*PtrNewFcb)->NTRequiredFCB = NULL; 2347 BrutePoint(); 2348 UDFReleaseObjectName(NewFCBName); 2349 return STATUS_ACCESS_DENIED; 2350 } 2351 } 2352 2353 NtReqFcb = (*PtrNewFcb)->NTRequiredFCB; 2354 // Set times 2355 if(!Linked) { 2356 UDFGetFileXTime((*PtrNewFcb)->FileInfo, 2357 &(NtReqFcb->CreationTime.QuadPart), 2358 &(NtReqFcb->LastAccessTime.QuadPart), 2359 &(NtReqFcb->ChangeTime.QuadPart), 2360 &(NtReqFcb->LastWriteTime.QuadPart) ); 2361 2362 // Set the allocation size for the object is specified 2363 NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = 2364 UDFSysGetAllocSize(Vcb, NewFileInfo->Dloc->DataLoc.Length); 2365 // NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = UDFGetFileAllocationSize(Vcb, NewFileInfo); 2366 NtReqFcb->CommonFCBHeader.FileSize.QuadPart = 2367 NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = NewFileInfo->Dloc->DataLoc.Length; 2368 } 2369 // begin transaction 2370 UDFAcquireResourceExclusive(&(Vcb->FcbListResource), TRUE); 2371 2372 RC = UDFInitializeFCB(*PtrNewFcb, Vcb, NewFCBName, 2373 UDFIsADirectory(NewFileInfo) ? UDF_FCB_DIRECTORY : 0, PtrNewFileObject); 2374 if(!NT_SUCCESS(RC)) { 2375 if(!Linked) { 2376 MyFreePool__((*PtrNewFcb)->NTRequiredFCB); 2377 (*PtrNewFcb)->NTRequiredFCB = NULL; 2378 } 2379 UDFReleaseResource(&(Vcb->FcbListResource)); 2380 return RC; 2381 } 2382 // set Read-only attribute 2383 if(!UDFIsAStreamDir(NewFileInfo)) { 2384 hDirIndex = UDFGetDirIndexByFileInfo(NewFileInfo); 2385 #ifdef UDF_DBG 2386 if(!hDirIndex) { 2387 BrutePoint(); 2388 } else { 2389 #endif // UDF_DBG 2390 if(UDFAttributesToNT(DirIndex = UDFDirIndex(hDirIndex, NewFileInfo->Index),NULL) & FILE_ATTRIBUTE_READONLY) { 2391 (*PtrNewFcb)->FCBFlags |= UDF_FCB_READ_ONLY; 2392 } 2393 MyAppendUnicodeStringToStringTag(&(NewFCBName->ObjectName), &(DirIndex->FName), MEM_USOBJ_TAG); 2394 #ifdef UDF_DBG 2395 } 2396 #endif // UDF_DBG 2397 } else if (RelatedFileInfo->ParentFile) { 2398 hDirIndex = UDFGetDirIndexByFileInfo(RelatedFileInfo); 2399 if(UDFAttributesToNT(DirIndex = UDFDirIndex(hDirIndex, RelatedFileInfo->Index),NULL) & FILE_ATTRIBUTE_READONLY) { 2400 (*PtrNewFcb)->FCBFlags |= UDF_FCB_READ_ONLY; 2401 } 2402 RC = MyAppendUnicodeStringToStringTag(&(NewFCBName->ObjectName), CurName, MEM_USOBJ_TAG); 2403 // } else { 2404 // BrutePoint(); 2405 } 2406 // do not allocate CCB if it is internal Create/Open 2407 if(NT_SUCCESS(RC)) { 2408 if(PtrNewFileObject) { 2409 RC = UDFOpenFile(Vcb, PtrNewFileObject, *PtrNewFcb); 2410 } else { 2411 RC = STATUS_SUCCESS; 2412 } 2413 } 2414 UDFReleaseResource(&(Vcb->FcbListResource)); 2415 // end transaction 2416 2417 // if(!NT_SUCCESS(RC)) return RC; 2418 2419 return RC; 2420 } // end UDFFirstOpenFile() 2421 2422 /************************************************************************* 2423 * 2424 * Function: UDFOpenFile() 2425 * 2426 * Description: 2427 * Open a file/dir for the caller. 2428 * 2429 * Expected Interrupt Level (for execution) : 2430 * 2431 * IRQL_PASSIVE_LEVEL 2432 * 2433 * Return Value: STATUS_SUCCESS/Error 2434 * 2435 *************************************************************************/ 2436 NTSTATUS 2437 UDFOpenFile( 2438 PVCB Vcb, // volume control block 2439 PFILE_OBJECT PtrNewFileObject, // I/O Mgr. created file object 2440 PtrUDFFCB PtrNewFcb 2441 ) 2442 { 2443 NTSTATUS RC = STATUS_SUCCESS; 2444 PtrUDFCCB Ccb = NULL; 2445 PtrUDFNTRequiredFCB NtReqFcb; 2446 2447 AdPrint(("UDFOpenFile\n")); 2448 ASSERT((PtrNewFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB) 2449 ||(PtrNewFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB)); 2450 2451 _SEH2_TRY { 2452 2453 #if 0 2454 CollectStatistics2(Vcb, CreateHits); 2455 #endif 2456 // create a new CCB structure 2457 if (!(Ccb = UDFAllocateCCB())) { 2458 AdPrint(("Can't allocate CCB\n")); 2459 PtrNewFileObject->FsContext2 = NULL; 2460 // 2461 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); 2462 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); 2463 RC = STATUS_INSUFFICIENT_RESOURCES; 2464 try_return(RC); 2465 } 2466 // initialize the CCB 2467 Ccb->Fcb = PtrNewFcb; 2468 // initialize the CCB to point to the file object 2469 Ccb->FileObject = PtrNewFileObject; 2470 2471 // initialize the file object appropriately 2472 PtrNewFileObject->FsContext2 = (PVOID)(Ccb); 2473 PtrNewFileObject->Vpb = Vcb->Vpb; 2474 PtrNewFileObject->FsContext = (PVOID)(NtReqFcb = PtrNewFcb->NTRequiredFCB); 2475 PtrNewFileObject->SectionObjectPointer = &(NtReqFcb->SectionObject); 2476 #ifdef DBG 2477 // NtReqFcb ->FileObject = PtrNewFileObject; 2478 #endif //DBG 2479 2480 #ifdef UDF_DELAYED_CLOSE 2481 PtrNewFcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE; 2482 #endif //UDF_DELAYED_CLOSE 2483 2484 UDFAcquireResourceExclusive(&(PtrNewFcb->CcbListResource),TRUE); 2485 // insert CCB into linked list of open file object to Fcb or 2486 // to Vcb and do other intialization 2487 InsertTailList(&(PtrNewFcb->NextCCB), &(Ccb->NextCCB)); 2488 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); 2489 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); 2490 UDFReleaseResource(&(PtrNewFcb->CcbListResource)); 2491 2492 try_exit: NOTHING; 2493 } _SEH2_FINALLY { 2494 NOTHING; 2495 } _SEH2_END; 2496 2497 return(RC); 2498 } // end UDFOpenFile() 2499 2500 2501 /************************************************************************* 2502 * 2503 * Function: UDFInitializeFCB() 2504 * 2505 * Description: 2506 * Initialize a new FCB structure and also the sent-in file object 2507 * (if supplied) 2508 * 2509 * Expected Interrupt Level (for execution) : 2510 * 2511 * IRQL_PASSIVE_LEVEL 2512 * 2513 * Return Value: None 2514 * 2515 *************************************************************************/ 2516 NTSTATUS 2517 UDFInitializeFCB( 2518 IN PtrUDFFCB PtrNewFcb, // FCB structure to be initialized 2519 IN PVCB Vcb, // logical volume (VCB) pointer 2520 IN PtrUDFObjectName PtrObjectName, // name of the object 2521 IN ULONG Flags, // is this a file/directory, etc. 2522 IN PFILE_OBJECT FileObject) // optional file object to be initialized 2523 { 2524 AdPrint(("UDFInitializeFCB\n")); 2525 NTSTATUS status; 2526 BOOLEAN Linked = TRUE; 2527 2528 if(!PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource) { 2529 // record signature 2530 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode = UDF_NODE_TYPE_NT_REQ_FCB; 2531 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeByteSize = sizeof(UDFNTRequiredFCB); 2532 // Initialize the ERESOURCE objects 2533 if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->NTRequiredFCB->MainResource)))) { 2534 AdPrint((" Can't init resource\n")); 2535 return status; 2536 } 2537 if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->NTRequiredFCB->PagingIoResource)))) { 2538 AdPrint((" Can't init resource (2)\n")); 2539 UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->MainResource)); 2540 return status; 2541 } 2542 // Fill NT required Fcb part 2543 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource = &(PtrNewFcb->NTRequiredFCB->MainResource); 2544 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource = &(PtrNewFcb->NTRequiredFCB->PagingIoResource); 2545 // Itialize byte-range locks support structure 2546 FsRtlInitializeFileLock(&(PtrNewFcb->NTRequiredFCB->FileLock),NULL,NULL); 2547 // Init reference counter 2548 PtrNewFcb->NTRequiredFCB->CommonRefCount = 0; 2549 Linked = FALSE; 2550 } else { 2551 ASSERT(PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB); 2552 } 2553 if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->CcbListResource)))) { 2554 AdPrint((" Can't init resource (3)\n")); 2555 BrutePoint(); 2556 if(!Linked) { 2557 UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->PagingIoResource)); 2558 UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->MainResource)); 2559 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource = 2560 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource = NULL; 2561 FsRtlUninitializeFileLock(&(PtrNewFcb->NTRequiredFCB->FileLock)); 2562 } 2563 return status; 2564 } 2565 2566 // caller MUST ensure that VCB has been acquired exclusively 2567 InsertTailList(&(Vcb->NextFCB), &(PtrNewFcb->NextFCB)); 2568 2569 // initialize the various list heads 2570 InitializeListHead(&(PtrNewFcb->NextCCB)); 2571 2572 PtrNewFcb->ReferenceCount = 0; 2573 PtrNewFcb->OpenHandleCount = 0; 2574 2575 PtrNewFcb->FCBFlags = Flags | UDF_FCB_INITIALIZED_CCB_LIST_RESOURCE; 2576 2577 PtrNewFcb->FCBName = PtrObjectName; 2578 2579 PtrNewFcb->Vcb = Vcb; 2580 2581 return STATUS_SUCCESS; 2582 } // end UDFInitializeFCB() 2583 2584