1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
10 * Module: UDF File System Driver (Kernel mode execution only)
13 * Contains code to handle the "Create"/"Open" dispatch entry point.
15 *************************************************************************/
19 #define IsFileObjectReadOnly(FO) (!((FO)->WriteAccess | (FO)->DeleteAccess))
21 // define the file specific bug-check id
22 #define UDF_BUG_CHECK_ID UDF_FILE_CREATE
24 #define MEM_USABS_TAG "US_Abs"
25 #define MEM_USLOC_TAG "US_Loc"
26 #define MEM_USOBJ_TAG "US_Obj"
28 #define UDF_LOG_CREATE_DISPOSITION
30 /*************************************************************************
32 * Function: UDFCreate()
35 * The I/O Manager will invoke this routine to handle a create/open
38 * Expected Interrupt Level (for execution) :
40 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
41 * to be deferred to a worker thread context)
43 * Return Value: STATUS_SUCCESS/Error
45 *************************************************************************/
49 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
50 PIRP Irp
) // I/O Request Packet
52 NTSTATUS RC
= STATUS_SUCCESS
;
53 PtrUDFIrpContext PtrIrpContext
;
54 BOOLEAN AreWeTopLevel
= FALSE
;
56 TmPrint(("UDFCreate:\n"));
58 FsRtlEnterFileSystem();
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)
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
;
77 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
78 FsRtlExitFileSystem();
82 // set the top level context
83 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
87 // get an IRP context structure and issue the request
88 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
90 RC
= UDFCommonCreate(PtrIrpContext
, Irp
);
92 RC
= STATUS_INSUFFICIENT_RESOURCES
;
93 Irp
->IoStatus
.Status
= RC
;
94 Irp
->IoStatus
.Information
= 0;
96 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
99 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
101 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
103 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
107 IoSetTopLevelIrp(NULL
);
110 AdPrint(("UDFCreate: %x\n", RC
));
112 FsRtlExitFileSystem();
122 UDFReleaseResFromCreate(
123 IN PERESOURCE
* PagingIoRes
,
129 UDFReleaseResource(*PagingIoRes
);
130 (*PagingIoRes
) = NULL
;
133 UDFReleaseResource(*Res1
);
137 UDFReleaseResource(*Res2
);
140 } // end UDFReleaseResFromCreate()
147 IN PUDF_FILE_INFO RelatedFileInfo
,
152 if(RelatedFileInfo
->Fcb
&&
153 RelatedFileInfo
->Fcb
->ParentFcb
) {
155 UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo
->Fcb
->ParentFcb
->NTRequiredFCB
);
156 UDFAcquireResourceExclusive((*Res2
) = &(RelatedFileInfo
->Fcb
->ParentFcb
->NTRequiredFCB
->MainResource
),TRUE
);
159 UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo
->Fcb
->NTRequiredFCB
);
160 UDFAcquireResourceExclusive((*Res1
) = &(RelatedFileInfo
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
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()
168 /*************************************************************************
170 * Function: UDFCommonCreate()
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
178 * Expected Interrupt Level (for execution) :
182 * Return Value: STATUS_SUCCESS/Error
184 *************************************************************************/
187 PtrUDFIrpContext PtrIrpContext
,
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
;
203 ULONG ExtAttrLength
= 0;
204 ACCESS_MASK DesiredAccess
;
205 PACCESS_STATE AccessState
;
208 _SEH2_VOLATILE BOOLEAN AcquiredVcb
= FALSE
;
209 BOOLEAN OpenExisting
= FALSE
;
210 PERESOURCE Res1
= NULL
;
211 PERESOURCE Res2
= NULL
;
212 PERESOURCE PagingIoRes
= NULL
;
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;
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?
230 PtrUDFCCB PtrRelatedCCB
= NULL
, PtrNewCcb
= NULL
;
231 PtrUDFFCB PtrRelatedFCB
= NULL
, PtrNewFcb
= NULL
;
232 PtrUDFNTRequiredFCB NtReqFcb
;
234 ULONG ReturnedInformation
;
236 UNICODE_STRING TargetObjectName
;
237 UNICODE_STRING RelatedObjectName
;
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'
247 PUDF_FILE_INFO RelatedFileInfo
;
248 PUDF_FILE_INFO OldRelatedFileInfo
= NULL
;
249 PUDF_FILE_INFO NewFileInfo
= NULL
;
250 PUDF_FILE_INFO LastGoodFileInfo
= NULL
;
252 ULONG TreeLength
= 0;
255 BOOLEAN StreamOpen
= FALSE
;
256 BOOLEAN StreamExists
= FALSE
;
257 BOOLEAN RestoreVCBOpenCounter
= FALSE
;
258 BOOLEAN RestoreShareAccess
= FALSE
;
259 PWCHAR TailNameBuffer
= NULL
;
260 ULONG SNameIndex
= 0;
262 TmPrint(("UDFCommonCreate:\n"));
264 ASSERT(PtrIrpContext
);
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
)) {
275 ReturnedInformation
= FILE_OPENED
;
276 try_return(RC
= STATUS_SUCCESS
);
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
);
285 // If the caller cannot block, post the request to be handled
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 ...
291 RC
= UDFPostRequest(PtrIrpContext
, Irp
);
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
299 PtrNewFileObject
= IrpSp
->FileObject
;
300 TargetObjectName
= PtrNewFileObject
->FileName
;
301 PtrRelatedFileObject
= PtrNewFileObject
->RelatedFileObject
;
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
;
321 // Allocation size is only used if a new file is created
322 // or a file is superseded.
323 AllocationSize
= Irp
->Overlay
.AllocationSize
.QuadPart
;
325 // Get a ptr to the supplied security context
326 PtrSecurityContext
= IrpSp
->Parameters
.Create
.SecurityContext
;
327 AccessState
= PtrSecurityContext
->AccessState
;
329 // The desired access can be obtained from the SecurityContext
330 DesiredAccess
= PtrSecurityContext
->DesiredAccess
;
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
);
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;
341 //#ifdef UDF_LOG_CREATE_DISPOSITION
342 switch(RequestedDisposition
) {
344 AdPrint((" Dispos: FILE_SUPERSEDE\n"));
347 AdPrint((" Dispos: FILE_OPEN\n"));
350 AdPrint((" Dispos: FILE_CREATE\n"));
353 AdPrint((" Dispos: FILE_OPEN_IF\n"));
356 AdPrint((" Dispos: FILE_OVERWRITE\n"));
358 case FILE_OVERWRITE_IF
:
359 AdPrint((" Dispos: FILE_OVERWRITE_IF\n"));
362 AdPrint((" Dispos: *** Unknown ***\n"));
365 //#endif // UDF_LOG_CREATE_DISPOSITION
367 FileAttributes
= (USHORT
)(IrpSp
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
);
368 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
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
375 // But some applications _require_ EA support
376 // (Notepad... rather strange, isn't it ?)
378 // So, for such stupid ones
379 // !!! We shall ignore these parameters !!!
381 // PtrExtAttrBuffer = (struct _FILE_FULL_EA_INFORMATION *) Irp->AssociatedIrp.SystemBuffer;
382 // ExtAttrLength = IrpSp->Parameters.Create.EaLength;
384 // Get the options supplied by the user
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)
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)
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).
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)
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)
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
;
416 #define SequentialIoRequested (RequestedOptions & FILE_SEQUENTIAL_ONLY ? TRUE : FALSE)
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
;
429 if(DeleteOnCloseSpecified
) {
430 AdPrint((" DeleteOnClose\n"));
433 #define NoExtAttrKnowledge /*(RequestedOptions & FILE_NO_EA_KNOWLEDGE) ?*/ TRUE /*: FALSE*/
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;
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.
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
448 #define OpenByFileId (RequestedOptions & FILE_OPEN_BY_FILE_ID)
450 // Are we dealing with a page file?
451 PageFileManipulation
= (IrpSp
->Flags
& SL_OPEN_PAGING_FILE
) ? TRUE
: FALSE
;
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
;
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
;
462 // Ensure that the operation has been directed to a valid VCB ...
463 Vcb
= (PVCB
)(PtrIrpContext
->TargetDeviceObject
->DeviceExtension
);
465 ASSERT(Vcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
466 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
468 WriteThroughRequested
= WriteThroughRequested
||
469 (Vcb
->CompatFlags
& UDF_VCB_IC_FORCE_WRITE_THROUGH
);
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
);
481 ReturnedInformation
= 0;
482 AdPrint(("Can't create file with EAs\n"));
483 try_return(RC
= STATUS_EAS_NOT_SUPPORTED
);
486 UDFFlushTryBreak(Vcb
);
488 if (Vcb
->SoftEjectReq
) {
489 AdPrint((" Eject requested\n"));
490 try_return(RC
= STATUS_FILE_INVALID
);
493 // If the volume has been locked, fail the request
494 if ((Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_LOCKED
) &&
495 (Vcb
->VolumeLockPID
!= GetCurrentPID())) {
496 AdPrint((" Volume is locked\n"));
497 RC
= STATUS_ACCESS_DENIED
;
500 // We need EXCLUSIVE access to Vcb to avoid parallel calls to UDFVerifyVcb()
501 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
504 // Disk based file systems might decide to verify the logical volume
505 // (if required and only if removable media are supported) at this time
506 RC
= UDFVerifyVcb(PtrIrpContext
,Vcb
);
510 UDFConvertExclusiveToSharedLite(&(Vcb
->VCBResource
));
512 ASSERT(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
);
514 // We fail in the following cases for Read-Only volumes
515 // - Open a target directory.
519 ((Vcb
->origIntegrityType
== INTEGRITY_TYPE_OPEN
) &&
520 (Vcb
->CompatFlags
& UDF_VCB_IC_DIRTY_RO
))
521 #ifndef UDF_READ_ONLY_BUILD
522 || (Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
)
523 #endif //UDF_READ_ONLY_BUILD
525 (DeleteOnCloseSpecified
||
526 OpenTargetDirectory
||
527 (RequestedDisposition
== FILE_CREATE
) ||
528 (RequestedDisposition
== FILE_OVERWRITE
) ||
529 (RequestedDisposition
== FILE_OVERWRITE_IF
) ||
530 (RequestedDisposition
== FILE_SUPERSEDE
) ||
532 ReturnedInformation
= 0;
533 AdPrint((" Write protected or dirty\n"));
534 try_return(RC
= STATUS_MEDIA_WRITE_PROTECTED
);
537 /* if(DesiredAccess & (FILE_READ_EA | FILE_WRITE_EA)) {
538 ReturnedInformation = 0;
539 AdPrint((" EAs not supported\n"));
540 try_return(RC = STATUS_ACCESS_DENIED);
544 // If a Volume open is requested, satisfy it now
546 if (!(PtrNewFileObject
->FileName
.Length
) && (!PtrRelatedFileObject
||
547 (PtrRelatedFCB
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
))) {
549 BOOLEAN UndoLock
= FALSE
;
551 AdPrint((" Opening Volume\n"));
552 // If the supplied file name is NULL *and* either there exists
553 // no related file object *or* if a related file object was supplied
554 // but it too refers to a previously opened instance of a logical
555 // volume, this open must be for a logical volume.
557 // Note: the FSD might decide to do "special" things (whatever they
558 // might be) in response to an open request for the logical volume.
560 // Logical volume open requests are done primarily to get/set volume
561 // information, lock the volume, dismount the volume (using the IOCTL
562 // FSCTL_DISMOUNT_VOLUME) etc.
564 // If a volume open is requested, perform checks to ensure that
565 // invalid options have not also been specified ...
566 if ((OpenTargetDirectory
) || (PtrExtAttrBuffer
)) {
567 try_return(RC
= STATUS_INVALID_PARAMETER
);
570 if (DirectoryOnlyRequested
) {
571 // a volume is not a directory
572 try_return(RC
= STATUS_NOT_A_DIRECTORY
);
575 #ifndef UDF_READ_ONLY_BUILD
576 if (DeleteOnCloseSpecified
) {
577 // delete volume.... hmm
578 try_return(RC
= STATUS_CANNOT_DELETE
);
581 if ((RequestedDisposition
!= FILE_OPEN
) && (RequestedDisposition
!= FILE_OPEN_IF
)) {
582 // cannot create a new volume, I'm afraid ...
583 try_return(RC
= STATUS_ACCESS_DENIED
);
585 #endif //UDF_READ_ONLY_BUILD
587 UDFPrint((" ShareAccess %x, DesiredAccess %x\n", ShareAccess
, DesiredAccess
));
589 if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE)) &&
590 !(DesiredAccess & (FILE_GENERIC_WRITE & ~SYNCHRONIZE)) &&
591 (ShareAccess & FILE_SHARE_READ) ) {
593 if(!(DesiredAccess
& ((GENERIC_WRITE
| FILE_GENERIC_WRITE
) & ~(SYNCHRONIZE
| READ_CONTROL
))) &&
594 (ShareAccess
& FILE_SHARE_READ
) ) {
595 UDFPrint((" R/O volume open\n"));
598 UDFPrint((" R/W volume open\n"));
599 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_MEDIA_READ_ONLY
) {
600 UDFPrint((" media-ro\n"));
601 try_return(RC
= STATUS_MEDIA_WRITE_PROTECTED
);
605 if(!(ShareAccess
& (FILE_SHARE_WRITE
| FILE_SHARE_DELETE
)) &&
606 !(DesiredAccess
& ((GENERIC_WRITE
| FILE_GENERIC_WRITE
) & ~(SYNCHRONIZE
| READ_CONTROL
))) &&
607 (ShareAccess
& FILE_SHARE_READ
) ) {
611 if(!(ShareAccess
& FILE_SHARE_READ
) ||
612 (DesiredAccess
& ((GENERIC_WRITE
| FILE_GENERIC_WRITE
) & ~(SYNCHRONIZE
| READ_CONTROL
))) ) {
613 // As soon as OpenVolume flushes the volume
614 // we should complete all pending requests (Close)
616 UDFPrint((" set UDF_IRP_CONTEXT_FLUSH2_REQUIRED\n"));
617 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_FLUSH2_REQUIRED
;
620 UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
621 UDFReleaseResource(&(Vcb->VCBResource));
624 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) {
625 UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
627 #ifdef UDF_DELAYED_CLOSE
628 UDFCloseAllDelayed(Vcb);
629 #endif //UDF_DELAYED_CLOSE
631 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
633 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
638 // If the user does not want to share write or delete then we will try
639 // and take out a lock on the volume.
640 if(!(ShareAccess
& (FILE_SHARE_WRITE
| FILE_SHARE_DELETE
))) {
641 // Do a quick check here for handles on exclusive open.
642 if ((Vcb
->VCBHandleCount
) &&
643 !(ShareAccess
& FILE_SHARE_READ
)) {
645 UDFPrint((" !FILE_SHARE_READ + open handles (%d)\n", Vcb
->VCBHandleCount
));
646 try_return(RC
= STATUS_SHARING_VIOLATION
);
648 if(PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_FLUSH2_REQUIRED
) {
650 UDFPrint((" perform flush\n"));
651 PtrIrpContext
->IrpContextFlags
&= ~UDF_IRP_CONTEXT_FLUSH2_REQUIRED
;
653 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBOpenCount
));
654 UDFReleaseResource(&(Vcb
->VCBResource
));
657 if(!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
)) {
658 UDFCloseAllSystemDelayedInDir(Vcb
, Vcb
->RootDirFCB
->FileInfo
);
660 #ifdef UDF_DELAYED_CLOSE
661 UDFCloseAllDelayed(Vcb
);
662 #endif //UDF_DELAYED_CLOSE
664 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
666 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
668 UDFFlushLogicalVolume(NULL
, NULL
, Vcb
);
670 if((ShareAccess
& FILE_SHARE_READ
) &&
671 ((Vcb
->VCBOpenCount
- UDF_RESIDUAL_REFERENCE
) != (Vcb
->VCBOpenCountRO
))) {
672 UDFPrint((" FILE_SHARE_READ + R/W handles: %d(%d) -> STATUS_SHARING_VIOLATION ?\n",
673 Vcb
->VCBOpenCount
- UDF_RESIDUAL_REFERENCE
,
674 Vcb
->VCBOpenCountRO
));
675 /* we shall not check it here, let System do it in IoCheckShareAccess() */
676 //try_return(RC = STATUS_SHARING_VIOLATION);
680 if(!(ShareAccess
& FILE_SHARE_READ
)) {
681 UDFPrint((" set Lock\n"));
682 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_VOLUME_LOCKED
;
683 Vcb
->VolumeLockFileObject
= PtrNewFileObject
;
686 if(DesiredAccess
& ((GENERIC_WRITE
| FILE_GENERIC_WRITE
) & ~(SYNCHRONIZE
| READ_CONTROL
))) {
687 UDFPrint((" set UDF_IRP_CONTEXT_FLUSH_REQUIRED\n"));
688 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_FLUSH_REQUIRED
;
692 PtrNewFcb
= (PtrUDFFCB
)Vcb
;
693 ASSERT(!(PtrNewFcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
));
695 RC
= UDFOpenFile(Vcb
, PtrNewFileObject
, PtrNewFcb
);
697 goto op_vol_accs_dnd
;
699 PtrNewCcb
= (PtrUDFCCB
)(PtrNewFileObject
->FsContext2
);
700 if(PtrNewCcb
) PtrNewCcb
->CCBFlags
|= UDF_CCB_VOLUME_OPEN
;
702 RC
= UDFCheckAccessRights(NULL
, AccessState
, Vcb
->RootDirFCB
, PtrNewCcb
, DesiredAccess
, ShareAccess
);
703 if (!NT_SUCCESS(RC
)) {
704 AdPrint((" Access violation (Volume)\n"));
705 goto op_vol_accs_dnd
;
707 // Check _ShareAccess_
708 RC
= UDFCheckAccessRights(PtrNewFileObject
, AccessState
, PtrNewFcb
, PtrNewCcb
, DesiredAccess
, ShareAccess
);
709 if(!NT_SUCCESS(RC
)) {
710 AdPrint((" Sharing violation (Volume)\n"));
713 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_VOLUME_LOCKED
;
714 Vcb
->VolumeLockFileObject
= NULL
;
719 // NoBufferingSpecified = TRUE; See #define above
720 RequestedOptions
|= FILE_NO_INTERMEDIATE_BUFFERING
;
722 ReturnedInformation
= FILE_OPENED
;
723 UDFNotifyVolumeEvent(PtrNewFileObject
, FSRTL_VOLUME_LOCK
);
727 if((Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) &&
728 (!(Vcb
->CompatFlags
& UDF_VCB_IC_SHOW_BLANK_CD
) || UDFGlobalData
.AutoFormatCount
)) {
729 ReturnedInformation
= 0;
730 AdPrint((" Can't open anything on blank volume ;)\n"));
731 try_return(RC
= STATUS_OBJECT_NAME_NOT_FOUND
);
734 if(UdfIllegalFcbAccess(Vcb
,DesiredAccess
)) {
735 ReturnedInformation
= 0;
736 AdPrint((" Illegal share access\n"));
737 try_return(RC
= STATUS_ACCESS_DENIED
);
739 // we could mount blank R/RW media in order to allow
740 // user-mode applications to get access with Write privileges
741 ASSERT(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
);
743 // we should check appropriate privilege if OpenForBackup requested
745 RC
= SeSinglePrivilegeCheck(SeExports
->SeBackupPrivilege
, UserMode
);
750 // The FSD might wish to implement the open-by-id option. The "id"
751 // is some unique numerical representation of the on-disk object.
752 // The caller then therefore give us this file id and the FSD
753 // should be completely capable of "opening" the object (it must
754 // exist since the caller received an id for the object from the
755 // FSD in a "query file" call ...
757 // If the file has been deleted in the meantime, we'll return
764 // perform the open ...
765 PUNICODE_STRING TmpPath
;
768 UDFPrint((" open by File ID\n"));
769 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) {
770 ReturnedInformation
= 0;
771 AdPrint((" Can't open by FileID on blank volume ;)\n"));
772 try_return(RC
= STATUS_OBJECT_NAME_NOT_FOUND
);
775 if (TargetObjectName
.Length
!= sizeof(FILE_ID
)) {
776 AdPrint((" Invalid file ID\n"));
777 try_return(RC
= STATUS_INVALID_PARAMETER
);
779 Id
= *((FILE_ID
*)(TargetObjectName
.Buffer
));
780 AdPrint((" Opening by ID %8.8x%8.8x\n", (ULONG
)(Id
>>32), (ULONG
)Id
));
781 if ((RequestedDisposition
!= FILE_OPEN
) &&
782 (RequestedDisposition
!= FILE_OPEN_IF
)) {
783 AdPrint((" Illegal disposition for ID open\n"));
784 try_return(RC
= STATUS_ACCESS_DENIED
);
787 RC
= UDFGetOpenParamsByFileId(Vcb
, Id
, &TmpPath
, &IgnoreCase
);
788 if(!NT_SUCCESS(RC
)) {
789 AdPrint((" ID open failed\n"));
792 // simulate absolute path open
793 /* if(!NT_SUCCESS(RC = MyInitUnicodeString(&TargetObjectName, L"")) ||
794 !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&TargetObjectName, TmpPath, MEM_USABS_TAG))) {*/
795 if(!NT_SUCCESS(RC
= MyCloneUnicodeString(&TargetObjectName
, TmpPath
))) {
796 AdPrint((" Init String failed\n"));
799 //ASSERT(TargetObjectName.Buffer);
800 AbsolutePathName
= TargetObjectName
;
801 PtrRelatedFileObject
= NULL
;
806 // Now determine the starting point from which to begin the parsing
807 if (PtrRelatedFileObject
) {
808 // We have a user supplied related file object.
809 // This implies a "relative" open i.e. relative to the directory
810 // represented by the related file object ...
812 UDFPrint((" PtrRelatedFileObject %x, FCB %x\n", PtrRelatedFileObject
, PtrRelatedFCB
));
813 // Note: The only purpose FSD implementations ever have for
814 // the related file object is to determine whether this
815 // is a relative open or not. At all other times (including
816 // during I/O operations), this field is meaningless from
817 // the FSD's perspective.
818 if (!(PtrRelatedFCB
->FCBFlags
& UDF_FCB_DIRECTORY
)) {
819 // we must have a directory as the "related" object
820 RC
= STATUS_INVALID_PARAMETER
;
821 AdPrint((" Related object must be a directory\n"));
822 AdPrint((" Flags %x\n", PtrRelatedFCB
->FCBFlags
));
824 AdPrint((" ObjName %x, ", PtrRelatedFCB
->FCBName
->ObjectName
));
825 AdPrint((" Name %S\n", PtrRelatedFCB
->FCBName
->ObjectName
.Buffer
));
826 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
827 AdPrint((" exception when printing name\n"));
832 // So we have a directory, ensure that the name begins with
833 // a "\" i.e. begins at the root and does *not* begin with a "\\"
834 // NOTE: This is just an example of the kind of path-name string
835 // validation that a FSD must do. Although the remainder of
836 // the code may not include such checks, any commercial
837 // FSD *must* include such checking (no one else, including
838 // the I/O Manager will perform checks on the FSD's behalf)
839 if (!(RelatedObjectName
.Length
) || (RelatedObjectName
.Buffer
[0] != L
'\\')) {
840 AdPrint((" Wrong pathname (1)\n"));
841 RC
= STATUS_INVALID_PARAMETER
;
844 // similarly, if the target file name starts with a "\", it
845 // is wrong since the target file name can no longer be absolute
846 ASSERT(TargetObjectName
.Buffer
|| !TargetObjectName
.Length
);
847 if (TargetObjectName
.Length
&& (TargetObjectName
.Buffer
[0] == L
'\\')) {
848 AdPrint((" Wrong pathname (2)\n"));
849 RC
= STATUS_INVALID_PARAMETER
;
852 // Create an absolute path-name. We could potentially use
853 // the absolute path-name if we cache previously opened
854 // file/directory object names.
855 /* if(!NT_SUCCESS(RC = MyInitUnicodeString(&AbsolutePathName, L"")) ||
856 !NT_SUCCESS(RC MyAppendUnicodeStringToStringTag(&AbsolutePathName, &RelatedObjectName, MEM_USABS_TAG)))*/
857 if(!NT_SUCCESS(RC
= MyCloneUnicodeString(&AbsolutePathName
, &RelatedObjectName
)))
859 if(RelatedObjectName
.Length
&&
860 (RelatedObjectName
.Buffer
[ (RelatedObjectName
.Length
/sizeof(WCHAR
)) - 1 ] != L
'\\')) {
861 RC
= MyAppendUnicodeToString(&AbsolutePathName
, L
"\\");
862 if(!NT_SUCCESS(RC
)) try_return(RC
);
864 if(!AbsolutePathName
.Length
||
865 (AbsolutePathName
.Buffer
[ (AbsolutePathName
.Length
/sizeof(WCHAR
)) - 1 ] != L
'\\')) {
866 ASSERT(TargetObjectName
.Buffer
);
867 if(TargetObjectName
.Length
&& TargetObjectName
.Buffer
[0] != L
'\\') {
868 RC
= MyAppendUnicodeToString(&AbsolutePathName
, L
"\\");
869 if(!NT_SUCCESS(RC
)) try_return(RC
);
872 //ASSERT(TargetObjectName.Buffer);
873 RC
= MyAppendUnicodeStringToStringTag(&AbsolutePathName
, &TargetObjectName
, MEM_USABS_TAG
);
881 // The suplied path-name must be an absolute path-name i.e.
882 // starting at the root of the file system tree
883 UDFPrint((" Absolute open\n"));
884 ASSERT(TargetObjectName
.Buffer
);
885 if (!TargetObjectName
.Length
|| TargetObjectName
.Buffer
[0] != L
'\\') {
886 AdPrint((" Wrong target name (1)\n"));
887 try_return(RC
= STATUS_INVALID_PARAMETER
);
889 /* if(!NT_SUCCESS(RC = MyInitUnicodeString(&AbsolutePathName, L"")) ||
890 !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&AbsolutePathName, &TargetObjectName, MEM_USABS_TAG)))*/
891 ASSERT(TargetObjectName
.Buffer
);
892 if(!NT_SUCCESS(RC
= MyCloneUnicodeString(&AbsolutePathName
, &TargetObjectName
)))
895 // Win 32 protection :)
896 if ((AbsolutePathName
.Length
>= sizeof(WCHAR
)*2) &&
897 (AbsolutePathName
.Buffer
[1] == L
'\\') &&
898 (AbsolutePathName
.Buffer
[0] == L
'\\')) {
900 // If there are still two beginning backslashes, the name is bogus.
901 if ((AbsolutePathName
.Length
> 2*sizeof(WCHAR
)) &&
902 (AbsolutePathName
.Buffer
[2] == L
'\\')) {
903 AdPrint((" Wrong target name (2)\n"));
904 try_return (RC
= STATUS_OBJECT_NAME_INVALID
);
906 // Slide the name down in the buffer.
907 RtlMoveMemory( AbsolutePathName
.Buffer
,
908 AbsolutePathName
.Buffer
+ 1,
909 AbsolutePathName
.Length
); // .Length includes
911 AbsolutePathName
.Length
-= sizeof(WCHAR
);
913 if ( (AbsolutePathName
.Length
> sizeof(WCHAR
) ) &&
914 (AbsolutePathName
.Buffer
[ (AbsolutePathName
.Length
/sizeof(WCHAR
)) - 1 ] == L
'\\') ) {
916 AbsolutePathName
.Length
-= sizeof(WCHAR
);
919 AbsolutePathName
.Buffer
[AbsolutePathName
.Length
/sizeof(WCHAR
)] = 0;
921 // Sometimes W2000 decides to duplicate handle of
922 // already opened File/Dir. In this case it sends us
923 // RelatedFileObject & specifies zero-filled RelativePath
924 if(!TargetObjectName
.Length
) {
925 TargetObjectName
= AbsolutePathName
;
928 //ASSERT(TargetObjectName.Buffer);
931 // First, check if the caller simply wishes to open the Root
932 // of the file system tree.
934 if (AbsolutePathName
.Length
== sizeof(WCHAR
)) {
935 AdPrint((" Opening RootDir\n"));
936 // this is an open of the root directory, ensure that the caller
937 // has not requested a file only
938 if (FileOnlyRequested
|| (RequestedDisposition
== FILE_SUPERSEDE
) ||
939 (RequestedDisposition
== FILE_OVERWRITE
) ||
940 (RequestedDisposition
== FILE_OVERWRITE_IF
)) {
941 AdPrint((" Can't overwrite RootDir\n"));
942 RC
= STATUS_FILE_IS_A_DIRECTORY
;
947 CollectStatistics(Vcb
, MetaDataReads
);
950 if (DeleteOnCloseSpecified
) {
951 // delete RootDir.... rather strange idea... I dislike it
952 AdPrint((" Can't delete RootDir\n"));
953 try_return(RC
= STATUS_CANNOT_DELETE
);
956 PtrNewFcb
= Vcb
->RootDirFCB
;
957 RC
= UDFOpenFile(Vcb
, PtrNewFileObject
, PtrNewFcb
);
958 if(!NT_SUCCESS(RC
)) try_return(RC
);
959 // DbgPrint("UDF: Open/Create RootDir : ReferenceCount %x\n",PtrNewFcb->ReferenceCount);
960 UDFReferenceFile__(PtrNewFcb
->FileInfo
);
961 PtrNewCcb
= (PtrUDFCCB
)(PtrNewFileObject
->FsContext2
);
964 RC
= UDFCheckAccessRights(PtrNewFileObject
, AccessState
, PtrNewFcb
, PtrNewCcb
, DesiredAccess
, ShareAccess
);
965 if(!NT_SUCCESS(RC
)) {
966 AdPrint((" Access/Sharing violation (RootDir)\n"));
970 ReturnedInformation
= FILE_OPENED
;
973 } // end of OpenRootDir
976 AdPrint((" Opening file %ws %8.8x\n",AbsolutePathName
.Buffer
, PtrNewFileObject
));
977 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
978 AdPrint((" Exception when printing FN\n"));
981 // Check if we have DuplicateHandle (or Reopen) request
986 // We don't handle OpenTargetDirectory in this case
987 if(OpenTargetDirectory
)
988 try_return(RC
= STATUS_INVALID_PARAMETER
);
990 // Init environment to simulate normal open procedure behavior
991 /* if(!NT_SUCCESS(RC = MyInitUnicodeString(&LocalPath, L"")) ||
992 !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&LocalPath, &TargetObjectName, MEM_USLOC_TAG)))*/
993 ASSERT(TargetObjectName
.Buffer
);
994 if(!NT_SUCCESS(RC
= MyCloneUnicodeString(&LocalPath
, &TargetObjectName
)))
997 ASSERT(PtrRelatedFCB
);
998 RelatedFileInfo
= PtrRelatedFCB
->FileInfo
;
1000 RC
= STATUS_SUCCESS
;
1002 LastGoodFileInfo
= RelatedFileInfo
;
1005 OldRelatedFileInfo
= RelatedFileInfo
->ParentFile
;
1006 PtrRelatedFCB
= PtrRelatedFCB
->ParentFcb
;
1007 // prevent releasing parent structures
1008 UDFAcquireParent(RelatedFileInfo
, &Res1
, &Res2
);
1011 if(Res1
) UDFReleaseResource(Res1
);
1012 if(Res2
) UDFReleaseResource(Res2
);
1014 UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo
->Fcb
->NTRequiredFCB
);
1015 UDFAcquireResourceExclusive(Res2
= &(RelatedFileInfo
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1016 PtrNewFcb
= NewFileInfo
->Fcb
;
1018 UDF_CHECK_PAGING_IO_RESOURCE(PtrNewFcb
->NTRequiredFCB
);
1019 UDFAcquireResourceExclusive(Res1
= &(PtrNewFcb
->NTRequiredFCB
->MainResource
),TRUE
);
1020 UDFReferenceFile__(NewFileInfo
);
1026 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) {
1027 ReturnedInformation
= 0;
1028 AdPrint((" Can't open File on blank volume ;)\n"));
1029 try_return(RC
= STATUS_OBJECT_NAME_NOT_FOUND
);
1032 //AdPrint((" Opening file %ws %8.8x\n",AbsolutePathName.Buffer, PtrNewFileObject));
1034 if(AbsolutePathName
.Length
> UDF_X_PATH_LEN
*sizeof(WCHAR
)) {
1035 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
1038 // validate path specified
1039 // (sometimes we can see here very strange characters ;)
1040 if(!UDFIsNameValid(&AbsolutePathName
, &StreamOpen
, &SNameIndex
)) {
1041 AdPrint((" Absolute path is not valid\n"));
1042 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
1044 if(StreamOpen
&& !UDFStreamsSupported(Vcb
)) {
1045 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
1048 RC
= MyInitUnicodeString(&LocalPath
, L
"");
1051 if (PtrRelatedFileObject
) {
1052 // Our "start directory" is the one identified
1053 // by the related file object
1054 RelatedFileInfo
= PtrRelatedFCB
->FileInfo
;
1055 if(RelatedFileInfo
!= Vcb
->RootDirFCB
->FileInfo
) {
1056 RC
= MyAppendUnicodeStringToStringTag(&LocalPath
, &(PtrRelatedFCB
->FCBName
->ObjectName
), MEM_USLOC_TAG
);
1060 if(TargetObjectName
.Buffer
!= AbsolutePathName
.Buffer
) {
1061 ASSERT(TargetObjectName
.Buffer
);
1062 if(!NT_SUCCESS(RC
= MyCloneUnicodeString(&TailName
, &TargetObjectName
))) {
1063 AdPrint((" Init String 'TargetObjectName' failed\n"));
1066 TailNameBuffer
= TailName
.Buffer
;
1068 TailName
= AbsolutePathName
;
1071 // Start at the root of the file system
1072 RelatedFileInfo
= Vcb
->RootDirFCB
->FileInfo
;
1073 TailName
= AbsolutePathName
;
1077 StreamName
= AbsolutePathName
;
1078 StreamName
.Buffer
+= SNameIndex
;
1079 StreamName
.Length
-= (USHORT
)SNameIndex
*sizeof(WCHAR
);
1080 // if StreamOpen specified & stream name starts with NULL character
1081 // we should create Stream Dir at first
1082 TailName
.Length
-= (AbsolutePathName
.Length
- (USHORT
)SNameIndex
*sizeof(WCHAR
));
1083 AbsolutePathName
.Length
= (USHORT
)SNameIndex
*sizeof(WCHAR
);
1085 CurName
.MaximumLength
= TailName
.MaximumLength
;
1087 RC
= STATUS_SUCCESS
;
1088 LastGoodName
.Length
= 0;
1089 LastGoodFileInfo
= RelatedFileInfo
;
1090 // reference RelatedObject to prevent releasing parent structures
1091 UDFAcquireParent(RelatedFileInfo
, &Res1
, &Res2
);
1094 // go into a loop parsing the supplied name
1096 // Note that we may have to "open" intermediate directory objects
1097 // while traversing the path. We should __try to reuse existing code
1098 // whenever possible therefore we should consider using a common
1099 // open routine regardless of whether the open is on behalf of the
1100 // caller or an intermediate (internal) open performed by the driver.
1103 // now we'll parse path to desired file
1108 // remember last 'good' ('good' means NO ERRORS before) path tail
1109 if(NT_SUCCESS(RC
)) {
1110 LastGoodTail
= TailName
;
1111 while(LastGoodTail
.Buffer
[0] == L
'\\') {
1112 LastGoodTail
.Buffer
++;
1113 LastGoodTail
.Length
-= sizeof(WCHAR
);
1116 // get next path part...
1117 TmpBuffer
= TailName
.Buffer
;
1118 TailName
.Buffer
= UDFDissectName(TailName
.Buffer
,&(CurName
.Length
) );
1119 TailName
.Length
-= (USHORT
)((ULONG
)(TailName
.Buffer
) - (ULONG
)TmpBuffer
);
1120 CurName
.Buffer
= TailName
.Buffer
- CurName
.Length
;
1121 CurName
.Length
*= sizeof(WCHAR
);
1122 CurName
.MaximumLength
= CurName
.Length
+ sizeof(WCHAR
);
1123 // check if we have already opened the component before last one
1124 // in this case OpenTargetDir request will be served in a special
1126 if(OpenTargetDirectory
&& NT_SUCCESS(RC
) && !TailName
.Length
) {
1127 // check if we should open SDir..
1129 (TailName
.Buffer
[0]!=L
':')) {
1130 // no, we should not. Continue with OpenTargetDir
1135 if( CurName
.Length
&&
1136 (NT_SUCCESS(RC
) || !StreamOpen
)) {
1137 // ...wow! non-zero! try to open!
1138 if(!NT_SUCCESS(RC
)) {
1139 AdPrint((" Error opening path component\n"));
1140 // we haven't reached last name part... hm..
1141 // probably, the path specified is invalid..
1142 // or we had a hard error... What else can we do ?
1143 // Only say ..CK OFF !!!!
1144 if(RC
== STATUS_OBJECT_NAME_NOT_FOUND
)
1145 RC
= STATUS_OBJECT_PATH_NOT_FOUND
;
1149 ASSERT_REF(RelatedFileInfo
->Fcb
->ReferenceCount
>= RelatedFileInfo
->RefCount
);
1151 if(RelatedFileInfo
&& (TreeLength
>1)) {
1152 // it was an internal Open operation. Thus, assume
1153 // RelatedFileInfo's Fcb to be valid
1154 RelatedFileInfo
->Fcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_VALID
;
1155 RelatedFileInfo
->Fcb
->FCBFlags
|= UDF_FCB_VALID
;
1157 // check path fragment size
1158 if(CurName
.Length
> UDF_X_NAME_LEN
* sizeof(WCHAR
)) {
1159 AdPrint((" Path component is too long\n"));
1160 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
1162 // ...and now release previously acquired objects,
1163 if(Res1
) UDFReleaseResource(Res1
);
1165 UDFReleaseResource(Res2
);
1168 // acquire new _parent_ directory & try to open what
1171 UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo
->Fcb
->NTRequiredFCB
);
1172 UDFAcquireResourceExclusive(Res1
= &(RelatedFileInfo
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1174 // check traverse rights
1175 RC
= UDFCheckAccessRights(NULL
, NULL
, RelatedFileInfo
->Fcb
, PtrRelatedCCB
, FILE_TRAVERSE
, 0);
1176 if(!NT_SUCCESS(RC
)) {
1178 AdPrint((" Traverse check failed\n"));
1179 goto Skip_open_attempt
;
1181 // check if we should open normal File/Dir or SDir
1182 if(CurName
.Buffer
[0] != ':') {
1183 // standard open, nothing interesting....
1184 RC
= UDFOpenFile__(Vcb
,
1185 IgnoreCase
,TRUE
,&CurName
,
1186 RelatedFileInfo
,&NewFileInfo
,NULL
);
1187 if(RC
== STATUS_FILE_DELETED
) {
1188 // file has gone, but system still remembers it...
1190 AdPrint((" File deleted\n"));
1191 RC
= STATUS_ACCESS_DENIED
;
1194 if(RC
== STATUS_NOT_A_DIRECTORY
) {
1195 AdPrint((" Not a directory\n"));
1198 if(RC
== STATUS_SHARING_PAUSED
) {
1199 AdPrint((" Dloc is being initialized\n"));
1201 RC
= STATUS_SHARING_VIOLATION
;
1204 // And here we should open Stream Dir (if any, of cource)
1205 RC
= UDFOpenStreamDir__(Vcb
, RelatedFileInfo
, &NewFileInfo
);
1206 if(NT_SUCCESS(RC
)) {
1208 // this indicates that we needn't Stream Dir creation
1209 StreamExists
= TRUE
;
1210 StreamName
.Buffer
++;
1211 StreamName
.Length
-=sizeof(WCHAR
);
1213 TailName
= StreamName
;
1215 if(RC
== STATUS_NOT_FOUND
) {
1216 #ifndef UDF_READ_ONLY_BUILD
1217 // Stream Dir doesn't exist, but caller wants it to be
1218 // created. Lets try to help him...
1219 if((RequestedDisposition
== FILE_CREATE
) ||
1220 (RequestedDisposition
== FILE_OPEN_IF
) ||
1221 (RequestedDisposition
== FILE_OVERWRITE_IF
) ||
1222 OpenTargetDirectory
) {
1223 RC
= UDFCreateStreamDir__(Vcb
, RelatedFileInfo
, &NewFileInfo
);
1225 goto SuccessOpen_SDir
;
1227 #endif //UDF_READ_ONLY_BUILD
1230 AdPrint((" File deleted (2)\n"));
1231 RC = STATUS_ACCESS_DENIED;*/
1234 CollectStatistics(Vcb
, MetaDataReads
);
1239 // check if we have successfully opened path component
1240 if(NT_SUCCESS(RC
)) {
1242 if (!(PtrNewFcb
= NewFileInfo
->Fcb
)) {
1243 // It is a first open operation
1245 // Here we set FileObject pointer to NULL to avoid
1246 // new CCB allocation
1247 RC
= UDFFirstOpenFile(Vcb
,
1248 NULL
, &PtrNewFcb
, RelatedFileInfo
, NewFileInfo
,
1249 &LocalPath
, &CurName
);
1251 if(!NT_SUCCESS(RC
)) {
1253 AdPrint((" Can't perform FirstOpen\n"));
1254 UDFCloseFile__(Vcb
, NewFileInfo
);
1255 if(PtrNewFcb
) UDFCleanUpFCB(PtrNewFcb
);
1257 NewFileInfo
->Fcb
= NULL
;
1258 if(UDFCleanUpFile__(Vcb
, NewFileInfo
)) {
1259 MyFreePool__(NewFileInfo
);
1265 // It is not a first open operation
1266 // Validate Fcb. It is possible to get
1267 // not completly initialized Fcb here.
1268 if(!(PtrNewFcb
->FCBFlags
& UDF_FCB_VALID
)) {
1270 AdPrint((" Fcb not valid\n"));
1271 UDFCloseFile__(Vcb
, NewFileInfo
);
1273 if(UDFCleanUpFile__(Vcb
, NewFileInfo
)) {
1274 MyFreePool__(NewFileInfo
);
1277 try_return(RC
= STATUS_ACCESS_DENIED
);
1280 // Acquire newly opened File...
1282 UDF_CHECK_PAGING_IO_RESOURCE(NewFileInfo
->Fcb
->NTRequiredFCB
);
1283 UDFAcquireResourceExclusive(Res1
= &(NewFileInfo
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1284 // ...and reference it
1285 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->ReferenceCount
));
1286 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->NTRequiredFCB
->CommonRefCount
));
1288 ASSERT_REF(PtrNewFcb
->ReferenceCount
>= NewFileInfo
->RefCount
);
1289 // update unwind information
1290 LastGoodFileInfo
= NewFileInfo
;
1291 LastGoodName
= CurName
;
1293 // update current path
1295 ((CurName
.Buffer
[0] != L
':') &&
1296 (!LocalPath
.Length
|| (LocalPath
.Buffer
[LocalPath
.Length
/sizeof(WCHAR
)-1] != L
':'))) ) {
1297 // we should not insert '\' before or after ':'
1298 ASSERT(!LocalPath
.Length
||
1299 (LocalPath
.Buffer
[LocalPath
.Length
/2-1] != L
'\\'));
1300 RC
= MyAppendUnicodeToString(&LocalPath
, L
"\\");
1301 if(!NT_SUCCESS(RC
)) try_return(RC
);
1303 RC
= MyAppendUnicodeStringToStringTag(&LocalPath
, &CurName
, MEM_USLOC_TAG
);
1306 // DbgPrint("UDF: Open/Create File %ws : ReferenceCount %x\n",CurName.Buffer,PtrNewFcb->ReferenceCount);
1308 AdPrint((" Can't open file\n"));
1309 // We have failed durring last Open attempt
1310 // Roll back to last good state
1311 PtrUDFNTRequiredFCB NtReqFcb
= NULL
;
1312 // Cleanup FileInfo if any
1314 PtrNewFcb
= NewFileInfo
->Fcb
;
1315 // acquire appropriate resource if possible
1317 PtrNewFcb
->NTRequiredFCB
) {
1318 NtReqFcb
= PtrNewFcb
->NTRequiredFCB
;
1320 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
1321 UDFAcquireResourceExclusive(Res1
= &(NtReqFcb
->MainResource
),TRUE
);
1323 // cleanup pointer to Fcb in FileInfo to allow
1324 // UDF_INFO package release FileInfo if there are
1325 // no more references
1327 !PtrNewFcb
->ReferenceCount
&&
1328 !PtrNewFcb
->OpenHandleCount
) {
1329 NewFileInfo
->Fcb
= NULL
;
1331 // cleanup pointer to CommonFcb in Dloc to allow
1332 // UDF_INFO package release Dloc if there are
1333 // no more references
1334 if(NewFileInfo
->Dloc
&&
1335 !NewFileInfo
->Dloc
->LinkRefCount
&&
1336 (!PtrNewFcb
|| !PtrNewFcb
->ReferenceCount
)) {
1337 NewFileInfo
->Dloc
->CommonFcb
= NULL
;
1339 // try to release FileInfo
1340 if(UDFCleanUpFile__(Vcb
, NewFileInfo
)) {
1344 UDFCleanUpFCB(PtrNewFcb
);
1346 MyFreePool__(NewFileInfo
);
1348 // if we can't release FileInfo
1349 // restore pointers to Fcb & CommonFcb in
1351 NewFileInfo
->Fcb
= PtrNewFcb
;
1353 NewFileInfo
->Dloc
->CommonFcb
= NtReqFcb
;
1355 // forget about last FileInfo & Fcb,
1356 // further unwind staff needs only last good
1363 // should return error if 'delete in progress'
1364 if(LastGoodFileInfo
->Fcb
->FCBFlags
& (UDF_FCB_DELETE_ON_CLOSE
|
1366 UDF_FCB_POSTED_RENAME
)) {
1367 AdPrint((" Return DeletePending (no err)\n"));
1368 try_return(RC
= STATUS_DELETE_PENDING
);
1370 // update last good state information...
1371 OldRelatedFileInfo
= RelatedFileInfo
;
1372 RelatedFileInfo
= NewFileInfo
;
1373 // ...and go to the next open cycle
1376 if(StreamOpen
&& (RC
== STATUS_NOT_FOUND
))
1377 // handle SDir return code
1378 RC
= STATUS_OBJECT_NAME_NOT_FOUND
;
1379 if(RC
== STATUS_OBJECT_NAME_NOT_FOUND
) {
1380 // good path, but no such file.... Amen
1381 // break open loop and continue with Create
1384 if (!NT_SUCCESS(RC
)) {
1385 // Hard error or damaged data structures ...
1387 if((RC
!= STATUS_OBJECT_PATH_NOT_FOUND
) &&
1388 (RC
!= STATUS_ACCESS_DENIED
) &&
1389 (RC
!= STATUS_NOT_A_DIRECTORY
)) {
1390 AdPrint((" Hard error or damaged data structures\n"));
1393 // ... and exit with error
1396 // discard changes for last successfully opened file
1397 UDFInterlockedDecrement((PLONG
)&(PtrNewFcb
->ReferenceCount
));
1398 UDFInterlockedDecrement((PLONG
)&(PtrNewFcb
->NTRequiredFCB
->CommonRefCount
));
1399 RC
= STATUS_SUCCESS
;
1400 ASSERT(!OpenTargetDirectory
);
1401 // break open loop and continue with Open
1402 // (Create will be skipped)
1405 } // end of while(TRUE)
1408 // If "open target directory" was specified
1410 if(OpenTargetDirectory
) {
1412 if(!UDFIsADirectory(LastGoodFileInfo
)) {
1413 AdPrint((" Not a directory (2)\n"));
1414 RC
= STATUS_NOT_A_DIRECTORY
;
1416 if(!NT_SUCCESS(RC
) ||
1418 AdPrint((" Target name should not contain (back)slashes\n"));
1420 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
1423 NewFileInfo
= LastGoodFileInfo
;
1424 RtlCopyUnicodeString(&(PtrNewFileObject
->FileName
), &CurName
);
1426 // now we have to check if last component exists...
1427 if(NT_SUCCESS(RC
= UDFFindFile__(Vcb
, IgnoreCase
,
1428 &CurName
, RelatedFileInfo
))) {
1429 // file exists, set this information in the Information field
1430 ReturnedInformation
= FILE_EXISTS
;
1431 AdPrint((" Open Target: FILE_EXISTS\n"));
1433 if(RC
== STATUS_OBJECT_NAME_NOT_FOUND
) {
1435 // check name. If there are '\\'s in TailName, some
1436 // directories in path specified do not exist
1437 for(TmpBuffer
= LastGoodTail
.Buffer
; *TmpBuffer
; TmpBuffer
++) {
1438 if((*TmpBuffer
) == L
'\\') {
1440 AdPrint((" Target name should not contain (back)slashes\n"));
1441 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
1445 // Tell the I/O Manager that file does not exit
1446 ReturnedInformation
= FILE_DOES_NOT_EXIST
;
1447 AdPrint((" Open Target: FILE_DOES_NOT_EXIST\n"));
1448 RC
= STATUS_SUCCESS
; // is already set here
1450 AdPrint((" Open Target: unexpected error\n"));
1452 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
1455 // RC = STATUS_SUCCESS; // is already set here
1457 // Update the file object FsContext and FsContext2 fields
1458 // to reflect the fact that the parent directory of the
1459 // target has been opened
1460 PtrNewFcb
= NewFileInfo
->Fcb
;
1461 UDFInterlockedDecrement((PLONG
)&(PtrNewFcb
->ReferenceCount
));
1462 UDFInterlockedDecrement((PLONG
)&(PtrNewFcb
->NTRequiredFCB
->CommonRefCount
));
1463 RC
= UDFOpenFile(Vcb
, PtrNewFileObject
, PtrNewFcb
);
1464 ASSERT_REF(PtrNewFcb
->ReferenceCount
>= NewFileInfo
->RefCount
);
1465 if (!NT_SUCCESS(RC
)) {
1466 AdPrint((" Can't perform OpenFile operation for target\n"));
1469 PtrNewCcb
= (PtrUDFCCB
)(PtrNewFileObject
->FsContext2
);
1472 RC
= UDFCheckAccessRights(PtrNewFileObject
, AccessState
, PtrNewFcb
, PtrNewCcb
, DesiredAccess
, ShareAccess
);
1473 if(!NT_SUCCESS(RC
)) {
1474 AdPrint((" Access/Share access check failed (Open Target)\n"));
1481 // should we CREATE a new file ?
1483 if (!NT_SUCCESS(RC
)) {
1484 if (RC
== STATUS_OBJECT_NAME_NOT_FOUND
||
1485 RC
== STATUS_OBJECT_PATH_NOT_FOUND
) {
1486 if( ((RequestedDisposition
== FILE_OPEN
) ||
1487 (RequestedDisposition
== FILE_OVERWRITE
)) /*&&
1488 (!StreamOpen || !StreamExists)*/ ){
1489 ReturnedInformation
= FILE_DOES_NOT_EXIST
;
1490 AdPrint((" File doesn't exist\n"));
1494 // Any other operation return STATUS_ACCESS_DENIED.
1495 AdPrint((" Can't create due to unexpected error\n"));
1498 // Object was not found, create if requested
1499 if ((RequestedDisposition
!= FILE_CREATE
) && (RequestedDisposition
!= FILE_OPEN_IF
) &&
1500 (RequestedDisposition
!= FILE_OVERWRITE_IF
) && (RequestedDisposition
!= FILE_SUPERSEDE
)) {
1501 AdPrint((" File doesn't exist (2)\n"));
1504 // Check Volume ReadOnly attr
1505 #ifndef UDF_READ_ONLY_BUILD
1506 if((Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
)) {
1507 #endif //UDF_READ_ONLY_BUILD
1508 ReturnedInformation
= 0;
1509 AdPrint((" Write protected\n"));
1510 try_return(RC
= STATUS_MEDIA_WRITE_PROTECTED
);
1511 #ifndef UDF_READ_ONLY_BUILD
1513 // Check r/o + delete on close
1514 if(DeleteOnCloseSpecified
&&
1515 (FileAttributes
& FILE_ATTRIBUTE_READONLY
)) {
1516 AdPrint((" Can't create r/o file marked for deletion\n"));
1517 try_return(RC
= STATUS_CANNOT_DELETE
);
1520 // Create a new file/directory here ...
1522 StreamName
.Buffer
[StreamName
.Length
/sizeof(WCHAR
)] = 0;
1523 for(TmpBuffer
= LastGoodTail
.Buffer
; *TmpBuffer
; TmpBuffer
++) {
1524 if((*TmpBuffer
) == L
'\\') {
1525 AdPrint((" Target name should not contain (back)slashes\n"));
1526 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
1529 if( DirectoryOnlyRequested
&&
1530 ((IrpSp
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_TEMPORARY
) ||
1531 StreamOpen
|| FALSE
)) {
1532 AdPrint((" Creation of _temporary_ directory not permited\n"));
1533 try_return(RC
= STATUS_INVALID_PARAMETER
);
1535 // check access rights
1537 RC
= UDFCheckAccessRights(NULL
, NULL
, OldRelatedFileInfo
->Fcb
, PtrRelatedCCB
, DirectoryOnlyRequested
? FILE_ADD_SUBDIRECTORY
: FILE_ADD_FILE
, 0);
1538 if(!NT_SUCCESS(RC
)) {
1539 AdPrint((" Creation of File/Dir not permitted\n"));
1542 // Note that a FCB structure will be allocated at this time
1543 // and so will a CCB structure. Assume that these are called
1544 // PtrNewFcb and PtrNewCcb respectively.
1545 // Further, note that since the file is being created, no other
1546 // thread can have the file stream open at this time.
1547 RelatedFileInfo
= OldRelatedFileInfo
;
1549 RC
= UDFCreateFile__(Vcb
, IgnoreCase
, &LastGoodTail
, 0, 0,
1550 Vcb
->UseExtendedFE
|| (StreamOpen
&& !StreamExists
),
1551 (RequestedDisposition
== FILE_CREATE
), RelatedFileInfo
, &NewFileInfo
);
1552 if(!NT_SUCCESS(RC
)) {
1553 AdPrint((" Creation error\n"));
1556 PtrNewFcb
= NewFileInfo
->Fcb
;
1559 !PtrNewFcb
->ReferenceCount
&&
1560 !PtrNewFcb
->OpenHandleCount
) {
1561 NewFileInfo
->Fcb
= NULL
;
1563 if(NewFileInfo
->Dloc
&&
1564 !NewFileInfo
->Dloc
->LinkRefCount
) {
1565 NewFileInfo
->Dloc
->CommonFcb
= NULL
;
1567 if(UDFCleanUpFile__(Vcb
, NewFileInfo
)) {
1570 UDFCleanUpFCB(PtrNewFcb
);
1572 MyFreePool__(NewFileInfo
);
1573 PtrNewFcb
= PtrNewFcb
;
1575 NewFileInfo
->Fcb
= PtrNewFcb
;
1581 // Update parent object
1582 if((Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_DIR_WRITE
) &&
1584 PtrRelatedFileObject
&&
1585 (PtrRelatedFCB
->FileInfo
== NewFileInfo
->ParentFile
)) {
1586 PtrRelatedFileObject
->Flags
|= (FO_FILE_MODIFIED
| FO_FILE_SIZE_CHANGED
);
1589 CollectStatistics(Vcb
, MetaDataWrites
);
1592 if(DirectoryOnlyRequested
) {
1593 // user wants the directory to be created
1594 RC
= UDFRecordDirectory__(Vcb
, NewFileInfo
);
1595 if(!NT_SUCCESS(RC
)) {
1596 AdPrint((" Can't transform to directory\n"));
1598 if((RC
!= STATUS_FILE_IS_A_DIRECTORY
) &&
1599 (RC
!= STATUS_NOT_A_DIRECTORY
) &&
1600 (RC
!= STATUS_ACCESS_DENIED
)) {
1601 UDFFlushFile__(Vcb
, NewFileInfo
);
1602 UDFUnlinkFile__(Vcb
, NewFileInfo
, TRUE
);
1604 UDFCloseFile__(Vcb
, NewFileInfo
);
1606 goto Creation_Err_1
;
1609 CollectStatistics(Vcb
, MetaDataWrites
);
1611 } else if(AllocationSize
) {
1612 // set initial file size
1613 /* if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) {
1614 AdPrint((" Can't set initial file size\n"));
1617 CollectStatistics(Vcb, MetaDataWrites);*/
1620 if(StreamOpen
&& !StreamExists
) {
1624 // Open the newly created object (file)
1625 if (!(PtrNewFcb
= NewFileInfo
->Fcb
)) {
1626 // It is a first open operation
1628 // Here we set FileObject pointer to NULL to avoid
1629 // new CCB allocation
1630 RC
= UDFFirstOpenFile(Vcb
,
1631 NULL
, &PtrNewFcb
, RelatedFileInfo
, NewFileInfo
,
1632 &LocalPath
, &LastGoodTail
);
1633 if(!NT_SUCCESS(RC
)) {
1634 AdPrint((" Can't perform FirstOpenFile operation for file to contain stream\n"));
1636 UDFCleanUpFCB(NewFileInfo
->Fcb
);
1637 NewFileInfo
->Fcb
= NULL
;
1638 goto Creation_Err_1
;
1644 // Update unwind information
1646 LastGoodFileInfo
= NewFileInfo
;
1648 RC
= MyAppendUnicodeToString(&LocalPath
, L
"\\");
1649 if(!NT_SUCCESS(RC
)) try_return(RC
);
1650 RC
= MyAppendUnicodeStringToStringTag(&LocalPath
, &LastGoodTail
, MEM_USLOC_TAG
);
1652 goto Creation_Err_1
;
1653 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->ReferenceCount
));
1654 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->NTRequiredFCB
->CommonRefCount
));
1655 ASSERT_REF(PtrNewFcb
->ReferenceCount
>= NewFileInfo
->RefCount
);
1656 PtrNewFcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_VALID
;
1657 PtrNewFcb
->FCBFlags
|= UDF_FCB_VALID
;
1659 UDFNotifyFullReportChange( Vcb
, NewFileInfo
,
1660 UDFIsADirectory(NewFileInfo
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
1665 // we need to create Stream Dir
1666 RelatedFileInfo
= NewFileInfo
;
1667 RC
= UDFCreateStreamDir__(Vcb
, RelatedFileInfo
, &NewFileInfo
);
1668 if(!NT_SUCCESS(RC
)) {
1669 AdPrint((" Can't create SDir\n"));
1671 goto Creation_Err_1
;
1674 CollectStatistics(Vcb
, MetaDataWrites
);
1677 // normalize stream name
1678 StreamName
.Buffer
++;
1679 StreamName
.Length
-=sizeof(WCHAR
);
1680 // Open the newly created object
1681 if (!(PtrNewFcb
= NewFileInfo
->Fcb
)) {
1682 // It is a first open operation
1684 // Here we set FileObject pointer to NULL to avoid
1685 // new CCB allocation
1686 RC
= UDFFirstOpenFile(Vcb
,
1687 NULL
, &PtrNewFcb
, RelatedFileInfo
, NewFileInfo
,
1688 &LocalPath
, &(UDFGlobalData
.UnicodeStrSDir
));
1692 if(!NT_SUCCESS(RC
)) {
1693 AdPrint((" Can't perform OpenFile operation for SDir\n"));
1695 goto Creation_Err_1
;
1698 // Update unwind information
1700 LastGoodFileInfo
= NewFileInfo
;
1702 RC
= MyAppendUnicodeStringToStringTag(&LocalPath
, &(UDFGlobalData
.UnicodeStrSDir
), MEM_USLOC_TAG
);
1703 if(!NT_SUCCESS(RC
)) {
1704 AdPrint((" Can't append UNC str\n"));
1706 goto Creation_Err_1
;
1708 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->ReferenceCount
));
1709 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->NTRequiredFCB
->CommonRefCount
));
1710 ASSERT_REF(PtrNewFcb
->ReferenceCount
>= NewFileInfo
->RefCount
);
1711 PtrNewFcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_VALID
;
1712 PtrNewFcb
->FCBFlags
|= UDF_FCB_VALID
;
1717 RelatedFileInfo
= NewFileInfo
;
1718 RC
= UDFCreateFile__(Vcb
, IgnoreCase
, &StreamName
, 0, 0,
1719 Vcb
->UseExtendedFE
, (RequestedDisposition
== FILE_CREATE
),
1720 RelatedFileInfo
, &NewFileInfo
);
1721 if(!NT_SUCCESS(RC
)) {
1722 AdPrint((" Can't create Stream\n"));
1724 goto Creation_Err_1
;
1727 CollectStatistics(Vcb
, MetaDataWrites
);
1730 // Update unwind information
1731 LastGoodTail
= StreamName
;
1733 // NT wants ARCHIVE bit to be set on Files
1734 if(!DirectoryOnlyRequested
)
1735 FileAttributes
|= FILE_ATTRIBUTE_ARCHIVE
;
1736 // Open the newly created object
1737 if (!(PtrNewFcb
= NewFileInfo
->Fcb
)) {
1738 // It is a first open operation
1740 // Set attributes for the file ...
1741 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo
),NewFileInfo
->Index
),
1742 NewFileInfo
->Dloc
->FileEntry
, FileAttributes
);
1745 // Here we set FileObject pointer to NULL to avoid
1746 // new CCB allocation
1747 RC
= UDFFirstOpenFile(Vcb
,
1748 PtrNewFileObject
, &PtrNewFcb
, RelatedFileInfo
, NewFileInfo
,
1749 &LocalPath
, &LastGoodTail
);
1754 if(!NT_SUCCESS(RC
)) {
1755 AdPrint((" Can't perform OpenFile operation for file or stream\n"));
1760 PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.FileSize
.QuadPart
=
1761 PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.ValidDataLength
.QuadPart
= 0;
1762 if(AllocationSize
) {
1763 // inform NT about size changes
1764 PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
.QuadPart
= AllocationSize
;
1765 MmPrint((" CcIsFileCached()\n"));
1766 if(CcIsFileCached(PtrNewFileObject
)) {
1767 MmPrint((" CcSetFileSizes()\n"));
1769 CcSetFileSizes(PtrNewFileObject
, (PCC_FILE_SIZES
)&(PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
));
1770 PtrNewFcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_MODIFIED
;
1774 // Update unwind information
1776 LastGoodFileInfo
= NewFileInfo
;
1778 // Set the Share Access for the file stream.
1779 // The FCBShareAccess field will be set by the I/O Manager.
1780 PtrNewCcb
= (PtrUDFCCB
)(PtrNewFileObject
->FsContext2
);
1781 RC
= UDFSetAccessRights(PtrNewFileObject
, AccessState
, PtrNewFcb
, PtrNewCcb
, DesiredAccess
, ShareAccess
);
1783 if(!NT_SUCCESS(RC
)) {
1784 AdPrint((" Can't set Access Rights on Create\n"));
1786 UDFFlushFile__(Vcb
, NewFileInfo
);
1787 UDFUnlinkFile__(Vcb
, NewFileInfo
, TRUE
);
1792 // Set attributes for the file ...
1793 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo
),NewFileInfo
->Index
),
1794 NewFileInfo
->Dloc
->FileEntry
, FileAttributes
);
1795 // It is rather strange for me, but NT requires us to allow
1796 // Create operation for r/o + WriteAccess, but denies all
1797 // the rest operations in this case. Thus, we should update
1798 // r/o flag in Fcb _after_ Access check :-/
1799 if(FileAttributes
& FILE_ATTRIBUTE_READONLY
)
1800 PtrNewFcb
->FCBFlags
|= UDF_FCB_READ_ONLY
;
1802 // We call the notify package to report that the
1803 // we have added a stream.
1804 if(UDFIsAStream(NewFileInfo
)) {
1805 UDFNotifyFullReportChange( Vcb
, NewFileInfo
,
1806 FILE_NOTIFY_CHANGE_STREAM_NAME
,
1807 FILE_ACTION_ADDED_STREAM
);
1809 UDFNotifyFullReportChange( Vcb
, NewFileInfo
,
1810 UDFIsADirectory(NewFileInfo
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
1816 PDIR_INDEX_HDR hDirIndex = NewFileInfo->ParentFile->Dloc->DirIndex;
1818 for(i=0;DirIndex[i].FName.Buffer;i++) {
1819 AdPrint(("%ws\n", DirIndex[i].FName.Buffer));
1823 ReturnedInformation
= FILE_CREATED
;
1826 #endif //UDF_READ_ONLY_BUILD
1833 // we have always STATUS_SUCCESS here
1836 ASSERT(NewFileInfo
!= OldRelatedFileInfo
);
1837 // A new CCB will be allocated.
1838 // Assume that this structure named PtrNewCcb
1839 RC
= UDFOpenFile(Vcb
, PtrNewFileObject
, PtrNewFcb
);
1840 if (!NT_SUCCESS(RC
)) try_return(RC
);
1841 PtrNewCcb
= (PtrUDFCCB
)(PtrNewFileObject
->FsContext2
);
1843 if(RequestedDisposition
== FILE_CREATE
) {
1844 ReturnedInformation
= FILE_EXISTS
;
1845 AdPrint((" Object name collision\n"));
1846 try_return(RC
= STATUS_OBJECT_NAME_COLLISION
);
1849 NtReqFcb
= PtrNewFcb
->NTRequiredFCB
;
1850 NtReqFcb
->CommonFCBHeader
.IsFastIoPossible
= UDFIsFastIoPossible(PtrNewFcb
);
1852 // Check if caller wanted a directory only and target object
1853 // is not a directory, or caller wanted a file only and target
1854 // object is not a file ...
1855 if((PtrNewFcb
->FCBFlags
& UDF_FCB_DIRECTORY
) && ((RequestedDisposition
== FILE_SUPERSEDE
) ||
1856 (RequestedDisposition
== FILE_OVERWRITE
) || (RequestedDisposition
== FILE_OVERWRITE_IF
) ||
1857 FileOnlyRequested
)) {
1858 if(FileOnlyRequested
) {
1859 AdPrint((" Can't open directory as a plain file\n"));
1861 AdPrint((" Can't supersede directory\n"));
1863 RC
= STATUS_FILE_IS_A_DIRECTORY
;
1867 if(DirectoryOnlyRequested
&& !(PtrNewFcb
->FCBFlags
& UDF_FCB_DIRECTORY
)) {
1868 AdPrint((" This is not a directory\n"));
1869 RC
= STATUS_NOT_A_DIRECTORY
;
1873 if(DeleteOnCloseSpecified
&& (PtrNewFcb
->FCBFlags
& UDF_FCB_READ_ONLY
)) {
1874 AdPrint((" Can't delete Read-Only file\n"));
1875 RC
= STATUS_CANNOT_DELETE
;
1878 // Check share access and fail if the share conflicts with an existing
1880 ASSERT(Res1
!= NULL
);
1881 ASSERT(Res2
!= NULL
);
1882 RC
= UDFCheckAccessRights(PtrNewFileObject
, AccessState
, PtrNewFcb
, PtrNewCcb
, DesiredAccess
, ShareAccess
);
1883 if(!NT_SUCCESS(RC
)) {
1884 AdPrint((" Access/Share access check failed\n"));
1888 RestoreShareAccess
= TRUE
;
1890 if(FileOnlyRequested
) {
1891 // If the user wants 'write access' access to the file make sure there
1892 // is not a process mapping this file as an image. Any attempt to
1893 // delete the file will be stopped in fileinfo.cpp
1895 // If the user wants to delete on close, we must check at this
1897 if( (DesiredAccess
& FILE_WRITE_DATA
) || DeleteOnCloseSpecified
) {
1898 MmPrint((" MmFlushImageSection();\n"));
1899 NtReqFcb
->AcqFlushCount
++;
1900 if(!MmFlushImageSection( &(NtReqFcb
->SectionObject
),
1901 MmFlushForWrite
)) {
1903 NtReqFcb
->AcqFlushCount
--;
1904 RC
= DeleteOnCloseSpecified
? STATUS_CANNOT_DELETE
:
1905 STATUS_SHARING_VIOLATION
;
1906 AdPrint((" File is mapped or deletion in progress\n"));
1909 NtReqFcb
->AcqFlushCount
--;
1911 if( NoBufferingSpecified
&&
1912 /* (PtrNewFileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) &&*/
1913 !(PtrNewFcb
->CachedOpenHandleCount
) &&
1914 (NtReqFcb
->SectionObject
.DataSectionObject
) ) {
1915 // If this is a non-cached open, and there are no open cached
1916 // handles, but there is still a data section, attempt a flush
1917 // and purge operation to avoid cache coherency overhead later.
1918 // We ignore any I/O errors from the flush.
1919 MmPrint((" CcFlushCache()\n"));
1920 CcFlushCache( &(NtReqFcb
->SectionObject
), NULL
, 0, NULL
);
1921 MmPrint((" CcPurgeCacheSection()\n"));
1922 CcPurgeCacheSection( &(NtReqFcb
->SectionObject
), NULL
, 0, FALSE
);
1926 if(DeleteOnCloseSpecified
&& UDFIsADirectory(NewFileInfo
) && !UDFIsDirEmpty__(NewFileInfo
)) {
1927 AdPrint((" Directory in not empry\n"));
1928 try_return (RC
= STATUS_DIRECTORY_NOT_EMPTY
);
1931 // Get attributes for the file ...
1933 (USHORT
)UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo
), NewFileInfo
->Index
),
1934 NewFileInfo
->Dloc
->FileEntry
);
1936 if(DeleteOnCloseSpecified
&&
1937 (TmpFileAttributes
& FILE_ATTRIBUTE_READONLY
)) {
1938 ASSERT(Res1
!= NULL
);
1939 ASSERT(Res2
!= NULL
);
1940 RC
= UDFCheckAccessRights(NULL
, NULL
, OldRelatedFileInfo
->Fcb
, PtrRelatedCCB
, FILE_DELETE_CHILD
, 0);
1941 if(!NT_SUCCESS(RC
)) {
1942 AdPrint((" Read-only. DeleteOnClose attempt failed\n"));
1943 try_return (RC
= STATUS_CANNOT_DELETE
);
1947 // If a supersede or overwrite was requested, do so now ...
1948 if((RequestedDisposition
== FILE_SUPERSEDE
) ||
1949 (RequestedDisposition
== FILE_OVERWRITE
) ||
1950 (RequestedDisposition
== FILE_OVERWRITE_IF
)) {
1951 // Attempt the operation here ...
1953 #ifndef UDF_READ_ONLY_BUILD
1954 ASSERT(!UDFIsADirectory(NewFileInfo
));
1956 if(RequestedDisposition
== FILE_SUPERSEDE
) {
1957 BOOLEAN RestoreRO
= FALSE
;
1959 ASSERT(Res1
!= NULL
);
1960 ASSERT(Res2
!= NULL
);
1961 // NT wants us to allow Supersede on RO files
1962 if(PtrNewFcb
->FCBFlags
& UDF_FCB_READ_ONLY
) {
1963 // Imagine, that file is not RO and check other permissions
1965 PtrNewFcb
->FCBFlags
&= ~UDF_FCB_READ_ONLY
;
1967 RC
= UDFCheckAccessRights(NULL
, NULL
, PtrNewFcb
, PtrNewCcb
, DELETE
, 0);
1969 // Restore RO state if changed
1970 PtrNewFcb
->FCBFlags
|= UDF_FCB_READ_ONLY
;
1972 if(!NT_SUCCESS(RC
)) {
1973 AdPrint((" Can't supersede. DELETE permission required\n"));
1977 ASSERT(Res1
!= NULL
);
1978 ASSERT(Res2
!= NULL
);
1979 RC
= UDFCheckAccessRights(NULL
, NULL
, PtrNewFcb
, PtrNewCcb
,
1980 FILE_WRITE_DATA
| FILE_WRITE_EA
| FILE_WRITE_ATTRIBUTES
, 0);
1981 if(!NT_SUCCESS(RC
)) {
1982 AdPrint((" Can't overwrite. Permission denied\n"));
1986 // Existing & requested System and Hidden bits must match
1987 if( (TmpFileAttributes
& (FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
)) &
1988 (FileAttributes
^ (FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
)) ) {
1989 AdPrint((" The Hidden and/or System bits do not match\n"));
1990 try_return(RC
= STATUS_ACCESS_DENIED
);
1993 // Before we actually truncate, check to see if the purge
1994 // is going to fail.
1995 MmPrint((" MmCanFileBeTruncated()\n"));
1996 if (!MmCanFileBeTruncated( &NtReqFcb
->SectionObject
,
1997 &(UDFGlobalData
.UDFLargeZero
) )) {
1998 AdPrint((" Can't truncate. File is mapped\n"));
1999 try_return(RC
= STATUS_USER_MAPPED_FILE
);
2002 ASSERT(Res1
!= NULL
);
2003 ASSERT(Res2
!= NULL
);
2006 CollectStatistics(Vcb
, MetaDataWrites
);
2008 // Synchronize with PagingIo
2009 UDFAcquireResourceExclusive(PagingIoRes
= &(NtReqFcb
->PagingIoResource
),TRUE
);
2011 if(!NT_SUCCESS(RC
= UDFResizeFile__(Vcb
, NewFileInfo
, 0))) {
2012 AdPrint((" Error during resize operation\n"));
2015 /* if(AllocationSize) {
2016 if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) {
2017 AdPrint((" Error during resize operation (2)\n"));
2021 NtReqFcb
->CommonFCBHeader
.AllocationSize
.QuadPart
= UDFSysGetAllocSize(Vcb
, AllocationSize
);
2022 NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
=
2023 NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
= 0 /*AllocationSize*/;
2024 PtrNewFcb
->FCBFlags
&= ~UDF_FCB_DELAY_CLOSE
;
2025 MmPrint((" CcSetFileSizes()\n"));
2026 CcSetFileSizes(PtrNewFileObject
, (PCC_FILE_SIZES
)&(NtReqFcb
->CommonFCBHeader
.AllocationSize
));
2027 NtReqFcb
->NtReqFCBFlags
|= UDF_NTREQ_FCB_MODIFIED
;
2028 // Release PagingIoResource
2029 UDFReleaseResource(PagingIoRes
);
2032 if(NT_SUCCESS(RC
)) {
2033 FileAttributes
|= FILE_ATTRIBUTE_ARCHIVE
;
2034 if (RequestedDisposition
== FILE_SUPERSEDE
) {
2035 // Set attributes for the file ...
2036 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo
), NewFileInfo
->Index
),
2037 NewFileInfo
->Dloc
->FileEntry
, FileAttributes
);
2038 ReturnedInformation
= FILE_SUPERSEDED
;
2040 // Get attributes for the file ...
2041 FileAttributes
|= TmpFileAttributes
;
2042 // Set attributes for the file ...
2043 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo
), NewFileInfo
->Index
),
2044 NewFileInfo
->Dloc
->FileEntry
, FileAttributes
);
2045 ReturnedInformation
= FILE_OVERWRITTEN
;
2049 UDFNotifyFullReportChange( Vcb
, NewFileInfo
,
2050 FILE_NOTIFY_CHANGE_LAST_WRITE
| FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
,
2051 FILE_ACTION_MODIFIED
);
2053 // Update parent object
2054 if((Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_DIR_WRITE
) &&
2056 PtrRelatedFileObject
&&
2057 (PtrRelatedFCB
->FileInfo
== NewFileInfo
->ParentFile
)) {
2058 PtrRelatedFileObject
->Flags
|= (FO_FILE_MODIFIED
| FO_FILE_SIZE_CHANGED
);
2060 #else //UDF_READ_ONLY_BUILD
2061 try_return(RC
= STATUS_ACCESS_DENIED
);
2062 #endif //UDF_READ_ONLY_BUILD
2064 ReturnedInformation
= FILE_OPENED
;
2067 // Update parent object
2068 if((Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_DIR_READ
) &&
2070 PtrRelatedFileObject
&&
2071 (PtrRelatedFCB
->FileInfo
== NewFileInfo
->ParentFile
)) {
2072 PtrRelatedFileObject
->Flags
|= FO_FILE_FAST_IO_READ
;
2078 // Complete the request unless we are here as part of unwinding
2079 // when an exception condition was encountered, OR
2080 // if the request has been deferred (i.e. posted for later handling)
2082 if(RestoreVCBOpenCounter
) {
2083 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
2084 RestoreVCBOpenCounter
= FALSE
;
2087 if (RC
!= STATUS_PENDING
) {
2088 // If any intermediate (directory) open operations were performed,
2089 // implement the corresponding close (do *not* however close
2090 // the target we have opened on behalf of the caller ...).
2093 if(NT_SUCCESS(RC
)) {
2094 CollectStatistics2(Vcb
, SuccessfulCreates
);
2096 CollectStatistics2(Vcb
, FailedCreates
);
2100 if (NT_SUCCESS(RC
) && PtrNewFcb
) {
2101 // Update the file object such that:
2102 // (a) the FsContext field points to the NTRequiredFCB field
2104 // (b) the FsContext2 field points to the CCB created as a
2105 // result of the open operation
2107 // If write-through was requested, then mark the file object
2110 // directories are not cached
2111 // so we should prevent flush attepmts on cleanup
2112 if(!(PtrNewFcb
->FCBFlags
& UDF_FCB_DIRECTORY
)) {
2113 #ifndef UDF_READ_ONLY_BUILD
2114 if(WriteThroughRequested
) {
2115 PtrNewFileObject
->Flags
|= FO_WRITE_THROUGH
;
2116 PtrNewFcb
->FCBFlags
|= UDF_FCB_WRITE_THROUGH
;
2117 MmPrint((" FO_WRITE_THROUGH\n"));
2119 #endif //UDF_READ_ONLY_BUILD
2120 if(SequentialIoRequested
&&
2121 !(Vcb
->CompatFlags
& UDF_VCB_IC_IGNORE_SEQUENTIAL_IO
)) {
2122 PtrNewFileObject
->Flags
|= FO_SEQUENTIAL_ONLY
;
2123 MmPrint((" FO_SEQUENTIAL_ONLY\n"));
2124 #ifndef UDF_READ_ONLY_BUILD
2125 if(Vcb
->TargetDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
2126 PtrNewFileObject
->Flags
&= ~FO_WRITE_THROUGH
;
2127 PtrNewFcb
->FCBFlags
&= ~UDF_FCB_WRITE_THROUGH
;
2128 MmPrint((" FILE_REMOVABLE_MEDIA + FO_SEQUENTIAL_ONLY => ~FO_WRITE_THROUGH\n"));
2130 #endif //UDF_READ_ONLY_BUILD
2131 if(PtrNewFcb
->FileInfo
) {
2132 UDFSetFileAllocMode__(PtrNewFcb
->FileInfo
, EXTENT_FLAG_ALLOC_SEQUENTIAL
);
2135 if(NoBufferingSpecified
) {
2136 PtrNewFileObject
->Flags
|= FO_NO_INTERMEDIATE_BUFFERING
;
2137 MmPrint((" FO_NO_INTERMEDIATE_BUFFERING\n"));
2139 PtrNewFileObject
->Flags
|= FO_CACHE_SUPPORTED
;
2140 MmPrint((" FO_CACHE_SUPPORTED\n"));
2144 if((DesiredAccess
& FILE_EXECUTE
) /*&&
2145 !(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)*/) {
2146 MmPrint((" FO_FILE_FAST_IO_READ\n"));
2147 PtrNewFileObject
->Flags
|= FO_FILE_FAST_IO_READ
;
2149 // All right. Now we can safely increment OpenHandleCount
2150 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBHandleCount
));
2151 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->OpenHandleCount
));
2153 if(PtrNewFileObject
->Flags
& FO_CACHE_SUPPORTED
)
2154 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->CachedOpenHandleCount
));
2155 // Store some flags in CCB
2157 PtrNewCcb
->TreeLength
= TreeLength
;
2159 #ifndef UDF_READ_ONLY_BUILD
2160 if(DeleteOnCloseSpecified
) {
2161 ASSERT(!(PtrNewFcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
2162 PtrNewCcb
->CCBFlags
|= UDF_CCB_DELETE_ON_CLOSE
;
2164 #endif //UDF_READ_ONLY_BUILD
2167 // remember this for possible Rename/Move operation
2168 PtrNewCcb
->CCBFlags
|= UDF_CCB_CASE_SENSETIVE
;
2169 PtrNewFileObject
->Flags
|= FO_OPENED_CASE_SENSITIVE
;
2171 if(IsFileObjectReadOnly(PtrNewFileObject
)) {
2172 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBOpenCountRO
));
2173 PtrNewCcb
->CCBFlags
|= UDF_CCB_READ_ONLY
;
2178 // it was a stream...
2180 PtrNewFileObject
->Flags
|= FO_STREAM_FILE
;
2181 // PtrNewCcb->CCBFlags |= UDF_CCB_VALID;
2182 // increment the number of outstanding open operations on this
2183 // logical volume (i.e. volume cannot be dismounted)
2184 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBOpenCount
));
2185 PtrNewFcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_VALID
;
2186 PtrNewFcb
->FCBFlags
|= UDF_FCB_VALID
;
2188 // We have no FileInfo for Volume
2189 if(PtrNewFcb
->FileInfo
) {
2190 ASSERT_REF(PtrNewFcb
->ReferenceCount
>= PtrNewFcb
->FileInfo
->RefCount
);
2193 AdPrint((" FCB %x, CCB %x, FO %x, Flags %x\n", PtrNewFcb
, PtrNewCcb
, PtrNewFileObject
, PtrNewFcb
->FCBFlags
));
2195 UDFReleaseResFromCreate(&PagingIoRes
, &Res1
, &Res2
);
2197 } else if(!NT_SUCCESS(RC
)) {
2198 // Perform failure related post-processing now
2199 if(RestoreShareAccess
&& NtReqFcb
&& PtrNewFileObject
) {
2200 IoRemoveShareAccess(PtrNewFileObject
, &(NtReqFcb
->FCBShareAccess
));
2202 UDFCleanUpCCB(PtrNewCcb
);
2203 if(PtrNewFileObject
) {
2204 PtrNewFileObject
->FsContext2
= NULL
;
2206 // We have successfully opened LastGoodFileInfo,
2207 // so mark it as VALID to avoid future troubles...
2208 if(LastGoodFileInfo
&& LastGoodFileInfo
->Fcb
) {
2209 LastGoodFileInfo
->Fcb
->FCBFlags
|= UDF_FCB_VALID
;
2210 if(LastGoodFileInfo
->Fcb
->NTRequiredFCB
) {
2211 LastGoodFileInfo
->Fcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_VALID
;
2214 // Release resources...
2215 UDFReleaseResFromCreate(&PagingIoRes
, &Res1
, &Res2
);
2216 ASSERT(AcquiredVcb
);
2218 UDFCloseFileInfoChain(Vcb
, LastGoodFileInfo
, TreeLength
, TRUE
);
2219 // cleanup FCBs (if any)
2220 if( Vcb
&& (PtrNewFcb
!= Vcb
->RootDirFCB
) &&
2221 LastGoodFileInfo
) {
2222 UDFCleanUpFcbChain(Vcb
, LastGoodFileInfo
, TreeLength
, TRUE
);
2224 ASSERT(!LastGoodFileInfo
);
2227 UDFReleaseResFromCreate(&PagingIoRes
, &Res1
, &Res2
);
2229 // As long as this unwinding is not being performed as a result of
2230 // an exception condition, complete the IRP ...
2231 if (!_SEH2_AbnormalTermination()) {
2232 Irp
->IoStatus
.Status
= RC
;
2233 Irp
->IoStatus
.Information
= ReturnedInformation
;
2236 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2237 // Free up the Irp Context
2238 UDFReleaseIrpContext(PtrIrpContext
);
2241 UDFReleaseResFromCreate(&PagingIoRes
, &Res1
, &Res2
);
2245 UDFReleaseResource(&(Vcb
->VCBResource
));
2247 // free allocated tmp buffers (if any)
2248 if(AbsolutePathName
.Buffer
)
2249 MyFreePool__(AbsolutePathName
.Buffer
);
2250 if(LocalPath
.Buffer
)
2251 MyFreePool__(LocalPath
.Buffer
);
2253 MyFreePool__(TailNameBuffer
);
2257 } // end UDFCommonCreate()
2259 /*************************************************************************
2261 * Function: UDFFirstOpenFile()
2264 * Perform first Open/Create initialization.
2266 * Expected Interrupt Level (for execution) :
2268 * IRQL_PASSIVE_LEVEL
2270 * Return Value: STATUS_SUCCESS/Error
2272 *************************************************************************/
2275 IN PVCB Vcb
, // volume control block
2276 IN PFILE_OBJECT PtrNewFileObject
, // I/O Mgr. created file object
2277 OUT PtrUDFFCB
* PtrNewFcb
,
2278 IN PUDF_FILE_INFO RelatedFileInfo
,
2279 IN PUDF_FILE_INFO NewFileInfo
,
2280 IN PUNICODE_STRING LocalPath
,
2281 IN PUNICODE_STRING CurName
2284 // DIR_INDEX NewFileIndex;
2285 PtrUDFObjectName NewFCBName
;
2286 PtrUDFNTRequiredFCB NtReqFcb
;
2288 BOOLEAN Linked
= TRUE
;
2289 PDIR_INDEX_HDR hDirIndex
;
2290 PDIR_INDEX_ITEM DirIndex
;
2292 AdPrint(("UDFFirstOpenFile\n"));
2294 if(!((*PtrNewFcb
) = UDFAllocateFCB())) {
2295 AdPrint(("Can't allocate FCB\n"));
2296 return STATUS_INSUFFICIENT_RESOURCES
;
2299 // Allocate and set new FCB unique name (equal to absolute path name)
2300 if(!(NewFCBName
= UDFAllocateObjectName())) return STATUS_INSUFFICIENT_RESOURCES
;
2302 if(RelatedFileInfo
&& RelatedFileInfo
->Fcb
&&
2303 !(RelatedFileInfo
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
)) {
2304 RC
= MyCloneUnicodeString(&(NewFCBName
->ObjectName
), &(RelatedFileInfo
->Fcb
->FCBName
->ObjectName
));
2306 RC
= MyInitUnicodeString(&(NewFCBName
->ObjectName
), L
"");
2309 return STATUS_INSUFFICIENT_RESOURCES
;
2310 if( (CurName
->Buffer
[0] != L
':') &&
2311 (!LocalPath
->Length
||
2312 ((LocalPath
->Buffer
[LocalPath
->Length
/sizeof(WCHAR
)-1] != L
':') /*&&
2313 (LocalPath->Buffer[LocalPath->Length/sizeof(WCHAR)-1] != L'\\')*/) )) {
2314 RC
= MyAppendUnicodeToString(&(NewFCBName
->ObjectName
), L
"\\");
2315 if(!NT_SUCCESS(RC
)) return STATUS_INSUFFICIENT_RESOURCES
;
2318 // Make link between Fcb and FileInfo
2319 (*PtrNewFcb
)->FileInfo
= NewFileInfo
;
2320 NewFileInfo
->Fcb
= (*PtrNewFcb
);
2321 (*PtrNewFcb
)->ParentFcb
= RelatedFileInfo
->Fcb
;
2323 if(!((*PtrNewFcb
)->NTRequiredFCB
= NewFileInfo
->Dloc
->CommonFcb
)) {
2324 if(!((*PtrNewFcb
)->NTRequiredFCB
=
2325 (PtrUDFNTRequiredFCB
)MyAllocatePool__(NonPagedPool
, UDFQuadAlign(sizeof(UDFNTRequiredFCB
))) ) )
2326 return STATUS_INSUFFICIENT_RESOURCES
;
2328 UDFPrint(("UDFAllocateNtReqFCB: %x\n", (*PtrNewFcb
)->NTRequiredFCB
));
2329 RtlZeroMemory((*PtrNewFcb
)->NTRequiredFCB
, UDFQuadAlign(sizeof(UDFNTRequiredFCB
)));
2330 (*PtrNewFcb
)->FileInfo
->Dloc
->CommonFcb
= (*PtrNewFcb
)->NTRequiredFCB
;
2333 if(!(NewFileInfo
->Dloc
->CommonFcb
->NtReqFCBFlags
& UDF_NTREQ_FCB_VALID
)) {
2334 (*PtrNewFcb
)->NTRequiredFCB
= NULL
;
2336 return STATUS_ACCESS_DENIED
;
2340 NtReqFcb
= (*PtrNewFcb
)->NTRequiredFCB
;
2343 UDFGetFileXTime((*PtrNewFcb
)->FileInfo
,
2344 &(NtReqFcb
->CreationTime
.QuadPart
),
2345 &(NtReqFcb
->LastAccessTime
.QuadPart
),
2346 &(NtReqFcb
->ChangeTime
.QuadPart
),
2347 &(NtReqFcb
->LastWriteTime
.QuadPart
) );
2349 // Set the allocation size for the object is specified
2350 NtReqFcb
->CommonFCBHeader
.AllocationSize
.QuadPart
=
2351 UDFSysGetAllocSize(Vcb
, NewFileInfo
->Dloc
->DataLoc
.Length
);
2352 // NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = UDFGetFileAllocationSize(Vcb, NewFileInfo);
2353 NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
=
2354 NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
= NewFileInfo
->Dloc
->DataLoc
.Length
;
2356 // begin transaction
2357 UDFAcquireResourceExclusive(&(Vcb
->FcbListResource
), TRUE
);
2359 RC
= UDFInitializeFCB(*PtrNewFcb
, Vcb
, NewFCBName
,
2360 UDFIsADirectory(NewFileInfo
) ? UDF_FCB_DIRECTORY
: 0, PtrNewFileObject
);
2361 if(!NT_SUCCESS(RC
)) {
2363 MyFreePool__((*PtrNewFcb
)->NTRequiredFCB
);
2364 (*PtrNewFcb
)->NTRequiredFCB
= NULL
;
2366 UDFReleaseResource(&(Vcb
->FcbListResource
));
2369 // set Read-only attribute
2370 if(!UDFIsAStreamDir(NewFileInfo
)) {
2371 hDirIndex
= UDFGetDirIndexByFileInfo(NewFileInfo
);
2377 if(UDFAttributesToNT(DirIndex
= UDFDirIndex(hDirIndex
, NewFileInfo
->Index
),NULL
) & FILE_ATTRIBUTE_READONLY
) {
2378 (*PtrNewFcb
)->FCBFlags
|= UDF_FCB_READ_ONLY
;
2380 MyAppendUnicodeStringToStringTag(&(NewFCBName
->ObjectName
), &(DirIndex
->FName
), MEM_USOBJ_TAG
);
2384 } else if (RelatedFileInfo
->ParentFile
) {
2385 hDirIndex
= UDFGetDirIndexByFileInfo(RelatedFileInfo
);
2386 if(UDFAttributesToNT(DirIndex
= UDFDirIndex(hDirIndex
, RelatedFileInfo
->Index
),NULL
) & FILE_ATTRIBUTE_READONLY
) {
2387 (*PtrNewFcb
)->FCBFlags
|= UDF_FCB_READ_ONLY
;
2389 RC
= MyAppendUnicodeStringToStringTag(&(NewFCBName
->ObjectName
), CurName
, MEM_USOBJ_TAG
);
2393 // do not allocate CCB if it is internal Create/Open
2394 if(NT_SUCCESS(RC
)) {
2395 if(PtrNewFileObject
) {
2396 RC
= UDFOpenFile(Vcb
, PtrNewFileObject
, *PtrNewFcb
);
2398 RC
= STATUS_SUCCESS
;
2401 UDFReleaseResource(&(Vcb
->FcbListResource
));
2404 // if(!NT_SUCCESS(RC)) return RC;
2407 } // end UDFFirstOpenFile()
2409 /*************************************************************************
2411 * Function: UDFOpenFile()
2414 * Open a file/dir for the caller.
2416 * Expected Interrupt Level (for execution) :
2418 * IRQL_PASSIVE_LEVEL
2420 * Return Value: STATUS_SUCCESS/Error
2422 *************************************************************************/
2425 PVCB Vcb
, // volume control block
2426 PFILE_OBJECT PtrNewFileObject
, // I/O Mgr. created file object
2430 NTSTATUS RC
= STATUS_SUCCESS
;
2431 PtrUDFCCB Ccb
= NULL
;
2432 PtrUDFNTRequiredFCB NtReqFcb
;
2434 AdPrint(("UDFOpenFile\n"));
2435 ASSERT((PtrNewFcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_FCB
)
2436 ||(PtrNewFcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
));
2441 CollectStatistics2(Vcb
, CreateHits
);
2443 // create a new CCB structure
2444 if (!(Ccb
= UDFAllocateCCB())) {
2445 AdPrint(("Can't allocate CCB\n"));
2446 PtrNewFileObject
->FsContext2
= NULL
;
2448 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->ReferenceCount
));
2449 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->NTRequiredFCB
->CommonRefCount
));
2450 RC
= STATUS_INSUFFICIENT_RESOURCES
;
2453 // initialize the CCB
2454 Ccb
->Fcb
= PtrNewFcb
;
2455 // initialize the CCB to point to the file object
2456 Ccb
->FileObject
= PtrNewFileObject
;
2458 // initialize the file object appropriately
2459 PtrNewFileObject
->FsContext2
= (PVOID
)(Ccb
);
2460 PtrNewFileObject
->Vpb
= Vcb
->Vpb
;
2461 PtrNewFileObject
->FsContext
= (PVOID
)(NtReqFcb
= PtrNewFcb
->NTRequiredFCB
);
2462 PtrNewFileObject
->SectionObjectPointer
= &(NtReqFcb
->SectionObject
);
2464 // NtReqFcb ->FileObject = PtrNewFileObject;
2467 #ifdef UDF_DELAYED_CLOSE
2468 PtrNewFcb
->FCBFlags
&= ~UDF_FCB_DELAY_CLOSE
;
2469 #endif //UDF_DELAYED_CLOSE
2471 UDFAcquireResourceExclusive(&(PtrNewFcb
->CcbListResource
),TRUE
);
2472 // insert CCB into linked list of open file object to Fcb or
2473 // to Vcb and do other intialization
2474 InsertTailList(&(PtrNewFcb
->NextCCB
), &(Ccb
->NextCCB
));
2475 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->ReferenceCount
));
2476 UDFInterlockedIncrement((PLONG
)&(PtrNewFcb
->NTRequiredFCB
->CommonRefCount
));
2477 UDFReleaseResource(&(PtrNewFcb
->CcbListResource
));
2485 } // end UDFOpenFile()
2488 /*************************************************************************
2490 * Function: UDFInitializeFCB()
2493 * Initialize a new FCB structure and also the sent-in file object
2496 * Expected Interrupt Level (for execution) :
2498 * IRQL_PASSIVE_LEVEL
2500 * Return Value: None
2502 *************************************************************************/
2505 IN PtrUDFFCB PtrNewFcb
, // FCB structure to be initialized
2506 IN PVCB Vcb
, // logical volume (VCB) pointer
2507 IN PtrUDFObjectName PtrObjectName
, // name of the object
2508 IN ULONG Flags
, // is this a file/directory, etc.
2509 IN PFILE_OBJECT FileObject
) // optional file object to be initialized
2511 AdPrint(("UDFInitializeFCB\n"));
2513 BOOLEAN Linked
= TRUE
;
2515 if(!PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.Resource
) {
2517 PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.NodeTypeCode
= UDF_NODE_TYPE_NT_REQ_FCB
;
2518 PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.NodeByteSize
= sizeof(UDFNTRequiredFCB
);
2519 // Initialize the ERESOURCE objects
2520 if(!NT_SUCCESS(status
= UDFInitializeResourceLite(&(PtrNewFcb
->NTRequiredFCB
->MainResource
)))) {
2521 AdPrint((" Can't init resource\n"));
2524 if(!NT_SUCCESS(status
= UDFInitializeResourceLite(&(PtrNewFcb
->NTRequiredFCB
->PagingIoResource
)))) {
2525 AdPrint((" Can't init resource (2)\n"));
2526 UDFDeleteResource(&(PtrNewFcb
->NTRequiredFCB
->MainResource
));
2529 // Fill NT required Fcb part
2530 PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.Resource
= &(PtrNewFcb
->NTRequiredFCB
->MainResource
);
2531 PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.PagingIoResource
= &(PtrNewFcb
->NTRequiredFCB
->PagingIoResource
);
2532 // Itialize byte-range locks support structure
2533 FsRtlInitializeFileLock(&(PtrNewFcb
->NTRequiredFCB
->FileLock
),NULL
,NULL
);
2534 // Init reference counter
2535 PtrNewFcb
->NTRequiredFCB
->CommonRefCount
= 0;
2538 ASSERT(PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.NodeTypeCode
== UDF_NODE_TYPE_NT_REQ_FCB
);
2540 if(!NT_SUCCESS(status
= UDFInitializeResourceLite(&(PtrNewFcb
->CcbListResource
)))) {
2541 AdPrint((" Can't init resource (3)\n"));
2544 UDFDeleteResource(&(PtrNewFcb
->NTRequiredFCB
->PagingIoResource
));
2545 UDFDeleteResource(&(PtrNewFcb
->NTRequiredFCB
->MainResource
));
2546 PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.Resource
=
2547 PtrNewFcb
->NTRequiredFCB
->CommonFCBHeader
.PagingIoResource
= NULL
;
2548 FsRtlUninitializeFileLock(&(PtrNewFcb
->NTRequiredFCB
->FileLock
));
2553 // caller MUST ensure that VCB has been acquired exclusively
2554 InsertTailList(&(Vcb
->NextFCB
), &(PtrNewFcb
->NextFCB
));
2556 // initialize the various list heads
2557 InitializeListHead(&(PtrNewFcb
->NextCCB
));
2559 PtrNewFcb
->ReferenceCount
= 0;
2560 PtrNewFcb
->OpenHandleCount
= 0;
2562 PtrNewFcb
->FCBFlags
= Flags
| UDF_FCB_INITIALIZED_CCB_LIST_RESOURCE
;
2564 PtrNewFcb
->FCBName
= PtrObjectName
;
2566 PtrNewFcb
->Vcb
= Vcb
;
2568 return STATUS_SUCCESS
;
2569 } // end UDFInitializeFCB()