test: create.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# create.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     Create.c
    00008
    00009 Abstract:
    00010
    00011     This module implements the File Create routine for Udfs called by the
    00012     Fsd/Fsp dispatch routines.
    00013
    00014 Author:
    00015
    00016     Dan Lovinger    [DanLo]     9-October-1996
    00017
    00018 Revision History:
    00019
    00020 --*/
    00021
    00022 #include "UdfProcs.h"
    00023
    00024 //
    00025 //  The Bug check file id for this module
    00026 //
    00027
    00028 #define BugCheckFileId                   (UDFS_BUG_CHECK_CREATE)
    00029
    00030 //
    00031 //  The local debug trace level
    00032 //
    00033
    00034 #define Dbg                              (UDFS_DEBUG_LEVEL_CREATE)
    00035
    00036 //
    00037 //  Local support routines
    00038 //
    00039
    00040 NTSTATUS
    00041 UdfNormalizeFileNames (
    00042     IN PIRP_CONTEXT IrpContext,
    00043     IN PVCB Vcb,
    00044     IN BOOLEAN OpenByFileId,
    00045     IN BOOLEAN IgnoreCase,
    00046     IN TYPE_OF_OPEN RelatedTypeOfOpen,
    00047     IN PCCB RelatedCcb OPTIONAL,
    00048     IN PUNICODE_STRING RelatedFileName OPTIONAL,
    00049     IN OUT PUNICODE_STRING FileName,
    00050     IN OUT PUNICODE_STRING RemainingName
    00051     );
    00052
    00053 NTSTATUS
    00054 UdfOpenExistingFcb (
    00055     IN PIRP_CONTEXT IrpContext,
    00056     IN PIO_STACK_LOCATION IrpSp,
    00057     IN OUT PFCB *CurrentFcb,
    00058     IN PLCB OpenLcb,
    00059     IN TYPE_OF_OPEN TypeOfOpen,
    00060     IN BOOLEAN IgnoreCase,
    00061     IN PCCB RelatedCcb OPTIONAL
    00062     );
    00063
    00064 NTSTATUS
    00065 UdfOpenObjectByFileId (
    00066     IN PIRP_CONTEXT IrpContext,
    00067     IN PIO_STACK_LOCATION IrpSp,
    00068     IN PVCB Vcb,
    00069     IN OUT PFCB *CurrentFcb
    00070     );
    00071
    00072 NTSTATUS
    00073 UdfOpenObjectFromDirContext (
    00074     IN PIRP_CONTEXT IrpContext,
    00075     IN PIO_STACK_LOCATION IrpSp,
    00076     IN PVCB Vcb,
    00077     IN OUT PFCB *CurrentFcb,
    00078     IN BOOLEAN ShortNameMatch,
    00079     IN BOOLEAN IgnoreCase,
    00080     IN PDIR_ENUM_CONTEXT DirContext,
    00081     IN BOOLEAN PerformUserOpen,
    00082     IN PCCB RelatedCcb OPTIONAL
    00083     );
    00084
    00085 NTSTATUS
    00086 UdfCompleteFcbOpen (
    00087     IN PIRP_CONTEXT IrpContext,
    00088     PIO_STACK_LOCATION IrpSp,
    00089     IN PVCB Vcb,
    00090     IN OUT PFCB *CurrentFcb,
    00091     IN PLCB OpenLcb,
    00092     IN TYPE_OF_OPEN TypeOfOpen,
    00093     IN ULONG UserCcbFlags,
    00094     IN ACCESS_MASK DesiredAccess
    00095     );
    00096
    00097 #ifdef ALLOC_PRAGMA
    00098 #pragma alloc_text(PAGE, UdfCommonCreate)
    00099 #pragma alloc_text(PAGE, UdfCompleteFcbOpen)
    00100 #pragma alloc_text(PAGE, UdfNormalizeFileNames)
    00101 #pragma alloc_text(PAGE, UdfOpenObjectByFileId)
    00102 #pragma alloc_text(PAGE, UdfOpenExistingFcb)
    00103 #pragma alloc_text(PAGE, UdfOpenObjectFromDirContext)
    00104 #endif
    00105
    00106
    00107 NTSTATUS
    00108 UdfCommonCreate (
    00109     IN PIRP_CONTEXT IrpContext,
    00110     IN PIRP Irp
    00111     )
    00112
    00113 /*++
    00114
    00115 Routine Description:
    00116
    00117     This is the common routine for opening a file called by both the
    00118     Fsp and Fsd threads.
    00119
    00120     The file can be opened either by name or by file Id either with or without
    00121     a relative name.  The file name field in the file object passed to this routine
    00122     contains either a unicode string or a 64 bit value which is the file Id.
    00123     If there is a related file object with a name then we will already have converted
    00124     that name to Oem.
    00125
    00126     We will store the full name for the file in the file object on a successful
    00127     open.  We will allocate a larger buffer if necessary and combine the
    00128     related and file object names.  The only exception is the relative open
    00129     when the related file object is for an OpenByFileId file.  If we need to
    00130     allocate a buffer for a case insensitive name then we allocate it at
    00131     the tail of the buffer we will store into the file object.  The upcased
    00132     portion will begin immediately after the name defined by the FileName
    00133     in the file object.
    00134
    00135     Once we have the full name in the file object we don't want to split the
    00136     name in the event of a retry.  We use a flag in the IrpContext to indicate
    00137     that the name has been split.
    00138
    00139 Arguments:
    00140
    00141     Irp - Supplies the Irp to process
    00142
    00143 Return Value:
    00144
    00145     NTSTATUS - This is the status from this open operation.
    00146
    00147 --*/
    00148
    00149 {
    00150     NTSTATUS Status = STATUS_SUCCESS;
    00151     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
    00152
    00153     PFILE_OBJECT FileObject;
    00154
    00155     DIR_ENUM_CONTEXT DirContext;
    00156     BOOLEAN CleanupDirContext = FALSE;
    00157
    00158     BOOLEAN FoundEntry;
    00159
    00160     PVCB Vcb;
    00161
    00162     BOOLEAN OpenByFileId;
    00163     BOOLEAN IgnoreCase;
    00164     ULONG CreateDisposition;
    00165
    00166     BOOLEAN ShortNameMatch;
    00167
    00168     BOOLEAN VolumeOpen = FALSE;
    00169
    00170     //
    00171     //  We will be acquiring and releasing file Fcb's as we move down the
    00172     //  directory tree during opens.  At any time we need to know the deepest
    00173     //  point we have traversed down in the tree in case we need to cleanup
    00174     //  any structures created here.
    00175     //
    00176     //  CurrentFcb - represents this point.  If non-null it means we have
    00177     //      acquired it and need to release it in finally clause.
    00178     //
    00179     //  NextFcb - represents the NextFcb to walk to but haven't acquired yet.
    00180     //
    00181     //  CurrentLcb - represents the name of the CurrentFcb.
    00182     //
    00183
    00184     TYPE_OF_OPEN RelatedTypeOfOpen = UnopenedFileObject;
    00185     PFILE_OBJECT RelatedFileObject;
    00186     PCCB RelatedCcb = NULL;
    00187
    00188     PFCB NextFcb;
    00189     PFCB CurrentFcb = NULL;
    00190
    00191     PLCB CurrentLcb = NULL;
    00192
    00193     //
    00194     //  During the open we need to combine the related file object name
    00195     //  with the remaining name.  We also may need to upcase the file name
    00196     //  in order to do a case-insensitive name comparison.  We also need
    00197     //  to restore the name in the file object in the event that we retry
    00198     //  the request.  We use the following string variables to manage the
    00199     //  name.  We will can put these strings into either Unicode or Ansi
    00200     //  form.
    00201     //
    00202     //  FileName - Pointer to name as currently stored in the file
    00203     //      object.  We store the full name into the file object early in
    00204     //      the open operation.
    00205     //
    00206     //  RelatedFileName - Pointer to the name in the related file object.
    00207     //
    00208     //  RemainingName - String containing remaining name to parse.
    00209     //
    00210
    00211     PUNICODE_STRING FileName;
    00212     PUNICODE_STRING RelatedFileName;
    00213
    00214     UNICODE_STRING RemainingName;
    00215     UNICODE_STRING FinalName;
    00216
    00217     PAGED_CODE();
    00218
    00219     //
    00220     //  If we were called with our file system device object instead of a
    00221     //  volume device object, just complete this request with STATUS_SUCCESS.
    00222     //
    00223
    00224     if (IrpContext->Vcb == NULL) {
    00225
    00226         UdfCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
    00227         return STATUS_SUCCESS;
    00228     }
    00229
    00230     //
    00231     //  Get create parameters from the Irp.
    00232     //
    00233
    00234     OpenByFileId = BooleanFlagOn( IrpSp->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID );
    00235     IgnoreCase = !BooleanFlagOn( IrpSp->Flags, SL_CASE_SENSITIVE );
    00236     CreateDisposition = (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff;
    00237
    00238     //
    00239     //  Do some preliminary checks to make sure the operation is supported.
    00240     //  We fail in the following cases immediately.
    00241     //
    00242     //      - Open a paging file.
    00243     //      - Open a target directory.
    00244     //      - Open a file with Eas.
    00245     //      - Create a file.
    00246     //
    00247
    00248     if (FlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE | SL_OPEN_TARGET_DIRECTORY) ||
    00249         (IrpSp->Parameters.Create.EaLength != 0) ||
    00250         (CreateDisposition == FILE_CREATE)) {
    00251
    00252         UdfCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED );
    00253         return STATUS_ACCESS_DENIED;
    00254     }
    00255
    00256     //
    00257     //  Copy the Vcb to a local.  Assume the starting directory is the root.
    00258     //
    00259
    00260     Vcb = IrpContext->Vcb;
    00261     NextFcb = Vcb->RootIndexFcb;
    00262
    00263     //
    00264     //  Reference our input parameters to make things easier
    00265     //
    00266
    00267     FileObject = IrpSp->FileObject;
    00268     RelatedFileObject = NULL;
    00269
    00270     FileName = &FileObject->FileName;
    00271
    00272     //
    00273     //  Set up the file object's Vpb pointer in case anything happens.
    00274     //  This will allow us to get a reasonable pop-up.
    00275     //
    00276
    00277     if ((FileObject->RelatedFileObject != NULL) && !OpenByFileId) {
    00278
    00279         RelatedFileObject = FileObject->RelatedFileObject;
    00280         FileObject->Vpb = RelatedFileObject->Vpb;
    00281
    00282         RelatedTypeOfOpen = UdfDecodeFileObject( RelatedFileObject, &NextFcb, &RelatedCcb );
    00283
    00284         //
    00285         //  Fail the request if this is not a user file object.
    00286         //
    00287
    00288         if (RelatedTypeOfOpen < UserVolumeOpen) {
    00289
    00290             UdfCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
    00291             return STATUS_INVALID_PARAMETER;
    00292         }
    00293
    00294         //
    00295         //  Remember the name in the related file object.
    00296         //
    00297
    00298         RelatedFileName = &RelatedFileObject->FileName;
    00299     }
    00300
    00301     //
    00302     //  If we haven't initialized the names then make sure the strings are valid.
    00303     //  If this an OpenByFileId then verify the file id buffer.
    00304     //
    00305     //  After this routine returns we know that the full name is in the
    00306     //  FileName buffer and the buffer will hold the upcased portion
    00307     //  of the name yet to parse immediately after the full name in the
    00308     //  buffer.  Any trailing backslash has been removed and the flag
    00309     //  in the IrpContext will indicate whether we removed the
    00310     //  backslash.
    00311     //
    00312
    00313     Status = UdfNormalizeFileNames( IrpContext,
    00314                                     Vcb,
    00315                                     OpenByFileId,
    00316                                     IgnoreCase,
    00317                                     RelatedTypeOfOpen,
    00318                                     RelatedCcb,
    00319                                     RelatedFileName,
    00320                                     FileName,
    00321                                     &RemainingName );
    00322
    00323     //
    00324     //  Return the error code if not successful.
    00325     //
    00326
    00327     if (!NT_SUCCESS( Status )) {
    00328
    00329         UdfCompleteRequest( IrpContext, Irp, Status );
    00330         return Status;
    00331     }
    00332
    00333     //
    00334     //  We want to acquire the Vcb.  Exclusively for a volume open, shared otherwise.
    00335     //  The file name is empty for a volume open.
    00336     //
    00337
    00338     if ((FileName->Length == 0) &&
    00339         (RelatedTypeOfOpen <= UserVolumeOpen) &&
    00340         !OpenByFileId) {
    00341
    00342         VolumeOpen = TRUE;
    00343         UdfAcquireVcbExclusive( IrpContext, Vcb, FALSE );
    00344
    00345     } else {
    00346
    00347         UdfAcquireVcbShared( IrpContext, Vcb, FALSE );
    00348     }
    00349
    00350     //
    00351     //  Use a try-finally to facilitate cleanup.
    00352     //
    00353
    00354     try {
    00355
    00356         //
    00357         //  Verify that the Vcb is not in an unusable condition.  This routine
    00358         //  will raise if not usable.
    00359         //
    00360
    00361         UdfVerifyVcb( IrpContext, Vcb );
    00362
    00363         //
    00364         //  If the Vcb is locked then we cannot open another file
    00365         //
    00366
    00367         if (FlagOn( Vcb->VcbState, VCB_STATE_LOCKED )) {
    00368
    00369             try_leave( Status = STATUS_ACCESS_DENIED );
    00370         }
    00371
    00372         //
    00373         //  If we are opening this file by FileId then process this immediately
    00374         //  and exit.
    00375         //
    00376
    00377         if (OpenByFileId) {
    00378
    00379             //
    00380             //  The only create disposition we allow is OPEN.
    00381             //
    00382
    00383             if ((CreateDisposition != FILE_OPEN) &&
    00384                 (CreateDisposition != FILE_OPEN_IF)) {
    00385
    00386                 try_leave( Status = STATUS_ACCESS_DENIED );
    00387             }
    00388
    00389             try_leave( Status = UdfOpenObjectByFileId( IrpContext,
    00390                                                        IrpSp,
    00391                                                        Vcb,
    00392                                                        &CurrentFcb ));
    00393         }
    00394
    00395         //
    00396         //  If we are opening this volume Dasd then process this immediately
    00397         //  and exit.
    00398         //
    00399
    00400         if (VolumeOpen) {
    00401
    00402             //
    00403             //  The only create disposition we allow is OPEN.
    00404             //
    00405
    00406             if ((CreateDisposition != FILE_OPEN) &&
    00407                 (CreateDisposition != FILE_OPEN_IF)) {
    00408
    00409                 try_leave( Status = STATUS_ACCESS_DENIED );
    00410             }
    00411
    00412             //
    00413             //  If they wanted to open a directory, surprise.
    00414             //
    00415
    00416             if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
    00417
    00418                 try_leave( Status = STATUS_NOT_A_DIRECTORY );
    00419             }
    00420
    00421             //
    00422             //  Acquire the Fcb first.
    00423             //
    00424
    00425             CurrentFcb = Vcb->VolumeDasdFcb;
    00426             UdfAcquireFcbExclusive( IrpContext, CurrentFcb, FALSE );
    00427
    00428             try_leave( Status = UdfOpenExistingFcb( IrpContext,
    00429                                                     IrpSp,
    00430                                                     &CurrentFcb,
    00431                                                     NULL,
    00432                                                     UserVolumeOpen,
    00433                                                     FALSE,
    00434                                                     NULL ));
    00435         }
    00436
    00437         //
    00438         //  Acquire the Fcb at the beginning of our search to keep it from being
    00439         //  deleted beneath us.
    00440         //
    00441
    00442         UdfAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
    00443         CurrentFcb = NextFcb;
    00444
    00445         //
    00446         //  Do a prefix search if there is more of the name to parse.
    00447         //
    00448
    00449         if (RemainingName.Length != 0) {
    00450
    00451             //
    00452             //  Do the prefix search to find the longest matching name.
    00453             //
    00454
    00455             CurrentLcb = UdfFindPrefix( IrpContext,
    00456                                         &CurrentFcb,
    00457                                         &RemainingName,
    00458                                         IgnoreCase );
    00459         }
    00460
    00461         //
    00462         //  At this point CurrentFcb points at the lowest Fcb in the tree for this
    00463         //  file name, CurrentLcb is that name, and RemainingName is the rest of the
    00464         //  name we have to do any directory traversals for.
    00465         //
    00466
    00467         //
    00468         //  If the remaining name length is zero then we have found our
    00469         //  target.
    00470         //
    00471
    00472         if (RemainingName.Length == 0) {
    00473
    00474             //
    00475             //  If this is a file so verify the user didn't want to open
    00476             //  a directory.
    00477             //
    00478
    00479             if (SafeNodeType( CurrentFcb ) == UDFS_NTC_FCB_DATA) {
    00480
    00481                 if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH ) ||
    00482                     FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
    00483
    00484                     try_leave( Status = STATUS_NOT_A_DIRECTORY );
    00485                 }
    00486
    00487                 //
    00488                 //  The only create disposition we allow is OPEN.
    00489                 //
    00490
    00491                 if ((CreateDisposition != FILE_OPEN) &&
    00492                     (CreateDisposition != FILE_OPEN_IF)) {
    00493
    00494                     try_leave( Status = STATUS_ACCESS_DENIED );
    00495                 }
    00496
    00497                 try_leave( Status = UdfOpenExistingFcb( IrpContext,
    00498                                                          IrpSp,
    00499                                                          &CurrentFcb,
    00500                                                          CurrentLcb,
    00501                                                          UserFileOpen,
    00502                                                          IgnoreCase,
    00503                                                          RelatedCcb ));
    00504
    00505             //
    00506             //  This is a directory.  Verify the user didn't want to open
    00507             //  as a file.
    00508             //
    00509
    00510             } else if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
    00511
    00512                 try_leave( Status = STATUS_FILE_IS_A_DIRECTORY );
    00513
    00514             //
    00515             //  Open the file as a directory.
    00516             //
    00517
    00518             } else {
    00519
    00520                 //
    00521                 //  The only create disposition we allow is OPEN.
    00522                 //
    00523
    00524                 if ((CreateDisposition != FILE_OPEN) &&
    00525                     (CreateDisposition != FILE_OPEN_IF)) {
    00526
    00527                     try_leave( Status = STATUS_ACCESS_DENIED );
    00528                 }
    00529
    00530                 try_leave( Status = UdfOpenExistingFcb( IrpContext,
    00531                                                          IrpSp,
    00532                                                          &CurrentFcb,
    00533                                                          CurrentLcb,
    00534                                                          UserDirectoryOpen,
    00535                                                          IgnoreCase,
    00536                                                          RelatedCcb ));
    00537             }
    00538         }
    00539
    00540         //
    00541         //  We have more work to do.  We have a starting Fcb which we own shared.
    00542         //  We also have the remaining name to parse.  Walk through the name
    00543         //  component by component looking for the full name.
    00544         //
    00545
    00546         //
    00547         //  Our starting Fcb better be a directory.
    00548         //
    00549
    00550         if (!FlagOn( CurrentFcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
    00551
    00552             try_leave( Status = STATUS_OBJECT_PATH_NOT_FOUND );
    00553         }
    00554
    00555         //
    00556         //  If we can't wait then post this request.
    00557         //
    00558
    00559         if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
    00560
    00561             UdfRaiseStatus( IrpContext, STATUS_CANT_WAIT );
    00562         }
    00563
    00564         //
    00565         //  Prepare the enumeration context for use.
    00566         //
    00567
    00568         UdfInitializeDirContext( IrpContext, &DirContext );
    00569         CleanupDirContext = TRUE;
    00570
    00571         while (TRUE) {
    00572
    00573             ShortNameMatch = FALSE;
    00574
    00575             //
    00576             //  Split off the next component from the name.
    00577             //
    00578
    00579             UdfDissectName( IrpContext,
    00580                             &RemainingName,
    00581                             &FinalName );
    00582
    00583             //
    00584             //  Go ahead and look this entry up in the directory.
    00585             //
    00586
    00587             FoundEntry = UdfFindDirEntry( IrpContext,
    00588                                           CurrentFcb,
    00589                                           &FinalName,
    00590                                           IgnoreCase,
    00591                                           FALSE,
    00592                                           &DirContext );
    00593
    00594             //
    00595             //  If we didn't find the entry then check if the current name
    00596             //  is a possible short name.
    00597             //
    00598
    00599             if (!FoundEntry && UdfCandidateShortName( IrpContext, &FinalName)) {
    00600
    00601                 //
    00602                 //  If the name looks like it could be a short name, try to find
    00603                 //  a matching real directory entry.
    00604                 //
    00605
    00606                 ShortNameMatch =
    00607                 FoundEntry = UdfFindDirEntry( IrpContext,
    00608                                               CurrentFcb,
    00609                                               &FinalName,
    00610                                               IgnoreCase,
    00611                                               TRUE,
    00612                                               &DirContext );
    00613             }
    00614
    00615             //
    00616             //  If we didn't find a match then check what the caller was trying to do to
    00617             //  determine which error code to return.
    00618             //
    00619
    00620             if (!FoundEntry) {
    00621
    00622                 if ((CreateDisposition == FILE_OPEN) ||
    00623                     (CreateDisposition == FILE_OVERWRITE)) {
    00624
    00625                     try_leave( Status = STATUS_OBJECT_NAME_NOT_FOUND );
    00626                 }
    00627
    00628                 //
    00629                 //  Any other operation return STATUS_ACCESS_DENIED.
    00630                 //
    00631
    00632                 try_leave( Status = STATUS_ACCESS_DENIED );
    00633             }
    00634
    00635             //
    00636             //  If this is an ignore case open then copy the exact case
    00637             //  in the file object name.
    00638             //
    00639
    00640             if (IgnoreCase && !ShortNameMatch) {
    00641
    00642                 ASSERT( FinalName.Length == DirContext.ObjectName.Length );
    00643
    00644                 RtlCopyMemory( FinalName.Buffer,
    00645                                DirContext.ObjectName.Buffer,
    00646                                DirContext.ObjectName.Length );
    00647             }
    00648
    00649             //
    00650             //  If we have found the last component then break out to open for the caller.
    00651             //
    00652
    00653             if (RemainingName.Length == 0) {
    00654
    00655                 break;
    00656             }
    00657
    00658             //
    00659             //  The object we just found must be a directory.
    00660             //
    00661
    00662             if (!FlagOn( DirContext.Fid->Flags, NSR_FID_F_DIRECTORY )) {
    00663
    00664                 try_leave( Status = STATUS_OBJECT_PATH_NOT_FOUND );
    00665             }
    00666
    00667             //
    00668             //  Now open an Fcb for this intermediate index Fcb.
    00669             //
    00670
    00671             UdfOpenObjectFromDirContext( IrpContext,
    00672                                          IrpSp,
    00673                                          Vcb,
    00674                                          &CurrentFcb,
    00675                                          ShortNameMatch,
    00676                                          IgnoreCase,
    00677                                          &DirContext,
    00678                                          FALSE,
    00679                                          NULL );
    00680         }
    00681
    00682         //
    00683         //  Make sure our opener is about to get what they expect.
    00684         //
    00685
    00686         if ((FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH ) ||
    00687              FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) &&
    00688             !FlagOn( DirContext.Fid->Flags, NSR_FID_F_DIRECTORY )) {
    00689
    00690             try_leave( Status = STATUS_NOT_A_DIRECTORY );
    00691
    00692         }
    00693
    00694         if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE ) &&
    00695             FlagOn( DirContext.Fid->Flags, NSR_FID_F_DIRECTORY )) {
    00696
    00697             try_leave( Status = STATUS_FILE_IS_A_DIRECTORY );
    00698         }
    00699
    00700         //
    00701         //  The only create disposition we allow is OPEN.
    00702         //
    00703
    00704         if ((CreateDisposition != FILE_OPEN) &&
    00705             (CreateDisposition != FILE_OPEN_IF)) {
    00706
    00707             try_leave( Status = STATUS_ACCESS_DENIED );
    00708         }
    00709
    00710         //
    00711         //  Open the object for the caller.
    00712         //
    00713
    00714         try_leave( Status = UdfOpenObjectFromDirContext( IrpContext,
    00715                                                          IrpSp,
    00716                                                          Vcb,
    00717                                                          &CurrentFcb,
    00718                                                          ShortNameMatch,
    00719                                                          IgnoreCase,
    00720                                                          &DirContext,
    00721                                                          TRUE,
    00722                                                          RelatedCcb ));
    00723     } finally {
    00724
    00725         //
    00726         //  Cleanup the enumeration context if initialized.
    00727         //
    00728
    00729         if (CleanupDirContext) {
    00730
    00731             UdfCleanupDirContext( IrpContext, &DirContext );
    00732         }
    00733
    00734         //
    00735         //  The result of this open could be success, pending or some error
    00736         //  condition.
    00737         //
    00738
    00739         if (AbnormalTermination()) {
    00740
    00741
    00742             //
    00743             //  In the error path we start by calling our teardown routine if we
    00744             //  have a CurrentFcb.
    00745             //
    00746
    00747             if (CurrentFcb != NULL) {
    00748
    00749                 BOOLEAN RemovedFcb;
    00750
    00751                 UdfTeardownStructures( IrpContext, CurrentFcb, FALSE, &RemovedFcb );
    00752
    00753                 if (RemovedFcb) {
    00754
    00755                     CurrentFcb = NULL;
    00756                 }
    00757             }
    00758
    00759             //
    00760             //  No need to complete the request.
    00761             //
    00762
    00763             IrpContext = NULL;
    00764             Irp = NULL;
    00765
    00766         //
    00767         //  If we posted this request through the oplock package we need
    00768         //  to show that there is no reason to complete the request.
    00769         //
    00770
    00771         } else if (Status == STATUS_PENDING) {
    00772
    00773             IrpContext = NULL;
    00774             Irp = NULL;
    00775         }
    00776
    00777         //
    00778         //  Release the Current Fcb if still acquired.
    00779         //
    00780
    00781         if (CurrentFcb != NULL) {
    00782
    00783             UdfReleaseFcb( IrpContext, CurrentFcb );
    00784         }
    00785
    00786         //
    00787         //  Release the Vcb.
    00788         //
    00789
    00790         UdfReleaseVcb( IrpContext, Vcb );
    00791
    00792         //
    00793         //  Call our completion routine.  It will handle the case where either
    00794         //  the Irp and/or IrpContext are gone.
    00795         //
    00796
    00797         UdfCompleteRequest( IrpContext, Irp, Status );
    00798     }
    00799
    00800     return Status;
    00801 }
    00802
    00803
    00804 //
    00805 //  Local support routine
    00806 //
    00807
    00808 NTSTATUS
    00809 UdfNormalizeFileNames (
    00810     IN PIRP_CONTEXT IrpContext,
    00811     IN PVCB Vcb,
    00812     IN BOOLEAN OpenByFileId,
    00813     IN BOOLEAN IgnoreCase,
    00814     IN TYPE_OF_OPEN RelatedTypeOfOpen,
    00815     IN PCCB RelatedCcb OPTIONAL,
    00816     IN PUNICODE_STRING RelatedFileName OPTIONAL,
    00817     IN OUT PUNICODE_STRING FileName,
    00818     IN OUT PUNICODE_STRING RemainingName
    00819     )
    00820
    00821 /*++
    00822
    00823 Routine Description:
    00824
    00825     This routine is called to store the full name and upcased name into the
    00826     filename buffer.  We only upcase the portion yet to parse.  We also
    00827     check for a trailing backslash and lead-in double backslashes.  This
    00828     routine also verifies the mode of the related open against the name
    00829     currently in the filename.
    00830
    00831 Arguments:
    00832
    00833     Vcb - Vcb for this volume.
    00834
    00835     OpenByFileId - Indicates if the filename should be a 64 bit FileId.
    00836
    00837     IgnoreCase - Indicates if this open is a case-insensitive operation.
    00838
    00839     RelatedTypeOfOpen - Indicates the type of the related file object.
    00840
    00841     RelatedCcb - Ccb for the related open.  Ignored if no relative open.
    00842
    00843     RelatedFileName - FileName buffer for related open.  Ignored if no
    00844         relative open.
    00845
    00846     FileName - FileName to update in this routine.  The name should
    00847         either be a 64-bit FileId or a Unicode string.
    00848
    00849     RemainingName - Name with the remaining portion of the name.  This
    00850         will begin after the related name and any separator.  For a
    00851         non-relative open we also step over the initial separator.
    00852
    00853 Return Value:
    00854
    00855     NTSTATUS - STATUS_SUCCESS if the names are OK, appropriate error code
    00856         otherwise.
    00857
    00858 --*/
    00859
    00860 {
    00861     ULONG RemainingNameLength;
    00862     ULONG RelatedNameLength = 0;
    00863     ULONG SeparatorLength = 0;
    00864
    00865     ULONG BufferLength;
    00866
    00867     UNICODE_STRING NewFileName;
    00868
    00869     PAGED_CODE();
    00870
    00871     //
    00872     //  If this is the first pass then we need to build the full name and
    00873     //  check for name compatibility.
    00874     //
    00875
    00876     if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_FULL_NAME )) {
    00877
    00878         //
    00879         //  Deal with the regular file name case first.
    00880         //
    00881
    00882         if (!OpenByFileId) {
    00883
    00884             //
    00885             //  Here is the  "M A R K   L U C O V S K Y"  hack.
    00886             //
    00887             //  It's here because Mark says he can't avoid sending me double beginning
    00888             //  backslashes via the Win32 layer.
    00889             //
    00890
    00891             if ((FileName->Length > sizeof( WCHAR )) &&
    00892                 (FileName->Buffer[1] == L'\\') &&
    00893                 (FileName->Buffer[0] == L'\\')) {
    00894
    00895                 //
    00896                 //  If there are still two beginning backslashes, the name is bogus.
    00897                 //
    00898
    00899                 if ((FileName->Length > 2 * sizeof( WCHAR )) &&
    00900                     (FileName->Buffer[2] == L'\\')) {
    00901
    00902                     return STATUS_OBJECT_NAME_INVALID;
    00903                 }
    00904
    00905                 //
    00906                 //  Slide the name down in the buffer.
    00907                 //
    00908
    00909                 RtlMoveMemory( FileName->Buffer,
    00910                                FileName->Buffer + 1,
    00911                                FileName->Length );
    00912
    00913                 FileName->Length -= sizeof( WCHAR );
    00914             }
    00915
    00916             //
    00917             //  Check for a trailing backslash.  Don't strip off if only character
    00918             //  in the full name or for relative opens where this is illegal.
    00919             //
    00920
    00921             if (((FileName->Length > sizeof( WCHAR)) ||
    00922                  ((FileName->Length == sizeof( WCHAR )) && (RelatedTypeOfOpen == UserDirectoryOpen))) &&
    00923                 (FileName->Buffer[ (FileName->Length/2) - 1 ] == L'\\')) {
    00924
    00925                 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_TRAIL_BACKSLASH );
    00926                 FileName->Length -= sizeof( WCHAR );
    00927             }
    00928
    00929             //
    00930             //  Remember the length we need for this portion of the name.
    00931             //
    00932
    00933             RemainingNameLength = FileName->Length;
    00934
    00935             //
    00936             //  If this is a related file object then we verify the compatibility
    00937             //  of the name in the file object with the relative file object.
    00938             //
    00939
    00940             if (RelatedTypeOfOpen != UnopenedFileObject) {
    00941
    00942                 //
    00943                 //  If the filename length was zero then it must be legal.
    00944                 //  If there are characters then check with the related
    00945                 //  type of open.
    00946                 //
    00947
    00948                 if (FileName->Length != 0) {
    00949
    00950                     //
    00951                     //  The name length must always be zero for a volume open.
    00952                     //
    00953
    00954                     if (RelatedTypeOfOpen <= UserVolumeOpen) {
    00955
    00956                         return STATUS_INVALID_PARAMETER;
    00957
    00958                     //
    00959                     //  The remaining name cannot begin with a backslash.
    00960                     //
    00961
    00962                     } else if (FileName->Buffer[0] == L'\\' ) {
    00963
    00964                         return STATUS_INVALID_PARAMETER;
    00965
    00966                     //
    00967                     //  If the related file is a user file then there
    00968                     //  is no file with this path.
    00969                     //
    00970
    00971                     } else if (RelatedTypeOfOpen == UserFileOpen) {
    00972
    00973                         return STATUS_OBJECT_PATH_NOT_FOUND;
    00974                     }
    00975                 }
    00976
    00977                 //
    00978                 //  Remember the length of the related name when building
    00979                 //  the full name.  We leave the RelatedNameLength and
    00980                 //  SeparatorLength at zero if the relative file is opened
    00981                 //  by Id.
    00982                 //
    00983
    00984                 if (!FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID )) {
    00985
    00986                     //
    00987                     //  Add a separator if the name length is non-zero
    00988                     //  unless the relative Fcb is at the root.
    00989                     //
    00990
    00991                     if ((FileName->Length != 0) &&
    00992                         (RelatedCcb->Fcb != Vcb->RootIndexFcb)) {
    00993
    00994                         SeparatorLength = sizeof( WCHAR );
    00995                     }
    00996
    00997                     RelatedNameLength = RelatedFileName->Length;
    00998                 }
    00999
    01000             //
    01001             //  The full name is already in the filename.  It must either
    01002             //  be length 0 or begin with a backslash.
    01003             //
    01004
    01005             } else if (FileName->Length != 0) {
    01006
    01007                 if (FileName->Buffer[0] != L'\\') {
    01008
    01009                     return STATUS_INVALID_PARAMETER;
    01010                 }
    01011
    01012                 //
    01013                 //  We will want to trim the leading backslash from the
    01014                 //  remaining name we return.
    01015                 //
    01016
    01017                 RemainingNameLength -= sizeof( WCHAR );
    01018                 SeparatorLength = sizeof( WCHAR );
    01019             }
    01020
    01021             //
    01022             //  Now see if the buffer is large enough to hold the full name.
    01023             //
    01024
    01025             BufferLength = RelatedNameLength + SeparatorLength + RemainingNameLength;
    01026
    01027             //
    01028             //  Check for an overflow of the maximum filename size.
    01029             //
    01030
    01031             if (BufferLength > MAXUSHORT) {
    01032
    01033                 return STATUS_INVALID_PARAMETER;
    01034             }
    01035
    01036             //
    01037             //  Now see if we need to allocate a new buffer.
    01038             //
    01039
    01040             if (FileName->MaximumLength < BufferLength) {
    01041
    01042                 NewFileName.Buffer = FsRtlAllocatePoolWithTag( UdfPagedPool,
    01043                                                                BufferLength,
    01044                                                                TAG_FILE_NAME );
    01045
    01046                 NewFileName.MaximumLength = (USHORT) BufferLength;
    01047
    01048             } else {
    01049
    01050                 NewFileName.Buffer = FileName->Buffer;
    01051                 NewFileName.MaximumLength = FileName->MaximumLength;
    01052             }
    01053
    01054             //
    01055             //  If there is a related name then we need to slide the remaining bytes up and
    01056             //  insert the related name.  Otherwise the name is in the correct position
    01057             //  already.
    01058             //
    01059
    01060             if (RelatedNameLength != 0) {
    01061
    01062                 //
    01063                 //  Store the remaining name in its correct position.
    01064                 //
    01065
    01066                 if (RemainingNameLength != 0) {
    01067
    01068                     RtlMoveMemory( Add2Ptr( NewFileName.Buffer, RelatedNameLength + SeparatorLength, PVOID ),
    01069                                    FileName->Buffer,
    01070                                    RemainingNameLength );
    01071                 }
    01072
    01073                 RtlCopyMemory( NewFileName.Buffer,
    01074                                RelatedFileName->Buffer,
    01075                                RelatedNameLength );
    01076
    01077                 //
    01078                 //  Add the separator if needed.
    01079                 //
    01080
    01081                 if (SeparatorLength != 0) {
    01082
    01083                     *(Add2Ptr( NewFileName.Buffer, RelatedNameLength, PWCHAR )) = L'\\';
    01084                 }
    01085
    01086                 //
    01087                 //  Update the filename value we got from the user.
    01088                 //
    01089
    01090                 if (NewFileName.Buffer != FileName->Buffer) {
    01091
    01092                     if (FileName->Buffer != NULL) {
    01093
    01094                         ExFreePool( FileName->Buffer );
    01095                     }
    01096
    01097                     FileName->Buffer = NewFileName.Buffer;
    01098                     FileName->MaximumLength = NewFileName.MaximumLength;
    01099                 }
    01100
    01101                 //
    01102                 //  Copy the name length to the user's filename.
    01103                 //
    01104
    01105                 FileName->Length = (USHORT) (RelatedNameLength + SeparatorLength + RemainingNameLength);
    01106             }
    01107
    01108             //
    01109             //  Now update the remaining name to parse.
    01110             //
    01111
    01112             RemainingName->MaximumLength =
    01113             RemainingName->Length = (USHORT) RemainingNameLength;
    01114
    01115             RemainingName->Buffer = Add2Ptr( FileName->Buffer,
    01116                                              RelatedNameLength + SeparatorLength,
    01117                                              PWCHAR );
    01118
    01119             //
    01120             //  Upcase the name if necessary.
    01121             //
    01122
    01123             if (IgnoreCase && (RemainingNameLength != 0)) {
    01124
    01125                 UdfUpcaseName( IrpContext,
    01126                                RemainingName,
    01127                                RemainingName );
    01128             }
    01129
    01130             //
    01131             //  Do a quick check to make sure there are no wildcards.
    01132             //
    01133
    01134             if (FsRtlDoesNameContainWildCards( RemainingName )) {
    01135
    01136                 return STATUS_OBJECT_NAME_INVALID;
    01137             }
    01138
    01139         //
    01140         //  For the open by file Id case we verify the name really contains
    01141         //  a 64 bit value.
    01142         //
    01143
    01144         } else {
    01145
    01146             //
    01147             //  Check for validity of the buffer.
    01148             //
    01149
    01150             if (FileName->Length != sizeof( FILE_ID )) {
    01151
    01152                 return STATUS_INVALID_PARAMETER;
    01153             }
    01154         }
    01155
    01156         SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_FULL_NAME );
    01157
    01158     //
    01159     //  If we are in the retry path then the full name is already in the
    01160     //  file object name.  If this is a case-sensitive operation then
    01161     //  we need to upcase the name from the end of any related file name already stored
    01162     //  there.
    01163     //
    01164
    01165     } else {
    01166
    01167         //
    01168         //  Assume there is no relative name.
    01169         //
    01170
    01171         *RemainingName = *FileName;
    01172
    01173         //
    01174         //  Nothing to do if the name length is zero.
    01175         //
    01176
    01177         if (RemainingName->Length != 0) {
    01178
    01179             //
    01180             //  If there is a relative name then we need to walk past it.
    01181             //
    01182
    01183             if (RelatedTypeOfOpen != UnopenedFileObject) {
    01184
    01185                 //
    01186                 //  Nothing to walk past if the RelatedCcb is opened by FileId.
    01187                 //
    01188
    01189
    01190                 if (!FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID )) {
    01191
    01192                     //
    01193                     //  Related file name is a proper prefix of the full name.
    01194                     //  We step over the related name and if we are then
    01195                     //  pointing at a separator character we step over that.
    01196                     //
    01197
    01198                     RemainingName->Buffer = Add2Ptr( RemainingName->Buffer,
    01199                                                      RelatedFileName->Length,
    01200                                                      PWCHAR );
    01201
    01202                     RemainingName->Length -= RelatedFileName->Length;
    01203                 }
    01204             }
    01205
    01206             //
    01207             //  If we are pointing at a separator character then step past that.
    01208             //
    01209
    01210             if (RemainingName->Length != 0) {
    01211
    01212                 if (*(RemainingName->Buffer) == L'\\') {
    01213
    01214                     RemainingName->Buffer = Add2Ptr( RemainingName->Buffer,
    01215                                                      sizeof( WCHAR ),
    01216                                                      PWCHAR );
    01217
    01218                     RemainingName->Length -= sizeof( WCHAR );
    01219                 }
    01220             }
    01221         }
    01222
    01223         //
    01224         //  Upcase the name if necessary.
    01225         //
    01226
    01227         if (IgnoreCase && (RemainingName->Length != 0)) {
    01228
    01229             UdfUpcaseName( IrpContext,
    01230                            RemainingName,
    01231                            RemainingName );
    01232         }
    01233     }
    01234
    01235     return STATUS_SUCCESS;
    01236 }
    01237
    01238
    01239 //
    01240 //  Local support routine
    01241 //
    01242
    01243 NTSTATUS
    01244 UdfOpenObjectByFileId (
    01245     IN PIRP_CONTEXT IrpContext,
    01246     IN PIO_STACK_LOCATION IrpSp,
    01247     IN PVCB Vcb,
    01248     IN OUT PFCB *CurrentFcb
    01249     )
    01250
    01251 /*++
    01252
    01253 Routine Description:
    01254
    01255     This routine is called to open a file by the FileId.  The file Id is in
    01256     the FileObject name buffer and has been verified to be 64 bits.
    01257
    01258     We extract the Id number and then check to see whether we are opening a
    01259     file or directory and compare that with the create options.  If this
    01260     generates no error then optimistically look up the Fcb in the Fcb Table.
    01261
    01262     If we don't find the Fcb then we take what is effectively a wild-a** guess.
    01263     Since we would need more than 64bits to contain the root extent length along
    01264     with the partition, lbn and dir/file flag we have to speculate that the
    01265     opener knows what they are doing and try to crack an ICB hierarchy at the
    01266     specified location.  This can fail for any number of reasons, which then have
    01267     to be mapped to an open failure.
    01268
    01269     If found then build the Fcb from this entry and store the new Fcb in the
    01270     tree.
    01271
    01272     Finally we call our worker routine to complete the open on this Fcb.
    01273
    01274 Arguments:
    01275
    01276     IrpSp - Stack location within the create Irp.
    01277
    01278     Vcb - Vcb for this volume.
    01279
    01280     CurrentFcb - Address to store the Fcb for this open.  We only store the
    01281         CurrentFcb here when we have acquired it so our caller knows to
    01282         free or deallocate it.
    01283
    01284 Return Value:
    01285
    01286     NTSTATUS - Status indicating the result of the operation.
    01287
    01288 --*/
    01289
    01290 {
    01291     NTSTATUS Status = STATUS_ACCESS_DENIED;
    01292
    01293     BOOLEAN UnlockVcb = FALSE;
    01294     BOOLEAN Found;
    01295     BOOLEAN FcbExisted;
    01296
    01297     ICB_SEARCH_CONTEXT IcbContext;
    01298     BOOLEAN CleanupIcbContext = FALSE;
    01299
    01300     NODE_TYPE_CODE NodeTypeCode;
    01301     TYPE_OF_OPEN TypeOfOpen;
    01302
    01303     FILE_ID FileId;
    01304
    01305     PFCB NextFcb = NULL;
    01306
    01307     PAGED_CODE();
    01308
    01309     //
    01310     //  Check inputs.
    01311     //
    01312
    01313     ASSERT_IRP_CONTEXT( IrpContext );
    01314     ASSERT_VCB( Vcb );
    01315
    01316     //
    01317     //  Extract the FileId from the FileObject.
    01318     //
    01319
    01320     RtlCopyMemory( &FileId, IrpSp->FileObject->FileName.Buffer, sizeof( FILE_ID ));
    01321
    01322     //
    01323     //  Now do a quick check that the reserved, unused chunk of the fileid is
    01324     //  unused in this specimen.
    01325     //
    01326
    01327     if (UdfGetFidReservedZero( FileId )) {
    01328
    01329         return STATUS_INVALID_PARAMETER;
    01330     }
    01331
    01332     //
    01333     //  Go ahead and figure out the TypeOfOpen and NodeType.  We can
    01334     //  get these from the input FileId.
    01335     //
    01336
    01337     if (UdfIsFidDirectory( FileId )) {
    01338
    01339         TypeOfOpen = UserDirectoryOpen;
    01340         NodeTypeCode = UDFS_NTC_FCB_INDEX;
    01341
    01342     } else {
    01343
    01344         TypeOfOpen = UserFileOpen;
    01345         NodeTypeCode = UDFS_NTC_FCB_DATA;
    01346     }
    01347
    01348     //
    01349     //  Use a try-finally to facilitate cleanup.
    01350     //
    01351
    01352     try {
    01353
    01354         //
    01355         //  Acquire the Vcb and check if there is already an Fcb.
    01356         //  If not we will need to carefully hunt for the on-disc
    01357         //  structures.
    01358         //
    01359         //  We will post the request if we don't find the Fcb and this
    01360         //  request can't wait.
    01361         //
    01362
    01363         UdfLockVcb( IrpContext, Vcb );
    01364         UnlockVcb = TRUE;
    01365
    01366         NextFcb = UdfCreateFcb( IrpContext, FileId, NodeTypeCode, &FcbExisted );
    01367
    01368         //
    01369         //  Now, if the Fcb was not already here we have some work to do.
    01370         //
    01371
    01372         if (!FcbExisted) {
    01373
    01374             //
    01375             //  If we can't wait then post this request.
    01376             //
    01377
    01378             if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
    01379
    01380                 UdfRaiseStatus( IrpContext, STATUS_CANT_WAIT );
    01381             }
    01382
    01383             //
    01384             //  Use a try-finally to transform errors we get as a result of going
    01385             //  off on a wild goose chase into a simple open failure.
    01386             //
    01387
    01388             try {
    01389
    01390                 NextFcb->FileId = FileId;
    01391
    01392                 UdfInitializeIcbContextFromFcb( IrpContext, &IcbContext, NextFcb );
    01393                 CleanupIcbContext = TRUE;
    01394
    01395                 UdfLookupActiveIcb( IrpContext, &IcbContext );
    01396
    01397                 UdfInitializeFcbFromIcbContext( IrpContext,
    01398                                                 NextFcb,
    01399                                                 &IcbContext );
    01400
    01401                 UdfCleanupIcbContext( IrpContext, &IcbContext );
    01402                 CleanupIcbContext = FALSE;
    01403
    01404             } except( UdfExceptionFilter( IrpContext, GetExceptionInformation() )) {
    01405
    01406                 //
    01407                 //   Any error we receive is an indication that the given fileid is
    01408                 //   not valid.
    01409                 //
    01410
    01411                 Status = STATUS_INVALID_PARAMETER;
    01412             }
    01413
    01414             //
    01415             //  Do a little dance to leave the exception handler if we had problems.
    01416             //
    01417
    01418             if (Status == STATUS_INVALID_PARAMETER) {
    01419
    01420                 try_leave( NOTHING );
    01421             }
    01422         }
    01423
    01424         //
    01425         //  We have the Fcb.  Check that the type of the file is compatible with
    01426         //  the desired type of file to open.
    01427         //
    01428
    01429         if (FlagOn( NextFcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
    01430
    01431             if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NON_DIRECTORY_FILE )) {
    01432
    01433                 try_leave( Status = STATUS_FILE_IS_A_DIRECTORY );
    01434             }
    01435
    01436         } else if (FlagOn( IrpSp->Parameters.Create.Options, FILE_DIRECTORY_FILE )) {
    01437
    01438             try_leave( Status = STATUS_NOT_A_DIRECTORY );
    01439         }
    01440
    01441         //
    01442         //  We now know the Fcb and currently hold the Vcb lock.
    01443         //  Try to acquire this Fcb without waiting.  Otherwise we
    01444         //  need to reference it, drop the Vcb, acquire the Fcb, the
    01445         //  Vcb and then dereference the Fcb.
    01446         //
    01447
    01448         if (!UdfAcquireFcbExclusive( IrpContext, NextFcb, TRUE )) {
    01449
    01450             NextFcb->FcbReference += 1;
    01451             UdfUnlockVcb( IrpContext, Vcb );
    01452
    01453             UdfAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
    01454
    01455             UdfLockVcb( IrpContext, Vcb );
    01456             NextFcb->FcbReference -= 1;
    01457         }
    01458
    01459         UdfUnlockVcb( IrpContext, Vcb );
    01460         UnlockVcb = FALSE;
    01461
    01462         //
    01463         //  Move to this Fcb.
    01464         //
    01465
    01466         *CurrentFcb = NextFcb;
    01467
    01468         //
    01469         //  Check the requested access on this Fcb.
    01470         //
    01471
    01472         if (!UdfIllegalFcbAccess( IrpContext,
    01473                                   TypeOfOpen,
    01474                                   IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
    01475
    01476             //
    01477             //  Call our worker routine to complete the open.
    01478             //
    01479
    01480             Status = UdfCompleteFcbOpen( IrpContext,
    01481                                          IrpSp,
    01482                                          Vcb,
    01483                                          CurrentFcb,
    01484                                          NULL,
    01485                                          TypeOfOpen,
    01486                                          CCB_FLAG_OPEN_BY_ID,
    01487                                          IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
    01488         }
    01489
    01490     } finally {
    01491
    01492         if (UnlockVcb) {
    01493
    01494             UdfUnlockVcb( IrpContext, Vcb );
    01495         }
    01496
    01497         if (CleanupIcbContext) {
    01498
    01499             UdfCleanupIcbContext( IrpContext, &IcbContext );
    01500         }
    01501
    01502         //
    01503         //  Destroy the new Fcb if it was not fully initialized.
    01504         //
    01505
    01506         if (NextFcb && !FlagOn( NextFcb->FcbState, FCB_STATE_INITIALIZED )) {
    01507
    01508             UdfDeleteFcb( IrpContext, NextFcb );
    01509         }
    01510
    01511     }
    01512
    01513     return Status;
    01514 }
    01515
    01516
    01517 //
    01518 //  Local support routine
    01519 //
    01520
    01521 NTSTATUS
    01522 UdfOpenExistingFcb (
    01523     IN PIRP_CONTEXT IrpContext,
    01524     IN PIO_STACK_LOCATION IrpSp,
    01525     IN OUT PFCB *CurrentFcb,
    01526     IN PLCB OpenLcb,
    01527     IN TYPE_OF_OPEN TypeOfOpen,
    01528     IN BOOLEAN IgnoreCase,
    01529     IN PCCB RelatedCcb OPTIONAL
    01530     )
    01531
    01532 /*++
    01533
    01534 Routine Description:
    01535
    01536     This routine is called to open an Fcb which is already in the Fcb table.
    01537     We will verify the access to the file and then call our worker routine
    01538     to perform the final operations.
    01539
    01540 Arguments:
    01541
    01542     IrpSp - Pointer to the stack location for this open.
    01543
    01544     CurrentFcb - Address of Fcb to open.  We will clear this if the Fcb
    01545         is released here.
    01546
    01547     OpenLcb - Lcb used to find this Fcb.
    01548
    01549     TypeOfOpen - Indicates whether we are opening a file, directory or volume.
    01550
    01551     IgnoreCase - Indicates if this open is case-insensitive.
    01552
    01553     RelatedCcb - Ccb for related file object if relative open.  We use
    01554         this when setting the Ccb flags for this open.  It will tell
    01555         us whether the name currently in the file object is relative or
    01556         absolute.
    01557
    01558 Return Value:
    01559
    01560     NTSTATUS - Status indicating the result of the operation.
    01561
    01562 --*/
    01563
    01564 {
    01565     ULONG CcbFlags = 0;
    01566
    01567     NTSTATUS Status = STATUS_ACCESS_DENIED;
    01568
    01569     PAGED_CODE();
    01570
    01571     //
    01572     //  Check inputs.
    01573     //
    01574
    01575     ASSERT_IRP_CONTEXT( IrpContext );
    01576     ASSERT_EXCLUSIVE_FCB( *CurrentFcb );
    01577     ASSERT_OPTIONAL_CCB( RelatedCcb );
    01578
    01579     //
    01580     //  Check that the desired access is legal.
    01581     //
    01582
    01583     if (!UdfIllegalFcbAccess( IrpContext,
    01584                               TypeOfOpen,
    01585                               IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
    01586
    01587         //
    01588         //  Set the Ignore case.
    01589         //
    01590
    01591         if (IgnoreCase) {
    01592
    01593             SetFlag( CcbFlags, CCB_FLAG_IGNORE_CASE );
    01594         }
    01595
    01596         //
    01597         //  Check the related Ccb to see if this was an OpenByFileId and
    01598         //  whether there was a version.
    01599         //
    01600
    01601         if (ARGUMENT_PRESENT( RelatedCcb )) {
    01602
    01603             if (FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID | CCB_FLAG_OPEN_RELATIVE_BY_ID )) {
    01604
    01605                 SetFlag( CcbFlags, CCB_FLAG_OPEN_RELATIVE_BY_ID );
    01606             }
    01607         }
    01608
    01609         //
    01610         //  Call our worker routine to complete the open.
    01611         //
    01612
    01613         Status = UdfCompleteFcbOpen( IrpContext,
    01614                                      IrpSp,
    01615                                      (*CurrentFcb)->Vcb,
    01616                                      CurrentFcb,
    01617                                      OpenLcb,
    01618                                      TypeOfOpen,
    01619                                      CcbFlags,
    01620                                      IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
    01621     }
    01622
    01623     return Status;
    01624 }
    01625
    01626
    01627 //
    01628 //  Local support routine
    01629 //
    01630
    01631 NTSTATUS
    01632 UdfOpenObjectFromDirContext (
    01633     IN PIRP_CONTEXT IrpContext,
    01634     IN PIO_STACK_LOCATION IrpSp,
    01635     IN PVCB Vcb,
    01636     IN OUT PFCB *CurrentFcb,
    01637     IN BOOLEAN ShortNameMatch,
    01638     IN BOOLEAN IgnoreCase,
    01639     IN PDIR_ENUM_CONTEXT DirContext,
    01640     IN BOOLEAN PerformUserOpen,
    01641     IN PCCB RelatedCcb OPTIONAL
    01642     )
    01643
    01644 /*++
    01645
    01646 Routine Description:
    01647
    01648     This routine is called to open an object found in a directory scan.  This
    01649     can be a directory or a file as indicated in the scan's results.
    01650
    01651     We first check that the desired access is legal for this file.  Then we
    01652     construct the FileId for this and do a check to see if it is the Fcb
    01653     Table.  It is always possible that either it was created since or simply
    01654     wasn't in the prefix table at the time of the prefix table search.
    01655     Lookup the active ICB, initialize the Fcb and store into the FcbTable
    01656     if not present.
    01657
    01658     Next we will add this to the prefix table of our parent if needed.
    01659
    01660     Once we know that the new Fcb has been initialized then we move our pointer
    01661     in the tree down to this position.
    01662
    01663     This routine does not own the Vcb lock on entry.  We must be sure to release
    01664     it on exit.
    01665
    01666 Arguments:
    01667
    01668     IrpSp - Stack location for this request.
    01669
    01670     Vcb - Vcb for the current volume.
    01671
    01672     CurrentFcb - On input this is the parent of the Fcb to open.  On output we
    01673         store the Fcb for the file being opened.
    01674
    01675     ShortNameMatch - Indicates whether this object was opened by the shortname.
    01676
    01677     IgnoreCase - Indicates the case sensitivity of the caller.
    01678
    01679     DirContext - This is the context used to find the object.
    01680
    01681     PerformUserOpen - Indicates if we are at the object the user wants to finally open.
    01682
    01683     RelatedCcb - RelatedCcb for relative file object used to make this open.
    01684
    01685 Return Value:
    01686
    01687     NTSTATUS - Status indicating the result of the operation.
    01688
    01689 --*/
    01690
    01691 {
    01692     ULONG CcbFlags = 0;
    01693     FILE_ID FileId;
    01694
    01695     BOOLEAN UnlockVcb = FALSE;
    01696     BOOLEAN FcbExisted;
    01697
    01698     PFCB NextFcb = NULL;
    01699     PFCB ParentFcb = NULL;
    01700
    01701     TYPE_OF_OPEN TypeOfOpen;
    01702     NODE_TYPE_CODE NodeTypeCode;
    01703
    01704     ICB_SEARCH_CONTEXT IcbContext;
    01705     BOOLEAN CleanupIcbContext = FALSE;
    01706
    01707     PLCB OpenLcb;
    01708
    01709     NTSTATUS Status;
    01710
    01711     PAGED_CODE();
    01712
    01713     //
    01714     //  Figure out what kind of open we will be performing here.  The caller has already insured
    01715     //  that the user is expecting us to do this.
    01716     //
    01717
    01718     if (FlagOn( DirContext->Fid->Flags, NSR_FID_F_DIRECTORY )) {
    01719
    01720         TypeOfOpen = UserDirectoryOpen;
    01721         NodeTypeCode = UDFS_NTC_FCB_INDEX;
    01722
    01723     } else {
    01724
    01725         TypeOfOpen = UserFileOpen;
    01726         NodeTypeCode = UDFS_NTC_FCB_DATA;
    01727     }
    01728
    01729     //
    01730     //  Check for illegal access to this file.
    01731     //
    01732
    01733     if (PerformUserOpen &&
    01734         UdfIllegalFcbAccess( IrpContext,
    01735                              TypeOfOpen,
    01736                              IrpSp->Parameters.Create.SecurityContext->DesiredAccess )) {
    01737
    01738         return STATUS_ACCESS_DENIED;
    01739     }
    01740
    01741     //
    01742     //  Use a try-finally to facilitate cleanup.
    01743     //
    01744
    01745     try {
    01746
    01747         //
    01748         //  Check the related Ccb to see if this was an OpenByFileId.
    01749         //
    01750
    01751         if (ARGUMENT_PRESENT( RelatedCcb ) &&
    01752             FlagOn( RelatedCcb->Flags, CCB_FLAG_OPEN_BY_ID | CCB_FLAG_OPEN_RELATIVE_BY_ID )) {
    01753
    01754             SetFlag( CcbFlags, CCB_FLAG_OPEN_RELATIVE_BY_ID );
    01755         }
    01756
    01757         if (IgnoreCase) {
    01758
    01759             SetFlag( CcbFlags, CCB_FLAG_IGNORE_CASE );
    01760         }
    01761
    01762         //
    01763         //  Build the file Id for this object.
    01764         //
    01765
    01766         UdfSetFidFromLbAddr( FileId, DirContext->Fid->Icb.Start );
    01767
    01768         if (TypeOfOpen == UserDirectoryOpen) {
    01769
    01770             UdfSetFidDirectory( FileId );
    01771         }
    01772
    01773         //
    01774         //  Lock the Vcb so we can examine the Fcb Table.
    01775         //
    01776
    01777         UdfLockVcb( IrpContext, Vcb );
    01778         UnlockVcb = TRUE;
    01779
    01780         //
    01781         //  Get the Fcb for this file.
    01782         //
    01783
    01784         NextFcb = UdfCreateFcb( IrpContext, FileId, NodeTypeCode, &FcbExisted );
    01785
    01786         //
    01787         //  If the Fcb was created here then initialize from the values in the
    01788         //  dirent.  We have optimistically assumed that there isn't any corrupt
    01789         //  information to this point - we're about to discover it if there is.
    01790         //
    01791
    01792         if (!FcbExisted) {
    01793
    01794             //
    01795             //  Set the root extent length and go get the active ICB, initialize.
    01796             //
    01797
    01798             NextFcb->RootExtentLength = DirContext->Fid->Icb.Length.Length;
    01799
    01800             UdfInitializeIcbContextFromFcb( IrpContext, &IcbContext, NextFcb );
    01801             CleanupIcbContext = TRUE;
    01802
    01803             UdfLookupActiveIcb( IrpContext, &IcbContext );
    01804
    01805             UdfInitializeFcbFromIcbContext( IrpContext,
    01806                                             NextFcb,
    01807                                             &IcbContext );
    01808
    01809             UdfCleanupIcbContext( IrpContext, &IcbContext );
    01810             CleanupIcbContext = FALSE;
    01811
    01812         }
    01813
    01814         //
    01815         //  Now try to acquire the new Fcb without waiting.  We will reference
    01816         //  the Fcb and retry with wait if unsuccessful.
    01817         //
    01818
    01819         if (!UdfAcquireFcbExclusive( IrpContext, NextFcb, TRUE )) {
    01820
    01821             NextFcb->FcbReference += 1;
    01822
    01823             UdfUnlockVcb( IrpContext, Vcb );
    01824
    01825             UdfReleaseFcb( IrpContext, *CurrentFcb );
    01826             UdfAcquireFcbExclusive( IrpContext, NextFcb, FALSE );
    01827             UdfAcquireFcbExclusive( IrpContext, *CurrentFcb, FALSE );
    01828
    01829             UdfLockVcb( IrpContext, Vcb );
    01830             NextFcb->FcbReference -= 1;
    01831         }
    01832
    01833         //
    01834         //  Move down to this new Fcb.  Remember that we still own the parent however.
    01835         //
    01836
    01837         ParentFcb = *CurrentFcb;
    01838         *CurrentFcb = NextFcb;
    01839
    01840         //
    01841         //  Store this name into the prefix table for the parent.
    01842         //
    01843
    01844         OpenLcb = UdfInsertPrefix( IrpContext,
    01845                                    NextFcb,
    01846                                    ( ShortNameMatch?
    01847                                      &DirContext->ShortObjectName :
    01848                                      &DirContext->CaseObjectName ),
    01849                                    ShortNameMatch,
    01850                                    IgnoreCase,
    01851                                    ParentFcb );
    01852
    01853         //
    01854         //  Now increment the reference counts for the parent and drop the Vcb.
    01855         //
    01856
    01857         DebugTrace(( +1, Dbg,
    01858                      "UdfOpenObjectFromDirContext, PFcb %08x Vcb %d/%d Fcb %d/%d\n", ParentFcb,
    01859                      Vcb->VcbReference,
    01860                      Vcb->VcbUserReference,
    01861                      ParentFcb->FcbReference,
    01862                      ParentFcb->FcbUserReference ));
    01863
    01864         UdfIncrementReferenceCounts( IrpContext, ParentFcb, 1, 1 );
    01865
    01866         DebugTrace(( -1, Dbg,
    01867                      "UdfOpenObjectFromDirContext, Vcb %d/%d Fcb %d/%d\n",
    01868                      Vcb->VcbReference,
    01869                      Vcb->VcbUserReference,
    01870                      ParentFcb->FcbReference,
    01871                      ParentFcb->FcbUserReference ));
    01872
    01873         UdfUnlockVcb( IrpContext, Vcb );
    01874         UnlockVcb = FALSE;
    01875
    01876         //
    01877         //  Perform initialization associated with the directory context.
    01878         //
    01879
    01880         UdfInitializeLcbFromDirContext( IrpContext,
    01881                                         OpenLcb,
    01882                                         DirContext );
    01883
    01884         //
    01885         //  Release the parent Fcb at this point.
    01886         //
    01887
    01888         UdfReleaseFcb( IrpContext, ParentFcb );
    01889         ParentFcb = NULL;
    01890
    01891         //
    01892         //  Call our worker routine to complete the open.
    01893         //
    01894
    01895         if (PerformUserOpen) {
    01896
    01897             Status = UdfCompleteFcbOpen( IrpContext,
    01898                                          IrpSp,
    01899                                          Vcb,
    01900                                          CurrentFcb,
    01901                                          OpenLcb,
    01902                                          TypeOfOpen,
    01903                                          CcbFlags,
    01904                                          IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
    01905         }
    01906
    01907     } finally {
    01908
    01909         //
    01910         //  Unlock the Vcb if held.
    01911         //
    01912
    01913         if (UnlockVcb) {
    01914
    01915             UdfUnlockVcb( IrpContext, Vcb );
    01916         }
    01917
    01918         //
    01919         //  Release the parent if held.
    01920         //
    01921
    01922         if (ParentFcb != NULL) {
    01923
    01924             UdfReleaseFcb( IrpContext, ParentFcb );
    01925         }
    01926
    01927         //
    01928         //  Destroy the new Fcb if it was not fully initialized.
    01929         //
    01930
    01931         if (NextFcb && !FlagOn( NextFcb->FcbState, FCB_STATE_INITIALIZED )) {
    01932
    01933             UdfDeleteFcb( IrpContext, NextFcb );
    01934         }
    01935
    01936         //
    01937         //  Clean up the Icb context if used.
    01938         //
    01939
    01940         if (CleanupIcbContext) {
    01941
    01942             UdfCleanupIcbContext( IrpContext, &IcbContext );
    01943         }
    01944     }
    01945
    01946     return Status;
    01947 }
    01948
    01949
    01950 //
    01951 //  Local support routine
    01952 //
    01953
    01954 NTSTATUS
    01955 UdfCompleteFcbOpen (
    01956     IN PIRP_CONTEXT IrpContext,
    01957     PIO_STACK_LOCATION IrpSp,
    01958     IN PVCB Vcb,
    01959     IN OUT PFCB *CurrentFcb,
    01960     IN PLCB OpenLcb OPTIONAL,
    01961     IN TYPE_OF_OPEN TypeOfOpen,
    01962     IN ULONG UserCcbFlags,
    01963     IN ACCESS_MASK DesiredAccess
    01964     )
    01965
    01966 /*++
    01967
    01968 Routine Description:
    01969
    01970     This is the worker routine which takes an existing Fcb and completes
    01971     the open.  We will do any necessary oplock checks and sharing checks.
    01972     Finally we will create the Ccb and update the file object and any
    01973     file object flags.
    01974
    01975 Arguments:
    01976
    01977     IrpSp - Stack location for the current request.
    01978
    01979     Vcb - Vcb for the current volume.
    01980
    01981     CurrentFcb - Address of pointer to Fcb to open.  We clear this field if
    01982         we release the resource for this file.
    01983
    01984     OpenLcb - Lcb this Fcb is being opened by
    01985
    01986     TypeOfOpen - Type of open for this request.
    01987
    01988     UserCcbFlags - Flags to OR into the Ccb flags.
    01989
    01990     DesiredAccess - Desired access for this open.
    01991
    01992 Return Value:
    01993
    01994     NTSTATUS - STATUS_SUCCESS if we complete this request, STATUS_PENDING if
    01995         the oplock package takes the Irp or SHARING_VIOLATION if there is a
    01996         sharing check conflict.
    01997
    01998 --*/
    01999
    02000 {
    02001     NTSTATUS Status;
    02002     NTSTATUS OplockStatus = STATUS_SUCCESS;
    02003     ULONG Information = FILE_OPENED;
    02004
    02005     BOOLEAN LockVolume = FALSE;
    02006
    02007     PFCB Fcb = *CurrentFcb;
    02008     PCCB Ccb;
    02009
    02010     PAGED_CODE();
    02011
    02012     //
    02013     //  If this a volume open and the user wants to lock the volume then
    02014     //  purge and lock the volume.
    02015     //
    02016
    02017     if ((TypeOfOpen <= UserVolumeOpen) &&
    02018         !FlagOn( IrpSp->Parameters.Create.ShareAccess, FILE_SHARE_READ )) {
    02019
    02020         //
    02021         //  If there are open handles then fail this immediately.
    02022         //
    02023
    02024         if (Vcb->VcbCleanup != 0) {
    02025
    02026             return STATUS_SHARING_VIOLATION;
    02027         }
    02028
    02029         //
    02030         //  If we can't wait then force this to be posted.
    02031         //
    02032
    02033         if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) {
    02034
    02035             UdfRaiseStatus( IrpContext, STATUS_CANT_WAIT );
    02036         }
    02037
    02038         LockVolume = TRUE;
    02039
    02040         //
    02041         //  Purge the volume and make sure all of the user references
    02042         //  are gone.
    02043         //
    02044
    02045         Status = UdfPurgeVolume( IrpContext, Vcb, FALSE );
    02046
    02047         if (Status != STATUS_SUCCESS) {
    02048
    02049             return Status;
    02050         }
    02051
    02052         //
    02053         //  Now force all of the delayed close operations to go away.
    02054         //
    02055
    02056         UdfFspClose( Vcb );
    02057
    02058         if (Vcb->VcbUserReference > Vcb->VcbResidualUserReference) {
    02059
    02060             return STATUS_SHARING_VIOLATION;
    02061         }
    02062     }
    02063
    02064     //
    02065     //  If the Fcb already existed then we need to check the oplocks and
    02066     //  the share access.
    02067     //
    02068
    02069     if (Fcb->FcbCleanup != 0) {
    02070
    02071         //
    02072         //  If this is a user file open then check whether there are any
    02073         //  batch oplock.
    02074         //
    02075
    02076         if (TypeOfOpen == UserFileOpen) {
    02077
    02078             //
    02079             //  Store the address of the Fcb for a possible teardown into
    02080             //  the IrpContext.  We will release this in the call to
    02081             //  prepost the Irp.
    02082             //
    02083
    02084             IrpContext->TeardownFcb = CurrentFcb;
    02085
    02086             if (FsRtlCurrentBatchOplock( &Fcb->Oplock )) {
    02087
    02088                 //
    02089                 //  We remember if a batch oplock break is underway for the
    02090                 //  case where the sharing check fails.
    02091                 //
    02092
    02093                 Information = FILE_OPBATCH_BREAK_UNDERWAY;
    02094
    02095                 OplockStatus = FsRtlCheckOplock( &Fcb->Oplock,
    02096                                                  IrpContext->Irp,
    02097                                                  IrpContext,
    02098                                                  UdfOplockComplete,
    02099                                                  UdfPrePostIrp );
    02100
    02101                 if (OplockStatus == STATUS_PENDING) {
    02102
    02103                     return STATUS_PENDING;
    02104                 }
    02105             }
    02106
    02107             //
    02108             //  Check the share access before breaking any exclusive oplocks.
    02109             //
    02110
    02111             Status = IoCheckShareAccess( DesiredAccess,
    02112                                          IrpSp->Parameters.Create.ShareAccess,
    02113                                          IrpSp->FileObject,
    02114                                          &Fcb->ShareAccess,
    02115                                          FALSE );
    02116
    02117             if (!NT_SUCCESS( Status )) {
    02118
    02119                 return Status;
    02120             }
    02121
    02122             //
    02123             //  Now check that we can continue based on the oplock state of the
    02124             //  file.
    02125             //
    02126
    02127             OplockStatus = FsRtlCheckOplock( &Fcb->Oplock,
    02128                                              IrpContext->Irp,
    02129                                              IrpContext,
    02130                                              UdfOplockComplete,
    02131                                              UdfPrePostIrp );
    02132
    02133             if (OplockStatus == STATUS_PENDING) {
    02134
    02135                 return STATUS_PENDING;
    02136             }
    02137
    02138             IrpContext->TeardownFcb = NULL;
    02139
    02140         //
    02141         //  Otherwise just do the sharing check.
    02142         //
    02143
    02144         } else {
    02145
    02146             Status = IoCheckShareAccess( DesiredAccess,
    02147                                          IrpSp->Parameters.Create.ShareAccess,
    02148                                          IrpSp->FileObject,
    02149                                          &Fcb->ShareAccess,
    02150                                          FALSE );
    02151
    02152             if (!NT_SUCCESS( Status )) {
    02153
    02154                 return Status;
    02155             }
    02156         }
    02157     }
    02158
    02159     //
    02160     //  Create the Ccb now.
    02161     //
    02162
    02163     Ccb = UdfCreateCcb( IrpContext, Fcb, OpenLcb, UserCcbFlags );
    02164
    02165     //
    02166     //  Update the share access.
    02167     //
    02168
    02169     if (Fcb->FcbCleanup == 0) {
    02170
    02171         IoSetShareAccess( DesiredAccess,
    02172                           IrpSp->Parameters.Create.ShareAccess,
    02173                           IrpSp->FileObject,
    02174                           &Fcb->ShareAccess );
    02175
    02176     } else {
    02177
    02178         IoUpdateShareAccess( IrpSp->FileObject, &Fcb->ShareAccess );
    02179     }
    02180
    02181     //
    02182     //  Set the file object type.
    02183     //
    02184
    02185     UdfSetFileObject( IrpContext, IrpSp->FileObject, TypeOfOpen, Fcb, Ccb );
    02186
    02187     //
    02188     //  Set the appropriate cache flags for a user file object.
    02189     //
    02190
    02191     if (TypeOfOpen == UserFileOpen) {
    02192
    02193         if (FlagOn( IrpSp->Parameters.Create.Options, FILE_NO_INTERMEDIATE_BUFFERING )) {
    02194
    02195             SetFlag( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING );
    02196
    02197         } else {
    02198
    02199             SetFlag( IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED );
    02200         }
    02201     }
    02202     //
    02203     //  Update the open and cleanup counts.  Check the fast io state here.
    02204     //
    02205
    02206     UdfLockVcb( IrpContext, Vcb );
    02207
    02208     UdfIncrementCleanupCounts( IrpContext, Fcb );
    02209
    02210     DebugTrace(( +1, Dbg,
    02211                  "UdfCompleteFcbOpen, Fcb %08x Vcb %d/%d Fcb %d/%d\n", Fcb,
    02212                  Vcb->VcbReference,
    02213                  Vcb->VcbUserReference,
    02214                  Fcb->FcbReference,
    02215                  Fcb->FcbUserReference ));
    02216
    02217     UdfIncrementReferenceCounts( IrpContext, Fcb, 1, 1 );
    02218
    02219     DebugTrace(( -1, Dbg,
    02220                  "UdfCompleteFcbOpen, Vcb %d/%d Fcb %d/%d\n",
    02221                  Vcb->VcbReference,
    02222                  Vcb->VcbUserReference,
    02223                  Fcb->FcbReference,
    02224                  Fcb->FcbUserReference ));
    02225
    02226     if (LockVolume) {
    02227
    02228         Vcb->VolumeLockFileObject = IrpSp->FileObject;
    02229         SetFlag( Vcb->VcbState, VCB_STATE_LOCKED );
    02230     }
    02231
    02232     UdfUnlockVcb( IrpContext, Vcb );
    02233
    02234     UdfLockFcb( IrpContext, Fcb );
    02235
    02236     if (TypeOfOpen == UserFileOpen) {
    02237
    02238         Fcb->IsFastIoPossible = UdfIsFastIoPossible( Fcb );
    02239
    02240     } else {
    02241
    02242         Fcb->IsFastIoPossible = FastIoIsNotPossible;
    02243     }
    02244
    02245     UdfUnlockFcb( IrpContext, Fcb );
    02246
    02247     //
    02248     //  Show that we opened the file.
    02249     //
    02250
    02251     IrpContext->Irp->IoStatus.Information = Information;
    02252
    02253     //
    02254     //  Point to the section object pointer in the non-paged Fcb.
    02255     //
    02256
    02257     IrpSp->FileObject->SectionObjectPointer = &Fcb->FcbNonpaged->SegmentObject;
    02258     return OplockStatus;
    02259 }
    02260