[CDFS_NEW] _SEH2_FINALLY implement SEH support for real instead of its current stub.
[reactos.git] / drivers / filesystems / cdfs_new / create.c
1 /*++
2
3 Copyright (c) 1989-2000 Microsoft Corporation
4
5 Module Name:
6
7 Create.c
8
9 Abstract:
10
11 This module implements the File Create routine for Cdfs called by the
12 Fsd/Fsp dispatch routines.
13
14
15 --*/
16
17 #include "cdprocs.h"
18
19 //
20 // The Bug check file id for this module
21 //
22
23 #define BugCheckFileId (CDFS_BUG_CHECK_CREATE)
24
25 //
26 // Local support routines
27 //
28
29 NTSTATUS
30 CdNormalizeFileNames (
31 IN PIRP_CONTEXT IrpContext,
32 IN PVCB Vcb,
33 IN BOOLEAN OpenByFileId,
34 IN BOOLEAN IgnoreCase,
35 IN TYPE_OF_OPEN RelatedTypeOfOpen,
36 IN PCCB RelatedCcb OPTIONAL,
37 IN PUNICODE_STRING RelatedFileName OPTIONAL,
38 IN OUT PUNICODE_STRING FileName,
39 IN OUT PCD_NAME RemainingName
40 );
41
42 NTSTATUS
43 CdOpenByFileId (
44 IN PIRP_CONTEXT IrpContext,
45 IN PIO_STACK_LOCATION IrpSp,
46 IN PVCB Vcb,
47 IN OUT PFCB *CurrentFcb
48 );
49
50 NTSTATUS
51 CdOpenExistingFcb (
52 IN PIRP_CONTEXT IrpContext,
53 IN PIO_STACK_LOCATION IrpSp,
54 IN OUT PFCB *CurrentFcb,
55 IN TYPE_OF_OPEN TypeOfOpen,
56 IN BOOLEAN IgnoreCase,
57 IN PCCB RelatedCcb OPTIONAL
58 );
59
60 NTSTATUS
61 CdOpenDirectoryFromPathEntry (
62 IN PIRP_CONTEXT IrpContext,
63 IN PIO_STACK_LOCATION IrpSp,
64 IN PVCB Vcb,
65 IN OUT PFCB *CurrentFcb,
66 IN PCD_NAME DirName,
67 IN BOOLEAN IgnoreCase,
68 IN BOOLEAN ShortNameMatch,
69 IN PPATH_ENTRY PathEntry,
70 IN BOOLEAN PerformUserOpen,
71 IN PCCB RelatedCcb OPTIONAL
72 );
73
74 NTSTATUS
75 CdOpenFileFromFileContext (
76 IN PIRP_CONTEXT IrpContext,
77 IN PIO_STACK_LOCATION IrpSp,
78 IN PVCB Vcb,
79 IN OUT PFCB *CurrentFcb,
80 IN PCD_NAME FileName,
81 IN BOOLEAN IgnoreCase,
82 IN BOOLEAN ShortNameMatch,
83 IN PFILE_ENUM_CONTEXT FileContext,
84 IN PCCB RelatedCcb OPTIONAL
85 );
86
87 NTSTATUS
88 CdCompleteFcbOpen (
89 IN PIRP_CONTEXT IrpContext,
90 PIO_STACK_LOCATION IrpSp,
91 IN PVCB Vcb,
92 IN OUT PFCB *CurrentFcb,
93 IN TYPE_OF_OPEN TypeOfOpen,
94 IN ULONG UserCcbFlags,
95 IN ACCESS_MASK DesiredAccess
96 );
97
98 #ifdef ALLOC_PRAGMA
99 #pragma alloc_text(PAGE, CdCommonCreate)
100 #pragma alloc_text(PAGE, CdCompleteFcbOpen)
101 #pragma alloc_text(PAGE, CdNormalizeFileNames)
102 #pragma alloc_text(PAGE, CdOpenByFileId)
103 #pragma alloc_text(PAGE, CdOpenDirectoryFromPathEntry)
104 #pragma alloc_text(PAGE, CdOpenExistingFcb)
105 #pragma alloc_text(PAGE, CdOpenFileFromFileContext)
106 #endif
107
108 \f
109 NTSTATUS
110 CdCommonCreate (
111 IN PIRP_CONTEXT IrpContext,
112 IN PIRP Irp
113 )
114
115 /*++
116
117 Routine Description:
118
119 This is the common routine for opening a file called by both the
120 Fsp and Fsd threads.
121
122 The file can be opened either by name or by file Id either with or without
123 a relative name. The file name field in the file object passed to this routine
124 contains either a unicode string or a 64 bit value which is the file Id.
125 If this is not a Joliet disk then we will convert the unicode name to
126 an Oem string in this routine. If there is a related file object with
127 a name then we will already have converted that name to Oem.
128
129 We will store the full name for the file in the file object on a successful
130 open. We will allocate a larger buffer if necessary and combine the
131 related and file object names. The only exception is the relative open
132 when the related file object is for an OpenByFileId file. If we need to
133 allocate a buffer for a case insensitive name then we allocate it at
134 the tail of the buffer we will store into the file object. The upcased
135 portion will begin immediately after the name defined by the FileName
136 in the file object.
137
138 Once we have the full name in the file object we don't want to split the
139 name in the event of a retry. We use a flag in the IrpContext to indicate
140 that the name has been split.
141
142 Arguments:
143
144 Irp - Supplies the Irp to process
145
146 Return Value:
147
148 NTSTATUS - This is the status from this open operation.
149
150 --*/
151
152 {
153 NTSTATUS Status = STATUS_SUCCESS;
154 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
155
156 PFILE_OBJECT FileObject;
157
158 COMPOUND_PATH_ENTRY CompoundPathEntry;
159 BOOLEAN CleanupCompoundPathEntry = FALSE;
160
161 FILE_ENUM_CONTEXT FileContext;
162 BOOLEAN CleanupFileContext = FALSE;
163 BOOLEAN FoundEntry;
164
165 PVCB Vcb;
166
167 BOOLEAN OpenByFileId;
168 BOOLEAN IgnoreCase;
169 ULONG CreateDisposition;
170
171 BOOLEAN ShortNameMatch;
172 ULONG ShortNameDirentOffset;
173
174 BOOLEAN VolumeOpen = FALSE;
175
176 //
177 // We will be acquiring and releasing file Fcb's as we move down the
178 // directory tree during opens. At any time we need to know the deepest
179 // point we have traversed down in the tree in case we need to cleanup
180 // any structures created here.
181 //
182 // CurrentFcb - represents this point. If non-null it means we have
183 // acquired it and need to release it in finally clause.
184 //
185 // NextFcb - represents the NextFcb to walk to but haven't acquired yet.
186 //
187
188 TYPE_OF_OPEN RelatedTypeOfOpen = UnopenedFileObject;
189 PFILE_OBJECT RelatedFileObject;
190 PCCB RelatedCcb = NULL;
191
192 PFCB NextFcb;
193 PFCB CurrentFcb = NULL;
194
195 //
196 // During the open we need to combine the related file object name
197 // with the remaining name. We also may need to upcase the file name
198 // in order to do a case-insensitive name comparison. We also need
199 // to restore the name in the file object in the event that we retry
200 // the request. We use the following string variables to manage the
201 // name. We will can put these strings into either Unicode or Ansi
202 // form.
203 //
204 // FileName - Pointer to name as currently stored in the file
205 // object. We store the full name into the file object early in
206 // the open operation.
207 //
208 // RelatedFileName - Pointer to the name in the related file object.
209 //
210 // RemainingName - String containing remaining name to parse.
211 //
212 // MatchingName - Address of name structure in FileContext which matched.
213 // We need this to know whether we matched the long or short name.
214 //
215
216 PUNICODE_STRING FileName;
217 PUNICODE_STRING RelatedFileName = NULL;
218
219 CD_NAME RemainingName;
220 CD_NAME FinalName;
221 PCD_NAME MatchingName;
222
223 PAGED_CODE();
224
225 //
226 // If we were called with our file system device object instead of a
227 // volume device object, just complete this request with STATUS_SUCCESS.
228 //
229
230 if (IrpContext->Vcb == NULL) {
231
232 CdCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
233 return STATUS_SUCCESS;
234 }
235
236 //
237 // Get create parameters from the Irp.
238 //
239
240 OpenByFileId = BooleanFlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID );
241 IgnoreCase = !BooleanFlagOn( IrpSp->Flags, SL_CASE_SENSITIVE );
242 CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff;
243
244 //
245 // Do some preliminary checks to make sure the operation is supported.
246 // We fail in the following cases immediately.
247 //
248 // - Open a paging file.
249 // - Open a target directory.
250 // - Open a file with Eas.
251 // - Create a file.
252 //
253
254 if (FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE | SL_OPEN_TARGET_DIRECTORY) ||
255 (IrpSp->Parameters.Create.EaLength != 0) ||
256 (CreateDisposition == FILE_CREATE)) {
257
258 CdCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
259 return STATUS_ACCESS_DENIED;
260 }
261
262 //
263 // Copy the Vcb to a local. Assume the starting directory is the root.
264 //
265
266 Vcb = IrpContext->Vcb;
267 NextFcb = Vcb->RootIndexFcb;
268
269 //
270 // Reference our input parameters to make things easier
271 //
272
273 FileObject = IrpSp->FileObject;
274 RelatedFileObject = NULL;
275
276 FileName = &FileObject->FileName;
277
278 //
279 // Set up the file object's Vpb pointer in case anything happens.
280 // This will allow us to get a reasonable pop-up.
281 //
282
283 if ((FileObject->RelatedFileObject != NULL) && !OpenByFileId) {
284
285 RelatedFileObject = FileObject->RelatedFileObject;
286 FileObject->Vpb = RelatedFileObject->Vpb;
287
288 RelatedTypeOfOpen = CdDecodeFileObject( IrpContext, RelatedFileObject, &NextFcb, &RelatedCcb );
289
290 //
291 // Fail the request if this is not a user file object.
292 //
293
294 if (RelatedTypeOfOpen < UserVolumeOpen) {
295
296 CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
297 return STATUS_INVALID_PARAMETER;
298 }
299
300 //
301 // Remember the name in the related file object.
302 //
303
304 RelatedFileName = &RelatedFileObject->FileName;
305 }
306
307 //
308 // If we haven't initialized the names then make sure the strings are valid.
309 // If this an OpenByFileId then verify the file id buffer.
310 //
311 // After this routine returns we know that the full name is in the
312 // FileName buffer and the buffer will hold the upcased portion
313 // of the name yet to parse immediately after the full name in the
314 // buffer. Any trailing backslash has been removed and the flag
315 // in the IrpContext will indicate whether we removed the
316 // backslash.
317 //
318
319 Status = CdNormalizeFileNames( IrpContext,
320 Vcb,
321 OpenByFileId,
322 IgnoreCase,
323 RelatedTypeOfOpen,
324 RelatedCcb,
325 RelatedFileName,
326 FileName,
327 &RemainingName );
328
329 //
330 // Return the error code if not successful.
331 //
332
333 if (!NT_SUCCESS( Status )) {
334
335 CdCompleteRequest( IrpContext, Irp, Status );
336 return Status;
337 }
338
339 //
340 // We want to acquire the Vcb. Exclusively for a volume open, shared otherwise.
341 // The file name is empty for a volume open.
342 //
343
344 if ((FileName->Length == 0) &&
345 (RelatedTypeOfOpen <= UserVolumeOpen) &&
346 !OpenByFileId) {
347
348 VolumeOpen = TRUE;
349 CdAcquireVcbExclusive( IrpContext, Vcb, FALSE );
350
351 } else {
352
353 CdAcquireVcbShared( IrpContext, Vcb, FALSE );
354 }
355
356 //
357 // Use a try-finally to facilitate cleanup.
358 //
359
360 _SEH2_TRY {
361
362 //
363 // Verify that the Vcb is not in an unusable condition. This routine
364 // will raise if not usable.
365 //
366
367 CdVerifyVcb( IrpContext, Vcb );
368
369 //
370 // If the Vcb is locked then we cannot open another file
371 //
372
373 if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) {
374
375 try_return( Status = STATUS_ACCESS_DENIED );
376 }
377
378 //
379 // If we are opening this file by FileId then process this immediately
380 // and exit.
381 //
382
383 if (OpenByFileId) {
384
385 //
386 // We only allow Dasd opens of audio disks. Fail this request at
387 // this point.
388 //
389
390 if (FlagOn( Vcb->VcbState, VCB_STATE_AUDIO_DISK )) {
391
392 try_return( Status = STATUS_INVALID_DEVICE_REQUEST );
393 }
394
395 //
396 // The only create disposition we allow is OPEN.
397 //
398
399 if ((CreateDisposition != FILE_OPEN) &&
400 (CreateDisposition != FILE_OPEN_IF)) {
401
402 try_return( Status = STATUS_ACCESS_DENIED );
403 }
404
405 //
406 // Make sure we can wait for this request.
407 //
408
409 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
410
411 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
412 }
413
414 try_return( Status = CdOpenByFileId( IrpContext,
415 IrpSp,
416 Vcb,
417 &CurrentFcb ));
418 }
419
420 //
421 // If we are opening this volume Dasd then process this immediately
422 // and exit.
423 //
424
425 if (VolumeOpen) {
426
427 //
428 // The only create disposition we allow is OPEN.
429 //
430
431 if ((CreateDisposition != FILE_OPEN) &&
432 (CreateDisposition != FILE_OPEN_IF)) {
433
434 try_return( Status = STATUS_ACCESS_DENIED );
435 }
436
437 //
438 // If they wanted to open a directory, surprise.
439 //
440
441 if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
442
443 try_return( Status = STATUS_NOT_A_DIRECTORY );
444 }
445
446 //
447 // Acquire the Fcb first.
448 //
449
450 CurrentFcb = Vcb->VolumeDasdFcb;
451 CdAcquireFcbExclusive( IrpContext, CurrentFcb, FALSE );
452
453 try_return( Status = CdOpenExistingFcb( IrpContext,
454 IrpSp,
455 &CurrentFcb,
456 UserVolumeOpen,
457 FALSE,
458 NULL ));
459 }
460
461 //
462 // At this point CurrentFcb points to the deepest Fcb for this open
463 // in the tree. Let's acquire this Fcb to keep it from being deleted
464 // beneath us.
465 //
466
467 CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
468 CurrentFcb = NextFcb;
469
470 //
471 // Do a prefix search if there is more of the name to parse.
472 //
473
474 if (RemainingName.FileName.Length != 0) {
475
476 //
477 // Do the prefix search to find the longest matching name.
478 //
479
480 CdFindPrefix( IrpContext,
481 &CurrentFcb,
482 &RemainingName.FileName,
483 IgnoreCase );
484 }
485
486 //
487 // If the remaining name length is zero then we have found our
488 // target.
489 //
490
491 if (RemainingName.FileName.Length == 0) {
492
493 //
494 // If this is a file so verify the user didn't want to open
495 // a directory.
496 //
497
498 if (SafeNodeType( CurrentFcb ) == CDFS_NTC_FCB_DATA) {
499
500 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH ) ||
501 FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
502
503 try_return( Status = STATUS_NOT_A_DIRECTORY );
504 }
505
506 //
507 // The only create disposition we allow is OPEN.
508 //
509
510 if ((CreateDisposition != FILE_OPEN) &&
511 (CreateDisposition != FILE_OPEN_IF)) {
512
513 try_return( Status = STATUS_ACCESS_DENIED );
514 }
515
516 try_return( Status = CdOpenExistingFcb( IrpContext,
517 IrpSp,
518 &CurrentFcb,
519 UserFileOpen,
520 IgnoreCase,
521 RelatedCcb ));
522
523 //
524 // This is a directory. Verify the user didn't want to open
525 // as a file.
526 //
527
528 } else if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
529
530 try_return( Status = STATUS_FILE_IS_A_DIRECTORY );
531
532 //
533 // Open the file as a directory.
534 //
535
536 } else {
537
538 //
539 // The only create disposition we allow is OPEN.
540 //
541
542 if ((CreateDisposition != FILE_OPEN) &&
543 (CreateDisposition != FILE_OPEN_IF)) {
544
545 try_return( Status = STATUS_ACCESS_DENIED );
546 }
547
548 try_return( Status = CdOpenExistingFcb( IrpContext,
549 IrpSp,
550 &CurrentFcb,
551 UserDirectoryOpen,
552 IgnoreCase,
553 RelatedCcb ));
554 }
555 }
556
557 //
558 // We have more work to do. We have a starting Fcb which we own shared.
559 // We also have the remaining name to parse. Walk through the name
560 // component by component looking for the full name.
561 //
562
563 //
564 // Our starting Fcb better be a directory.
565 //
566
567 if (!FlagOn( CurrentFcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
568
569 try_return( Status = STATUS_OBJECT_PATH_NOT_FOUND );
570 }
571
572 //
573 // If we can't wait then post this request.
574 //
575
576 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
577
578 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
579 }
580
581 //
582 // Make sure the final name has no version string.
583 //
584
585 FinalName.VersionString.Length = 0;
586
587 while (TRUE) {
588
589 ShortNameMatch = FALSE;
590
591 //
592 // Split off the next component from the name.
593 //
594
595 CdDissectName( IrpContext,
596 &RemainingName.FileName,
597 &FinalName.FileName );
598
599 //
600 // Go ahead and look this entry up in the path table.
601 //
602
603 CdInitializeCompoundPathEntry( IrpContext, &CompoundPathEntry );
604 CleanupCompoundPathEntry = TRUE;
605
606 FoundEntry = CdFindPathEntry( IrpContext,
607 CurrentFcb,
608 &FinalName,
609 IgnoreCase,
610 &CompoundPathEntry );
611
612 //
613 // If we didn't find the entry then check if the current name
614 // is a possible short name.
615 //
616
617 if (!FoundEntry) {
618
619 ShortNameDirentOffset = CdShortNameDirentOffset( IrpContext, &FinalName.FileName );
620
621 //
622 // If there is an embedded short name offset then look for the
623 // matching long name in the directory.
624 //
625
626 if (ShortNameDirentOffset != MAXULONG) {
627
628 if (CleanupFileContext) {
629
630 CdCleanupFileContext( IrpContext, &FileContext );
631 }
632
633 CdInitializeFileContext( IrpContext, &FileContext );
634 CleanupFileContext = TRUE;
635
636 FoundEntry = CdFindFileByShortName( IrpContext,
637 CurrentFcb,
638 &FinalName,
639 IgnoreCase,
640 ShortNameDirentOffset,
641 &FileContext );
642
643 //
644 // If we found an entry and it is a directory then look
645 // this up in the path table.
646 //
647
648 if (FoundEntry) {
649
650 ShortNameMatch = TRUE;
651
652 if (FlagOn( FileContext.InitialDirent->Dirent.DirentFlags,
653 CD_ATTRIBUTE_DIRECTORY )) {
654
655 CdCleanupCompoundPathEntry( IrpContext, &CompoundPathEntry );
656 CdInitializeCompoundPathEntry( IrpContext, &CompoundPathEntry );
657
658 FoundEntry = CdFindPathEntry( IrpContext,
659 CurrentFcb,
660 &FileContext.InitialDirent->Dirent.CdCaseFileName,
661 IgnoreCase,
662 &CompoundPathEntry );
663
664 //
665 // We better find this entry.
666 //
667
668 if (!FoundEntry) {
669
670 CdRaiseStatus( IrpContext, STATUS_FILE_CORRUPT_ERROR );
671 }
672
673 //
674 // Upcase the name with the short name if case
675 // insensitive.
676 //
677
678 if (IgnoreCase) {
679
680 CdUpcaseName( IrpContext, &FinalName, &FinalName );
681 }
682
683 //
684 // We found a matching file. If we are at the last
685 // entry then break out of the loop and open the
686 // file below. Otherwise we return an error.
687 //
688
689 } else if (RemainingName.FileName.Length == 0) {
690
691 //
692 // Break out of the loop. We will process the dirent
693 // below.
694 //
695
696 MatchingName = &FileContext.ShortName;
697 break;
698
699 } else {
700
701 try_return( Status = STATUS_OBJECT_PATH_NOT_FOUND );
702 }
703 }
704 }
705
706 //
707 // We didn't find the name in either the path table or as
708 // a short name in a directory. If the remaining name
709 // length is zero then break out of the loop to search
710 // the directory.
711 //
712
713 if (!FoundEntry) {
714
715 if (RemainingName.FileName.Length == 0) {
716
717 break;
718
719 //
720 // Otherwise this path could not be cracked.
721 //
722
723 } else {
724
725 try_return( Status = STATUS_OBJECT_PATH_NOT_FOUND );
726 }
727 }
728 }
729
730 //
731 // If this is an ignore case open then copy the exact case
732 // in the file object name. If it was a short name match then
733 // the name must be upcase already.
734 //
735
736 if (IgnoreCase && !ShortNameMatch) {
737
738 RtlCopyMemory( FinalName.FileName.Buffer,
739 CompoundPathEntry.PathEntry.CdDirName.FileName.Buffer,
740 CompoundPathEntry.PathEntry.CdDirName.FileName.Length );
741 }
742
743 //
744 // If we have found the last component then open this as a directory
745 // and return to our caller.
746 //
747
748 if (RemainingName.FileName.Length == 0) {
749
750 if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
751
752 try_return( Status = STATUS_FILE_IS_A_DIRECTORY );
753 }
754
755 //
756 // The only create disposition we allow is OPEN.
757 //
758
759 if ((CreateDisposition != FILE_OPEN) &&
760 (CreateDisposition != FILE_OPEN_IF)) {
761
762 try_return( Status = STATUS_ACCESS_DENIED );
763 }
764
765 try_return( Status = CdOpenDirectoryFromPathEntry( IrpContext,
766 IrpSp,
767 Vcb,
768 &CurrentFcb,
769 &FinalName,
770 IgnoreCase,
771 ShortNameMatch,
772 &CompoundPathEntry.PathEntry,
773 TRUE,
774 RelatedCcb ));
775 }
776
777 //
778 // Otherwise open an Fcb for this intermediate index Fcb.
779 //
780
781 CdOpenDirectoryFromPathEntry( IrpContext,
782 IrpSp,
783 Vcb,
784 &CurrentFcb,
785 &FinalName,
786 IgnoreCase,
787 ShortNameMatch,
788 &CompoundPathEntry.PathEntry,
789 FALSE,
790 NULL );
791
792 CdCleanupCompoundPathEntry( IrpContext, &CompoundPathEntry );
793 CleanupCompoundPathEntry = FALSE;
794 }
795
796 //
797 // We need to scan the current directory for a matching file name
798 // if we don't already have one.
799 //
800
801 if (!FoundEntry) {
802
803 if (CleanupFileContext) {
804
805 CdCleanupFileContext( IrpContext, &FileContext );
806 }
807
808 CdInitializeFileContext( IrpContext, &FileContext );
809 CleanupFileContext = TRUE;
810
811 //
812 // Split our search name into separate components.
813 //
814
815 CdConvertNameToCdName( IrpContext, &FinalName );
816
817 FoundEntry = CdFindFile( IrpContext,
818 CurrentFcb,
819 &FinalName,
820 IgnoreCase,
821 &FileContext,
822 &MatchingName );
823 }
824
825 //
826 // If we didn't find a match then check if the name is invalid to
827 // determine which error code to return.
828 //
829
830 if (!FoundEntry) {
831
832 if ((CreateDisposition == FILE_OPEN) ||
833 (CreateDisposition == FILE_OVERWRITE)) {
834
835 try_return( Status = STATUS_OBJECT_NAME_NOT_FOUND );
836 }
837
838 //
839 // Any other operation return STATUS_ACCESS_DENIED.
840 //
841
842 try_return( Status = STATUS_ACCESS_DENIED );
843 }
844
845 //
846 // If this is a directory then the disk is corrupt because it wasn't
847 // in the Path Table.
848 //
849
850 if (FlagOn( FileContext.InitialDirent->Dirent.Flags, CD_ATTRIBUTE_DIRECTORY )) {
851
852 CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
853 }
854
855 //
856 // Make sure our opener didn't want a directory.
857 //
858
859 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH ) ||
860 FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
861
862 try_return( Status = STATUS_NOT_A_DIRECTORY );
863 }
864
865 //
866 // The only create disposition we allow is OPEN.
867 //
868
869 if ((CreateDisposition != FILE_OPEN) &&
870 (CreateDisposition != FILE_OPEN_IF)) {
871
872 try_return( Status = STATUS_ACCESS_DENIED );
873 }
874
875 //
876 // If this is an ignore case open then copy the exact case
877 // in the file object name. Any version portion should
878 // already be upcased.
879 //
880
881 if (IgnoreCase) {
882
883 RtlCopyMemory( FinalName.FileName.Buffer,
884 MatchingName->FileName.Buffer,
885 MatchingName->FileName.Length );
886 }
887
888 //
889 // Open the file using the file context. We already have the
890 // first and last dirents.
891 //
892
893 try_return( Status = CdOpenFileFromFileContext( IrpContext,
894 IrpSp,
895 Vcb,
896 &CurrentFcb,
897 &FinalName,
898 IgnoreCase,
899 (BOOLEAN) (MatchingName == &FileContext.ShortName),
900 &FileContext,
901 RelatedCcb ));
902
903 try_exit: NOTHING;
904 } _SEH2_FINALLY {
905
906 //
907 // Cleanup the PathEntry if initialized.
908 //
909
910 if (CleanupCompoundPathEntry) {
911
912 CdCleanupCompoundPathEntry( IrpContext, &CompoundPathEntry );
913 }
914
915 //
916 // Cleanup the FileContext if initialized.
917 //
918
919 if (CleanupFileContext) {
920
921 CdCleanupFileContext( IrpContext, &FileContext );
922 }
923
924 //
925 // The result of this open could be success, pending or some error
926 // condition.
927 //
928
929 if (_SEH2_AbnormalTermination()) {
930
931
932 //
933 // In the error path we start by calling our teardown routine if we
934 // have a CurrentFcb.
935 //
936
937 if (CurrentFcb != NULL) {
938
939 BOOLEAN RemovedFcb;
940
941 CdTeardownStructures( IrpContext, CurrentFcb, &RemovedFcb );
942
943 if (RemovedFcb) {
944
945 CurrentFcb = NULL;
946 }
947 }
948
949 //
950 // No need to complete the request.
951 //
952
953 IrpContext = NULL;
954 Irp = NULL;
955
956 //
957 // If we posted this request through the oplock package we need
958 // to show that there is no reason to complete the request.
959 //
960
961 } else if (Status == STATUS_PENDING) {
962
963 IrpContext = NULL;
964 Irp = NULL;
965 }
966
967 //
968 // Release the Current Fcb if still acquired.
969 //
970
971 if (CurrentFcb != NULL) {
972
973 CdReleaseFcb( IrpContext, CurrentFcb );
974 }
975
976 //
977 // Release the Vcb.
978 //
979
980 CdReleaseVcb( IrpContext, Vcb );
981
982 //
983 // Call our completion routine. It will handle the case where either
984 // the Irp and/or IrpContext are gone.
985 //
986
987 CdCompleteRequest( IrpContext, Irp, Status );
988 } _SEH2_END;
989
990 return Status;
991 }
992
993 \f
994 //
995 // Local support routine
996 //
997
998 NTSTATUS
999 CdNormalizeFileNames (
1000 IN PIRP_CONTEXT IrpContext,
1001 IN PVCB Vcb,
1002 IN BOOLEAN OpenByFileId,
1003 IN BOOLEAN IgnoreCase,
1004 IN TYPE_OF_OPEN RelatedTypeOfOpen,
1005 IN PCCB RelatedCcb OPTIONAL,
1006 IN PUNICODE_STRING RelatedFileName OPTIONAL,
1007 IN OUT PUNICODE_STRING FileName,
1008 IN OUT PCD_NAME RemainingName
1009 )
1010
1011 /*++
1012
1013 Routine Description:
1014
1015 This routine is called to store the full name and upcased name into the
1016 filename buffer. We only upcase the portion yet to parse. We also
1017 check for a trailing backslash and lead-in double backslashes. This
1018 routine also verifies the mode of the related open against the name
1019 currently in the filename.
1020
1021 Arguments:
1022
1023 Vcb - Vcb for this volume.
1024
1025 OpenByFileId - Indicates if the filename should be a 64 bit FileId.
1026
1027 IgnoreCase - Indicates if this open is a case-insensitive operation.
1028
1029 RelatedTypeOfOpen - Indicates the type of the related file object.
1030
1031 RelatedCcb - Ccb for the related open. Ignored if no relative open.
1032
1033 RelatedFileName - FileName buffer for related open. Ignored if no
1034 relative open.
1035
1036 FileName - FileName to update in this routine. The name should
1037 either be a 64-bit FileId or a Unicode string.
1038
1039 RemainingName - Name with the remaining portion of the name. This
1040 will begin after the related name and any separator. For a
1041 non-relative open we also step over the initial separator.
1042
1043 Return Value:
1044
1045 NTSTATUS - STATUS_SUCCESS if the names are OK, appropriate error code
1046 otherwise.
1047
1048 --*/
1049
1050 {
1051 ULONG RemainingNameLength;
1052 ULONG RelatedNameLength = 0;
1053 ULONG SeparatorLength = 0;
1054
1055 ULONG BufferLength;
1056
1057 UNICODE_STRING NewFileName;
1058
1059 PAGED_CODE();
1060
1061 //
1062 // If this is the first pass then we need to build the full name and
1063 // check for name compatibility.
1064 //
1065
1066 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_FULL_NAME )) {
1067
1068 //
1069 // Deal with the regular file name case first.
1070 //
1071
1072 if (!OpenByFileId) {
1073
1074 //
1075 // This is here because the Win32 layer can't avoid sending me double
1076 // beginning backslashes.
1077 //
1078
1079 if ((FileName->Length > sizeof( WCHAR )) &&
1080 (FileName->Buffer[1] == L'\\') &&
1081 (FileName->Buffer[0] == L'\\')) {
1082
1083 //
1084 // If there are still two beginning backslashes, the name is bogus.
1085 //
1086
1087 if ((FileName->Length > 2 * sizeof( WCHAR )) &&
1088 (FileName->Buffer[2] == L'\\')) {
1089
1090 return STATUS_OBJECT_NAME_INVALID;
1091 }
1092
1093 //
1094 // Slide the name down in the buffer.
1095 //
1096
1097 FileName->Length -= sizeof( WCHAR );
1098
1099 RtlMoveMemory( FileName->Buffer,
1100 FileName->Buffer + 1,
1101 FileName->Length );
1102 }
1103
1104 //
1105 // Check for a trailing backslash. Don't strip off if only character
1106 // in the full name or for relative opens where this is illegal.
1107 //
1108
1109 if (((FileName->Length > sizeof( WCHAR)) ||
1110 ((FileName->Length == sizeof( WCHAR )) && (RelatedTypeOfOpen == UserDirectoryOpen))) &&
1111 (FileName->Buffer[ (FileName->Length/2) - 1 ] == L'\\')) {
1112
1113 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH );
1114 FileName->Length -= sizeof( WCHAR );
1115 }
1116
1117 //
1118 // Remember the length we need for this portion of the name.
1119 //
1120
1121 RemainingNameLength = FileName->Length;
1122
1123 //
1124 // If this is a related file object then we verify the compatibility
1125 // of the name in the file object with the relative file object.
1126 //
1127
1128 if (RelatedTypeOfOpen != UnopenedFileObject) {
1129
1130 //
1131 // If the filename length was zero then it must be legal.
1132 // If there are characters then check with the related
1133 // type of open.
1134 //
1135
1136 if (FileName->Length != 0) {
1137
1138 //
1139 // The name length must always be zero for a volume open.
1140 //
1141
1142 if (RelatedTypeOfOpen <= UserVolumeOpen) {
1143
1144 return STATUS_INVALID_PARAMETER;
1145
1146 //
1147 // The remaining name cannot begin with a backslash.
1148 //
1149
1150 } else if (FileName->Buffer[0] == L'\\' ) {
1151
1152 return STATUS_INVALID_PARAMETER;
1153
1154 //
1155 // If the related file is a user file then there
1156 // is no file with this path.
1157 //
1158
1159 } else if (RelatedTypeOfOpen == UserFileOpen) {
1160
1161 return STATUS_OBJECT_PATH_NOT_FOUND;
1162 }
1163 }
1164
1165 //
1166 // Remember the length of the related name when building
1167 // the full name. We leave the RelatedNameLength and
1168 // SeparatorLength at zero if the relative file is opened
1169 // by Id.
1170 //
1171
1172 if (!FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID )) {
1173
1174 //
1175 // Add a separator if the name length is non-zero
1176 // unless the relative Fcb is at the root.
1177 //
1178
1179 if ((FileName->Length != 0) &&
1180 (RelatedCcb->Fcb != Vcb->RootIndexFcb)) {
1181
1182 SeparatorLength = sizeof( WCHAR );
1183 }
1184
1185 RelatedNameLength = RelatedFileName->Length;
1186 }
1187
1188 //
1189 // The full name is already in the filename. It must either
1190 // be length 0 or begin with a backslash.
1191 //
1192
1193 } else if (FileName->Length != 0) {
1194
1195 if (FileName->Buffer[0] != L'\\') {
1196
1197 return STATUS_INVALID_PARAMETER;
1198 }
1199
1200 //
1201 // We will want to trim the leading backslash from the
1202 // remaining name we return.
1203 //
1204
1205 RemainingNameLength -= sizeof( WCHAR );
1206 SeparatorLength = sizeof( WCHAR );
1207 }
1208
1209 //
1210 // Now see if the buffer is large enough to hold the full name.
1211 //
1212
1213 BufferLength = RelatedNameLength + SeparatorLength + RemainingNameLength;
1214
1215 //
1216 // Check for an overflow of the maximum filename size.
1217 //
1218
1219 if (BufferLength > MAXUSHORT) {
1220
1221 return STATUS_INVALID_PARAMETER;
1222 }
1223
1224 //
1225 // Now see if we need to allocate a new buffer.
1226 //
1227
1228 if (FileName->MaximumLength < BufferLength) {
1229
1230 NewFileName.Buffer = FsRtlAllocatePoolWithTag( CdPagedPool,
1231 BufferLength,
1232 TAG_FILE_NAME );
1233
1234 NewFileName.MaximumLength = (USHORT) BufferLength;
1235
1236 } else {
1237
1238 NewFileName.Buffer = FileName->Buffer;
1239 NewFileName.MaximumLength = FileName->MaximumLength;
1240 }
1241
1242 //
1243 // If there is a related name then we need to slide the remaining bytes up and
1244 // insert the related name. Otherwise the name is in the correct position
1245 // already.
1246 //
1247
1248 if (RelatedNameLength != 0) {
1249
1250 //
1251 // Store the remaining name in its correct position.
1252 //
1253
1254 if (RemainingNameLength != 0) {
1255
1256 RtlMoveMemory( Add2Ptr( NewFileName.Buffer, RelatedNameLength + SeparatorLength, PVOID ),
1257 FileName->Buffer,
1258 RemainingNameLength );
1259 }
1260
1261 RtlCopyMemory( NewFileName.Buffer,
1262 RelatedFileName->Buffer,
1263 RelatedNameLength );
1264
1265 //
1266 // Add the separator if needed.
1267 //
1268
1269 if (SeparatorLength != 0) {
1270
1271 *(Add2Ptr( NewFileName.Buffer, RelatedNameLength, PWCHAR )) = L'\\';
1272 }
1273
1274 //
1275 // Update the filename value we got from the user.
1276 //
1277
1278 if (NewFileName.Buffer != FileName->Buffer) {
1279
1280 if (FileName->Buffer != NULL) {
1281
1282 CdFreePool( &FileName->Buffer );
1283 }
1284
1285 FileName->Buffer = NewFileName.Buffer;
1286 FileName->MaximumLength = NewFileName.MaximumLength;
1287 }
1288
1289 //
1290 // Copy the name length to the user's filename.
1291 //
1292
1293 FileName->Length = (USHORT) (RelatedNameLength + SeparatorLength + RemainingNameLength);
1294 }
1295
1296 //
1297 // Now update the remaining name to parse.
1298 //
1299
1300 RemainingName->FileName.MaximumLength =
1301 RemainingName->FileName.Length = (USHORT) RemainingNameLength;
1302 RemainingName->VersionString.Length = 0;
1303
1304 RemainingName->FileName.Buffer = Add2Ptr( FileName->Buffer,
1305 RelatedNameLength + SeparatorLength,
1306 PWCHAR );
1307
1308 //
1309 // Upcase the name if necessary.
1310 //
1311
1312 if (IgnoreCase && (RemainingNameLength != 0)) {
1313
1314 CdUpcaseName( IrpContext,
1315 RemainingName,
1316 RemainingName );
1317 }
1318
1319 //
1320 // Do a quick check to make sure there are no wildcards.
1321 //
1322
1323 if (FsRtlDoesNameContainWildCards( &RemainingName->FileName )) {
1324
1325 return STATUS_OBJECT_NAME_INVALID;
1326 }
1327
1328 //
1329 // For the open by file Id case we verify the name really contains
1330 // a 64 bit value.
1331 //
1332
1333 } else {
1334
1335 //
1336 // Check for validity of the buffer.
1337 //
1338
1339 if (FileName->Length != sizeof( FILE_ID )) {
1340
1341 return STATUS_INVALID_PARAMETER;
1342 }
1343 }
1344
1345 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FULL_NAME );
1346
1347 //
1348 // If we are in the retry path then the full name is already in the
1349 // file object name. If this is a case-sensitive operation then
1350 // we need to upcase the name from the end of any related file name already stored
1351 // there.
1352 //
1353
1354 } else {
1355
1356 //
1357 // Assume there is no relative name.
1358 //
1359
1360 RemainingName->FileName = *FileName;
1361 RemainingName->VersionString.Length = 0;
1362
1363 //
1364 // Nothing to do if the name length is zero.
1365 //
1366
1367 if (RemainingName->FileName.Length != 0) {
1368
1369 //
1370 // If there is a relative name then we need to walk past it.
1371 //
1372
1373 if (RelatedTypeOfOpen != UnopenedFileObject) {
1374
1375 //
1376 // Nothing to walk past if the RelatedCcb is opened by FileId.
1377 //
1378
1379
1380 if (!FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID )) {
1381
1382 //
1383 // Related file name is a proper prefix of the full name.
1384 // We step over the related name and if we are then
1385 // pointing at a separator character we step over that.
1386 //
1387
1388 RemainingName->FileName.Buffer = Add2Ptr( RemainingName->FileName.Buffer,
1389 RelatedFileName->Length,
1390 PWCHAR );
1391
1392 RemainingName->FileName.Length -= RelatedFileName->Length;
1393 }
1394 }
1395
1396 //
1397 // If we are pointing at a separator character then step past that.
1398 //
1399
1400 if (RemainingName->FileName.Length != 0) {
1401
1402 if (*(RemainingName->FileName.Buffer) == L'\\') {
1403
1404 RemainingName->FileName.Buffer = Add2Ptr( RemainingName->FileName.Buffer,
1405 sizeof( WCHAR ),
1406 PWCHAR );
1407
1408 RemainingName->FileName.Length -= sizeof( WCHAR );
1409 }
1410 }
1411 }
1412
1413 //
1414 // Upcase the name if necessary.
1415 //
1416
1417 if (IgnoreCase && (RemainingName->FileName.Length != 0)) {
1418
1419 CdUpcaseName( IrpContext,
1420 RemainingName,
1421 RemainingName );
1422 }
1423 }
1424
1425 return STATUS_SUCCESS;
1426 }
1427
1428 \f
1429 //
1430 // Local support routine
1431 //
1432
1433 NTSTATUS
1434 CdOpenByFileId (
1435 IN PIRP_CONTEXT IrpContext,
1436 IN PIO_STACK_LOCATION IrpSp,
1437 IN PVCB Vcb,
1438 IN OUT PFCB *CurrentFcb
1439 )
1440
1441 /*++
1442
1443 Routine Description:
1444
1445 This routine is called to open a file by the FileId. The file Id is in
1446 the FileObject name buffer and has been verified to be 64 bits.
1447
1448 We extract the Id number and then check to see whether we are opening a
1449 file or directory and compare that with the create options. If this
1450 generates no error then optimistically look up the Fcb in the Fcb Table.
1451
1452 If we don't find the Fcb then we need to carefully verify there is a file
1453 at this offset. First check whether the Parent Fcb is in the table. If
1454 not then lookup the parent at the path table offset given by file ID.
1455
1456 If found then build the Fcb from this entry and store the new Fcb in the
1457 tree.
1458
1459 We know have the parent Fcb. Do a directory scan to find the dirent at
1460 the given offset in this stream. This must point to the first entry
1461 of a valid file.
1462
1463 Finally we call our worker routine to complete the open on this Fcb.
1464
1465 Arguments:
1466
1467 IrpSp - Stack location within the create Irp.
1468
1469 Vcb - Vcb for this volume.
1470
1471 CurrentFcb - Address to store the Fcb for this open. We only store the
1472 CurrentFcb here when we have acquired it so our caller knows to
1473 free or deallocate it.
1474
1475 Return Value:
1476
1477 NTSTATUS - Status indicating the result of the operation.
1478
1479 --*/
1480
1481 {
1482 NTSTATUS Status = STATUS_ACCESS_DENIED;
1483
1484 BOOLEAN UnlockVcb = FALSE;
1485 BOOLEAN Found;
1486
1487 ULONG StreamOffset;
1488
1489 NODE_TYPE_CODE NodeTypeCode;
1490 TYPE_OF_OPEN TypeOfOpen;
1491
1492 FILE_ENUM_CONTEXT FileContext;
1493 BOOLEAN CleanupFileContext = FALSE;
1494
1495 COMPOUND_PATH_ENTRY CompoundPathEntry;
1496 BOOLEAN CleanupCompoundPathEntry = FALSE;
1497
1498 FILE_ID FileId;
1499 FILE_ID ParentFileId;
1500
1501 PFCB NextFcb;
1502
1503 PAGED_CODE();
1504
1505 //
1506 // Extract the FileId from the FileObject.
1507 //
1508
1509 RtlCopyMemory( &FileId, IrpSp->FileObject->FileName.Buffer, sizeof( FILE_ID ));
1510
1511 //
1512 // Use a try-finally to facilitate cleanup.
1513 //
1514
1515 _SEH2_TRY {
1516
1517 //
1518 // Go ahead and figure out the TypeOfOpen and NodeType. We can
1519 // get these from the input FileId.
1520 //
1521
1522 if (CdFidIsDirectory( FileId )) {
1523
1524 TypeOfOpen = UserDirectoryOpen;
1525 NodeTypeCode = CDFS_NTC_FCB_INDEX;
1526
1527 //
1528 // If the offset isn't zero then the file Id is bad.
1529 //
1530
1531 if (CdQueryFidDirentOffset( FileId ) != 0) {
1532
1533 try_return( Status = STATUS_INVALID_PARAMETER );
1534 }
1535
1536 } else {
1537
1538 TypeOfOpen = UserFileOpen;
1539 NodeTypeCode = CDFS_NTC_FCB_DATA;
1540 }
1541
1542 //
1543 // Acquire the Vcb and check if there is already an Fcb.
1544 // If not we will need to carefully verify the Fcb.
1545 // We will post the request if we don't find the Fcb and this
1546 // request can't wait.
1547 //
1548
1549 CdLockVcb( IrpContext, Vcb );
1550 UnlockVcb = TRUE;
1551
1552 NextFcb = CdLookupFcbTable( IrpContext, Vcb, FileId );
1553
1554 if (NextFcb == NULL) {
1555
1556 //
1557 // Get the path table offset from the file id.
1558 //
1559
1560 StreamOffset = CdQueryFidPathTableOffset( FileId );
1561
1562 //
1563 // Build the parent FileId for this and try looking it
1564 // up in the PathTable.
1565 //
1566
1567 CdSetFidDirentOffset( ParentFileId, 0 );
1568 CdSetFidPathTableOffset( ParentFileId, StreamOffset );
1569 CdFidSetDirectory( ParentFileId );
1570
1571 NextFcb = CdLookupFcbTable( IrpContext, Vcb, ParentFileId );
1572
1573 //
1574 // If not present then walk through the PathTable to this point.
1575 //
1576
1577 if (NextFcb == NULL) {
1578
1579 CdUnlockVcb( IrpContext, Vcb );
1580 UnlockVcb = FALSE;
1581
1582 //
1583 // Check that the path table offset lies within the path
1584 // table.
1585 //
1586
1587 if (StreamOffset > Vcb->PathTableFcb->FileSize.LowPart) {
1588
1589 try_return( Status = STATUS_INVALID_PARAMETER );
1590 }
1591
1592 CdInitializeCompoundPathEntry( IrpContext, &CompoundPathEntry );
1593 CleanupCompoundPathEntry = TRUE;
1594
1595 //
1596 // Start at the first entry in the PathTable.
1597 //
1598
1599 CdLookupPathEntry( IrpContext,
1600 Vcb->PathTableFcb->StreamOffset,
1601 1,
1602 TRUE,
1603 &CompoundPathEntry );
1604
1605 //
1606 // Continue looking until we have passed our target offset.
1607 //
1608
1609 while (TRUE) {
1610
1611 //
1612 // Move to the next entry.
1613 //
1614
1615 Found = CdLookupNextPathEntry( IrpContext,
1616 &CompoundPathEntry.PathContext,
1617 &CompoundPathEntry.PathEntry );
1618
1619 //
1620 // If we didn't find the entry or are beyond it then the
1621 // input Id is invalid.
1622 //
1623
1624 if (!Found ||
1625 (CompoundPathEntry.PathEntry.PathTableOffset > StreamOffset)) {
1626
1627 try_return( Status = STATUS_INVALID_PARAMETER );
1628 }
1629 }
1630
1631 //
1632 // If the FileId specified a directory then we have found
1633 // the entry. Make sure our caller wanted to open a directory.
1634 //
1635
1636 if ((TypeOfOpen == UserDirectoryOpen) &&
1637 FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
1638
1639 try_return( Status = STATUS_FILE_IS_A_DIRECTORY );
1640 }
1641
1642 //
1643 // Lock the Vcb and create the Fcb if necessary.
1644 //
1645
1646 CdLockVcb( IrpContext, Vcb );
1647 UnlockVcb = TRUE;
1648
1649 NextFcb = CdCreateFcb( IrpContext, ParentFileId, NodeTypeCode, &Found );
1650
1651 //
1652 // It's possible that someone got in here ahead of us.
1653 //
1654
1655 if (!Found) {
1656
1657 CdInitializeFcbFromPathEntry( IrpContext,
1658 NextFcb,
1659 NULL,
1660 &CompoundPathEntry.PathEntry );
1661 }
1662
1663 //
1664 // If the user wanted to open a directory then we have found
1665 // it. Store this Fcb into the CurrentFcb and skip the
1666 // directory scan.
1667 //
1668
1669 if (TypeOfOpen == UserDirectoryOpen) {
1670
1671 *CurrentFcb = NextFcb;
1672 NextFcb = NULL;
1673 }
1674 }
1675
1676 //
1677 // Perform the directory scan if we don't already have our target.
1678 //
1679
1680 if (NextFcb != NULL) {
1681
1682 //
1683 // Acquire the parent. We currently own the Vcb lock so
1684 // do this without waiting first.
1685 //
1686
1687 if (!CdAcquireFcbExclusive( IrpContext,
1688 NextFcb,
1689 TRUE )) {
1690
1691 NextFcb->FcbReference += 1;
1692 CdUnlockVcb( IrpContext, Vcb );
1693
1694 CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
1695
1696 CdLockVcb( IrpContext, Vcb );
1697 NextFcb->FcbReference -= 1;
1698 CdUnlockVcb( IrpContext, Vcb );
1699
1700 } else {
1701
1702 CdUnlockVcb( IrpContext, Vcb );
1703 }
1704
1705 UnlockVcb = FALSE;
1706
1707 //
1708 // Set up the CurrentFcb pointers. We know there was
1709 // no previous parent in this case.
1710 //
1711
1712 *CurrentFcb = NextFcb;
1713
1714 //
1715 // Calculate the offset in the stream.
1716 //
1717
1718 StreamOffset = CdQueryFidDirentOffset( FileId );
1719
1720 //
1721 // Create the stream file if it doesn't exist. This will update
1722 // the Fcb with the size from the self entry.
1723 //
1724
1725 if (NextFcb->FileObject == NULL) {
1726
1727 CdCreateInternalStream( IrpContext, Vcb, NextFcb );
1728 }
1729
1730 //
1731 // If our offset is beyond the end of the directory then the
1732 // FileId is invalid.
1733 //
1734
1735 if (StreamOffset > NextFcb->FileSize.LowPart) {
1736
1737 try_return( Status = STATUS_INVALID_PARAMETER );
1738 }
1739
1740 //
1741 // Otherwise position ourselves at the self entry and walk
1742 // through dirent by dirent until this location is found.
1743 //
1744
1745 CdInitializeFileContext( IrpContext, &FileContext );
1746 CdLookupInitialFileDirent( IrpContext,
1747 NextFcb,
1748 &FileContext,
1749 NextFcb->StreamOffset );
1750
1751 CleanupFileContext = TRUE;
1752
1753 while (TRUE) {
1754
1755 //
1756 // Move to the first entry of the next file.
1757 //
1758
1759 Found = CdLookupNextInitialFileDirent( IrpContext,
1760 NextFcb,
1761 &FileContext );
1762
1763 //
1764 // If we didn't find the entry or are beyond it then the
1765 // input Id is invalid.
1766 //
1767
1768 if (!Found ||
1769 (FileContext.InitialDirent->Dirent.DirentOffset > StreamOffset)) {
1770
1771 try_return( Status = STATUS_INVALID_PARAMETER );
1772 }
1773 }
1774
1775 //
1776 // This better not be a directory. Directory FileIds must
1777 // refer to the self entry for directories.
1778 //
1779
1780 if (FlagOn( FileContext.InitialDirent->Dirent.DirentFlags,
1781 CD_ATTRIBUTE_DIRECTORY )) {
1782
1783 try_return( Status = STATUS_INVALID_PARAMETER );
1784 }
1785
1786 //
1787 // Check that our caller wanted to open a file.
1788 //
1789
1790 if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
1791
1792 try_return( Status = STATUS_NOT_A_DIRECTORY );
1793 }
1794
1795 //
1796 // Otherwise we want to collect all of the dirents for this file
1797 // and create an Fcb with this.
1798 //
1799
1800 CdLookupLastFileDirent( IrpContext, NextFcb, &FileContext );
1801
1802 CdLockVcb( IrpContext, Vcb );
1803 UnlockVcb = TRUE;
1804
1805 NextFcb = CdCreateFcb( IrpContext, FileId, NodeTypeCode, &Found );
1806
1807 //
1808 // It's possible that someone has since created this Fcb since we
1809 // first checked. If so then can simply use this. Otherwise
1810 // we need to initialize a new Fcb and attach it to our parent
1811 // and insert it into the Fcb Table.
1812 //
1813
1814 if (!Found) {
1815
1816 CdInitializeFcbFromFileContext( IrpContext,
1817 NextFcb,
1818 *CurrentFcb,
1819 &FileContext );
1820 }
1821 }
1822
1823 //
1824 // We have the Fcb. Check that the type of the file is compatible with
1825 // the desired type of file to open.
1826 //
1827
1828 } else {
1829
1830 if (FlagOn( NextFcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
1831
1832 if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
1833
1834 try_return( Status = STATUS_FILE_IS_A_DIRECTORY );
1835 }
1836
1837 } else if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
1838
1839 try_return( Status = STATUS_NOT_A_DIRECTORY );
1840 }
1841 }
1842
1843 //
1844 // If we have a the previous Fcb and have inserted the next Fcb into
1845 // the Fcb Table. It is safe to release the current Fcb if present
1846 // since it is referenced through the child Fcb.
1847 //
1848
1849 if (*CurrentFcb != NULL) {
1850
1851 CdReleaseFcb( IrpContext, *CurrentFcb );
1852 }
1853
1854 //
1855 // We now know the Fcb and currently hold the Vcb lock.
1856 // Try to acquire this Fcb without waiting. Otherwise we
1857 // need to reference it, drop the Vcb, acquire the Fcb and
1858 // then dereference the Fcb.
1859 //
1860
1861 if (!CdAcquireFcbExclusive( IrpContext, NextFcb, TRUE )) {
1862
1863 NextFcb->FcbReference += 1;
1864
1865 CdUnlockVcb( IrpContext, Vcb );
1866
1867 CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
1868
1869 CdLockVcb( IrpContext, Vcb );
1870 NextFcb->FcbReference -= 1;
1871 CdUnlockVcb( IrpContext, Vcb );
1872
1873 } else {
1874
1875 CdUnlockVcb( IrpContext, Vcb );
1876 }
1877
1878 UnlockVcb = FALSE;
1879
1880 //
1881 // Move to this Fcb.
1882 //
1883
1884 *CurrentFcb = NextFcb;
1885
1886 //
1887 // Check the requested access on this Fcb.
1888 //
1889
1890 if (!CdIllegalFcbAccess( IrpContext,
1891 TypeOfOpen,
1892 IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
1893
1894 //
1895 // Call our worker routine to complete the open.
1896 //
1897
1898 Status = CdCompleteFcbOpen( IrpContext,
1899 IrpSp,
1900 Vcb,
1901 CurrentFcb,
1902 TypeOfOpen,
1903 CCB_FLAG_OPEN_BY_ID,
1904 IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
1905 }
1906
1907 try_exit: NOTHING;
1908 } _SEH2_FINALLY {
1909
1910 if (UnlockVcb) {
1911
1912 CdUnlockVcb( IrpContext, Vcb );
1913 }
1914
1915 if (CleanupFileContext) {
1916
1917 CdCleanupFileContext( IrpContext, &FileContext );
1918 }
1919
1920 if (CleanupCompoundPathEntry) {
1921
1922 CdCleanupCompoundPathEntry( IrpContext, &CompoundPathEntry );
1923 }
1924 } _SEH2_END;
1925
1926 return Status;
1927 }
1928
1929 \f
1930 //
1931 // Local support routine
1932 //
1933
1934 NTSTATUS
1935 CdOpenExistingFcb (
1936 IN PIRP_CONTEXT IrpContext,
1937 IN PIO_STACK_LOCATION IrpSp,
1938 IN OUT PFCB *CurrentFcb,
1939 IN TYPE_OF_OPEN TypeOfOpen,
1940 IN BOOLEAN IgnoreCase,
1941 IN PCCB RelatedCcb OPTIONAL
1942 )
1943
1944 /*++
1945
1946 Routine Description:
1947
1948 This routine is called to open an Fcb which is already in the Fcb table.
1949 We will verify the access to the file and then call our worker routine
1950 to perform the final operations.
1951
1952 Arguments:
1953
1954 IrpSp - Pointer to the stack location for this open.
1955
1956 CurrentFcb - Address of Fcb to open. We will clear this if the Fcb
1957 is released here.
1958
1959 TypeOfOpen - Indicates whether we are opening a file, directory or volume.
1960
1961 IgnoreCase - Indicates if this open is case-insensitive.
1962
1963 RelatedCcb - Ccb for related file object if relative open. We use
1964 this when setting the Ccb flags for this open. It will tell
1965 us whether the name currently in the file object is relative or
1966 absolute.
1967
1968 Return Value:
1969
1970 NTSTATUS - Status indicating the result of the operation.
1971
1972 --*/
1973
1974 {
1975 ULONG CcbFlags = 0;
1976
1977 NTSTATUS Status = STATUS_ACCESS_DENIED;
1978
1979 PAGED_CODE();
1980
1981 //
1982 // Check that the desired access is legal.
1983 //
1984
1985 if (!CdIllegalFcbAccess( IrpContext,
1986 TypeOfOpen,
1987 IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
1988
1989 //
1990 // Set the Ignore case.
1991 //
1992
1993 if (IgnoreCase) {
1994
1995 SetFlag( CcbFlags, CCB_FLAG_IGNORE_CASE );
1996 }
1997
1998 //
1999 // Check the related Ccb to see if this was an OpenByFileId and
2000 // whether there was a version.
2001 //
2002
2003 if (ARGUMENT_PRESENT( RelatedCcb )) {
2004
2005 SetFlag( CcbFlags, FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_WITH_VERSION ));
2006
2007
2008 if (FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID | CCB_FLAG_OPEN_RELATIVE_BY_ID )) {
2009
2010 SetFlag( CcbFlags, CCB_FLAG_OPEN_RELATIVE_BY_ID );
2011 }
2012 }
2013
2014 //
2015 // Call our worker routine to complete the open.
2016 //
2017
2018 Status = CdCompleteFcbOpen( IrpContext,
2019 IrpSp,
2020 (*CurrentFcb)->Vcb,
2021 CurrentFcb,
2022 TypeOfOpen,
2023 CcbFlags,
2024 IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
2025 }
2026
2027 return Status;
2028 }
2029
2030 \f
2031 //
2032 // Local support routine
2033 //
2034
2035 NTSTATUS
2036 CdOpenDirectoryFromPathEntry (
2037 IN PIRP_CONTEXT IrpContext,
2038 IN PIO_STACK_LOCATION IrpSp,
2039 IN PVCB Vcb,
2040 IN OUT PFCB *CurrentFcb,
2041 IN PCD_NAME DirName,
2042 IN BOOLEAN IgnoreCase,
2043 IN BOOLEAN ShortNameMatch,
2044 IN PPATH_ENTRY PathEntry,
2045 IN BOOLEAN PerformUserOpen,
2046 IN PCCB RelatedCcb OPTIONAL
2047 )
2048
2049 /*++
2050
2051 Routine Description:
2052
2053 This routine is called to open a directory where the directory was found
2054 in the path table. This routine is called in the case where this is the
2055 file to open for the user and where this is an intermediate node in the
2056 full path to open.
2057
2058 We first check that the desired access is legal for a directory. Then we
2059 construct the FileId for this and do a check to see if it is the Fcb
2060 Table. It is always possible that either it was created since or simply
2061 wasn't in the prefix table at the time of the prefix table search.
2062 Initialize the Fcb and store into the FcbTable if not present.
2063
2064 Next we will add this to the prefix table of our parent if needed.
2065
2066 Once we know that the new Fcb has been initialized then we move our pointer
2067 in the tree down to this position.
2068
2069 This routine does not own the Vcb lock on entry. We must be sure to release
2070 it on exit.
2071
2072 Arguments:
2073
2074 IrpSp - Stack location for this request.
2075
2076 Vcb - Vcb for this volume.
2077
2078 CurrentFcb - On input this is the parent of the Fcb to open. On output we
2079 store the Fcb for the file being opened.
2080
2081 DirName - This is always the exact name used to reach this file.
2082
2083 IgnoreCase - Indicates the type of case match for the open.
2084
2085 ShortNameMatch - Indicates if we are opening via the short name.
2086
2087 PathEntry - Path entry for the entry found.
2088
2089 PerformUserOpen - TRUE if we are to open this for a user, FALSE otherwise.
2090
2091 RelatedCcb - RelatedCcb for relative file object used to make this open.
2092
2093 Return Value:
2094
2095 NTSTATUS - Status indicating the result of the operation.
2096
2097 --*/
2098
2099 {
2100 ULONG CcbFlags = 0;
2101 FILE_ID FileId;
2102
2103 BOOLEAN UnlockVcb = FALSE;
2104 BOOLEAN FcbExisted;
2105
2106 PFCB NextFcb;
2107 PFCB ParentFcb = NULL;
2108
2109 NTSTATUS Status = STATUS_SUCCESS; /* ReactOS Change: GCC uninitialized variable */
2110
2111 PAGED_CODE();
2112
2113 //
2114 // Check for illegal access to this file.
2115 //
2116
2117 if (PerformUserOpen &&
2118 CdIllegalFcbAccess( IrpContext,
2119 UserDirectoryOpen,
2120 IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
2121
2122 return STATUS_ACCESS_DENIED;
2123 }
2124
2125 //
2126 // Use a try-finally to facilitate cleanup.
2127 //
2128
2129 _SEH2_TRY {
2130
2131 //
2132 // Check the related Ccb to see if this was an OpenByFileId.
2133 //
2134
2135 if (ARGUMENT_PRESENT( RelatedCcb ) &&
2136 FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID | CCB_FLAG_OPEN_RELATIVE_BY_ID )) {
2137
2138 CcbFlags = CCB_FLAG_OPEN_RELATIVE_BY_ID;
2139 }
2140
2141 if (IgnoreCase) {
2142
2143 SetFlag( CcbFlags, CCB_FLAG_IGNORE_CASE );
2144 }
2145
2146 //
2147 // Build the file Id for this file.
2148 //
2149
2150 FileId.QuadPart = 0;
2151 CdSetFidPathTableOffset( FileId, PathEntry->PathTableOffset );
2152 CdFidSetDirectory( FileId );
2153
2154 //
2155 // Lock the Vcb so we can examine the Fcb Table.
2156 //
2157
2158 CdLockVcb( IrpContext, Vcb );
2159 UnlockVcb = TRUE;
2160
2161 //
2162 // Get the Fcb for this directory.
2163 //
2164
2165 NextFcb = CdCreateFcb( IrpContext, FileId, CDFS_NTC_FCB_INDEX, &FcbExisted );
2166
2167 //
2168 // If the Fcb was created here then initialize from the values in the
2169 // path table entry.
2170 //
2171
2172 if (!FcbExisted) {
2173
2174 CdInitializeFcbFromPathEntry( IrpContext, NextFcb, *CurrentFcb, PathEntry );
2175 }
2176
2177 //
2178 // Now try to acquire the new Fcb without waiting. We will reference
2179 // the Fcb and retry with wait if unsuccessful.
2180 //
2181
2182 if (!CdAcquireFcbExclusive( IrpContext, NextFcb, TRUE )) {
2183
2184 NextFcb->FcbReference += 1;
2185
2186 CdUnlockVcb( IrpContext, Vcb );
2187
2188 CdReleaseFcb( IrpContext, *CurrentFcb );
2189 CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
2190 CdAcquireFcbExclusive( IrpContext, *CurrentFcb, FALSE );
2191
2192 CdLockVcb( IrpContext, Vcb );
2193 NextFcb->FcbReference -= 1;
2194 CdUnlockVcb( IrpContext, Vcb );
2195
2196 } else {
2197
2198 //
2199 // Unlock the Vcb and move down to this new Fcb. Remember that we still
2200 // own the parent however.
2201 //
2202
2203 CdUnlockVcb( IrpContext, Vcb );
2204 }
2205
2206 UnlockVcb = FALSE;
2207
2208 ParentFcb = *CurrentFcb;
2209 *CurrentFcb = NextFcb;
2210
2211 //
2212 // Store this name into the prefix table for the parent.
2213 //
2214
2215 if (ShortNameMatch) {
2216
2217 //
2218 // Make sure the exact case is always in the tree.
2219 //
2220
2221 CdInsertPrefix( IrpContext,
2222 NextFcb,
2223 DirName,
2224 FALSE,
2225 TRUE,
2226 ParentFcb );
2227
2228 if (IgnoreCase) {
2229
2230 CdInsertPrefix( IrpContext,
2231 NextFcb,
2232 DirName,
2233 TRUE,
2234 TRUE,
2235 ParentFcb );
2236 }
2237
2238 } else {
2239
2240 //
2241 // Make sure the exact case is always in the tree.
2242 //
2243
2244 CdInsertPrefix( IrpContext,
2245 NextFcb,
2246 &PathEntry->CdDirName,
2247 FALSE,
2248 FALSE,
2249 ParentFcb );
2250
2251 if (IgnoreCase) {
2252
2253 CdInsertPrefix( IrpContext,
2254 NextFcb,
2255 &PathEntry->CdCaseDirName,
2256 TRUE,
2257 FALSE,
2258 ParentFcb );
2259 }
2260 }
2261
2262 //
2263 // Release the parent Fcb at this point.
2264 //
2265
2266 CdReleaseFcb( IrpContext, ParentFcb );
2267 ParentFcb = NULL;
2268
2269 //
2270 // Call our worker routine to complete the open.
2271 //
2272
2273 if (PerformUserOpen) {
2274
2275 Status = CdCompleteFcbOpen( IrpContext,
2276 IrpSp,
2277 Vcb,
2278 CurrentFcb,
2279 UserDirectoryOpen,
2280 CcbFlags,
2281 IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
2282 }
2283
2284 } _SEH2_FINALLY {
2285
2286 //
2287 // Unlock the Vcb if held.
2288 //
2289
2290 if (UnlockVcb) {
2291
2292 CdUnlockVcb( IrpContext, Vcb );
2293 }
2294
2295 //
2296 // Release the parent if held.
2297 //
2298
2299 if (ParentFcb != NULL) {
2300
2301 CdReleaseFcb( IrpContext, ParentFcb );
2302 }
2303 } _SEH2_END;
2304
2305 return Status;
2306 }
2307
2308 \f
2309 //
2310 // Local support routine
2311 //
2312
2313 NTSTATUS
2314 CdOpenFileFromFileContext (
2315 IN PIRP_CONTEXT IrpContext,
2316 IN PIO_STACK_LOCATION IrpSp,
2317 IN PVCB Vcb,
2318 IN OUT PFCB *CurrentFcb,
2319 IN PCD_NAME FileName,
2320 IN BOOLEAN IgnoreCase,
2321 IN BOOLEAN ShortNameMatch,
2322 IN PFILE_ENUM_CONTEXT FileContext,
2323 IN PCCB RelatedCcb OPTIONAL
2324 )
2325
2326 /*++
2327
2328 Routine Description:
2329
2330 This routine is called to open a file where the file was found in a directory scan.
2331 This should only be for a file in the case since we will find the directories in the
2332 path table.
2333
2334 We first check that the desired access is legal for this file. Then we
2335 construct the FileId for this and do a check to see if it is the Fcb
2336 Table. It is always possible that either it was created since or simply
2337 wasn't in the prefix table at the time of the prefix table search.
2338 Initialize the Fcb and store into the FcbTable if not present.
2339
2340 Next we will add this to the prefix table of our parent if needed.
2341
2342 Once we know that the new Fcb has been initialized then we move our pointer
2343 in the tree down to this position.
2344
2345 This routine does not own the Vcb lock on entry. We must be sure to release
2346 it on exit.
2347
2348 Arguments:
2349
2350 IrpSp - Stack location for this request.
2351
2352 Vcb - Vcb for the current volume.
2353
2354 CurrentFcb - On input this is the parent of the Fcb to open. On output we
2355 store the Fcb for the file being opened.
2356
2357 FileName - This is always the exact name used to reach this file.
2358
2359 IgnoreCase - Indicates the type of case of CaseName above.
2360
2361 ShortNameMatch - Indicates if we are opening via the short name.
2362
2363 FileContext - This is the context used to find the file.
2364
2365 RelatedCcb - RelatedCcb for relative file object used to make this open.
2366
2367 Return Value:
2368
2369 NTSTATUS - Status indicating the result of the operation.
2370
2371 --*/
2372
2373 {
2374 ULONG CcbFlags = 0;
2375 FILE_ID FileId;
2376
2377 BOOLEAN UnlockVcb = FALSE;
2378 BOOLEAN FcbExisted;
2379
2380 PFCB NextFcb;
2381 PFCB ParentFcb = NULL;
2382
2383 NTSTATUS Status;
2384
2385 PAGED_CODE();
2386
2387 //
2388 // Check for illegal access to this file.
2389 //
2390
2391 if (CdIllegalFcbAccess( IrpContext,
2392 UserFileOpen,
2393 IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
2394
2395 return STATUS_ACCESS_DENIED;
2396 }
2397
2398 //
2399 // Use a try-finally to facilitate cleanup.
2400 //
2401
2402 _SEH2_TRY {
2403
2404 //
2405 // Check if a version number was used to open this file.
2406 //
2407
2408 if (FileName->VersionString.Length != 0) {
2409
2410 SetFlag( CcbFlags, CCB_FLAG_OPEN_WITH_VERSION );
2411 }
2412
2413 //
2414 // Check the related Ccb to see if this was an OpenByFileId.
2415 //
2416
2417 if (ARGUMENT_PRESENT( RelatedCcb ) &&
2418 FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID | CCB_FLAG_OPEN_RELATIVE_BY_ID )) {
2419
2420 SetFlag( CcbFlags, CCB_FLAG_OPEN_RELATIVE_BY_ID );
2421 }
2422
2423 if (IgnoreCase) {
2424
2425 SetFlag( CcbFlags, CCB_FLAG_IGNORE_CASE );
2426 }
2427
2428 //
2429 // Build the file Id for this file. We can use the path table offset from the
2430 // parent and the directory offset from the dirent.
2431 //
2432
2433 CdSetFidPathTableOffset( FileId, CdQueryFidPathTableOffset( (*CurrentFcb)->FileId ));
2434 CdSetFidDirentOffset( FileId, FileContext->InitialDirent->Dirent.DirentOffset );
2435
2436 //
2437 // Lock the Vcb so we can examine the Fcb Table.
2438 //
2439
2440 CdLockVcb( IrpContext, Vcb );
2441 UnlockVcb = TRUE;
2442
2443 //
2444 // Get the Fcb for this file.
2445 //
2446
2447 NextFcb = CdCreateFcb( IrpContext, FileId, CDFS_NTC_FCB_DATA, &FcbExisted );
2448
2449 //
2450 // If the Fcb was created here then initialize from the values in the
2451 // dirent.
2452 //
2453
2454 if (!FcbExisted) {
2455
2456 CdInitializeFcbFromFileContext( IrpContext,
2457 NextFcb,
2458 *CurrentFcb,
2459 FileContext );
2460 }
2461
2462 //
2463 // Now try to acquire the new Fcb without waiting. We will reference
2464 // the Fcb and retry with wait if unsuccessful.
2465 //
2466
2467 if (!CdAcquireFcbExclusive( IrpContext, NextFcb, TRUE )) {
2468
2469 NextFcb->FcbReference += 1;
2470
2471 CdUnlockVcb( IrpContext, Vcb );
2472
2473 CdReleaseFcb( IrpContext, *CurrentFcb );
2474 CdAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
2475 CdAcquireFcbExclusive( IrpContext, *CurrentFcb, FALSE );
2476
2477 CdLockVcb( IrpContext, Vcb );
2478 NextFcb->FcbReference -= 1;
2479 CdUnlockVcb( IrpContext, Vcb );
2480
2481 } else {
2482
2483 //
2484 // Unlock the Vcb and move down to this new Fcb. Remember that we still
2485 // own the parent however.
2486 //
2487
2488 CdUnlockVcb( IrpContext, Vcb );
2489 }
2490
2491 UnlockVcb = FALSE;
2492
2493 ParentFcb = *CurrentFcb;
2494 *CurrentFcb = NextFcb;
2495
2496 //
2497 // Store this name into the prefix table for the parent.
2498 //
2499
2500
2501 if (ShortNameMatch) {
2502
2503 //
2504 // Make sure the exact case is always in the tree.
2505 //
2506
2507 CdInsertPrefix( IrpContext,
2508 NextFcb,
2509 FileName,
2510 FALSE,
2511 TRUE,
2512 ParentFcb );
2513
2514 if (IgnoreCase) {
2515
2516 CdInsertPrefix( IrpContext,
2517 NextFcb,
2518 FileName,
2519 TRUE,
2520 TRUE,
2521 ParentFcb );
2522 }
2523
2524 //
2525 // Insert this into the prefix table if we found this without
2526 // using a version string.
2527 //
2528
2529 } else if (FileName->VersionString.Length == 0) {
2530
2531 //
2532 // Make sure the exact case is always in the tree.
2533 //
2534
2535 CdInsertPrefix( IrpContext,
2536 NextFcb,
2537 &FileContext->InitialDirent->Dirent.CdFileName,
2538 FALSE,
2539 FALSE,
2540 ParentFcb );
2541
2542 if (IgnoreCase) {
2543
2544 CdInsertPrefix( IrpContext,
2545 NextFcb,
2546 &FileContext->InitialDirent->Dirent.CdCaseFileName,
2547 TRUE,
2548 FALSE,
2549 ParentFcb );
2550 }
2551 }
2552
2553 //
2554 // Release the parent Fcb at this point.
2555 //
2556
2557 CdReleaseFcb( IrpContext, ParentFcb );
2558 ParentFcb = NULL;
2559
2560 //
2561 // Call our worker routine to complete the open.
2562 //
2563
2564 Status = CdCompleteFcbOpen( IrpContext,
2565 IrpSp,
2566 Vcb,
2567 CurrentFcb,
2568 UserFileOpen,
2569 CcbFlags,
2570 IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
2571
2572 } _SEH2_FINALLY {
2573
2574 //
2575 // Unlock the Vcb if held.
2576 //
2577
2578 if (UnlockVcb) {
2579
2580 CdUnlockVcb( IrpContext, Vcb );
2581 }
2582
2583 //
2584 // Release the parent if held.
2585 //
2586
2587 if (ParentFcb != NULL) {
2588
2589 CdReleaseFcb( IrpContext, ParentFcb );
2590 }
2591 } _SEH2_END;
2592
2593 return Status;
2594 }
2595
2596 \f
2597 //
2598 // Local support routine
2599 //
2600
2601 NTSTATUS
2602 CdCompleteFcbOpen (
2603 IN PIRP_CONTEXT IrpContext,
2604 PIO_STACK_LOCATION IrpSp,
2605 IN PVCB Vcb,
2606 IN OUT PFCB *CurrentFcb,
2607 IN TYPE_OF_OPEN TypeOfOpen,
2608 IN ULONG UserCcbFlags,
2609 IN ACCESS_MASK DesiredAccess
2610 )
2611
2612 /*++
2613
2614 Routine Description:
2615
2616 This is the worker routine which takes an existing Fcb and completes
2617 the open. We will do any necessary oplock checks and sharing checks.
2618 Finally we will create the Ccb and update the file object and any
2619 file object flags.
2620
2621 Arguments:
2622
2623 IrpSp - Stack location for the current request.
2624
2625 Vcb - Vcb for the current volume.
2626
2627 CurrentFcb - Address of pointer to Fcb to open. We clear this field if
2628 we release the resource for this file.
2629
2630 TypeOfOpen - Type of open for this request.
2631
2632 UserCcbFlags - Flags to OR into the Ccb flags.
2633
2634 DesiredAccess - Desired access for this open.
2635
2636 Return Value:
2637
2638 NTSTATUS - STATUS_SUCCESS if we complete this request, STATUS_PENDING if
2639 the oplock package takes the Irp or SHARING_VIOLATION if there is a
2640 sharing check conflict.
2641
2642 --*/
2643
2644 {
2645 NTSTATUS Status;
2646 NTSTATUS OplockStatus = STATUS_SUCCESS;
2647 ULONG Information = FILE_OPENED;
2648
2649 BOOLEAN LockVolume = FALSE;
2650
2651 PFCB Fcb = *CurrentFcb;
2652 PCCB Ccb;
2653
2654 PAGED_CODE();
2655
2656 //
2657 // Expand maximum allowed to something sensible for share access checking
2658 //
2659
2660 if (MAXIMUM_ALLOWED == DesiredAccess) {
2661
2662 DesiredAccess = FILE_ALL_ACCESS & ~((TypeOfOpen != UserVolumeOpen ?
2663 (FILE_WRITE_ATTRIBUTES |
2664 FILE_WRITE_DATA |
2665 FILE_WRITE_EA |
2666 FILE_ADD_FILE |
2667 FILE_ADD_SUBDIRECTORY |
2668 FILE_APPEND_DATA) : 0) |
2669 FILE_DELETE_CHILD |
2670 DELETE |
2671 WRITE_DAC );
2672 }
2673
2674 //
2675 // If this a volume open and the user wants to lock the volume then
2676 // purge and lock the volume.
2677 //
2678
2679 if ((TypeOfOpen <= UserVolumeOpen) &&
2680 !FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_READ )) {
2681
2682 //
2683 // If there are open handles then fail this immediately.
2684 //
2685
2686 if (Vcb->VcbCleanup != 0) {
2687
2688 return STATUS_SHARING_VIOLATION;
2689 }
2690
2691 //
2692 // If we can't wait then force this to be posted.
2693 //
2694
2695 if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
2696
2697 CdRaiseStatus( IrpContext, STATUS_CANT_WAIT );
2698 }
2699
2700 LockVolume = TRUE;
2701
2702 //
2703 // Purge the volume and make sure all of the user references
2704 // are gone.
2705 //
2706
2707 Status = CdPurgeVolume( IrpContext, Vcb, FALSE );
2708
2709 if (Status != STATUS_SUCCESS) {
2710
2711 return Status;
2712 }
2713
2714 //
2715 // Now force all of the delayed close operations to go away.
2716 //
2717
2718 CdFspClose( Vcb );
2719
2720 if (Vcb->VcbUserReference > CDFS_RESIDUAL_USER_REFERENCE) {
2721
2722 return STATUS_SHARING_VIOLATION;
2723 }
2724 }
2725
2726 //
2727 // If the Fcb already existed then we need to check the oplocks and
2728 // the share access.
2729 //
2730
2731 if (Fcb->FcbCleanup != 0) {
2732
2733 //
2734 // If this is a user file open then check whether there are any
2735 // batch oplock.
2736 //
2737
2738 if (TypeOfOpen == UserFileOpen) {
2739
2740 //
2741 // Store the address of the Fcb for a possible teardown into
2742 // the IrpContext. We will release this in the call to
2743 // prepost the Irp.
2744 //
2745
2746 IrpContext->TeardownFcb = CurrentFcb;
2747
2748 if (FsRtlCurrentBatchOplock( &Fcb->Oplock )) {
2749
2750 //
2751 // We remember if a batch oplock break is underway for the
2752 // case where the sharing check fails.
2753 //
2754
2755 Information = FILE_OPBATCH_BREAK_UNDERWAY;
2756
2757 OplockStatus = FsRtlCheckOplock( &Fcb->Oplock,
2758 IrpContext->Irp,
2759 IrpContext,
2760 (PVOID)CdOplockComplete, /* ReactOS Change: GCC "assignment from incompatible pointer type" */
2761 (PVOID)CdPrePostIrp ); /* ReactOS Change: GCC "assignment from incompatible pointer type" */
2762
2763 if (OplockStatus == STATUS_PENDING) {
2764
2765 return STATUS_PENDING;
2766 }
2767 }
2768
2769 //
2770 // Check the share access before breaking any exclusive oplocks.
2771 //
2772
2773 Status = IoCheckShareAccess( DesiredAccess,
2774 IrpSp->Parameters.Create.ShareAccess,
2775 IrpSp->FileObject,
2776 &Fcb->ShareAccess,
2777 FALSE );
2778
2779 if (!NT_SUCCESS( Status )) {
2780
2781 return Status;
2782 }
2783
2784 //
2785 // Now check that we can continue based on the oplock state of the
2786 // file.
2787 //
2788
2789 OplockStatus = FsRtlCheckOplock( &Fcb->Oplock,
2790 IrpContext->Irp,
2791 IrpContext,
2792 (PVOID)CdOplockComplete,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
2793 (PVOID)CdPrePostIrp );/* ReactOS Change: GCC "assignment from incompatible pointer type" */
2794
2795 if (OplockStatus == STATUS_PENDING) {
2796
2797 return STATUS_PENDING;
2798 }
2799
2800 IrpContext->TeardownFcb = NULL;
2801
2802 //
2803 // Otherwise just do the sharing check.
2804 //
2805
2806 } else {
2807
2808 Status = IoCheckShareAccess( DesiredAccess,
2809 IrpSp->Parameters.Create.ShareAccess,
2810 IrpSp->FileObject,
2811 &Fcb->ShareAccess,
2812 FALSE );
2813
2814 if (!NT_SUCCESS( Status )) {
2815
2816 return Status;
2817 }
2818 }
2819 }
2820
2821 //
2822 // Create the Ccb now.
2823 //
2824
2825 Ccb = CdCreateCcb( IrpContext, Fcb, UserCcbFlags );
2826
2827 //
2828 // Update the share access.
2829 //
2830
2831 if (Fcb->FcbCleanup == 0) {
2832
2833 IoSetShareAccess( DesiredAccess,
2834 IrpSp->Parameters.Create.ShareAccess,
2835 IrpSp->FileObject,
2836 &Fcb->ShareAccess );
2837
2838 } else {
2839
2840 IoUpdateShareAccess( IrpSp->FileObject, &Fcb->ShareAccess );
2841 }
2842
2843 //
2844 // Set the file object type.
2845 //
2846
2847 CdSetFileObject( IrpContext, IrpSp->FileObject, TypeOfOpen, Fcb, Ccb );
2848
2849 //
2850 // Set the appropriate cache flags for a user file object.
2851 //
2852
2853 if (TypeOfOpen == UserFileOpen) {
2854
2855 if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING )) {
2856
2857 SetFlag( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING );
2858
2859 } else {
2860
2861 SetFlag( IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED );
2862 }
2863 }
2864 else if (TypeOfOpen == UserVolumeOpen) {
2865
2866 SetFlag( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING );
2867 }
2868
2869 //
2870 // Update the open and cleanup counts. Check the fast io state here.
2871 //
2872
2873 CdLockVcb( IrpContext, Vcb );
2874
2875 CdIncrementCleanupCounts( IrpContext, Fcb );
2876 CdIncrementReferenceCounts( IrpContext, Fcb, 1, 1 );
2877
2878 if (LockVolume) {
2879
2880 Vcb->VolumeLockFileObject = IrpSp->FileObject;
2881 SetFlag( Vcb->VcbState, VCB_STATE_LOCKED );
2882 }
2883
2884 CdUnlockVcb( IrpContext, Vcb );
2885
2886 CdLockFcb( IrpContext, Fcb );
2887
2888 if (TypeOfOpen == UserFileOpen) {
2889
2890 Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb );
2891
2892 } else {
2893
2894 Fcb->IsFastIoPossible = FastIoIsNotPossible;
2895 }
2896
2897 CdUnlockFcb( IrpContext, Fcb );
2898
2899 //
2900 // Show that we opened the file.
2901 //
2902
2903 IrpContext->Irp->IoStatus.Information = Information;
2904
2905 //
2906 // Point to the section object pointer in the non-paged Fcb.
2907 //
2908
2909 IrpSp->FileObject->SectionObjectPointer = &Fcb->FcbNonpaged->SegmentObject;
2910 return OplockStatus;
2911 }
2912
2913
2914
2915
2916