[UDFS] Fix uninitialized var use in UDFCommonCreate, return the right error code
[reactos.git] / drivers / filesystems / udfs / create.cpp
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;
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 try_return(RC = STATUS_FILE_INVALID);
491 }
492
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;
498 try_return(RC);
499 }
500 // We need EXCLUSIVE access to Vcb to avoid parallel calls to UDFVerifyVcb()
501 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
502 AcquiredVcb = TRUE;
503
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);
507 if(!NT_SUCCESS(RC))
508 try_return(RC);
509
510 UDFConvertExclusiveToSharedLite(&(Vcb->VCBResource));
511
512 ASSERT(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED);
513
514 // We fail in the following cases for Read-Only volumes
515 // - Open a target directory.
516 // - Create a file.
517 if(
518 (
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
524 ) &&
525 (DeleteOnCloseSpecified ||
526 OpenTargetDirectory ||
527 (RequestedDisposition == FILE_CREATE) ||
528 (RequestedDisposition == FILE_OVERWRITE) ||
529 (RequestedDisposition == FILE_OVERWRITE_IF) ||
530 (RequestedDisposition == FILE_SUPERSEDE) ||
531 AllocationSize) ) {
532 ReturnedInformation = 0;
533 AdPrint((" Write protected or dirty\n"));
534 try_return(RC = STATUS_MEDIA_WRITE_PROTECTED);
535 }
536
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);
541 }*/
542
543 // ****************
544 // If a Volume open is requested, satisfy it now
545 // ****************
546 if (!(PtrNewFileObject->FileName.Length) && (!PtrRelatedFileObject ||
547 (PtrRelatedFCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB))) {
548
549 BOOLEAN UndoLock = FALSE;
550
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.
556
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.
559
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.
563
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);
568 }
569
570 if (DirectoryOnlyRequested) {
571 // a volume is not a directory
572 try_return(RC = STATUS_NOT_A_DIRECTORY);
573 }
574
575 #ifndef UDF_READ_ONLY_BUILD
576 if (DeleteOnCloseSpecified) {
577 // delete volume.... hmm
578 try_return(RC = STATUS_CANNOT_DELETE);
579 }
580
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);
584 }
585 #endif //UDF_READ_ONLY_BUILD
586
587 UDFPrint((" ShareAccess %x, DesiredAccess %x\n", ShareAccess, DesiredAccess));
588 /*
589 if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE)) &&
590 !(DesiredAccess & (FILE_GENERIC_WRITE & ~SYNCHRONIZE)) &&
591 (ShareAccess & FILE_SHARE_READ) ) {
592 */
593 if(!(DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) &&
594 (ShareAccess & FILE_SHARE_READ) ) {
595 UDFPrint((" R/O volume open\n"));
596 } else {
597
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);
602 }
603 }
604
605 if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE)) &&
606 !(DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) &&
607 (ShareAccess & FILE_SHARE_READ) ) {
608 // do nothing
609 } else {
610
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)
615
616 UDFPrint((" set UDF_IRP_CONTEXT_FLUSH2_REQUIRED\n"));
617 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FLUSH2_REQUIRED;
618
619 /*
620 UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
621 UDFReleaseResource(&(Vcb->VCBResource));
622 AcquiredVcb = FALSE;
623
624 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) {
625 UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
626 }
627 #ifdef UDF_DELAYED_CLOSE
628 UDFCloseAllDelayed(Vcb);
629 #endif //UDF_DELAYED_CLOSE
630
631 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
632 AcquiredVcb = TRUE;
633 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
634 */
635 }
636 }
637
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)) {
644 // Sharing violation
645 UDFPrint((" !FILE_SHARE_READ + open handles (%d)\n", Vcb->VCBHandleCount));
646 try_return(RC = STATUS_SHARING_VIOLATION);
647 }
648 if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_FLUSH2_REQUIRED) {
649
650 UDFPrint((" perform flush\n"));
651 PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_FLUSH2_REQUIRED;
652
653 UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
654 UDFReleaseResource(&(Vcb->VCBResource));
655 AcquiredVcb = FALSE;
656
657 if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) {
658 UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
659 }
660 #ifdef UDF_DELAYED_CLOSE
661 UDFCloseAllDelayed(Vcb);
662 #endif //UDF_DELAYED_CLOSE
663
664 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
665 AcquiredVcb = TRUE;
666 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
667
668 UDFFlushLogicalVolume(NULL, NULL, Vcb);
669
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);
677 }
678 }
679 // Lock the volume
680 if(!(ShareAccess & FILE_SHARE_READ)) {
681 UDFPrint((" set Lock\n"));
682 Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_LOCKED;
683 Vcb->VolumeLockFileObject = PtrNewFileObject;
684 UndoLock = TRUE;
685 } else
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;
689 }
690 }
691
692 PtrNewFcb = (PtrUDFFCB)Vcb;
693 ASSERT(!(PtrNewFcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE));
694
695 RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb);
696 if (!NT_SUCCESS(RC))
697 goto op_vol_accs_dnd;
698
699 PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2);
700 if(PtrNewCcb) PtrNewCcb->CCBFlags |= UDF_CCB_VOLUME_OPEN;
701 // Check _Security_
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;
706 }
707 // Check _ShareAccess_
708 RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess);
709 if(!NT_SUCCESS(RC)) {
710 AdPrint((" Sharing violation (Volume)\n"));
711 op_vol_accs_dnd:
712 if(UndoLock) {
713 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED;
714 Vcb->VolumeLockFileObject = NULL;
715 }
716 try_return(RC);
717 }
718
719 // NoBufferingSpecified = TRUE; See #define above
720 RequestedOptions |= FILE_NO_INTERMEDIATE_BUFFERING;
721
722 ReturnedInformation = FILE_OPENED;
723 UDFNotifyVolumeEvent(PtrNewFileObject, FSRTL_VOLUME_LOCK);
724 try_return(RC);
725 }
726
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);
732 }
733
734 if(UdfIllegalFcbAccess(Vcb,DesiredAccess)) {
735 ReturnedInformation = 0;
736 AdPrint((" Illegal share access\n"));
737 try_return(RC = STATUS_ACCESS_DENIED);
738 }
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);
742
743 // we should check appropriate privilege if OpenForBackup requested
744 if(OpenForBackup) {
745 if (!SeSinglePrivilegeCheck(SeExports->SeBackupPrivilege, UserMode)) {
746 try_return(RC = STATUS_PRIVILEGE_NOT_HELD);
747 }
748 }
749
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 ...
756
757 // If the file has been deleted in the meantime, we'll return
758 // "not found"
759
760 // ****************
761 // Open by FileID
762 // ****************
763 if (OpenByFileId) {
764 // perform the open ...
765 PUNICODE_STRING TmpPath;
766 LONGLONG Id;
767
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);
773 }
774
775 if (TargetObjectName.Length != sizeof(FILE_ID)) {
776 AdPrint((" Invalid file ID\n"));
777 try_return(RC = STATUS_INVALID_PARAMETER);
778 }
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);
785 }
786
787 RC = UDFGetOpenParamsByFileId(Vcb, Id, &TmpPath, &IgnoreCase);
788 if(!NT_SUCCESS(RC)) {
789 AdPrint((" ID open failed\n"));
790 try_return(RC);
791 }
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"));
797 try_return(RC);
798 }
799 //ASSERT(TargetObjectName.Buffer);
800 AbsolutePathName = TargetObjectName;
801 PtrRelatedFileObject = NULL;
802 } else
803 // ****************
804 // Relative open
805 // ****************
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 ...
811
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));
823 _SEH2_TRY {
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"));
828 } _SEH2_END;
829 try_return(RC);
830 }
831
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;
842 try_return(RC);
843 }
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;
850 try_return(RC);
851 }
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)))
858 try_return(RC);
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);
863 }
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);
870 }
871 }
872 //ASSERT(TargetObjectName.Buffer);
873 RC = MyAppendUnicodeStringToStringTag(&AbsolutePathName, &TargetObjectName, MEM_USABS_TAG);
874 if(!NT_SUCCESS(RC))
875 try_return(RC);
876
877 } else {
878 // ****************
879 // Absolute open
880 // ****************
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);
888 }
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)))
893 try_return(RC);
894 }
895 // Win 32 protection :)
896 if ((AbsolutePathName.Length >= sizeof(WCHAR)*2) &&
897 (AbsolutePathName.Buffer[1] == L'\\') &&
898 (AbsolutePathName.Buffer[0] == L'\\')) {
899
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);
905 }
906 // Slide the name down in the buffer.
907 RtlMoveMemory( AbsolutePathName.Buffer,
908 AbsolutePathName.Buffer + 1,
909 AbsolutePathName.Length ); // .Length includes
910 // NULL-terminator
911 AbsolutePathName.Length -= sizeof(WCHAR);
912 }
913 if ( (AbsolutePathName.Length > sizeof(WCHAR) ) &&
914 (AbsolutePathName.Buffer[ (AbsolutePathName.Length/sizeof(WCHAR)) - 1 ] == L'\\') ) {
915
916 AbsolutePathName.Length -= sizeof(WCHAR);
917 }
918 // TERMINATOR (2) ;)
919 AbsolutePathName.Buffer[AbsolutePathName.Length/sizeof(WCHAR)] = 0;
920
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;
926 OpenExisting = TRUE;
927 }
928 //ASSERT(TargetObjectName.Buffer);
929
930 // ****************
931 // First, check if the caller simply wishes to open the Root
932 // of the file system tree.
933 // ****************
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;
943 try_return(RC);
944 }
945
946 #if 0
947 CollectStatistics(Vcb, MetaDataReads);
948 #endif
949
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);
954 }
955
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);
962 TreeLength = 1;
963
964 RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess);
965 if(!NT_SUCCESS(RC)) {
966 AdPrint((" Access/Sharing violation (RootDir)\n"));
967 try_return(RC);
968 }
969
970 ReturnedInformation = FILE_OPENED;
971
972 try_return(RC);
973 } // end of OpenRootDir
974
975 _SEH2_TRY {
976 AdPrint((" Opening file %ws %8.8x\n",AbsolutePathName.Buffer, PtrNewFileObject));
977 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
978 AdPrint((" Exception when printing FN\n"));
979 } _SEH2_END;
980 // ****************
981 // Check if we have DuplicateHandle (or Reopen) request
982 // ****************
983 if(OpenExisting) {
984
985 // BrutePoint();
986 // We don't handle OpenTargetDirectory in this case
987 if(OpenTargetDirectory)
988 try_return(RC = STATUS_INVALID_PARAMETER);
989
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)))
995 try_return(RC);
996
997 ASSERT(PtrRelatedFCB);
998 RelatedFileInfo = PtrRelatedFCB->FileInfo;
999
1000 RC = STATUS_SUCCESS;
1001 NewFileInfo =
1002 LastGoodFileInfo = RelatedFileInfo;
1003
1004 RelatedFileInfo =
1005 OldRelatedFileInfo = RelatedFileInfo->ParentFile;
1006 PtrRelatedFCB = PtrRelatedFCB->ParentFcb;
1007 // prevent releasing parent structures
1008 UDFAcquireParent(RelatedFileInfo, &Res1, &Res2);
1009 TreeLength++;
1010
1011 if(Res1) UDFReleaseResource(Res1);
1012 if(Res2) UDFReleaseResource(Res2);
1013
1014 UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->NTRequiredFCB);
1015 UDFAcquireResourceExclusive(Res2 = &(RelatedFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE);
1016 PtrNewFcb = NewFileInfo->Fcb;
1017
1018 UDF_CHECK_PAGING_IO_RESOURCE(PtrNewFcb->NTRequiredFCB);
1019 UDFAcquireResourceExclusive(Res1 = &(PtrNewFcb->NTRequiredFCB->MainResource),TRUE);
1020 UDFReferenceFile__(NewFileInfo);
1021 TreeLength++;
1022
1023 goto AlreadyOpened;
1024 }
1025
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);
1030 }
1031
1032 //AdPrint((" Opening file %ws %8.8x\n",AbsolutePathName.Buffer, PtrNewFileObject));
1033
1034 if(AbsolutePathName.Length > UDF_X_PATH_LEN*sizeof(WCHAR)) {
1035 try_return(RC = STATUS_OBJECT_NAME_INVALID);
1036 }
1037
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);
1043 }
1044 if(StreamOpen && !UDFStreamsSupported(Vcb)) {
1045 try_return(RC = STATUS_OBJECT_NAME_INVALID);
1046 }
1047
1048 RC = MyInitUnicodeString(&LocalPath, L"");
1049 if(!NT_SUCCESS(RC))
1050 try_return(RC);
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);
1057 if(!NT_SUCCESS(RC))
1058 try_return(RC);
1059 }
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"));
1064 try_return(RC);
1065 }
1066 TailNameBuffer = TailName.Buffer;
1067 } else {
1068 TailName = AbsolutePathName;
1069 }
1070 } else {
1071 // Start at the root of the file system
1072 RelatedFileInfo = Vcb->RootDirFCB->FileInfo;
1073 TailName = AbsolutePathName;
1074 }
1075
1076 if(StreamOpen) {
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);
1084 }
1085 CurName.MaximumLength = TailName.MaximumLength;
1086
1087 RC = STATUS_SUCCESS;
1088 LastGoodName.Length = 0;
1089 LastGoodFileInfo = RelatedFileInfo;
1090 // reference RelatedObject to prevent releasing parent structures
1091 UDFAcquireParent(RelatedFileInfo, &Res1, &Res2);
1092 TreeLength++;
1093
1094 // go into a loop parsing the supplied name
1095
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.
1101
1102 // ****************
1103 // now we'll parse path to desired file
1104 // ****************
1105
1106 while (TRUE) {
1107
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);
1114 }
1115 }
1116 // get next path part...
1117 TmpBuffer = TailName.Buffer;
1118 TailName.Buffer = UDFDissectName(TailName.Buffer,&(CurName.Length) );
1119 TailName.Length -= (USHORT)((ULONG_PTR)(TailName.Buffer) - (ULONG_PTR)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
1125 // way...
1126 if(OpenTargetDirectory && NT_SUCCESS(RC) && !TailName.Length) {
1127 // check if we should open SDir..
1128 if(!StreamOpen ||
1129 (TailName.Buffer[0]!=L':')) {
1130 // no, we should not. Continue with OpenTargetDir
1131 break;
1132 }
1133 }
1134
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;
1146 ReturnedInformation = FILE_DOES_NOT_EXIST;
1147 try_return(RC);
1148 }
1149
1150 ASSERT_REF(RelatedFileInfo->Fcb->ReferenceCount >= RelatedFileInfo->RefCount);
1151
1152 if(RelatedFileInfo && (TreeLength>1)) {
1153 // it was an internal Open operation. Thus, assume
1154 // RelatedFileInfo's Fcb to be valid
1155 RelatedFileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID;
1156 RelatedFileInfo->Fcb->FCBFlags |= UDF_FCB_VALID;
1157 }
1158 // check path fragment size
1159 if(CurName.Length > UDF_X_NAME_LEN * sizeof(WCHAR)) {
1160 AdPrint((" Path component is too long\n"));
1161 try_return(RC = STATUS_OBJECT_NAME_INVALID);
1162 }
1163 // ...and now release previously acquired objects,
1164 if(Res1) UDFReleaseResource(Res1);
1165 if(Res2) {
1166 UDFReleaseResource(Res2);
1167 Res2 = NULL;
1168 }
1169 // acquire new _parent_ directory & try to open what
1170 // we want.
1171
1172 UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->NTRequiredFCB);
1173 UDFAcquireResourceExclusive(Res1 = &(RelatedFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE);
1174
1175 // check traverse rights
1176 RC = UDFCheckAccessRights(NULL, NULL, RelatedFileInfo->Fcb, PtrRelatedCCB, FILE_TRAVERSE, 0);
1177 if(!NT_SUCCESS(RC)) {
1178 NewFileInfo = NULL;
1179 AdPrint((" Traverse check failed\n"));
1180 goto Skip_open_attempt;
1181 }
1182 // check if we should open normal File/Dir or SDir
1183 if(CurName.Buffer[0] != ':') {
1184 // standard open, nothing interesting....
1185 RC = UDFOpenFile__(Vcb,
1186 IgnoreCase,TRUE,&CurName,
1187 RelatedFileInfo,&NewFileInfo,NULL);
1188 if(RC == STATUS_FILE_DELETED) {
1189 // file has gone, but system still remembers it...
1190 NewFileInfo = NULL;
1191 AdPrint((" File deleted\n"));
1192 RC = STATUS_ACCESS_DENIED;
1193 #ifdef UDF_DBG
1194 } else
1195 if(RC == STATUS_NOT_A_DIRECTORY) {
1196 AdPrint((" Not a directory\n"));
1197 #endif // UDF_DBG
1198 } else
1199 if(RC == STATUS_SHARING_PAUSED) {
1200 AdPrint((" Dloc is being initialized\n"));
1201 BrutePoint();
1202 RC = STATUS_SHARING_VIOLATION;
1203 }
1204 } else {
1205 // And here we should open Stream Dir (if any, of cource)
1206 RC = UDFOpenStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo);
1207 if(NT_SUCCESS(RC)) {
1208 SuccessOpen_SDir:
1209 // this indicates that we needn't Stream Dir creation
1210 StreamExists = TRUE;
1211 StreamName.Buffer++;
1212 StreamName.Length-=sizeof(WCHAR);
1213 // update TailName
1214 TailName = StreamName;
1215 } else
1216 if(RC == STATUS_NOT_FOUND) {
1217 #ifndef UDF_READ_ONLY_BUILD
1218 // Stream Dir doesn't exist, but caller wants it to be
1219 // created. Lets try to help him...
1220 if((RequestedDisposition == FILE_CREATE) ||
1221 (RequestedDisposition == FILE_OPEN_IF) ||
1222 (RequestedDisposition == FILE_OVERWRITE_IF) ||
1223 OpenTargetDirectory ) {
1224 RC = UDFCreateStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo);
1225 if(NT_SUCCESS(RC))
1226 goto SuccessOpen_SDir;
1227 }
1228 #endif //UDF_READ_ONLY_BUILD
1229 }
1230 /* } else {
1231 AdPrint((" File deleted (2)\n"));
1232 RC = STATUS_ACCESS_DENIED;*/
1233 }
1234 #if 0
1235 CollectStatistics(Vcb, MetaDataReads);
1236 #endif
1237
1238 Skip_open_attempt:
1239
1240 // check if we have successfully opened path component
1241 if(NT_SUCCESS(RC)) {
1242 // Yesss !!!
1243 if (!(PtrNewFcb = NewFileInfo->Fcb)) {
1244 // It is a first open operation
1245 // Allocate new FCB
1246 // Here we set FileObject pointer to NULL to avoid
1247 // new CCB allocation
1248 RC = UDFFirstOpenFile(Vcb,
1249 NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo,
1250 &LocalPath, &CurName);
1251
1252 if(!NT_SUCCESS(RC)) {
1253 BrutePoint();
1254 AdPrint((" Can't perform FirstOpen\n"));
1255 UDFCloseFile__(Vcb, NewFileInfo);
1256 if(PtrNewFcb) UDFCleanUpFCB(PtrNewFcb);
1257 PtrNewFcb = NULL;
1258 NewFileInfo->Fcb = NULL;
1259 if(UDFCleanUpFile__(Vcb, NewFileInfo)) {
1260 MyFreePool__(NewFileInfo);
1261 NewFileInfo = NULL;
1262 }
1263 try_return(RC);
1264 }
1265 } else {
1266 // It is not a first open operation
1267 // Validate Fcb. It is possible to get
1268 // not completly initialized Fcb here.
1269 if(!(PtrNewFcb->FCBFlags & UDF_FCB_VALID)) {
1270 BrutePoint();
1271 AdPrint((" Fcb not valid\n"));
1272 UDFCloseFile__(Vcb, NewFileInfo);
1273 PtrNewFcb = NULL;
1274 if(UDFCleanUpFile__(Vcb, NewFileInfo)) {
1275 MyFreePool__(NewFileInfo);
1276 NewFileInfo = NULL;
1277 }
1278 try_return(RC = STATUS_ACCESS_DENIED);
1279 }
1280 }
1281 // Acquire newly opened File...
1282 Res2 = Res1;
1283 UDF_CHECK_PAGING_IO_RESOURCE(NewFileInfo->Fcb->NTRequiredFCB);
1284 UDFAcquireResourceExclusive(Res1 = &(NewFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE);
1285 // ...and reference it
1286 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount));
1287 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount));
1288
1289 ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount);
1290 // update unwind information
1291 LastGoodFileInfo = NewFileInfo;
1292 LastGoodName = CurName;
1293 TreeLength++;
1294 // update current path
1295 if(!StreamOpen ||
1296 ((CurName.Buffer[0] != L':') &&
1297 (!LocalPath.Length || (LocalPath.Buffer[LocalPath.Length/sizeof(WCHAR)-1] != L':'))) ) {
1298 // we should not insert '\' before or after ':'
1299 ASSERT(!LocalPath.Length ||
1300 (LocalPath.Buffer[LocalPath.Length/2-1] != L'\\'));
1301 RC = MyAppendUnicodeToString(&LocalPath, L"\\");
1302 if(!NT_SUCCESS(RC)) try_return(RC);
1303 }
1304 RC = MyAppendUnicodeStringToStringTag(&LocalPath, &CurName, MEM_USLOC_TAG);
1305 if(!NT_SUCCESS(RC))
1306 try_return(RC);
1307 // DbgPrint("UDF: Open/Create File %ws : ReferenceCount %x\n",CurName.Buffer,PtrNewFcb->ReferenceCount);
1308 } else {
1309 AdPrint((" Can't open file\n"));
1310 // We have failed durring last Open attempt
1311 // Roll back to last good state
1312 PtrUDFNTRequiredFCB NtReqFcb = NULL;
1313 // Cleanup FileInfo if any
1314 if(NewFileInfo) {
1315 PtrNewFcb = NewFileInfo->Fcb;
1316 // acquire appropriate resource if possible
1317 if(PtrNewFcb &&
1318 PtrNewFcb->NTRequiredFCB) {
1319 NtReqFcb = PtrNewFcb->NTRequiredFCB;
1320 Res2 = Res1;
1321 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
1322 UDFAcquireResourceExclusive(Res1 = &(NtReqFcb->MainResource),TRUE);
1323 }
1324 // cleanup pointer to Fcb in FileInfo to allow
1325 // UDF_INFO package release FileInfo if there are
1326 // no more references
1327 if(PtrNewFcb &&
1328 !PtrNewFcb->ReferenceCount &&
1329 !PtrNewFcb->OpenHandleCount) {
1330 NewFileInfo->Fcb = NULL;
1331 }
1332 // cleanup pointer to CommonFcb in Dloc to allow
1333 // UDF_INFO package release Dloc if there are
1334 // no more references
1335 if(NewFileInfo->Dloc &&
1336 !NewFileInfo->Dloc->LinkRefCount &&
1337 (!PtrNewFcb || !PtrNewFcb->ReferenceCount)) {
1338 NewFileInfo->Dloc->CommonFcb = NULL;
1339 }
1340 // try to release FileInfo
1341 if(UDFCleanUpFile__(Vcb, NewFileInfo)) {
1342 ASSERT(!PtrNewFcb);
1343 if(PtrNewFcb) {
1344 BrutePoint();
1345 UDFCleanUpFCB(PtrNewFcb);
1346 }
1347 MyFreePool__(NewFileInfo);
1348 } else {
1349 // if we can't release FileInfo
1350 // restore pointers to Fcb & CommonFcb in
1351 // FileInfo & Dloc
1352 NewFileInfo->Fcb = PtrNewFcb;
1353 if(NtReqFcb)
1354 NewFileInfo->Dloc->CommonFcb = NtReqFcb;
1355 }
1356 // forget about last FileInfo & Fcb,
1357 // further unwind staff needs only last good
1358 // structures
1359 PtrNewFcb = NULL;
1360 NewFileInfo = NULL;
1361 }
1362 }
1363
1364 // should return error if 'delete in progress'
1365 if(LastGoodFileInfo->Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE |
1366 UDF_FCB_DELETED |
1367 UDF_FCB_POSTED_RENAME)) {
1368 AdPrint((" Return DeletePending (no err)\n"));
1369 try_return(RC = STATUS_DELETE_PENDING);
1370 }
1371 // update last good state information...
1372 OldRelatedFileInfo = RelatedFileInfo;
1373 RelatedFileInfo = NewFileInfo;
1374 // ...and go to the next open cycle
1375 } else {
1376 // ************
1377 if(StreamOpen && (RC == STATUS_NOT_FOUND))
1378 // handle SDir return code
1379 RC = STATUS_OBJECT_NAME_NOT_FOUND;
1380 if(RC == STATUS_OBJECT_NAME_NOT_FOUND) {
1381 // good path, but no such file.... Amen
1382 // break open loop and continue with Create
1383 break;
1384 }
1385 if (!NT_SUCCESS(RC)) {
1386 // Hard error or damaged data structures ...
1387 #ifdef UDF_DBG
1388 if((RC != STATUS_OBJECT_PATH_NOT_FOUND) &&
1389 (RC != STATUS_ACCESS_DENIED) &&
1390 (RC != STATUS_NOT_A_DIRECTORY)) {
1391 AdPrint((" Hard error or damaged data structures\n"));
1392 }
1393 #endif // UDF_DBG
1394 // ... and exit with error
1395 try_return(RC);
1396 }
1397 // discard changes for last successfully opened file
1398 UDFInterlockedDecrement((PLONG)&(PtrNewFcb->ReferenceCount));
1399 UDFInterlockedDecrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount));
1400 RC = STATUS_SUCCESS;
1401 ASSERT(!OpenTargetDirectory);
1402 // break open loop and continue with Open
1403 // (Create will be skipped)
1404 break;
1405 }
1406 } // end of while(TRUE)
1407
1408 // ****************
1409 // If "open target directory" was specified
1410 // ****************
1411 if(OpenTargetDirectory) {
1412
1413 if(!UDFIsADirectory(LastGoodFileInfo)) {
1414 AdPrint((" Not a directory (2)\n"));
1415 RC = STATUS_NOT_A_DIRECTORY;
1416 }
1417 if(!NT_SUCCESS(RC) ||
1418 TailName.Length) {
1419 AdPrint((" Target name should not contain (back)slashes\n"));
1420 NewFileInfo = NULL;
1421 try_return(RC = STATUS_OBJECT_NAME_INVALID);
1422 }
1423
1424 NewFileInfo = LastGoodFileInfo;
1425 RtlCopyUnicodeString(&(PtrNewFileObject->FileName), &CurName);
1426
1427 // now we have to check if last component exists...
1428 if(NT_SUCCESS(RC = UDFFindFile__(Vcb, IgnoreCase,
1429 &CurName, RelatedFileInfo))) {
1430 // file exists, set this information in the Information field
1431 ReturnedInformation = FILE_EXISTS;
1432 AdPrint((" Open Target: FILE_EXISTS\n"));
1433 } else
1434 if(RC == STATUS_OBJECT_NAME_NOT_FOUND) {
1435 #ifdef UDF_DBG
1436 // check name. If there are '\\'s in TailName, some
1437 // directories in path specified do not exist
1438 for(TmpBuffer = LastGoodTail.Buffer; *TmpBuffer; TmpBuffer++) {
1439 if((*TmpBuffer) == L'\\') {
1440 ASSERT(FALSE);
1441 AdPrint((" Target name should not contain (back)slashes\n"));
1442 try_return(RC = STATUS_OBJECT_NAME_INVALID);
1443 }
1444 }
1445 #endif // UDF_DBG
1446 // Tell the I/O Manager that file does not exit
1447 ReturnedInformation = FILE_DOES_NOT_EXIST;
1448 AdPrint((" Open Target: FILE_DOES_NOT_EXIST\n"));
1449 RC = STATUS_SUCCESS; // is already set here
1450 } else {
1451 AdPrint((" Open Target: unexpected error\n"));
1452 NewFileInfo = NULL;
1453 try_return(RC = STATUS_OBJECT_NAME_INVALID);
1454 }
1455
1456 // RC = STATUS_SUCCESS; // is already set here
1457
1458 // Update the file object FsContext and FsContext2 fields
1459 // to reflect the fact that the parent directory of the
1460 // target has been opened
1461 PtrNewFcb = NewFileInfo->Fcb;
1462 UDFInterlockedDecrement((PLONG)&(PtrNewFcb->ReferenceCount));
1463 UDFInterlockedDecrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount));
1464 RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb);
1465 ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount);
1466 if (!NT_SUCCESS(RC)) {
1467 AdPrint((" Can't perform OpenFile operation for target\n"));
1468 try_return(RC);
1469 }
1470 PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2);
1471
1472 ASSERT(Res1);
1473 RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess);
1474 if(!NT_SUCCESS(RC)) {
1475 AdPrint((" Access/Share access check failed (Open Target)\n"));
1476 }
1477
1478 try_return(RC);
1479 }
1480
1481 // ****************
1482 // should we CREATE a new file ?
1483 // ****************
1484 if (!NT_SUCCESS(RC)) {
1485 if (RC == STATUS_OBJECT_NAME_NOT_FOUND ||
1486 RC == STATUS_OBJECT_PATH_NOT_FOUND) {
1487 if( ((RequestedDisposition == FILE_OPEN) ||
1488 (RequestedDisposition == FILE_OVERWRITE)) /*&&
1489 (!StreamOpen || !StreamExists)*/ ){
1490 ReturnedInformation = FILE_DOES_NOT_EXIST;
1491 AdPrint((" File doesn't exist\n"));
1492 try_return(RC);
1493 }
1494 } else {
1495 // Any other operation return STATUS_ACCESS_DENIED.
1496 AdPrint((" Can't create due to unexpected error\n"));
1497 try_return(RC);
1498 }
1499 // Object was not found, create if requested
1500 if ((RequestedDisposition != FILE_CREATE) && (RequestedDisposition != FILE_OPEN_IF) &&
1501 (RequestedDisposition != FILE_OVERWRITE_IF) && (RequestedDisposition != FILE_SUPERSEDE)) {
1502 AdPrint((" File doesn't exist (2)\n"));
1503 try_return(RC);
1504 }
1505 // Check Volume ReadOnly attr
1506 #ifndef UDF_READ_ONLY_BUILD
1507 if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {
1508 #endif //UDF_READ_ONLY_BUILD
1509 ReturnedInformation = 0;
1510 AdPrint((" Write protected\n"));
1511 try_return(RC = STATUS_MEDIA_WRITE_PROTECTED);
1512 #ifndef UDF_READ_ONLY_BUILD
1513 }
1514 // Check r/o + delete on close
1515 if(DeleteOnCloseSpecified &&
1516 (FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1517 AdPrint((" Can't create r/o file marked for deletion\n"));
1518 try_return(RC = STATUS_CANNOT_DELETE);
1519 }
1520
1521 // Create a new file/directory here ...
1522 if(StreamOpen)
1523 StreamName.Buffer[StreamName.Length/sizeof(WCHAR)] = 0;
1524 for(TmpBuffer = LastGoodTail.Buffer; *TmpBuffer; TmpBuffer++) {
1525 if((*TmpBuffer) == L'\\') {
1526 AdPrint((" Target name should not contain (back)slashes\n"));
1527 try_return(RC = STATUS_OBJECT_NAME_INVALID);
1528 }
1529 }
1530 if( DirectoryOnlyRequested &&
1531 ((IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_TEMPORARY) ||
1532 StreamOpen || FALSE)) {
1533 AdPrint((" Creation of _temporary_ directory not permited\n"));
1534 try_return(RC = STATUS_INVALID_PARAMETER);
1535 }
1536 // check access rights
1537 ASSERT(Res1);
1538 RC = UDFCheckAccessRights(NULL, NULL, OldRelatedFileInfo->Fcb, PtrRelatedCCB, DirectoryOnlyRequested ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0);
1539 if(!NT_SUCCESS(RC)) {
1540 AdPrint((" Creation of File/Dir not permitted\n"));
1541 try_return(RC);
1542 }
1543 // Note that a FCB structure will be allocated at this time
1544 // and so will a CCB structure. Assume that these are called
1545 // PtrNewFcb and PtrNewCcb respectively.
1546 // Further, note that since the file is being created, no other
1547 // thread can have the file stream open at this time.
1548 RelatedFileInfo = OldRelatedFileInfo;
1549
1550 RC = UDFCreateFile__(Vcb, IgnoreCase, &LastGoodTail, 0, 0,
1551 Vcb->UseExtendedFE || (StreamOpen && !StreamExists),
1552 (RequestedDisposition == FILE_CREATE), RelatedFileInfo, &NewFileInfo);
1553 if(!NT_SUCCESS(RC)) {
1554 AdPrint((" Creation error\n"));
1555 Creation_Err_1:
1556 if(NewFileInfo) {
1557 PtrNewFcb = NewFileInfo->Fcb;
1558 ASSERT(!PtrNewFcb);
1559 if(PtrNewFcb &&
1560 !PtrNewFcb->ReferenceCount &&
1561 !PtrNewFcb->OpenHandleCount) {
1562 NewFileInfo->Fcb = NULL;
1563 }
1564 if(NewFileInfo->Dloc &&
1565 !NewFileInfo->Dloc->LinkRefCount) {
1566 NewFileInfo->Dloc->CommonFcb = NULL;
1567 }
1568 if(UDFCleanUpFile__(Vcb, NewFileInfo)) {
1569 if(PtrNewFcb) {
1570 BrutePoint();
1571 UDFCleanUpFCB(PtrNewFcb);
1572 }
1573 MyFreePool__(NewFileInfo);
1574 PtrNewFcb = PtrNewFcb;
1575 } else {
1576 NewFileInfo->Fcb = PtrNewFcb;
1577 }
1578 PtrNewFcb = NULL;
1579 }
1580 try_return(RC);
1581 }
1582 // Update parent object
1583 if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) &&
1584 PtrRelatedFCB &&
1585 PtrRelatedFileObject &&
1586 (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) {
1587 PtrRelatedFileObject->Flags |= (FO_FILE_MODIFIED | FO_FILE_SIZE_CHANGED);
1588 }
1589 #if 0
1590 CollectStatistics(Vcb, MetaDataWrites);
1591 #endif
1592
1593 if(DirectoryOnlyRequested) {
1594 // user wants the directory to be created
1595 RC = UDFRecordDirectory__(Vcb, NewFileInfo);
1596 if(!NT_SUCCESS(RC)) {
1597 AdPrint((" Can't transform to directory\n"));
1598 Undo_Create_1:
1599 if((RC != STATUS_FILE_IS_A_DIRECTORY) &&
1600 (RC != STATUS_NOT_A_DIRECTORY) &&
1601 (RC != STATUS_ACCESS_DENIED)) {
1602 UDFFlushFile__(Vcb, NewFileInfo);
1603 UDFUnlinkFile__(Vcb, NewFileInfo, TRUE);
1604 }
1605 UDFCloseFile__(Vcb, NewFileInfo);
1606 BrutePoint();
1607 goto Creation_Err_1;
1608 }
1609 #if 0
1610 CollectStatistics(Vcb, MetaDataWrites);
1611 #endif
1612 } else if(AllocationSize) {
1613 // set initial file size
1614 /* if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) {
1615 AdPrint((" Can't set initial file size\n"));
1616 goto Undo_Create_1;
1617 }
1618 CollectStatistics(Vcb, MetaDataWrites);*/
1619 }
1620
1621 if(StreamOpen && !StreamExists) {
1622
1623 // PHASE 0
1624
1625 // Open the newly created object (file)
1626 if (!(PtrNewFcb = NewFileInfo->Fcb)) {
1627 // It is a first open operation
1628 // Allocate new FCB
1629 // Here we set FileObject pointer to NULL to avoid
1630 // new CCB allocation
1631 RC = UDFFirstOpenFile(Vcb,
1632 NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo,
1633 &LocalPath, &LastGoodTail);
1634 if(!NT_SUCCESS(RC)) {
1635 AdPrint((" Can't perform FirstOpenFile operation for file to contain stream\n"));
1636 BrutePoint();
1637 UDFCleanUpFCB(NewFileInfo->Fcb);
1638 NewFileInfo->Fcb = NULL;
1639 goto Creation_Err_1;
1640 }
1641 } else {
1642 BrutePoint();
1643 }
1644
1645 // Update unwind information
1646 TreeLength++;
1647 LastGoodFileInfo = NewFileInfo;
1648 // update FCB tree
1649 RC = MyAppendUnicodeToString(&LocalPath, L"\\");
1650 if(!NT_SUCCESS(RC)) try_return(RC);
1651 RC = MyAppendUnicodeStringToStringTag(&LocalPath, &LastGoodTail, MEM_USLOC_TAG);
1652 if(!NT_SUCCESS(RC))
1653 goto Creation_Err_1;
1654 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount));
1655 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount));
1656 ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount);
1657 PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID;
1658 PtrNewFcb->FCBFlags |= UDF_FCB_VALID;
1659
1660 UDFNotifyFullReportChange( Vcb, NewFileInfo,
1661 UDFIsADirectory(NewFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
1662 FILE_ACTION_ADDED);
1663
1664 // PHASE 1
1665
1666 // we need to create Stream Dir
1667 RelatedFileInfo = NewFileInfo;
1668 RC = UDFCreateStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo);
1669 if(!NT_SUCCESS(RC)) {
1670 AdPrint((" Can't create SDir\n"));
1671 BrutePoint();
1672 goto Creation_Err_1;
1673 }
1674 #if 0
1675 CollectStatistics(Vcb, MetaDataWrites);
1676 #endif
1677
1678 // normalize stream name
1679 StreamName.Buffer++;
1680 StreamName.Length-=sizeof(WCHAR);
1681 // Open the newly created object
1682 if (!(PtrNewFcb = NewFileInfo->Fcb)) {
1683 // It is a first open operation
1684 // Allocate new FCB
1685 // Here we set FileObject pointer to NULL to avoid
1686 // new CCB allocation
1687 RC = UDFFirstOpenFile(Vcb,
1688 NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo,
1689 &LocalPath, &(UDFGlobalData.UnicodeStrSDir));
1690 } else {
1691 BrutePoint();
1692 }
1693 if(!NT_SUCCESS(RC)) {
1694 AdPrint((" Can't perform OpenFile operation for SDir\n"));
1695 BrutePoint();
1696 goto Creation_Err_1;
1697 }
1698
1699 // Update unwind information
1700 TreeLength++;
1701 LastGoodFileInfo = NewFileInfo;
1702 // update FCB tree
1703 RC = MyAppendUnicodeStringToStringTag(&LocalPath, &(UDFGlobalData.UnicodeStrSDir), MEM_USLOC_TAG);
1704 if(!NT_SUCCESS(RC)) {
1705 AdPrint((" Can't append UNC str\n"));
1706 BrutePoint();
1707 goto Creation_Err_1;
1708 }
1709 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount));
1710 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount));
1711 ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount);
1712 PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID;
1713 PtrNewFcb->FCBFlags |= UDF_FCB_VALID;
1714
1715 // PHASE 2
1716
1717 // create stream
1718 RelatedFileInfo = NewFileInfo;
1719 RC = UDFCreateFile__(Vcb, IgnoreCase, &StreamName, 0, 0,
1720 Vcb->UseExtendedFE, (RequestedDisposition == FILE_CREATE),
1721 RelatedFileInfo, &NewFileInfo);
1722 if(!NT_SUCCESS(RC)) {
1723 AdPrint((" Can't create Stream\n"));
1724 BrutePoint();
1725 goto Creation_Err_1;
1726 }
1727 #if 0
1728 CollectStatistics(Vcb, MetaDataWrites);
1729 #endif
1730
1731 // Update unwind information
1732 LastGoodTail = StreamName;
1733 }
1734 // NT wants ARCHIVE bit to be set on Files
1735 if(!DirectoryOnlyRequested)
1736 FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
1737 // Open the newly created object
1738 if (!(PtrNewFcb = NewFileInfo->Fcb)) {
1739 // It is a first open operation
1740 #ifndef IFS_40
1741 // Set attributes for the file ...
1742 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo),NewFileInfo->Index),
1743 NewFileInfo->Dloc->FileEntry, FileAttributes);
1744 #endif //IFS_40
1745 // Allocate new FCB
1746 // Here we set FileObject pointer to NULL to avoid
1747 // new CCB allocation
1748 RC = UDFFirstOpenFile(Vcb,
1749 PtrNewFileObject, &PtrNewFcb, RelatedFileInfo, NewFileInfo,
1750 &LocalPath, &LastGoodTail);
1751 } else {
1752 BrutePoint();
1753 }
1754
1755 if(!NT_SUCCESS(RC)) {
1756 AdPrint((" Can't perform OpenFile operation for file or stream\n"));
1757 BrutePoint();
1758 goto Undo_Create_1;
1759 }
1760
1761 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.FileSize.QuadPart =
1762 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength.QuadPart = 0;
1763 if(AllocationSize) {
1764 // inform NT about size changes
1765 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart = AllocationSize;
1766 MmPrint((" CcIsFileCached()\n"));
1767 if(CcIsFileCached(PtrNewFileObject)) {
1768 MmPrint((" CcSetFileSizes()\n"));
1769 BrutePoint();
1770 CcSetFileSizes(PtrNewFileObject, (PCC_FILE_SIZES)&(PtrNewFcb->NTRequiredFCB->CommonFCBHeader.AllocationSize));
1771 PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED;
1772 }
1773 }
1774
1775 // Update unwind information
1776 TreeLength++;
1777 LastGoodFileInfo = NewFileInfo;
1778
1779 // Set the Share Access for the file stream.
1780 // The FCBShareAccess field will be set by the I/O Manager.
1781 PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2);
1782 RC = UDFSetAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess);
1783
1784 if(!NT_SUCCESS(RC)) {
1785 AdPrint((" Can't set Access Rights on Create\n"));
1786 BrutePoint();
1787 UDFFlushFile__(Vcb, NewFileInfo);
1788 UDFUnlinkFile__(Vcb, NewFileInfo, TRUE);
1789 try_return(RC);
1790 }
1791
1792 #ifdef IFS_40
1793 // Set attributes for the file ...
1794 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo),NewFileInfo->Index),
1795 NewFileInfo->Dloc->FileEntry, FileAttributes);
1796 // It is rather strange for me, but NT requires us to allow
1797 // Create operation for r/o + WriteAccess, but denies all
1798 // the rest operations in this case. Thus, we should update
1799 // r/o flag in Fcb _after_ Access check :-/
1800 if(FileAttributes & FILE_ATTRIBUTE_READONLY)
1801 PtrNewFcb->FCBFlags |= UDF_FCB_READ_ONLY;
1802 #endif //IFS_40
1803 // We call the notify package to report that the
1804 // we have added a stream.
1805 if(UDFIsAStream(NewFileInfo)) {
1806 UDFNotifyFullReportChange( Vcb, NewFileInfo,
1807 FILE_NOTIFY_CHANGE_STREAM_NAME,
1808 FILE_ACTION_ADDED_STREAM );
1809 } else {
1810 UDFNotifyFullReportChange( Vcb, NewFileInfo,
1811 UDFIsADirectory(NewFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
1812 FILE_ACTION_ADDED);
1813 }
1814 /*#ifdef UDF_DBG
1815 {
1816 ULONG i;
1817 PDIR_INDEX_HDR hDirIndex = NewFileInfo->ParentFile->Dloc->DirIndex;
1818
1819 for(i=0;DirIndex[i].FName.Buffer;i++) {
1820 AdPrint(("%ws\n", DirIndex[i].FName.Buffer));
1821 }
1822 }
1823 #endif*/
1824 ReturnedInformation = FILE_CREATED;
1825
1826 try_return(RC);
1827 #endif //UDF_READ_ONLY_BUILD
1828
1829 }
1830
1831 AlreadyOpened:
1832
1833 // ****************
1834 // we have always STATUS_SUCCESS here
1835 // ****************
1836
1837 ASSERT(NewFileInfo != OldRelatedFileInfo);
1838 // A new CCB will be allocated.
1839 // Assume that this structure named PtrNewCcb
1840 RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb);
1841 if (!NT_SUCCESS(RC)) try_return(RC);
1842 PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2);
1843
1844 if(RequestedDisposition == FILE_CREATE) {
1845 ReturnedInformation = FILE_EXISTS;
1846 AdPrint((" Object name collision\n"));
1847 try_return(RC = STATUS_OBJECT_NAME_COLLISION);
1848 }
1849
1850 NtReqFcb = PtrNewFcb->NTRequiredFCB;
1851 NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(PtrNewFcb);
1852
1853 // Check if caller wanted a directory only and target object
1854 // is not a directory, or caller wanted a file only and target
1855 // object is not a file ...
1856 if((PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY) && ((RequestedDisposition == FILE_SUPERSEDE) ||
1857 (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF) ||
1858 FileOnlyRequested)) {
1859 if(FileOnlyRequested) {
1860 AdPrint((" Can't open directory as a plain file\n"));
1861 } else {
1862 AdPrint((" Can't supersede directory\n"));
1863 }
1864 RC = STATUS_FILE_IS_A_DIRECTORY;
1865 try_return(RC);
1866 }
1867
1868 if(DirectoryOnlyRequested && !(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)) {
1869 AdPrint((" This is not a directory\n"));
1870 RC = STATUS_NOT_A_DIRECTORY;
1871 try_return(RC);
1872 }
1873
1874 if(DeleteOnCloseSpecified && (PtrNewFcb->FCBFlags & UDF_FCB_READ_ONLY)) {
1875 AdPrint((" Can't delete Read-Only file\n"));
1876 RC = STATUS_CANNOT_DELETE;
1877 try_return(RC);
1878 }
1879 // Check share access and fail if the share conflicts with an existing
1880 // open.
1881 ASSERT(Res1 != NULL);
1882 ASSERT(Res2 != NULL);
1883 RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess);
1884 if(!NT_SUCCESS(RC)) {
1885 AdPrint((" Access/Share access check failed\n"));
1886 try_return(RC);
1887 }
1888
1889 RestoreShareAccess = TRUE;
1890
1891 if(FileOnlyRequested) {
1892 // If the user wants 'write access' access to the file make sure there
1893 // is not a process mapping this file as an image. Any attempt to
1894 // delete the file will be stopped in fileinfo.cpp
1895 //
1896 // If the user wants to delete on close, we must check at this
1897 // point though.
1898 if( (DesiredAccess & FILE_WRITE_DATA) || DeleteOnCloseSpecified ) {
1899 MmPrint((" MmFlushImageSection();\n"));
1900 NtReqFcb->AcqFlushCount++;
1901 if(!MmFlushImageSection( &(NtReqFcb->SectionObject),
1902 MmFlushForWrite )) {
1903
1904 NtReqFcb->AcqFlushCount--;
1905 RC = DeleteOnCloseSpecified ? STATUS_CANNOT_DELETE :
1906 STATUS_SHARING_VIOLATION;
1907 AdPrint((" File is mapped or deletion in progress\n"));
1908 try_return (RC);
1909 }
1910 NtReqFcb->AcqFlushCount--;
1911 }
1912 if( NoBufferingSpecified &&
1913 /* (PtrNewFileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) &&*/
1914 !(PtrNewFcb->CachedOpenHandleCount) &&
1915 (NtReqFcb->SectionObject.DataSectionObject) ) {
1916 // If this is a non-cached open, and there are no open cached
1917 // handles, but there is still a data section, attempt a flush
1918 // and purge operation to avoid cache coherency overhead later.
1919 // We ignore any I/O errors from the flush.
1920 MmPrint((" CcFlushCache()\n"));
1921 CcFlushCache( &(NtReqFcb->SectionObject), NULL, 0, NULL );
1922 MmPrint((" CcPurgeCacheSection()\n"));
1923 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );
1924 }
1925 }
1926
1927 if(DeleteOnCloseSpecified && UDFIsADirectory(NewFileInfo) && !UDFIsDirEmpty__(NewFileInfo)) {
1928 AdPrint((" Directory in not empry\n"));
1929 try_return (RC = STATUS_DIRECTORY_NOT_EMPTY);
1930 }
1931
1932 // Get attributes for the file ...
1933 TmpFileAttributes =
1934 (USHORT)UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index),
1935 NewFileInfo->Dloc->FileEntry);
1936
1937 if(DeleteOnCloseSpecified &&
1938 (TmpFileAttributes & FILE_ATTRIBUTE_READONLY)) {
1939 ASSERT(Res1 != NULL);
1940 ASSERT(Res2 != NULL);
1941 RC = UDFCheckAccessRights(NULL, NULL, OldRelatedFileInfo->Fcb, PtrRelatedCCB, FILE_DELETE_CHILD, 0);
1942 if(!NT_SUCCESS(RC)) {
1943 AdPrint((" Read-only. DeleteOnClose attempt failed\n"));
1944 try_return (RC = STATUS_CANNOT_DELETE);
1945 }
1946 }
1947
1948 // If a supersede or overwrite was requested, do so now ...
1949 if((RequestedDisposition == FILE_SUPERSEDE) ||
1950 (RequestedDisposition == FILE_OVERWRITE) ||
1951 (RequestedDisposition == FILE_OVERWRITE_IF)) {
1952 // Attempt the operation here ...
1953
1954 #ifndef UDF_READ_ONLY_BUILD
1955 ASSERT(!UDFIsADirectory(NewFileInfo));
1956
1957 if(RequestedDisposition == FILE_SUPERSEDE) {
1958 BOOLEAN RestoreRO = FALSE;
1959
1960 ASSERT(Res1 != NULL);
1961 ASSERT(Res2 != NULL);
1962 // NT wants us to allow Supersede on RO files
1963 if(PtrNewFcb->FCBFlags & UDF_FCB_READ_ONLY) {
1964 // Imagine, that file is not RO and check other permissions
1965 RestoreRO = TRUE;
1966 PtrNewFcb->FCBFlags &= ~UDF_FCB_READ_ONLY;
1967 }
1968 RC = UDFCheckAccessRights(NULL, NULL, PtrNewFcb, PtrNewCcb, DELETE, 0);
1969 if(RestoreRO) {
1970 // Restore RO state if changed
1971 PtrNewFcb->FCBFlags |= UDF_FCB_READ_ONLY;
1972 }
1973 if(!NT_SUCCESS(RC)) {
1974 AdPrint((" Can't supersede. DELETE permission required\n"));
1975 try_return (RC);
1976 }
1977 } else {
1978 ASSERT(Res1 != NULL);
1979 ASSERT(Res2 != NULL);
1980 RC = UDFCheckAccessRights(NULL, NULL, PtrNewFcb, PtrNewCcb,
1981 FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES, 0);
1982 if(!NT_SUCCESS(RC)) {
1983 AdPrint((" Can't overwrite. Permission denied\n"));
1984 try_return (RC);
1985 }
1986 }
1987 // Existing & requested System and Hidden bits must match
1988 if( (TmpFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) &
1989 (FileAttributes ^ (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) ) {
1990 AdPrint((" The Hidden and/or System bits do not match\n"));
1991 try_return(RC = STATUS_ACCESS_DENIED);
1992 }
1993
1994 // Before we actually truncate, check to see if the purge
1995 // is going to fail.
1996 MmPrint((" MmCanFileBeTruncated()\n"));
1997 if (!MmCanFileBeTruncated( &NtReqFcb->SectionObject,
1998 &(UDFGlobalData.UDFLargeZero) )) {
1999 AdPrint((" Can't truncate. File is mapped\n"));
2000 try_return(RC = STATUS_USER_MAPPED_FILE);
2001 }
2002
2003 ASSERT(Res1 != NULL);
2004 ASSERT(Res2 != NULL);
2005
2006 #if 0
2007 CollectStatistics(Vcb, MetaDataWrites);
2008 #endif
2009 // Synchronize with PagingIo
2010 UDFAcquireResourceExclusive(PagingIoRes = &(NtReqFcb->PagingIoResource),TRUE);
2011 // Set file sizes
2012 if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, 0))) {
2013 AdPrint((" Error during resize operation\n"));
2014 try_return(RC);
2015 }
2016 /* if(AllocationSize) {
2017 if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) {
2018 AdPrint((" Error during resize operation (2)\n"));
2019 try_return(RC);
2020 }
2021 }*/
2022 NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = UDFSysGetAllocSize(Vcb, AllocationSize);
2023 NtReqFcb->CommonFCBHeader.FileSize.QuadPart =
2024 NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = 0 /*AllocationSize*/;
2025 PtrNewFcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE;
2026 MmPrint((" CcSetFileSizes()\n"));
2027 CcSetFileSizes(PtrNewFileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize));
2028 NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED;
2029 // Release PagingIoResource
2030 UDFReleaseResource(PagingIoRes);
2031 PagingIoRes = NULL;
2032
2033 if(NT_SUCCESS(RC)) {
2034 FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
2035 if (RequestedDisposition == FILE_SUPERSEDE) {
2036 // Set attributes for the file ...
2037 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index),
2038 NewFileInfo->Dloc->FileEntry, FileAttributes);
2039 ReturnedInformation = FILE_SUPERSEDED;
2040 } else {
2041 // Get attributes for the file ...
2042 FileAttributes |= TmpFileAttributes;
2043 // Set attributes for the file ...
2044 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index),
2045 NewFileInfo->Dloc->FileEntry, FileAttributes);
2046 ReturnedInformation = FILE_OVERWRITTEN;
2047 }
2048 }
2049 // notify changes
2050 UDFNotifyFullReportChange( Vcb, NewFileInfo,
2051 FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE,
2052 FILE_ACTION_MODIFIED);
2053
2054 // Update parent object
2055 if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) &&
2056 PtrRelatedFCB &&
2057 PtrRelatedFileObject &&
2058 (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) {
2059 PtrRelatedFileObject->Flags |= (FO_FILE_MODIFIED | FO_FILE_SIZE_CHANGED);
2060 }
2061 #else //UDF_READ_ONLY_BUILD
2062 try_return(RC = STATUS_ACCESS_DENIED);
2063 #endif //UDF_READ_ONLY_BUILD
2064 } else {
2065 ReturnedInformation = FILE_OPENED;
2066 }
2067
2068 // Update parent object
2069 if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_READ) &&
2070 PtrRelatedFCB &&
2071 PtrRelatedFileObject &&
2072 (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) {
2073 PtrRelatedFileObject->Flags |= FO_FILE_FAST_IO_READ;
2074 }
2075
2076 try_exit: NOTHING;
2077
2078 } _SEH2_FINALLY {
2079 // Complete the request unless we are here as part of unwinding
2080 // when an exception condition was encountered, OR
2081 // if the request has been deferred (i.e. posted for later handling)
2082
2083 if(RestoreVCBOpenCounter) {
2084 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
2085 RestoreVCBOpenCounter = FALSE;
2086 }
2087
2088 if (RC != STATUS_PENDING) {
2089 // If any intermediate (directory) open operations were performed,
2090 // implement the corresponding close (do *not* however close
2091 // the target we have opened on behalf of the caller ...).
2092
2093 #if 0
2094 if(NT_SUCCESS(RC)) {
2095 CollectStatistics2(Vcb, SuccessfulCreates);
2096 } else {
2097 CollectStatistics2(Vcb, FailedCreates);
2098 }
2099 #endif
2100
2101 if (NT_SUCCESS(RC) && PtrNewFcb) {
2102 // Update the file object such that:
2103 // (a) the FsContext field points to the NTRequiredFCB field
2104 // in the FCB
2105 // (b) the FsContext2 field points to the CCB created as a
2106 // result of the open operation
2107
2108 // If write-through was requested, then mark the file object
2109 // appropriately
2110
2111 // directories are not cached
2112 // so we should prevent flush attepmts on cleanup
2113 if(!(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)) {
2114 #ifndef UDF_READ_ONLY_BUILD
2115 if(WriteThroughRequested) {
2116 PtrNewFileObject->Flags |= FO_WRITE_THROUGH;
2117 PtrNewFcb->FCBFlags |= UDF_FCB_WRITE_THROUGH;
2118 MmPrint((" FO_WRITE_THROUGH\n"));
2119 }
2120 #endif //UDF_READ_ONLY_BUILD
2121 if(SequentialIoRequested &&
2122 !(Vcb->CompatFlags & UDF_VCB_IC_IGNORE_SEQUENTIAL_IO)) {
2123 PtrNewFileObject->Flags |= FO_SEQUENTIAL_ONLY;
2124 MmPrint((" FO_SEQUENTIAL_ONLY\n"));
2125 #ifndef UDF_READ_ONLY_BUILD
2126 if(Vcb->TargetDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
2127 PtrNewFileObject->Flags &= ~FO_WRITE_THROUGH;
2128 PtrNewFcb->FCBFlags &= ~UDF_FCB_WRITE_THROUGH;
2129 MmPrint((" FILE_REMOVABLE_MEDIA + FO_SEQUENTIAL_ONLY => ~FO_WRITE_THROUGH\n"));
2130 }
2131 #endif //UDF_READ_ONLY_BUILD
2132 if(PtrNewFcb->FileInfo) {
2133 UDFSetFileAllocMode__(PtrNewFcb->FileInfo, EXTENT_FLAG_ALLOC_SEQUENTIAL);
2134 }
2135 }
2136 if(NoBufferingSpecified) {
2137 PtrNewFileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
2138 MmPrint((" FO_NO_INTERMEDIATE_BUFFERING\n"));
2139 } else {
2140 PtrNewFileObject->Flags |= FO_CACHE_SUPPORTED;
2141 MmPrint((" FO_CACHE_SUPPORTED\n"));
2142 }
2143 }
2144
2145 if((DesiredAccess & FILE_EXECUTE) /*&&
2146 !(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)*/) {
2147 MmPrint((" FO_FILE_FAST_IO_READ\n"));
2148 PtrNewFileObject->Flags |= FO_FILE_FAST_IO_READ;
2149 }
2150 // All right. Now we can safely increment OpenHandleCount
2151 UDFInterlockedIncrement((PLONG)&(Vcb->VCBHandleCount));
2152 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->OpenHandleCount));
2153
2154 if(PtrNewFileObject->Flags & FO_CACHE_SUPPORTED)
2155 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->CachedOpenHandleCount));
2156 // Store some flags in CCB
2157 if(PtrNewCcb) {
2158 PtrNewCcb->TreeLength = TreeLength;
2159 // delete on close
2160 #ifndef UDF_READ_ONLY_BUILD
2161 if(DeleteOnCloseSpecified) {
2162 ASSERT(!(PtrNewFcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
2163 PtrNewCcb->CCBFlags |= UDF_CCB_DELETE_ON_CLOSE;
2164 }
2165 #endif //UDF_READ_ONLY_BUILD
2166 // case sensetivity
2167 if(!IgnoreCase) {
2168 // remember this for possible Rename/Move operation
2169 PtrNewCcb->CCBFlags |= UDF_CCB_CASE_SENSETIVE;
2170 PtrNewFileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
2171 }
2172 if(IsFileObjectReadOnly(PtrNewFileObject)) {
2173 UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCountRO));
2174 PtrNewCcb->CCBFlags |= UDF_CCB_READ_ONLY;
2175 }
2176 } else {
2177 BrutePoint();
2178 }
2179 // it was a stream...
2180 if(StreamOpen)
2181 PtrNewFileObject->Flags |= FO_STREAM_FILE;
2182 // PtrNewCcb->CCBFlags |= UDF_CCB_VALID;
2183 // increment the number of outstanding open operations on this
2184 // logical volume (i.e. volume cannot be dismounted)
2185 UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
2186 PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID;
2187 PtrNewFcb->FCBFlags |= UDF_FCB_VALID;
2188 #ifdef UDF_DBG
2189 // We have no FileInfo for Volume
2190 if(PtrNewFcb->FileInfo) {
2191 ASSERT_REF(PtrNewFcb->ReferenceCount >= PtrNewFcb->FileInfo->RefCount);
2192 }
2193 #endif // UDF_DBG
2194 AdPrint((" FCB %x, CCB %x, FO %x, Flags %x\n", PtrNewFcb, PtrNewCcb, PtrNewFileObject, PtrNewFcb->FCBFlags));
2195
2196 UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2);
2197
2198 } else if(!NT_SUCCESS(RC)) {
2199 // Perform failure related post-processing now
2200 if(RestoreShareAccess && NtReqFcb && PtrNewFileObject) {
2201 IoRemoveShareAccess(PtrNewFileObject, &(NtReqFcb->FCBShareAccess));
2202 }
2203 UDFCleanUpCCB(PtrNewCcb);
2204 if(PtrNewFileObject) {
2205 PtrNewFileObject->FsContext2 = NULL;
2206 }
2207 // We have successfully opened LastGoodFileInfo,
2208 // so mark it as VALID to avoid future troubles...
2209 if(LastGoodFileInfo && LastGoodFileInfo->Fcb) {
2210 LastGoodFileInfo->Fcb->FCBFlags |= UDF_FCB_VALID;
2211 if(LastGoodFileInfo->Fcb->NTRequiredFCB) {
2212 LastGoodFileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID;
2213 }
2214 }
2215 // Release resources...
2216 UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2);
2217 ASSERT(AcquiredVcb);
2218 // close the chain
2219 UDFCloseFileInfoChain(Vcb, LastGoodFileInfo, TreeLength, TRUE);
2220 // cleanup FCBs (if any)
2221 if( Vcb && (PtrNewFcb != Vcb->RootDirFCB) &&
2222 LastGoodFileInfo ) {
2223 UDFCleanUpFcbChain(Vcb, LastGoodFileInfo, TreeLength, TRUE);
2224 } else {
2225 ASSERT(!LastGoodFileInfo);
2226 }
2227 } else {
2228 UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2);
2229 }
2230 // As long as this unwinding is not being performed as a result of
2231 // an exception condition, complete the IRP ...
2232 if (!_SEH2_AbnormalTermination()) {
2233 Irp->IoStatus.Status = RC;
2234 Irp->IoStatus.Information = ReturnedInformation;
2235
2236 // complete the IRP
2237 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2238 // Free up the Irp Context
2239 UDFReleaseIrpContext(PtrIrpContext);
2240 }
2241 } else {
2242 UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2);
2243 }
2244
2245 if(AcquiredVcb) {
2246 UDFReleaseResource(&(Vcb->VCBResource));
2247 }
2248 // free allocated tmp buffers (if any)
2249 if(AbsolutePathName.Buffer)
2250 MyFreePool__(AbsolutePathName.Buffer);
2251 if(LocalPath.Buffer)
2252 MyFreePool__(LocalPath.Buffer);
2253 if(TailNameBuffer)
2254 MyFreePool__(TailNameBuffer);
2255 } _SEH2_END;
2256
2257 return(RC);
2258 } // end UDFCommonCreate()
2259
2260 /*************************************************************************
2261 *
2262 * Function: UDFFirstOpenFile()
2263 *
2264 * Description:
2265 * Perform first Open/Create initialization.
2266 *
2267 * Expected Interrupt Level (for execution) :
2268 *
2269 * IRQL_PASSIVE_LEVEL
2270 *
2271 * Return Value: STATUS_SUCCESS/Error
2272 *
2273 *************************************************************************/
2274 NTSTATUS
2275 UDFFirstOpenFile(
2276 IN PVCB Vcb, // volume control block
2277 IN PFILE_OBJECT PtrNewFileObject, // I/O Mgr. created file object
2278 OUT PtrUDFFCB* PtrNewFcb,
2279 IN PUDF_FILE_INFO RelatedFileInfo,
2280 IN PUDF_FILE_INFO NewFileInfo,
2281 IN PUNICODE_STRING LocalPath,
2282 IN PUNICODE_STRING CurName
2283 )
2284 {
2285 // DIR_INDEX NewFileIndex;
2286 PtrUDFObjectName NewFCBName;
2287 PtrUDFNTRequiredFCB NtReqFcb;
2288 NTSTATUS RC;
2289 BOOLEAN Linked = TRUE;
2290 PDIR_INDEX_HDR hDirIndex;
2291 PDIR_INDEX_ITEM DirIndex;
2292
2293 AdPrint(("UDFFirstOpenFile\n"));
2294
2295 if(!((*PtrNewFcb) = UDFAllocateFCB())) {
2296 AdPrint(("Can't allocate FCB\n"));
2297 return STATUS_INSUFFICIENT_RESOURCES;
2298 }
2299
2300 // Allocate and set new FCB unique name (equal to absolute path name)
2301 if(!(NewFCBName = UDFAllocateObjectName())) return STATUS_INSUFFICIENT_RESOURCES;
2302
2303 if(RelatedFileInfo && RelatedFileInfo->Fcb &&
2304 !(RelatedFileInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)) {
2305 RC = MyCloneUnicodeString(&(NewFCBName->ObjectName), &(RelatedFileInfo->Fcb->FCBName->ObjectName));
2306 } else {
2307 RC = MyInitUnicodeString(&(NewFCBName->ObjectName), L"");
2308 }
2309 if(!NT_SUCCESS(RC))
2310 return STATUS_INSUFFICIENT_RESOURCES;
2311 if( (CurName->Buffer[0] != L':') &&
2312 (!LocalPath->Length ||
2313 ((LocalPath->Buffer[LocalPath->Length/sizeof(WCHAR)-1] != L':') /*&&
2314 (LocalPath->Buffer[LocalPath->Length/sizeof(WCHAR)-1] != L'\\')*/) )) {
2315 RC = MyAppendUnicodeToString(&(NewFCBName->ObjectName), L"\\");
2316 if(!NT_SUCCESS(RC)) {
2317 UDFReleaseObjectName(NewFCBName);
2318 return STATUS_INSUFFICIENT_RESOURCES;
2319 }
2320 }
2321
2322 // Make link between Fcb and FileInfo
2323 (*PtrNewFcb)->FileInfo = NewFileInfo;
2324 NewFileInfo->Fcb = (*PtrNewFcb);
2325 (*PtrNewFcb)->ParentFcb = RelatedFileInfo->Fcb;
2326
2327 if(!((*PtrNewFcb)->NTRequiredFCB = NewFileInfo->Dloc->CommonFcb)) {
2328 (*PtrNewFcb)->NTRequiredFCB = (PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB)));
2329 if(!((*PtrNewFcb)->NTRequiredFCB)) {
2330 UDFReleaseObjectName(NewFCBName);
2331 return STATUS_INSUFFICIENT_RESOURCES;
2332 }
2333
2334 UDFPrint(("UDFAllocateNtReqFCB: %x\n", (*PtrNewFcb)->NTRequiredFCB));
2335 RtlZeroMemory((*PtrNewFcb)->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB)));
2336 (*PtrNewFcb)->FileInfo->Dloc->CommonFcb = (*PtrNewFcb)->NTRequiredFCB;
2337 Linked = FALSE;
2338 } else {
2339 if(!(NewFileInfo->Dloc->CommonFcb->NtReqFCBFlags & UDF_NTREQ_FCB_VALID)) {
2340 (*PtrNewFcb)->NTRequiredFCB = NULL;
2341 BrutePoint();
2342 UDFReleaseObjectName(NewFCBName);
2343 return STATUS_ACCESS_DENIED;
2344 }
2345 }
2346
2347 NtReqFcb = (*PtrNewFcb)->NTRequiredFCB;
2348 // Set times
2349 if(!Linked) {
2350 UDFGetFileXTime((*PtrNewFcb)->FileInfo,
2351 &(NtReqFcb->CreationTime.QuadPart),
2352 &(NtReqFcb->LastAccessTime.QuadPart),
2353 &(NtReqFcb->ChangeTime.QuadPart),
2354 &(NtReqFcb->LastWriteTime.QuadPart) );
2355
2356 // Set the allocation size for the object is specified
2357 NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart =
2358 UDFSysGetAllocSize(Vcb, NewFileInfo->Dloc->DataLoc.Length);
2359 // NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = UDFGetFileAllocationSize(Vcb, NewFileInfo);
2360 NtReqFcb->CommonFCBHeader.FileSize.QuadPart =
2361 NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = NewFileInfo->Dloc->DataLoc.Length;
2362 }
2363 // begin transaction
2364 UDFAcquireResourceExclusive(&(Vcb->FcbListResource), TRUE);
2365
2366 RC = UDFInitializeFCB(*PtrNewFcb, Vcb, NewFCBName,
2367 UDFIsADirectory(NewFileInfo) ? UDF_FCB_DIRECTORY : 0, PtrNewFileObject);
2368 if(!NT_SUCCESS(RC)) {
2369 if(!Linked) {
2370 MyFreePool__((*PtrNewFcb)->NTRequiredFCB);
2371 (*PtrNewFcb)->NTRequiredFCB = NULL;
2372 }
2373 UDFReleaseResource(&(Vcb->FcbListResource));
2374 return RC;
2375 }
2376 // set Read-only attribute
2377 if(!UDFIsAStreamDir(NewFileInfo)) {
2378 hDirIndex = UDFGetDirIndexByFileInfo(NewFileInfo);
2379 #ifdef UDF_DBG
2380 if(!hDirIndex) {
2381 BrutePoint();
2382 } else {
2383 #endif // UDF_DBG
2384 if(UDFAttributesToNT(DirIndex = UDFDirIndex(hDirIndex, NewFileInfo->Index),NULL) & FILE_ATTRIBUTE_READONLY) {
2385 (*PtrNewFcb)->FCBFlags |= UDF_FCB_READ_ONLY;
2386 }
2387 MyAppendUnicodeStringToStringTag(&(NewFCBName->ObjectName), &(DirIndex->FName), MEM_USOBJ_TAG);
2388 #ifdef UDF_DBG
2389 }
2390 #endif // UDF_DBG
2391 } else if (RelatedFileInfo->ParentFile) {
2392 hDirIndex = UDFGetDirIndexByFileInfo(RelatedFileInfo);
2393 if(UDFAttributesToNT(DirIndex = UDFDirIndex(hDirIndex, RelatedFileInfo->Index),NULL) & FILE_ATTRIBUTE_READONLY) {
2394 (*PtrNewFcb)->FCBFlags |= UDF_FCB_READ_ONLY;
2395 }
2396 RC = MyAppendUnicodeStringToStringTag(&(NewFCBName->ObjectName), CurName, MEM_USOBJ_TAG);
2397 // } else {
2398 // BrutePoint();
2399 }
2400 // do not allocate CCB if it is internal Create/Open
2401 if(NT_SUCCESS(RC)) {
2402 if(PtrNewFileObject) {
2403 RC = UDFOpenFile(Vcb, PtrNewFileObject, *PtrNewFcb);
2404 } else {
2405 RC = STATUS_SUCCESS;
2406 }
2407 }
2408 UDFReleaseResource(&(Vcb->FcbListResource));
2409 // end transaction
2410
2411 // if(!NT_SUCCESS(RC)) return RC;
2412
2413 return RC;
2414 } // end UDFFirstOpenFile()
2415
2416 /*************************************************************************
2417 *
2418 * Function: UDFOpenFile()
2419 *
2420 * Description:
2421 * Open a file/dir for the caller.
2422 *
2423 * Expected Interrupt Level (for execution) :
2424 *
2425 * IRQL_PASSIVE_LEVEL
2426 *
2427 * Return Value: STATUS_SUCCESS/Error
2428 *
2429 *************************************************************************/
2430 NTSTATUS
2431 UDFOpenFile(
2432 PVCB Vcb, // volume control block
2433 PFILE_OBJECT PtrNewFileObject, // I/O Mgr. created file object
2434 PtrUDFFCB PtrNewFcb
2435 )
2436 {
2437 NTSTATUS RC = STATUS_SUCCESS;
2438 PtrUDFCCB Ccb = NULL;
2439 PtrUDFNTRequiredFCB NtReqFcb;
2440
2441 AdPrint(("UDFOpenFile\n"));
2442 ASSERT((PtrNewFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB)
2443 ||(PtrNewFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB));
2444
2445 _SEH2_TRY {
2446
2447 #if 0
2448 CollectStatistics2(Vcb, CreateHits);
2449 #endif
2450 // create a new CCB structure
2451 if (!(Ccb = UDFAllocateCCB())) {
2452 AdPrint(("Can't allocate CCB\n"));
2453 PtrNewFileObject->FsContext2 = NULL;
2454 //
2455 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount));
2456 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount));
2457 RC = STATUS_INSUFFICIENT_RESOURCES;
2458 try_return(RC);
2459 }
2460 // initialize the CCB
2461 Ccb->Fcb = PtrNewFcb;
2462 // initialize the CCB to point to the file object
2463 Ccb->FileObject = PtrNewFileObject;
2464
2465 // initialize the file object appropriately
2466 PtrNewFileObject->FsContext2 = (PVOID)(Ccb);
2467 PtrNewFileObject->Vpb = Vcb->Vpb;
2468 PtrNewFileObject->FsContext = (PVOID)(NtReqFcb = PtrNewFcb->NTRequiredFCB);
2469 PtrNewFileObject->SectionObjectPointer = &(NtReqFcb->SectionObject);
2470 #ifdef DBG
2471 // NtReqFcb ->FileObject = PtrNewFileObject;
2472 #endif //DBG
2473
2474 #ifdef UDF_DELAYED_CLOSE
2475 PtrNewFcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE;
2476 #endif //UDF_DELAYED_CLOSE
2477
2478 UDFAcquireResourceExclusive(&(PtrNewFcb->CcbListResource),TRUE);
2479 // insert CCB into linked list of open file object to Fcb or
2480 // to Vcb and do other intialization
2481 InsertTailList(&(PtrNewFcb->NextCCB), &(Ccb->NextCCB));
2482 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount));
2483 UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount));
2484 UDFReleaseResource(&(PtrNewFcb->CcbListResource));
2485
2486 try_exit: NOTHING;
2487 } _SEH2_FINALLY {
2488 NOTHING;
2489 } _SEH2_END;
2490
2491 return(RC);
2492 } // end UDFOpenFile()
2493
2494
2495 /*************************************************************************
2496 *
2497 * Function: UDFInitializeFCB()
2498 *
2499 * Description:
2500 * Initialize a new FCB structure and also the sent-in file object
2501 * (if supplied)
2502 *
2503 * Expected Interrupt Level (for execution) :
2504 *
2505 * IRQL_PASSIVE_LEVEL
2506 *
2507 * Return Value: None
2508 *
2509 *************************************************************************/
2510 NTSTATUS
2511 UDFInitializeFCB(
2512 IN PtrUDFFCB PtrNewFcb, // FCB structure to be initialized
2513 IN PVCB Vcb, // logical volume (VCB) pointer
2514 IN PtrUDFObjectName PtrObjectName, // name of the object
2515 IN ULONG Flags, // is this a file/directory, etc.
2516 IN PFILE_OBJECT FileObject) // optional file object to be initialized
2517 {
2518 AdPrint(("UDFInitializeFCB\n"));
2519 NTSTATUS status;
2520 BOOLEAN Linked = TRUE;
2521
2522 if(!PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource) {
2523 // record signature
2524 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode = UDF_NODE_TYPE_NT_REQ_FCB;
2525 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeByteSize = sizeof(UDFNTRequiredFCB);
2526 // Initialize the ERESOURCE objects
2527 if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->NTRequiredFCB->MainResource)))) {
2528 AdPrint((" Can't init resource\n"));
2529 return status;
2530 }
2531 if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->NTRequiredFCB->PagingIoResource)))) {
2532 AdPrint((" Can't init resource (2)\n"));
2533 UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->MainResource));
2534 return status;
2535 }
2536 // Fill NT required Fcb part
2537 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource = &(PtrNewFcb->NTRequiredFCB->MainResource);
2538 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource = &(PtrNewFcb->NTRequiredFCB->PagingIoResource);
2539 // Itialize byte-range locks support structure
2540 FsRtlInitializeFileLock(&(PtrNewFcb->NTRequiredFCB->FileLock),NULL,NULL);
2541 // Init reference counter
2542 PtrNewFcb->NTRequiredFCB->CommonRefCount = 0;
2543 Linked = FALSE;
2544 } else {
2545 ASSERT(PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB);
2546 }
2547 if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->CcbListResource)))) {
2548 AdPrint((" Can't init resource (3)\n"));
2549 BrutePoint();
2550 if(!Linked) {
2551 UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->PagingIoResource));
2552 UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->MainResource));
2553 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource =
2554 PtrNewFcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource = NULL;
2555 FsRtlUninitializeFileLock(&(PtrNewFcb->NTRequiredFCB->FileLock));
2556 }
2557 return status;
2558 }
2559
2560 // caller MUST ensure that VCB has been acquired exclusively
2561 InsertTailList(&(Vcb->NextFCB), &(PtrNewFcb->NextFCB));
2562
2563 // initialize the various list heads
2564 InitializeListHead(&(PtrNewFcb->NextCCB));
2565
2566 PtrNewFcb->ReferenceCount = 0;
2567 PtrNewFcb->OpenHandleCount = 0;
2568
2569 PtrNewFcb->FCBFlags = Flags | UDF_FCB_INITIALIZED_CCB_LIST_RESOURCE;
2570
2571 PtrNewFcb->FCBName = PtrObjectName;
2572
2573 PtrNewFcb->Vcb = Vcb;
2574
2575 return STATUS_SUCCESS;
2576 } // end UDFInitializeFCB()
2577