3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the File Create routine for Cdfs called by the
12 Fsd/Fsp dispatch routines.
20 // The Bug check file id for this module
23 #define BugCheckFileId (CDFS_BUG_CHECK_CREATE)
26 // Local support routines
30 CdNormalizeFileNames (
31 IN PIRP_CONTEXT IrpContext
,
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
44 IN PIRP_CONTEXT IrpContext
,
45 IN PIO_STACK_LOCATION IrpSp
,
47 IN OUT PFCB
*CurrentFcb
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
61 CdOpenDirectoryFromPathEntry (
62 IN PIRP_CONTEXT IrpContext
,
63 IN PIO_STACK_LOCATION IrpSp
,
65 IN OUT PFCB
*CurrentFcb
,
67 IN BOOLEAN IgnoreCase
,
68 IN BOOLEAN ShortNameMatch
,
69 IN PPATH_ENTRY PathEntry
,
70 IN BOOLEAN PerformUserOpen
,
71 IN PCCB RelatedCcb OPTIONAL
75 CdOpenFileFromFileContext (
76 IN PIRP_CONTEXT IrpContext
,
77 IN PIO_STACK_LOCATION IrpSp
,
79 IN OUT PFCB
*CurrentFcb
,
81 IN BOOLEAN IgnoreCase
,
82 IN BOOLEAN ShortNameMatch
,
83 IN PFILE_ENUM_CONTEXT FileContext
,
84 IN PCCB RelatedCcb OPTIONAL
89 IN PIRP_CONTEXT IrpContext
,
90 PIO_STACK_LOCATION IrpSp
,
92 IN OUT PFCB
*CurrentFcb
,
93 IN TYPE_OF_OPEN TypeOfOpen
,
94 IN ULONG UserCcbFlags
,
95 IN ACCESS_MASK DesiredAccess
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)
111 IN PIRP_CONTEXT IrpContext
,
119 This is the common routine for opening a file called by both the
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.
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
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.
144 Irp - Supplies the Irp to process
148 NTSTATUS - This is the status from this open operation.
153 NTSTATUS Status
= STATUS_SUCCESS
;
154 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
156 PFILE_OBJECT FileObject
;
158 COMPOUND_PATH_ENTRY CompoundPathEntry
;
159 BOOLEAN CleanupCompoundPathEntry
= FALSE
;
161 FILE_ENUM_CONTEXT FileContext
;
162 BOOLEAN CleanupFileContext
= FALSE
;
167 BOOLEAN OpenByFileId
;
169 ULONG CreateDisposition
;
171 BOOLEAN ShortNameMatch
;
172 ULONG ShortNameDirentOffset
;
174 BOOLEAN VolumeOpen
= FALSE
;
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.
182 // CurrentFcb - represents this point. If non-null it means we have
183 // acquired it and need to release it in finally clause.
185 // NextFcb - represents the NextFcb to walk to but haven't acquired yet.
188 TYPE_OF_OPEN RelatedTypeOfOpen
= UnopenedFileObject
;
189 PFILE_OBJECT RelatedFileObject
;
190 PCCB RelatedCcb
= NULL
;
193 PFCB CurrentFcb
= NULL
;
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
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.
208 // RelatedFileName - Pointer to the name in the related file object.
210 // RemainingName - String containing remaining name to parse.
212 // MatchingName - Address of name structure in FileContext which matched.
213 // We need this to know whether we matched the long or short name.
216 PUNICODE_STRING FileName
;
217 PUNICODE_STRING RelatedFileName
= NULL
;
219 CD_NAME RemainingName
;
221 PCD_NAME MatchingName
;
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.
230 if (IrpContext
->Vcb
== NULL
) {
232 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
233 return STATUS_SUCCESS
;
237 // Get create parameters from the Irp.
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;
245 // Do some preliminary checks to make sure the operation is supported.
246 // We fail in the following cases immediately.
248 // - Open a paging file.
249 // - Open a target directory.
250 // - Open a file with Eas.
254 if (FlagOn( IrpSp
->Flags
, SL_OPEN_PAGING_FILE
| SL_OPEN_TARGET_DIRECTORY
) ||
255 (IrpSp
->Parameters
.Create
.EaLength
!= 0) ||
256 (CreateDisposition
== FILE_CREATE
)) {
258 CdCompleteRequest( IrpContext
, Irp
, STATUS_ACCESS_DENIED
);
259 return STATUS_ACCESS_DENIED
;
263 // Copy the Vcb to a local. Assume the starting directory is the root.
266 Vcb
= IrpContext
->Vcb
;
267 NextFcb
= Vcb
->RootIndexFcb
;
270 // Reference our input parameters to make things easier
273 FileObject
= IrpSp
->FileObject
;
274 RelatedFileObject
= NULL
;
276 FileName
= &FileObject
->FileName
;
279 // Set up the file object's Vpb pointer in case anything happens.
280 // This will allow us to get a reasonable pop-up.
283 if ((FileObject
->RelatedFileObject
!= NULL
) && !OpenByFileId
) {
285 RelatedFileObject
= FileObject
->RelatedFileObject
;
286 FileObject
->Vpb
= RelatedFileObject
->Vpb
;
288 RelatedTypeOfOpen
= CdDecodeFileObject( IrpContext
, RelatedFileObject
, &NextFcb
, &RelatedCcb
);
291 // Fail the request if this is not a user file object.
294 if (RelatedTypeOfOpen
< UserVolumeOpen
) {
296 CdCompleteRequest( IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
297 return STATUS_INVALID_PARAMETER
;
301 // Remember the name in the related file object.
304 RelatedFileName
= &RelatedFileObject
->FileName
;
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.
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
319 Status
= CdNormalizeFileNames( IrpContext
,
330 // Return the error code if not successful.
333 if (!NT_SUCCESS( Status
)) {
335 CdCompleteRequest( IrpContext
, Irp
, Status
);
340 // We want to acquire the Vcb. Exclusively for a volume open, shared otherwise.
341 // The file name is empty for a volume open.
344 if ((FileName
->Length
== 0) &&
345 (RelatedTypeOfOpen
<= UserVolumeOpen
) &&
349 CdAcquireVcbExclusive( IrpContext
, Vcb
, FALSE
);
353 CdAcquireVcbShared( IrpContext
, Vcb
, FALSE
);
357 // Use a try-finally to facilitate cleanup.
363 // Verify that the Vcb is not in an unusable condition. This routine
364 // will raise if not usable.
367 CdVerifyVcb( IrpContext
, Vcb
);
370 // If the Vcb is locked then we cannot open another file
373 if (FlagOn( Vcb
->VcbState
, VCB_STATE_LOCKED
)) {
375 try_return( Status
= STATUS_ACCESS_DENIED
);
379 // If we are opening this file by FileId then process this immediately
386 // We only allow Dasd opens of audio disks. Fail this request at
390 if (FlagOn( Vcb
->VcbState
, VCB_STATE_AUDIO_DISK
)) {
392 try_return( Status
= STATUS_INVALID_DEVICE_REQUEST
);
396 // The only create disposition we allow is OPEN.
399 if ((CreateDisposition
!= FILE_OPEN
) &&
400 (CreateDisposition
!= FILE_OPEN_IF
)) {
402 try_return( Status
= STATUS_ACCESS_DENIED
);
406 // Make sure we can wait for this request.
409 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
411 CdRaiseStatus( IrpContext
, STATUS_CANT_WAIT
);
414 try_return( Status
= CdOpenByFileId( IrpContext
,
421 // If we are opening this volume Dasd then process this immediately
428 // The only create disposition we allow is OPEN.
431 if ((CreateDisposition
!= FILE_OPEN
) &&
432 (CreateDisposition
!= FILE_OPEN_IF
)) {
434 try_return( Status
= STATUS_ACCESS_DENIED
);
438 // If they wanted to open a directory, surprise.
441 if (FlagOn( IrpSp
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
)) {
443 try_return( Status
= STATUS_NOT_A_DIRECTORY
);
447 // Acquire the Fcb first.
450 CurrentFcb
= Vcb
->VolumeDasdFcb
;
451 CdAcquireFcbExclusive( IrpContext
, CurrentFcb
, FALSE
);
453 try_return( Status
= CdOpenExistingFcb( IrpContext
,
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
467 CdAcquireFcbExclusive( IrpContext
, NextFcb
, FALSE
);
468 CurrentFcb
= NextFcb
;
471 // Do a prefix search if there is more of the name to parse.
474 if (RemainingName
.FileName
.Length
!= 0) {
477 // Do the prefix search to find the longest matching name.
480 CdFindPrefix( IrpContext
,
482 &RemainingName
.FileName
,
487 // If the remaining name length is zero then we have found our
491 if (RemainingName
.FileName
.Length
== 0) {
494 // If this is a file so verify the user didn't want to open
498 if (SafeNodeType( CurrentFcb
) == CDFS_NTC_FCB_DATA
) {
500 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH
) ||
501 FlagOn( IrpSp
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
)) {
503 try_return( Status
= STATUS_NOT_A_DIRECTORY
);
507 // The only create disposition we allow is OPEN.
510 if ((CreateDisposition
!= FILE_OPEN
) &&
511 (CreateDisposition
!= FILE_OPEN_IF
)) {
513 try_return( Status
= STATUS_ACCESS_DENIED
);
516 try_return( Status
= CdOpenExistingFcb( IrpContext
,
524 // This is a directory. Verify the user didn't want to open
528 } else if (FlagOn( IrpSp
->Parameters
.Create
.Options
, FILE_NON_DIRECTORY_FILE
)) {
530 try_return( Status
= STATUS_FILE_IS_A_DIRECTORY
);
533 // Open the file as a directory.
539 // The only create disposition we allow is OPEN.
542 if ((CreateDisposition
!= FILE_OPEN
) &&
543 (CreateDisposition
!= FILE_OPEN_IF
)) {
545 try_return( Status
= STATUS_ACCESS_DENIED
);
548 try_return( Status
= CdOpenExistingFcb( IrpContext
,
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.
564 // Our starting Fcb better be a directory.
567 if (!FlagOn( CurrentFcb
->FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
)) {
569 try_return( Status
= STATUS_OBJECT_PATH_NOT_FOUND
);
573 // If we can't wait then post this request.
576 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
578 CdRaiseStatus( IrpContext
, STATUS_CANT_WAIT
);
582 // Make sure the final name has no version string.
585 FinalName
.VersionString
.Length
= 0;
589 ShortNameMatch
= FALSE
;
592 // Split off the next component from the name.
595 CdDissectName( IrpContext
,
596 &RemainingName
.FileName
,
597 &FinalName
.FileName
);
600 // Go ahead and look this entry up in the path table.
603 CdInitializeCompoundPathEntry( IrpContext
, &CompoundPathEntry
);
604 CleanupCompoundPathEntry
= TRUE
;
606 FoundEntry
= CdFindPathEntry( IrpContext
,
610 &CompoundPathEntry
);
613 // If we didn't find the entry then check if the current name
614 // is a possible short name.
619 ShortNameDirentOffset
= CdShortNameDirentOffset( IrpContext
, &FinalName
.FileName
);
622 // If there is an embedded short name offset then look for the
623 // matching long name in the directory.
626 if (ShortNameDirentOffset
!= MAXULONG
) {
628 if (CleanupFileContext
) {
630 CdCleanupFileContext( IrpContext
, &FileContext
);
633 CdInitializeFileContext( IrpContext
, &FileContext
);
634 CleanupFileContext
= TRUE
;
636 FoundEntry
= CdFindFileByShortName( IrpContext
,
640 ShortNameDirentOffset
,
644 // If we found an entry and it is a directory then look
645 // this up in the path table.
650 ShortNameMatch
= TRUE
;
652 if (FlagOn( FileContext
.InitialDirent
->Dirent
.DirentFlags
,
653 CD_ATTRIBUTE_DIRECTORY
)) {
655 CdCleanupCompoundPathEntry( IrpContext
, &CompoundPathEntry
);
656 CdInitializeCompoundPathEntry( IrpContext
, &CompoundPathEntry
);
658 FoundEntry
= CdFindPathEntry( IrpContext
,
660 &FileContext
.InitialDirent
->Dirent
.CdCaseFileName
,
662 &CompoundPathEntry
);
665 // We better find this entry.
670 CdRaiseStatus( IrpContext
, STATUS_FILE_CORRUPT_ERROR
);
674 // Upcase the name with the short name if case
680 CdUpcaseName( IrpContext
, &FinalName
, &FinalName
);
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.
689 } else if (RemainingName
.FileName
.Length
== 0) {
692 // Break out of the loop. We will process the dirent
696 MatchingName
= &FileContext
.ShortName
;
701 try_return( Status
= STATUS_OBJECT_PATH_NOT_FOUND
);
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
715 if (RemainingName
.FileName
.Length
== 0) {
720 // Otherwise this path could not be cracked.
725 try_return( Status
= STATUS_OBJECT_PATH_NOT_FOUND
);
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.
736 if (IgnoreCase
&& !ShortNameMatch
) {
738 RtlCopyMemory( FinalName
.FileName
.Buffer
,
739 CompoundPathEntry
.PathEntry
.CdDirName
.FileName
.Buffer
,
740 CompoundPathEntry
.PathEntry
.CdDirName
.FileName
.Length
);
744 // If we have found the last component then open this as a directory
745 // and return to our caller.
748 if (RemainingName
.FileName
.Length
== 0) {
750 if (FlagOn( IrpSp
->Parameters
.Create
.Options
, FILE_NON_DIRECTORY_FILE
)) {
752 try_return( Status
= STATUS_FILE_IS_A_DIRECTORY
);
756 // The only create disposition we allow is OPEN.
759 if ((CreateDisposition
!= FILE_OPEN
) &&
760 (CreateDisposition
!= FILE_OPEN_IF
)) {
762 try_return( Status
= STATUS_ACCESS_DENIED
);
765 try_return( Status
= CdOpenDirectoryFromPathEntry( IrpContext
,
772 &CompoundPathEntry
.PathEntry
,
778 // Otherwise open an Fcb for this intermediate index Fcb.
781 CdOpenDirectoryFromPathEntry( IrpContext
,
788 &CompoundPathEntry
.PathEntry
,
792 CdCleanupCompoundPathEntry( IrpContext
, &CompoundPathEntry
);
793 CleanupCompoundPathEntry
= FALSE
;
797 // We need to scan the current directory for a matching file name
798 // if we don't already have one.
803 if (CleanupFileContext
) {
805 CdCleanupFileContext( IrpContext
, &FileContext
);
808 CdInitializeFileContext( IrpContext
, &FileContext
);
809 CleanupFileContext
= TRUE
;
812 // Split our search name into separate components.
815 CdConvertNameToCdName( IrpContext
, &FinalName
);
817 FoundEntry
= CdFindFile( IrpContext
,
826 // If we didn't find a match then check if the name is invalid to
827 // determine which error code to return.
832 if ((CreateDisposition
== FILE_OPEN
) ||
833 (CreateDisposition
== FILE_OVERWRITE
)) {
835 try_return( Status
= STATUS_OBJECT_NAME_NOT_FOUND
);
839 // Any other operation return STATUS_ACCESS_DENIED.
842 try_return( Status
= STATUS_ACCESS_DENIED
);
846 // If this is a directory then the disk is corrupt because it wasn't
847 // in the Path Table.
850 if (FlagOn( FileContext
.InitialDirent
->Dirent
.Flags
, CD_ATTRIBUTE_DIRECTORY
)) {
852 CdRaiseStatus( IrpContext
, STATUS_DISK_CORRUPT_ERROR
);
856 // Make sure our opener didn't want a directory.
859 if (FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH
) ||
860 FlagOn( IrpSp
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
)) {
862 try_return( Status
= STATUS_NOT_A_DIRECTORY
);
866 // The only create disposition we allow is OPEN.
869 if ((CreateDisposition
!= FILE_OPEN
) &&
870 (CreateDisposition
!= FILE_OPEN_IF
)) {
872 try_return( Status
= STATUS_ACCESS_DENIED
);
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.
883 RtlCopyMemory( FinalName
.FileName
.Buffer
,
884 MatchingName
->FileName
.Buffer
,
885 MatchingName
->FileName
.Length
);
889 // Open the file using the file context. We already have the
890 // first and last dirents.
893 try_return( Status
= CdOpenFileFromFileContext( IrpContext
,
899 (BOOLEAN
) (MatchingName
== &FileContext
.ShortName
),
907 // Cleanup the PathEntry if initialized.
910 if (CleanupCompoundPathEntry
) {
912 CdCleanupCompoundPathEntry( IrpContext
, &CompoundPathEntry
);
916 // Cleanup the FileContext if initialized.
919 if (CleanupFileContext
) {
921 CdCleanupFileContext( IrpContext
, &FileContext
);
925 // The result of this open could be success, pending or some error
929 if (_SEH2_AbnormalTermination()) {
933 // In the error path we start by calling our teardown routine if we
934 // have a CurrentFcb.
937 if (CurrentFcb
!= NULL
) {
941 CdTeardownStructures( IrpContext
, CurrentFcb
, &RemovedFcb
);
950 // No need to complete the request.
957 // If we posted this request through the oplock package we need
958 // to show that there is no reason to complete the request.
961 } else if (Status
== STATUS_PENDING
) {
968 // Release the Current Fcb if still acquired.
971 if (CurrentFcb
!= NULL
) {
973 CdReleaseFcb( IrpContext
, CurrentFcb
);
980 CdReleaseVcb( IrpContext
, Vcb
);
983 // Call our completion routine. It will handle the case where either
984 // the Irp and/or IrpContext are gone.
987 CdCompleteRequest( IrpContext
, Irp
, Status
);
995 // Local support routine
999 CdNormalizeFileNames (
1000 IN PIRP_CONTEXT IrpContext
,
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
1013 Routine Description:
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.
1023 Vcb - Vcb for this volume.
1025 OpenByFileId - Indicates if the filename should be a 64 bit FileId.
1027 IgnoreCase - Indicates if this open is a case-insensitive operation.
1029 RelatedTypeOfOpen - Indicates the type of the related file object.
1031 RelatedCcb - Ccb for the related open. Ignored if no relative open.
1033 RelatedFileName - FileName buffer for related open. Ignored if no
1036 FileName - FileName to update in this routine. The name should
1037 either be a 64-bit FileId or a Unicode string.
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.
1045 NTSTATUS - STATUS_SUCCESS if the names are OK, appropriate error code
1051 ULONG RemainingNameLength
;
1052 ULONG RelatedNameLength
= 0;
1053 ULONG SeparatorLength
= 0;
1057 UNICODE_STRING NewFileName
;
1062 // If this is the first pass then we need to build the full name and
1063 // check for name compatibility.
1066 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FULL_NAME
)) {
1069 // Deal with the regular file name case first.
1072 if (!OpenByFileId
) {
1075 // This is here because the Win32 layer can't avoid sending me double
1076 // beginning backslashes.
1079 if ((FileName
->Length
> sizeof( WCHAR
)) &&
1080 (FileName
->Buffer
[1] == L
'\\') &&
1081 (FileName
->Buffer
[0] == L
'\\')) {
1084 // If there are still two beginning backslashes, the name is bogus.
1087 if ((FileName
->Length
> 2 * sizeof( WCHAR
)) &&
1088 (FileName
->Buffer
[2] == L
'\\')) {
1090 return STATUS_OBJECT_NAME_INVALID
;
1094 // Slide the name down in the buffer.
1097 FileName
->Length
-= sizeof( WCHAR
);
1099 RtlMoveMemory( FileName
->Buffer
,
1100 FileName
->Buffer
+ 1,
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.
1109 if (((FileName
->Length
> sizeof( WCHAR
)) ||
1110 ((FileName
->Length
== sizeof( WCHAR
)) && (RelatedTypeOfOpen
== UserDirectoryOpen
))) &&
1111 (FileName
->Buffer
[ (FileName
->Length
/2) - 1 ] == L
'\\')) {
1113 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH
);
1114 FileName
->Length
-= sizeof( WCHAR
);
1118 // Remember the length we need for this portion of the name.
1121 RemainingNameLength
= FileName
->Length
;
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.
1128 if (RelatedTypeOfOpen
!= UnopenedFileObject
) {
1131 // If the filename length was zero then it must be legal.
1132 // If there are characters then check with the related
1136 if (FileName
->Length
!= 0) {
1139 // The name length must always be zero for a volume open.
1142 if (RelatedTypeOfOpen
<= UserVolumeOpen
) {
1144 return STATUS_INVALID_PARAMETER
;
1147 // The remaining name cannot begin with a backslash.
1150 } else if (FileName
->Buffer
[0] == L
'\\' ) {
1152 return STATUS_INVALID_PARAMETER
;
1155 // If the related file is a user file then there
1156 // is no file with this path.
1159 } else if (RelatedTypeOfOpen
== UserFileOpen
) {
1161 return STATUS_OBJECT_PATH_NOT_FOUND
;
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
1172 if (!FlagOn( RelatedCcb
->Flags
, CCB_FLAG_OPEN_BY_ID
)) {
1175 // Add a separator if the name length is non-zero
1176 // unless the relative Fcb is at the root.
1179 if ((FileName
->Length
!= 0) &&
1180 (RelatedCcb
->Fcb
!= Vcb
->RootIndexFcb
)) {
1182 SeparatorLength
= sizeof( WCHAR
);
1185 RelatedNameLength
= RelatedFileName
->Length
;
1189 // The full name is already in the filename. It must either
1190 // be length 0 or begin with a backslash.
1193 } else if (FileName
->Length
!= 0) {
1195 if (FileName
->Buffer
[0] != L
'\\') {
1197 return STATUS_INVALID_PARAMETER
;
1201 // We will want to trim the leading backslash from the
1202 // remaining name we return.
1205 RemainingNameLength
-= sizeof( WCHAR
);
1206 SeparatorLength
= sizeof( WCHAR
);
1210 // Now see if the buffer is large enough to hold the full name.
1213 BufferLength
= RelatedNameLength
+ SeparatorLength
+ RemainingNameLength
;
1216 // Check for an overflow of the maximum filename size.
1219 if (BufferLength
> MAXUSHORT
) {
1221 return STATUS_INVALID_PARAMETER
;
1225 // Now see if we need to allocate a new buffer.
1228 if (FileName
->MaximumLength
< BufferLength
) {
1230 NewFileName
.Buffer
= FsRtlAllocatePoolWithTag( CdPagedPool
,
1234 NewFileName
.MaximumLength
= (USHORT
) BufferLength
;
1238 NewFileName
.Buffer
= FileName
->Buffer
;
1239 NewFileName
.MaximumLength
= FileName
->MaximumLength
;
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
1248 if (RelatedNameLength
!= 0) {
1251 // Store the remaining name in its correct position.
1254 if (RemainingNameLength
!= 0) {
1256 RtlMoveMemory( Add2Ptr( NewFileName
.Buffer
, RelatedNameLength
+ SeparatorLength
, PVOID
),
1258 RemainingNameLength
);
1261 RtlCopyMemory( NewFileName
.Buffer
,
1262 RelatedFileName
->Buffer
,
1263 RelatedNameLength
);
1266 // Add the separator if needed.
1269 if (SeparatorLength
!= 0) {
1271 *(Add2Ptr( NewFileName
.Buffer
, RelatedNameLength
, PWCHAR
)) = L
'\\';
1275 // Update the filename value we got from the user.
1278 if (NewFileName
.Buffer
!= FileName
->Buffer
) {
1280 if (FileName
->Buffer
!= NULL
) {
1282 CdFreePool( &FileName
->Buffer
);
1285 FileName
->Buffer
= NewFileName
.Buffer
;
1286 FileName
->MaximumLength
= NewFileName
.MaximumLength
;
1290 // Copy the name length to the user's filename.
1293 FileName
->Length
= (USHORT
) (RelatedNameLength
+ SeparatorLength
+ RemainingNameLength
);
1297 // Now update the remaining name to parse.
1300 RemainingName
->FileName
.MaximumLength
=
1301 RemainingName
->FileName
.Length
= (USHORT
) RemainingNameLength
;
1302 RemainingName
->VersionString
.Length
= 0;
1304 RemainingName
->FileName
.Buffer
= Add2Ptr( FileName
->Buffer
,
1305 RelatedNameLength
+ SeparatorLength
,
1309 // Upcase the name if necessary.
1312 if (IgnoreCase
&& (RemainingNameLength
!= 0)) {
1314 CdUpcaseName( IrpContext
,
1320 // Do a quick check to make sure there are no wildcards.
1323 if (FsRtlDoesNameContainWildCards( &RemainingName
->FileName
)) {
1325 return STATUS_OBJECT_NAME_INVALID
;
1329 // For the open by file Id case we verify the name really contains
1336 // Check for validity of the buffer.
1339 if (FileName
->Length
!= sizeof( FILE_ID
)) {
1341 return STATUS_INVALID_PARAMETER
;
1345 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_FULL_NAME
);
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
1357 // Assume there is no relative name.
1360 RemainingName
->FileName
= *FileName
;
1361 RemainingName
->VersionString
.Length
= 0;
1364 // Nothing to do if the name length is zero.
1367 if (RemainingName
->FileName
.Length
!= 0) {
1370 // If there is a relative name then we need to walk past it.
1373 if (RelatedTypeOfOpen
!= UnopenedFileObject
) {
1376 // Nothing to walk past if the RelatedCcb is opened by FileId.
1380 if (!FlagOn( RelatedCcb
->Flags
, CCB_FLAG_OPEN_BY_ID
)) {
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.
1388 RemainingName
->FileName
.Buffer
= Add2Ptr( RemainingName
->FileName
.Buffer
,
1389 RelatedFileName
->Length
,
1392 RemainingName
->FileName
.Length
-= RelatedFileName
->Length
;
1397 // If we are pointing at a separator character then step past that.
1400 if (RemainingName
->FileName
.Length
!= 0) {
1402 if (*(RemainingName
->FileName
.Buffer
) == L
'\\') {
1404 RemainingName
->FileName
.Buffer
= Add2Ptr( RemainingName
->FileName
.Buffer
,
1408 RemainingName
->FileName
.Length
-= sizeof( WCHAR
);
1414 // Upcase the name if necessary.
1417 if (IgnoreCase
&& (RemainingName
->FileName
.Length
!= 0)) {
1419 CdUpcaseName( IrpContext
,
1425 return STATUS_SUCCESS
;
1430 // Local support routine
1435 IN PIRP_CONTEXT IrpContext
,
1436 IN PIO_STACK_LOCATION IrpSp
,
1438 IN OUT PFCB
*CurrentFcb
1443 Routine Description:
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.
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.
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.
1456 If found then build the Fcb from this entry and store the new Fcb in the
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
1463 Finally we call our worker routine to complete the open on this Fcb.
1467 IrpSp - Stack location within the create Irp.
1469 Vcb - Vcb for this volume.
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.
1477 NTSTATUS - Status indicating the result of the operation.
1482 NTSTATUS Status
= STATUS_ACCESS_DENIED
;
1484 BOOLEAN UnlockVcb
= FALSE
;
1489 NODE_TYPE_CODE NodeTypeCode
;
1490 TYPE_OF_OPEN TypeOfOpen
;
1492 FILE_ENUM_CONTEXT FileContext
;
1493 BOOLEAN CleanupFileContext
= FALSE
;
1495 COMPOUND_PATH_ENTRY CompoundPathEntry
;
1496 BOOLEAN CleanupCompoundPathEntry
= FALSE
;
1499 FILE_ID ParentFileId
;
1506 // Extract the FileId from the FileObject.
1509 RtlCopyMemory( &FileId
, IrpSp
->FileObject
->FileName
.Buffer
, sizeof( FILE_ID
));
1512 // Use a try-finally to facilitate cleanup.
1518 // Go ahead and figure out the TypeOfOpen and NodeType. We can
1519 // get these from the input FileId.
1522 if (CdFidIsDirectory( FileId
)) {
1524 TypeOfOpen
= UserDirectoryOpen
;
1525 NodeTypeCode
= CDFS_NTC_FCB_INDEX
;
1528 // If the offset isn't zero then the file Id is bad.
1531 if (CdQueryFidDirentOffset( FileId
) != 0) {
1533 try_return( Status
= STATUS_INVALID_PARAMETER
);
1538 TypeOfOpen
= UserFileOpen
;
1539 NodeTypeCode
= CDFS_NTC_FCB_DATA
;
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.
1549 CdLockVcb( IrpContext
, Vcb
);
1552 NextFcb
= CdLookupFcbTable( IrpContext
, Vcb
, FileId
);
1554 if (NextFcb
== NULL
) {
1557 // Get the path table offset from the file id.
1560 StreamOffset
= CdQueryFidPathTableOffset( FileId
);
1563 // Build the parent FileId for this and try looking it
1564 // up in the PathTable.
1567 CdSetFidDirentOffset( ParentFileId
, 0 );
1568 CdSetFidPathTableOffset( ParentFileId
, StreamOffset
);
1569 CdFidSetDirectory( ParentFileId
);
1571 NextFcb
= CdLookupFcbTable( IrpContext
, Vcb
, ParentFileId
);
1574 // If not present then walk through the PathTable to this point.
1577 if (NextFcb
== NULL
) {
1579 CdUnlockVcb( IrpContext
, Vcb
);
1583 // Check that the path table offset lies within the path
1587 if (StreamOffset
> Vcb
->PathTableFcb
->FileSize
.LowPart
) {
1589 try_return( Status
= STATUS_INVALID_PARAMETER
);
1592 CdInitializeCompoundPathEntry( IrpContext
, &CompoundPathEntry
);
1593 CleanupCompoundPathEntry
= TRUE
;
1596 // Start at the first entry in the PathTable.
1599 CdLookupPathEntry( IrpContext
,
1600 Vcb
->PathTableFcb
->StreamOffset
,
1603 &CompoundPathEntry
);
1606 // Continue looking until we have passed our target offset.
1612 // Move to the next entry.
1615 Found
= CdLookupNextPathEntry( IrpContext
,
1616 &CompoundPathEntry
.PathContext
,
1617 &CompoundPathEntry
.PathEntry
);
1620 // If we didn't find the entry or are beyond it then the
1621 // input Id is invalid.
1625 (CompoundPathEntry
.PathEntry
.PathTableOffset
> StreamOffset
)) {
1627 try_return( Status
= STATUS_INVALID_PARAMETER
);
1632 // If the FileId specified a directory then we have found
1633 // the entry. Make sure our caller wanted to open a directory.
1636 if ((TypeOfOpen
== UserDirectoryOpen
) &&
1637 FlagOn( IrpSp
->Parameters
.Create
.Options
, FILE_NON_DIRECTORY_FILE
)) {
1639 try_return( Status
= STATUS_FILE_IS_A_DIRECTORY
);
1643 // Lock the Vcb and create the Fcb if necessary.
1646 CdLockVcb( IrpContext
, Vcb
);
1649 NextFcb
= CdCreateFcb( IrpContext
, ParentFileId
, NodeTypeCode
, &Found
);
1652 // It's possible that someone got in here ahead of us.
1657 CdInitializeFcbFromPathEntry( IrpContext
,
1660 &CompoundPathEntry
.PathEntry
);
1664 // If the user wanted to open a directory then we have found
1665 // it. Store this Fcb into the CurrentFcb and skip the
1669 if (TypeOfOpen
== UserDirectoryOpen
) {
1671 *CurrentFcb
= NextFcb
;
1677 // Perform the directory scan if we don't already have our target.
1680 if (NextFcb
!= NULL
) {
1683 // Acquire the parent. We currently own the Vcb lock so
1684 // do this without waiting first.
1687 if (!CdAcquireFcbExclusive( IrpContext
,
1691 NextFcb
->FcbReference
+= 1;
1692 CdUnlockVcb( IrpContext
, Vcb
);
1694 CdAcquireFcbExclusive( IrpContext
, NextFcb
, FALSE
);
1696 CdLockVcb( IrpContext
, Vcb
);
1697 NextFcb
->FcbReference
-= 1;
1698 CdUnlockVcb( IrpContext
, Vcb
);
1702 CdUnlockVcb( IrpContext
, Vcb
);
1708 // Set up the CurrentFcb pointers. We know there was
1709 // no previous parent in this case.
1712 *CurrentFcb
= NextFcb
;
1715 // Calculate the offset in the stream.
1718 StreamOffset
= CdQueryFidDirentOffset( FileId
);
1721 // Create the stream file if it doesn't exist. This will update
1722 // the Fcb with the size from the self entry.
1725 if (NextFcb
->FileObject
== NULL
) {
1727 CdCreateInternalStream( IrpContext
, Vcb
, NextFcb
);
1731 // If our offset is beyond the end of the directory then the
1732 // FileId is invalid.
1735 if (StreamOffset
> NextFcb
->FileSize
.LowPart
) {
1737 try_return( Status
= STATUS_INVALID_PARAMETER
);
1741 // Otherwise position ourselves at the self entry and walk
1742 // through dirent by dirent until this location is found.
1745 CdInitializeFileContext( IrpContext
, &FileContext
);
1746 CdLookupInitialFileDirent( IrpContext
,
1749 NextFcb
->StreamOffset
);
1751 CleanupFileContext
= TRUE
;
1756 // Move to the first entry of the next file.
1759 Found
= CdLookupNextInitialFileDirent( IrpContext
,
1764 // If we didn't find the entry or are beyond it then the
1765 // input Id is invalid.
1769 (FileContext
.InitialDirent
->Dirent
.DirentOffset
> StreamOffset
)) {
1771 try_return( Status
= STATUS_INVALID_PARAMETER
);
1776 // This better not be a directory. Directory FileIds must
1777 // refer to the self entry for directories.
1780 if (FlagOn( FileContext
.InitialDirent
->Dirent
.DirentFlags
,
1781 CD_ATTRIBUTE_DIRECTORY
)) {
1783 try_return( Status
= STATUS_INVALID_PARAMETER
);
1787 // Check that our caller wanted to open a file.
1790 if (FlagOn( IrpSp
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
)) {
1792 try_return( Status
= STATUS_NOT_A_DIRECTORY
);
1796 // Otherwise we want to collect all of the dirents for this file
1797 // and create an Fcb with this.
1800 CdLookupLastFileDirent( IrpContext
, NextFcb
, &FileContext
);
1802 CdLockVcb( IrpContext
, Vcb
);
1805 NextFcb
= CdCreateFcb( IrpContext
, FileId
, NodeTypeCode
, &Found
);
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.
1816 CdInitializeFcbFromFileContext( IrpContext
,
1824 // We have the Fcb. Check that the type of the file is compatible with
1825 // the desired type of file to open.
1830 if (FlagOn( NextFcb
->FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
)) {
1832 if (FlagOn( IrpSp
->Parameters
.Create
.Options
, FILE_NON_DIRECTORY_FILE
)) {
1834 try_return( Status
= STATUS_FILE_IS_A_DIRECTORY
);
1837 } else if (FlagOn( IrpSp
->Parameters
.Create
.Options
, FILE_DIRECTORY_FILE
)) {
1839 try_return( Status
= STATUS_NOT_A_DIRECTORY
);
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.
1849 if (*CurrentFcb
!= NULL
) {
1851 CdReleaseFcb( IrpContext
, *CurrentFcb
);
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.
1861 if (!CdAcquireFcbExclusive( IrpContext
, NextFcb
, TRUE
)) {
1863 NextFcb
->FcbReference
+= 1;
1865 CdUnlockVcb( IrpContext
, Vcb
);
1867 CdAcquireFcbExclusive( IrpContext
, NextFcb
, FALSE
);
1869 CdLockVcb( IrpContext
, Vcb
);
1870 NextFcb
->FcbReference
-= 1;
1871 CdUnlockVcb( IrpContext
, Vcb
);
1875 CdUnlockVcb( IrpContext
, Vcb
);
1881 // Move to this Fcb.
1884 *CurrentFcb
= NextFcb
;
1887 // Check the requested access on this Fcb.
1890 if (!CdIllegalFcbAccess( IrpContext
,
1892 IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
)) {
1895 // Call our worker routine to complete the open.
1898 Status
= CdCompleteFcbOpen( IrpContext
,
1903 CCB_FLAG_OPEN_BY_ID
,
1904 IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
1912 CdUnlockVcb( IrpContext
, Vcb
);
1915 if (CleanupFileContext
) {
1917 CdCleanupFileContext( IrpContext
, &FileContext
);
1920 if (CleanupCompoundPathEntry
) {
1922 CdCleanupCompoundPathEntry( IrpContext
, &CompoundPathEntry
);
1931 // Local support routine
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
1946 Routine Description:
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.
1954 IrpSp - Pointer to the stack location for this open.
1956 CurrentFcb - Address of Fcb to open. We will clear this if the Fcb
1959 TypeOfOpen - Indicates whether we are opening a file, directory or volume.
1961 IgnoreCase - Indicates if this open is case-insensitive.
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
1970 NTSTATUS - Status indicating the result of the operation.
1977 NTSTATUS Status
= STATUS_ACCESS_DENIED
;
1982 // Check that the desired access is legal.
1985 if (!CdIllegalFcbAccess( IrpContext
,
1987 IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
)) {
1990 // Set the Ignore case.
1995 SetFlag( CcbFlags
, CCB_FLAG_IGNORE_CASE
);
1999 // Check the related Ccb to see if this was an OpenByFileId and
2000 // whether there was a version.
2003 if (ARGUMENT_PRESENT( RelatedCcb
)) {
2005 SetFlag( CcbFlags
, FlagOn( RelatedCcb
->Flags
, CCB_FLAG_OPEN_WITH_VERSION
));
2008 if (FlagOn( RelatedCcb
->Flags
, CCB_FLAG_OPEN_BY_ID
| CCB_FLAG_OPEN_RELATIVE_BY_ID
)) {
2010 SetFlag( CcbFlags
, CCB_FLAG_OPEN_RELATIVE_BY_ID
);
2015 // Call our worker routine to complete the open.
2018 Status
= CdCompleteFcbOpen( IrpContext
,
2024 IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
2032 // Local support routine
2036 CdOpenDirectoryFromPathEntry (
2037 IN PIRP_CONTEXT IrpContext
,
2038 IN PIO_STACK_LOCATION IrpSp
,
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
2051 Routine Description:
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
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.
2064 Next we will add this to the prefix table of our parent if needed.
2066 Once we know that the new Fcb has been initialized then we move our pointer
2067 in the tree down to this position.
2069 This routine does not own the Vcb lock on entry. We must be sure to release
2074 IrpSp - Stack location for this request.
2076 Vcb - Vcb for this volume.
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.
2081 DirName - This is always the exact name used to reach this file.
2083 IgnoreCase - Indicates the type of case match for the open.
2085 ShortNameMatch - Indicates if we are opening via the short name.
2087 PathEntry - Path entry for the entry found.
2089 PerformUserOpen - TRUE if we are to open this for a user, FALSE otherwise.
2091 RelatedCcb - RelatedCcb for relative file object used to make this open.
2095 NTSTATUS - Status indicating the result of the operation.
2103 BOOLEAN UnlockVcb
= FALSE
;
2107 PFCB ParentFcb
= NULL
;
2109 NTSTATUS Status
= STATUS_SUCCESS
; /* ReactOS Change: GCC uninitialized variable */
2114 // Check for illegal access to this file.
2117 if (PerformUserOpen
&&
2118 CdIllegalFcbAccess( IrpContext
,
2120 IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
)) {
2122 return STATUS_ACCESS_DENIED
;
2126 // Use a try-finally to facilitate cleanup.
2132 // Check the related Ccb to see if this was an OpenByFileId.
2135 if (ARGUMENT_PRESENT( RelatedCcb
) &&
2136 FlagOn( RelatedCcb
->Flags
, CCB_FLAG_OPEN_BY_ID
| CCB_FLAG_OPEN_RELATIVE_BY_ID
)) {
2138 CcbFlags
= CCB_FLAG_OPEN_RELATIVE_BY_ID
;
2143 SetFlag( CcbFlags
, CCB_FLAG_IGNORE_CASE
);
2147 // Build the file Id for this file.
2150 FileId
.QuadPart
= 0;
2151 CdSetFidPathTableOffset( FileId
, PathEntry
->PathTableOffset
);
2152 CdFidSetDirectory( FileId
);
2155 // Lock the Vcb so we can examine the Fcb Table.
2158 CdLockVcb( IrpContext
, Vcb
);
2162 // Get the Fcb for this directory.
2165 NextFcb
= CdCreateFcb( IrpContext
, FileId
, CDFS_NTC_FCB_INDEX
, &FcbExisted
);
2168 // If the Fcb was created here then initialize from the values in the
2169 // path table entry.
2174 CdInitializeFcbFromPathEntry( IrpContext
, NextFcb
, *CurrentFcb
, PathEntry
);
2178 // Now try to acquire the new Fcb without waiting. We will reference
2179 // the Fcb and retry with wait if unsuccessful.
2182 if (!CdAcquireFcbExclusive( IrpContext
, NextFcb
, TRUE
)) {
2184 NextFcb
->FcbReference
+= 1;
2186 CdUnlockVcb( IrpContext
, Vcb
);
2188 CdReleaseFcb( IrpContext
, *CurrentFcb
);
2189 CdAcquireFcbExclusive( IrpContext
, NextFcb
, FALSE
);
2190 CdAcquireFcbExclusive( IrpContext
, *CurrentFcb
, FALSE
);
2192 CdLockVcb( IrpContext
, Vcb
);
2193 NextFcb
->FcbReference
-= 1;
2194 CdUnlockVcb( IrpContext
, Vcb
);
2199 // Unlock the Vcb and move down to this new Fcb. Remember that we still
2200 // own the parent however.
2203 CdUnlockVcb( IrpContext
, Vcb
);
2208 ParentFcb
= *CurrentFcb
;
2209 *CurrentFcb
= NextFcb
;
2212 // Store this name into the prefix table for the parent.
2215 if (ShortNameMatch
) {
2218 // Make sure the exact case is always in the tree.
2221 CdInsertPrefix( IrpContext
,
2230 CdInsertPrefix( IrpContext
,
2241 // Make sure the exact case is always in the tree.
2244 CdInsertPrefix( IrpContext
,
2246 &PathEntry
->CdDirName
,
2253 CdInsertPrefix( IrpContext
,
2255 &PathEntry
->CdCaseDirName
,
2263 // Release the parent Fcb at this point.
2266 CdReleaseFcb( IrpContext
, ParentFcb
);
2270 // Call our worker routine to complete the open.
2273 if (PerformUserOpen
) {
2275 Status
= CdCompleteFcbOpen( IrpContext
,
2281 IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
2287 // Unlock the Vcb if held.
2292 CdUnlockVcb( IrpContext
, Vcb
);
2296 // Release the parent if held.
2299 if (ParentFcb
!= NULL
) {
2301 CdReleaseFcb( IrpContext
, ParentFcb
);
2310 // Local support routine
2314 CdOpenFileFromFileContext (
2315 IN PIRP_CONTEXT IrpContext
,
2316 IN PIO_STACK_LOCATION IrpSp
,
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
2328 Routine Description:
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
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.
2340 Next we will add this to the prefix table of our parent if needed.
2342 Once we know that the new Fcb has been initialized then we move our pointer
2343 in the tree down to this position.
2345 This routine does not own the Vcb lock on entry. We must be sure to release
2350 IrpSp - Stack location for this request.
2352 Vcb - Vcb for the current volume.
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.
2357 FileName - This is always the exact name used to reach this file.
2359 IgnoreCase - Indicates the type of case of CaseName above.
2361 ShortNameMatch - Indicates if we are opening via the short name.
2363 FileContext - This is the context used to find the file.
2365 RelatedCcb - RelatedCcb for relative file object used to make this open.
2369 NTSTATUS - Status indicating the result of the operation.
2377 BOOLEAN UnlockVcb
= FALSE
;
2381 PFCB ParentFcb
= NULL
;
2388 // Check for illegal access to this file.
2391 if (CdIllegalFcbAccess( IrpContext
,
2393 IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
)) {
2395 return STATUS_ACCESS_DENIED
;
2399 // Use a try-finally to facilitate cleanup.
2405 // Check if a version number was used to open this file.
2408 if (FileName
->VersionString
.Length
!= 0) {
2410 SetFlag( CcbFlags
, CCB_FLAG_OPEN_WITH_VERSION
);
2414 // Check the related Ccb to see if this was an OpenByFileId.
2417 if (ARGUMENT_PRESENT( RelatedCcb
) &&
2418 FlagOn( RelatedCcb
->Flags
, CCB_FLAG_OPEN_BY_ID
| CCB_FLAG_OPEN_RELATIVE_BY_ID
)) {
2420 SetFlag( CcbFlags
, CCB_FLAG_OPEN_RELATIVE_BY_ID
);
2425 SetFlag( CcbFlags
, CCB_FLAG_IGNORE_CASE
);
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.
2433 CdSetFidPathTableOffset( FileId
, CdQueryFidPathTableOffset( (*CurrentFcb
)->FileId
));
2434 CdSetFidDirentOffset( FileId
, FileContext
->InitialDirent
->Dirent
.DirentOffset
);
2437 // Lock the Vcb so we can examine the Fcb Table.
2440 CdLockVcb( IrpContext
, Vcb
);
2444 // Get the Fcb for this file.
2447 NextFcb
= CdCreateFcb( IrpContext
, FileId
, CDFS_NTC_FCB_DATA
, &FcbExisted
);
2450 // If the Fcb was created here then initialize from the values in the
2456 CdInitializeFcbFromFileContext( IrpContext
,
2463 // Now try to acquire the new Fcb without waiting. We will reference
2464 // the Fcb and retry with wait if unsuccessful.
2467 if (!CdAcquireFcbExclusive( IrpContext
, NextFcb
, TRUE
)) {
2469 NextFcb
->FcbReference
+= 1;
2471 CdUnlockVcb( IrpContext
, Vcb
);
2473 CdReleaseFcb( IrpContext
, *CurrentFcb
);
2474 CdAcquireFcbExclusive( IrpContext
, NextFcb
, FALSE
);
2475 CdAcquireFcbExclusive( IrpContext
, *CurrentFcb
, FALSE
);
2477 CdLockVcb( IrpContext
, Vcb
);
2478 NextFcb
->FcbReference
-= 1;
2479 CdUnlockVcb( IrpContext
, Vcb
);
2484 // Unlock the Vcb and move down to this new Fcb. Remember that we still
2485 // own the parent however.
2488 CdUnlockVcb( IrpContext
, Vcb
);
2493 ParentFcb
= *CurrentFcb
;
2494 *CurrentFcb
= NextFcb
;
2497 // Store this name into the prefix table for the parent.
2501 if (ShortNameMatch
) {
2504 // Make sure the exact case is always in the tree.
2507 CdInsertPrefix( IrpContext
,
2516 CdInsertPrefix( IrpContext
,
2525 // Insert this into the prefix table if we found this without
2526 // using a version string.
2529 } else if (FileName
->VersionString
.Length
== 0) {
2532 // Make sure the exact case is always in the tree.
2535 CdInsertPrefix( IrpContext
,
2537 &FileContext
->InitialDirent
->Dirent
.CdFileName
,
2544 CdInsertPrefix( IrpContext
,
2546 &FileContext
->InitialDirent
->Dirent
.CdCaseFileName
,
2554 // Release the parent Fcb at this point.
2557 CdReleaseFcb( IrpContext
, ParentFcb
);
2561 // Call our worker routine to complete the open.
2564 Status
= CdCompleteFcbOpen( IrpContext
,
2570 IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
2575 // Unlock the Vcb if held.
2580 CdUnlockVcb( IrpContext
, Vcb
);
2584 // Release the parent if held.
2587 if (ParentFcb
!= NULL
) {
2589 CdReleaseFcb( IrpContext
, ParentFcb
);
2598 // Local support routine
2603 IN PIRP_CONTEXT IrpContext
,
2604 PIO_STACK_LOCATION IrpSp
,
2606 IN OUT PFCB
*CurrentFcb
,
2607 IN TYPE_OF_OPEN TypeOfOpen
,
2608 IN ULONG UserCcbFlags
,
2609 IN ACCESS_MASK DesiredAccess
2614 Routine Description:
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
2623 IrpSp - Stack location for the current request.
2625 Vcb - Vcb for the current volume.
2627 CurrentFcb - Address of pointer to Fcb to open. We clear this field if
2628 we release the resource for this file.
2630 TypeOfOpen - Type of open for this request.
2632 UserCcbFlags - Flags to OR into the Ccb flags.
2634 DesiredAccess - Desired access for this open.
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.
2646 NTSTATUS OplockStatus
= STATUS_SUCCESS
;
2647 ULONG Information
= FILE_OPENED
;
2649 BOOLEAN LockVolume
= FALSE
;
2651 PFCB Fcb
= *CurrentFcb
;
2657 // Expand maximum allowed to something sensible for share access checking
2660 if (MAXIMUM_ALLOWED
== DesiredAccess
) {
2662 DesiredAccess
= FILE_ALL_ACCESS
& ~((TypeOfOpen
!= UserVolumeOpen
?
2663 (FILE_WRITE_ATTRIBUTES
|
2667 FILE_ADD_SUBDIRECTORY
|
2668 FILE_APPEND_DATA
) : 0) |
2675 // If this a volume open and the user wants to lock the volume then
2676 // purge and lock the volume.
2679 if ((TypeOfOpen
<= UserVolumeOpen
) &&
2680 !FlagOn( IrpSp
->Parameters
.Create
.ShareAccess
, FILE_SHARE_READ
)) {
2683 // If there are open handles then fail this immediately.
2686 if (Vcb
->VcbCleanup
!= 0) {
2688 return STATUS_SHARING_VIOLATION
;
2692 // If we can't wait then force this to be posted.
2695 if (!FlagOn( IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)) {
2697 CdRaiseStatus( IrpContext
, STATUS_CANT_WAIT
);
2703 // Purge the volume and make sure all of the user references
2707 Status
= CdPurgeVolume( IrpContext
, Vcb
, FALSE
);
2709 if (Status
!= STATUS_SUCCESS
) {
2715 // Now force all of the delayed close operations to go away.
2720 if (Vcb
->VcbUserReference
> CDFS_RESIDUAL_USER_REFERENCE
) {
2722 return STATUS_SHARING_VIOLATION
;
2727 // If the Fcb already existed then we need to check the oplocks and
2728 // the share access.
2731 if (Fcb
->FcbCleanup
!= 0) {
2734 // If this is a user file open then check whether there are any
2738 if (TypeOfOpen
== UserFileOpen
) {
2741 // Store the address of the Fcb for a possible teardown into
2742 // the IrpContext. We will release this in the call to
2746 IrpContext
->TeardownFcb
= CurrentFcb
;
2748 if (FsRtlCurrentBatchOplock( &Fcb
->Oplock
)) {
2751 // We remember if a batch oplock break is underway for the
2752 // case where the sharing check fails.
2755 Information
= FILE_OPBATCH_BREAK_UNDERWAY
;
2757 OplockStatus
= FsRtlCheckOplock( &Fcb
->Oplock
,
2760 (PVOID
)CdOplockComplete
, /* ReactOS Change: GCC "assignment from incompatible pointer type" */
2761 (PVOID
)CdPrePostIrp
); /* ReactOS Change: GCC "assignment from incompatible pointer type" */
2763 if (OplockStatus
== STATUS_PENDING
) {
2765 return STATUS_PENDING
;
2770 // Check the share access before breaking any exclusive oplocks.
2773 Status
= IoCheckShareAccess( DesiredAccess
,
2774 IrpSp
->Parameters
.Create
.ShareAccess
,
2779 if (!NT_SUCCESS( Status
)) {
2785 // Now check that we can continue based on the oplock state of the
2789 OplockStatus
= FsRtlCheckOplock( &Fcb
->Oplock
,
2792 (PVOID
)CdOplockComplete
,/* ReactOS Change: GCC "assignment from incompatible pointer type" */
2793 (PVOID
)CdPrePostIrp
);/* ReactOS Change: GCC "assignment from incompatible pointer type" */
2795 if (OplockStatus
== STATUS_PENDING
) {
2797 return STATUS_PENDING
;
2800 IrpContext
->TeardownFcb
= NULL
;
2803 // Otherwise just do the sharing check.
2808 Status
= IoCheckShareAccess( DesiredAccess
,
2809 IrpSp
->Parameters
.Create
.ShareAccess
,
2814 if (!NT_SUCCESS( Status
)) {
2822 // Create the Ccb now.
2825 Ccb
= CdCreateCcb( IrpContext
, Fcb
, UserCcbFlags
);
2828 // Update the share access.
2831 if (Fcb
->FcbCleanup
== 0) {
2833 IoSetShareAccess( DesiredAccess
,
2834 IrpSp
->Parameters
.Create
.ShareAccess
,
2836 &Fcb
->ShareAccess
);
2840 IoUpdateShareAccess( IrpSp
->FileObject
, &Fcb
->ShareAccess
);
2844 // Set the file object type.
2847 CdSetFileObject( IrpContext
, IrpSp
->FileObject
, TypeOfOpen
, Fcb
, Ccb
);
2850 // Set the appropriate cache flags for a user file object.
2853 if (TypeOfOpen
== UserFileOpen
) {
2855 if (FlagOn( IrpSp
->Parameters
.Create
.Options
, FILE_NO_INTERMEDIATE_BUFFERING
)) {
2857 SetFlag( IrpSp
->FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
);
2861 SetFlag( IrpSp
->FileObject
->Flags
, FO_CACHE_SUPPORTED
);
2864 else if (TypeOfOpen
== UserVolumeOpen
) {
2866 SetFlag( IrpSp
->FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
);
2870 // Update the open and cleanup counts. Check the fast io state here.
2873 CdLockVcb( IrpContext
, Vcb
);
2875 CdIncrementCleanupCounts( IrpContext
, Fcb
);
2876 CdIncrementReferenceCounts( IrpContext
, Fcb
, 1, 1 );
2880 Vcb
->VolumeLockFileObject
= IrpSp
->FileObject
;
2881 SetFlag( Vcb
->VcbState
, VCB_STATE_LOCKED
);
2884 CdUnlockVcb( IrpContext
, Vcb
);
2886 CdLockFcb( IrpContext
, Fcb
);
2888 if (TypeOfOpen
== UserFileOpen
) {
2890 Fcb
->IsFastIoPossible
= CdIsFastIoPossible( Fcb
);
2894 Fcb
->IsFastIoPossible
= FastIoIsNotPossible
;
2897 CdUnlockFcb( IrpContext
, Fcb
);
2900 // Show that we opened the file.
2903 IrpContext
->Irp
->IoStatus
.Information
= Information
;
2906 // Point to the section object pointer in the non-paged Fcb.
2909 IrpSp
->FileObject
->SectionObjectPointer
= &Fcb
->FcbNonpaged
->SegmentObject
;
2910 return OplockStatus
;