Something went wrong. Try again.
Reactos
Something went wrong. Try again.
114 kB · 2583 lines
C++
at master
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584////////////////////////////////////////////////////////////////////// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine// All rights reserved// This file was released under the GPLv2 on June 2015./////////////////////////////////////////////////////////////////////*************************************************************************** File: Create.cpp** Module: UDF File System Driver (Kernel mode execution only)** Description:* Contains code to handle the "Create"/"Open" dispatch entry point.**************************************************************************/
#include "udffs.h"
#define IsFileObjectReadOnly(FO) (!((FO)->WriteAccess | (FO)->DeleteAccess))
// define the file specific bug-check id#define UDF_BUG_CHECK_ID UDF_FILE_CREATE
#define MEM_USABS_TAG "US_Abs"#define MEM_USLOC_TAG "US_Loc"#define MEM_USOBJ_TAG "US_Obj"
#define UDF_LOG_CREATE_DISPOSITION
/*************************************************************************** Function: UDFCreate()** Description:* The I/O Manager will invoke this routine to handle a create/open* request** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution* to be deferred to a worker thread context)** Return Value: STATUS_SUCCESS/Error**************************************************************************/NTSTATUSNTAPIUDFCreate( PDEVICE_OBJECT DeviceObject, // the logical volume device object PIRP Irp) // I/O Request Packet{ NTSTATUS RC = STATUS_SUCCESS; PtrUDFIrpContext PtrIrpContext; BOOLEAN AreWeTopLevel = FALSE;
TmPrint(("UDFCreate:\n"));
FsRtlEnterFileSystem(); ASSERT(DeviceObject); ASSERT(Irp);
// sometimes, we may be called here with the device object representing // the file system (instead of the device object created for a logical // volume. In this case, there is not much we wish to do (this create // typically will happen 'cause some process has to open the FSD device // object so as to be able to send an IOCTL to the FSD)
// All of the logical volume device objects we create have a device // extension whereas the device object representing the FSD has no // device extension. This seems like a good enough method to identify // between the two device objects ... if (UDFIsFSDevObj(DeviceObject)) { // this is an open of the FSD itself Irp->IoStatus.Status = RC; Irp->IoStatus.Information = FILE_OPENED;
IoCompleteRequest(Irp, IO_NO_INCREMENT); FsRtlExitFileSystem(); return(RC); }
// set the top level context AreWeTopLevel = UDFIsIrpTopLevel(Irp);
_SEH2_TRY {
// get an IRP context structure and issue the request PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); if(PtrIrpContext) { RC = UDFCommonCreate(PtrIrpContext, Irp); } else { RC = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Status = RC; Irp->IoStatus.Information = 0; // complete the IRP IoCompleteRequest(Irp, IO_DISK_INCREMENT); }
} _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
RC = UDFExceptionHandler(PtrIrpContext, Irp);
UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); } _SEH2_END;
if (AreWeTopLevel) { IoSetTopLevelIrp(NULL); }
AdPrint(("UDFCreate: %x\n", RC));
FsRtlExitFileSystem();
return(RC);
} // end UDFCreate()
/* */VOID__fastcallUDFReleaseResFromCreate( IN PERESOURCE* PagingIoRes, IN PERESOURCE* Res1, IN PERESOURCE* Res2 ){ if(*PagingIoRes) { UDFReleaseResource(*PagingIoRes); (*PagingIoRes) = NULL; } if(*Res1) { UDFReleaseResource(*Res1); (*Res1) = NULL; } if(*Res2) { UDFReleaseResource(*Res2); (*Res2) = NULL; }} // end UDFReleaseResFromCreate()
/* */VOID__fastcallUDFAcquireParent( IN PUDF_FILE_INFO RelatedFileInfo, IN PERESOURCE* Res1, IN PERESOURCE* Res2 ){ if(RelatedFileInfo->Fcb && RelatedFileInfo->Fcb->ParentFcb) {
UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->ParentFcb->NTRequiredFCB); UDFAcquireResourceExclusive((*Res2) = &(RelatedFileInfo->Fcb->ParentFcb->NTRequiredFCB->MainResource),TRUE); }
UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->NTRequiredFCB); UDFAcquireResourceExclusive((*Res1) = &(RelatedFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE);
UDFInterlockedIncrement((PLONG)&(RelatedFileInfo->Fcb->ReferenceCount)); UDFInterlockedIncrement((PLONG)&(RelatedFileInfo->Dloc->CommonFcb->CommonRefCount)); UDFReferenceFile__(RelatedFileInfo); ASSERT_REF(RelatedFileInfo->Fcb->ReferenceCount >= RelatedFileInfo->RefCount);} // end UDFAcquireParent()
/*************************************************************************** Function: UDFCommonCreate()** Description:* The actual work is performed here. This routine may be invoked in one'* of the two possible contexts:* (a) in the context of a system worker thread* (b) in the context of the original caller** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL** Return Value: STATUS_SUCCESS/Error**************************************************************************/NTSTATUSUDFCommonCreate( PtrUDFIrpContext PtrIrpContext, PIRP Irp ){ NTSTATUS RC = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp = NULL; PIO_SECURITY_CONTEXT PtrSecurityContext = NULL; PFILE_OBJECT PtrNewFileObject = NULL; PFILE_OBJECT PtrRelatedFileObject = NULL; LONGLONG AllocationSize; // if we create a new file PFILE_FULL_EA_INFORMATION PtrExtAttrBuffer = NULL; ULONG RequestedOptions; ULONG RequestedDisposition; USHORT FileAttributes; USHORT TmpFileAttributes; USHORT ShareAccess; ULONG ExtAttrLength = 0; ACCESS_MASK DesiredAccess; PACCESS_STATE AccessState;
_SEH2_VOLATILE PVCB Vcb = NULL; _SEH2_VOLATILE BOOLEAN AcquiredVcb = FALSE; BOOLEAN OpenExisting = FALSE; PERESOURCE Res1 = NULL; PERESOURCE Res2 = NULL; PERESOURCE PagingIoRes = NULL;
// BOOLEAN DirectoryOnlyRequested;// BOOLEAN FileOnlyRequested;// BOOLEAN NoBufferingSpecified; BOOLEAN WriteThroughRequested; BOOLEAN DeleteOnCloseSpecified;// BOOLEAN NoExtAttrKnowledge;// BOOLEAN CreateTreeConnection = FALSE;// BOOLEAN OpenByFileId;
// Are we dealing with a page file? BOOLEAN PageFileManipulation; // Is this open for a target directory (used in rename operations)? BOOLEAN OpenTargetDirectory; // Should we ignore case when attempting to locate the object? BOOLEAN IgnoreCase;
PtrUDFCCB PtrRelatedCCB = NULL, PtrNewCcb = NULL; PtrUDFFCB PtrRelatedFCB = NULL, PtrNewFcb = NULL; PtrUDFNTRequiredFCB NtReqFcb;
ULONG ReturnedInformation = 0;
UNICODE_STRING TargetObjectName; UNICODE_STRING RelatedObjectName;
UNICODE_STRING AbsolutePathName; // '\aaa\cdf\fff\rrrr.tre:s' UNICODE_STRING LocalPath; // '\aaa\cdf' UNICODE_STRING CurName; // 'cdf' UNICODE_STRING TailName; // 'fff\rrrr.tre:s' UNICODE_STRING LastGoodName; // it depends... UNICODE_STRING LastGoodTail; // it depends... UNICODE_STRING StreamName; // ':s'
PUDF_FILE_INFO RelatedFileInfo; PUDF_FILE_INFO OldRelatedFileInfo = NULL; PUDF_FILE_INFO NewFileInfo = NULL; PUDF_FILE_INFO LastGoodFileInfo = NULL; PWCHAR TmpBuffer; ULONG TreeLength = 0;// ULONG i = 0;
BOOLEAN StreamOpen = FALSE; BOOLEAN StreamExists = FALSE; BOOLEAN RestoreVCBOpenCounter = FALSE; BOOLEAN RestoreShareAccess = FALSE; PWCHAR TailNameBuffer = NULL; ULONG SNameIndex = 0;
TmPrint(("UDFCommonCreate:\n"));
ASSERT(PtrIrpContext); ASSERT(Irp);
_SEH2_TRY {
AbsolutePathName.Buffer = LocalPath.Buffer = NULL; // If we were called with our file system device object instead of a // volume device object, just complete this request with STATUS_SUCCESS. if (!(PtrIrpContext->TargetDeviceObject->DeviceExtension)) {
ReturnedInformation = FILE_OPENED; try_return(RC = STATUS_SUCCESS); }
AbsolutePathName.Length = AbsolutePathName.MaximumLength = LocalPath.Length = LocalPath.MaximumLength = 0; // First, get a pointer to the current I/O stack location IrpSp = IoGetCurrentIrpStackLocation(Irp); ASSERT(IrpSp);
// If the caller cannot block, post the request to be handled // asynchronously if (!(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK)) { // We must defer processing of this request since we could // block anytime while performing the create/open ... ASSERT(FALSE); RC = UDFPostRequest(PtrIrpContext, Irp); try_return(RC); }
// Now, we can obtain the parameters specified by the user. // Note that the file object is the new object created by the // I/O Manager in anticipation that this create/open request // will succeed. PtrNewFileObject = IrpSp->FileObject; TargetObjectName = PtrNewFileObject->FileName; PtrRelatedFileObject = PtrNewFileObject->RelatedFileObject;
// If a related file object is present, get the pointers // to the CCB and the FCB for the related file object if (PtrRelatedFileObject) { PtrRelatedCCB = (PtrUDFCCB)(PtrRelatedFileObject->FsContext2); ASSERT(PtrRelatedCCB); ASSERT(PtrRelatedCCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_CCB); // each CCB in turn points to a FCB PtrRelatedFCB = PtrRelatedCCB->Fcb; ASSERT(PtrRelatedFCB); ASSERT((PtrRelatedFCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB) ||(PtrRelatedFCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB)); RelatedObjectName = PtrRelatedFileObject->FileName; if (!(RelatedObjectName.Length) || (RelatedObjectName.Buffer[0] != L'\\')) { if(PtrRelatedFCB->FCBName) RelatedObjectName = PtrRelatedFCB->FCBName->ObjectName; } }
// Allocation size is only used if a new file is created // or a file is superseded. AllocationSize = Irp->Overlay.AllocationSize.QuadPart;
// Get a ptr to the supplied security context PtrSecurityContext = IrpSp->Parameters.Create.SecurityContext; AccessState = PtrSecurityContext->AccessState;
// The desired access can be obtained from the SecurityContext DesiredAccess = PtrSecurityContext->DesiredAccess;
// Two values are supplied in the Create.Options field: // (a) the actual user supplied options // (b) the create disposition RequestedOptions = (IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS);
// The file disposition is packed with the user options ... // Disposition includes FILE_SUPERSEDE, FILE_OPEN_IF, etc. RequestedDisposition = (IrpSp->Parameters.Create.Options >> 24);// & 0xFF;
//#ifdef UDF_LOG_CREATE_DISPOSITION switch(RequestedDisposition) { case FILE_SUPERSEDE: AdPrint((" Dispos: FILE_SUPERSEDE\n")); break; case FILE_OPEN: AdPrint((" Dispos: FILE_OPEN\n")); break; case FILE_CREATE: AdPrint((" Dispos: FILE_CREATE\n")); break; case FILE_OPEN_IF: AdPrint((" Dispos: FILE_OPEN_IF\n")); break; case FILE_OVERWRITE: AdPrint((" Dispos: FILE_OVERWRITE\n")); break; case FILE_OVERWRITE_IF: AdPrint((" Dispos: FILE_OVERWRITE_IF\n")); break; default: AdPrint((" Dispos: *** Unknown ***\n")); break; }//#endif // UDF_LOG_CREATE_DISPOSITION
FileAttributes = (USHORT)(IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS); ShareAccess = IrpSp->Parameters.Create.ShareAccess;
// If the FSD does not support EA manipulation, we might return // invalid parameter if the following are supplied. // EA arguments are only used if a new file is created or a file is // superseded
// But some applications _require_ EA support // (Notepad... rather strange, isn't it ?)
// So, for such stupid ones // !!! We shall ignore these parameters !!!
// PtrExtAttrBuffer = (struct _FILE_FULL_EA_INFORMATION *) Irp->AssociatedIrp.SystemBuffer;// ExtAttrLength = IrpSp->Parameters.Create.EaLength;
// Get the options supplied by the user
#define OpenForBackup (RequestedOptions & FILE_OPEN_FOR_BACKUP_INTENT) // User specifies that returned object MUST be a directory. // Lack of presence of this flag does not mean it *cannot* be a // directory *unless* FileOnlyRequested is set (see below)
// Presence of the flag however, does require that the returned object be // a directory (container) object.#define DirectoryOnlyRequested (RequestedOptions & FILE_DIRECTORY_FILE)
// User specifies that returned object MUST NOT be a directory. // Lack of presence of this flag does not mean it *cannot* be a // file *unless* DirectoryOnlyRequested is set (see above).
// Presence of the flag however does require that the returned object be // a simple file (non-container) object.#define FileOnlyRequested (RequestedOptions & FILE_NON_DIRECTORY_FILE)
// We cannot cache the file if the following flag is set. // However, things do get a little bit interesting if caching // has been already initiated due to a previous open ... // (maintaining consistency then becomes a little bit more // of a headache - see read/write file descriptions)#define NoBufferingSpecified (RequestedOptions & FILE_NO_INTERMEDIATE_BUFFERING)
// Write-through simply means that the FSD must *not* return from // a user write request until the data has been flushed to secondary // storage (either to disks directly connected to the node or across // the network in the case of a redirector) WriteThroughRequested = (RequestedOptions & FILE_WRITE_THROUGH) ? TRUE : FALSE;
#define SequentialIoRequested (RequestedOptions & FILE_SEQUENTIAL_ONLY ? TRUE : FALSE)
// Not all of the native file system implementations support // the delete-on-close option. All this means is that after the // last close on the FCB has been performed, the FSD should // delete the file. It simply saves the caller from issuing a // separate delete request. Also, some FSD implementations might choose // to implement a Windows NT idiosyncratic behavior wherein we // could create such "delete-on-close" marked files under directories // marked for deletion. Ordinarily, a FSD will not allow us to create // a new file under a directory that has been marked for deletion. DeleteOnCloseSpecified = (IrpSp->Parameters.Create.Options & FILE_DELETE_ON_CLOSE) ? TRUE : FALSE;
if(DeleteOnCloseSpecified) { AdPrint((" DeleteOnClose\n")); }
#define NoExtAttrKnowledge /*(RequestedOptions & FILE_NO_EA_KNOWLEDGE) ?*/ TRUE /*: FALSE*/
// The following flag is only used by the LAN Manager redirector // to initiate a "new mapping" to a remote share. Typically, // a FSD will not see this flag (especially disk based FSD's) // CreateTreeConnection = (RequestedOptions & FILE_CREATE_TREE_CONNECTION) ? TRUE : FALSE;
// The NTFS file system for exmaple supports the OpenByFileId option. // The FSD may also be able to associate a unique numerical ID with // an on-disk object. The caller would get this ID in a "query file // information" call.
// Later, the caller might decide to reopen the object, this time // though it may supply the FSD with the file identifier instead of // a file/path name.#define OpenByFileId (RequestedOptions & FILE_OPEN_BY_FILE_ID)
// Are we dealing with a page file? PageFileManipulation = (IrpSp->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
// The open target directory flag is used as part of the sequence of // operations performed by the I/O Manager is response to a file/dir // rename operation. See the explanation in the book for details. OpenTargetDirectory = (IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE;
// If the FSD supports case-sensitive file name checks, we may // choose to honor the following flag ... IgnoreCase = (IrpSp->Flags & SL_CASE_SENSITIVE) ? FALSE : TRUE;
// Ensure that the operation has been directed to a valid VCB ... Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); ASSERT(Vcb); ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);// Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
WriteThroughRequested = WriteThroughRequested || (Vcb->CompatFlags & UDF_VCB_IC_FORCE_WRITE_THROUGH);
// Do some preliminary checks to make sure the operation is supported. // We fail in the following cases immediately. // - Open a paging file. // - Open a file with Eas. if(PageFileManipulation) { ReturnedInformation = 0; AdPrint(("Can't create a page file\n")); try_return(RC = STATUS_ACCESS_DENIED); } if(ExtAttrLength) { ReturnedInformation = 0; AdPrint(("Can't create file with EAs\n")); try_return(RC = STATUS_EAS_NOT_SUPPORTED); }
UDFFlushTryBreak(Vcb);
if (Vcb->SoftEjectReq) { AdPrint((" Eject requested\n")); ReturnedInformation = FILE_DOES_NOT_EXIST; try_return(RC = STATUS_FILE_INVALID); }
// If the volume has been locked, fail the request if ((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED) && (Vcb->VolumeLockPID != GetCurrentPID())) { AdPrint((" Volume is locked\n")); RC = STATUS_ACCESS_DENIED; try_return(RC); } // We need EXCLUSIVE access to Vcb to avoid parallel calls to UDFVerifyVcb() UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); AcquiredVcb = TRUE;
// Disk based file systems might decide to verify the logical volume // (if required and only if removable media are supported) at this time RC = UDFVerifyVcb(PtrIrpContext,Vcb); if(!NT_SUCCESS(RC)) try_return(RC);
UDFConvertExclusiveToSharedLite(&(Vcb->VCBResource));
ASSERT(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED);
// We fail in the following cases for Read-Only volumes // - Open a target directory. // - Create a file. if( ( ((Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) && (Vcb->CompatFlags & UDF_VCB_IC_DIRTY_RO))#ifndef UDF_READ_ONLY_BUILD || (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)#endif //UDF_READ_ONLY_BUILD ) && (DeleteOnCloseSpecified || OpenTargetDirectory || (RequestedDisposition == FILE_CREATE) || (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF) || (RequestedDisposition == FILE_SUPERSEDE) || AllocationSize) ) { ReturnedInformation = 0; AdPrint((" Write protected or dirty\n")); try_return(RC = STATUS_MEDIA_WRITE_PROTECTED); }
/* if(DesiredAccess & (FILE_READ_EA | FILE_WRITE_EA)) { ReturnedInformation = 0; AdPrint((" EAs not supported\n")); try_return(RC = STATUS_ACCESS_DENIED); }*/
// **************** // If a Volume open is requested, satisfy it now // **************** if (!(PtrNewFileObject->FileName.Length) && (!PtrRelatedFileObject || (PtrRelatedFCB->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB))) {
BOOLEAN UndoLock = FALSE;
AdPrint((" Opening Volume\n")); // If the supplied file name is NULL *and* either there exists // no related file object *or* if a related file object was supplied // but it too refers to a previously opened instance of a logical // volume, this open must be for a logical volume.
// Note: the FSD might decide to do "special" things (whatever they // might be) in response to an open request for the logical volume.
// Logical volume open requests are done primarily to get/set volume // information, lock the volume, dismount the volume (using the IOCTL // FSCTL_DISMOUNT_VOLUME) etc.
// If a volume open is requested, perform checks to ensure that // invalid options have not also been specified ... if ((OpenTargetDirectory) || (PtrExtAttrBuffer)) { try_return(RC = STATUS_INVALID_PARAMETER); }
if (DirectoryOnlyRequested) { // a volume is not a directory try_return(RC = STATUS_NOT_A_DIRECTORY); }
#ifndef UDF_READ_ONLY_BUILD if (DeleteOnCloseSpecified) { // delete volume.... hmm try_return(RC = STATUS_CANNOT_DELETE); }
if ((RequestedDisposition != FILE_OPEN) && (RequestedDisposition != FILE_OPEN_IF)) { // cannot create a new volume, I'm afraid ... ReturnedInformation = FILE_DOES_NOT_EXIST; try_return(RC = STATUS_ACCESS_DENIED); }#endif //UDF_READ_ONLY_BUILD
UDFPrint((" ShareAccess %x, DesiredAccess %x\n", ShareAccess, DesiredAccess));/* if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE)) && !(DesiredAccess & (FILE_GENERIC_WRITE & ~SYNCHRONIZE)) && (ShareAccess & FILE_SHARE_READ) ) {*/ if(!(DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) && (ShareAccess & FILE_SHARE_READ) ) { UDFPrint((" R/O volume open\n")); } else {
UDFPrint((" R/W volume open\n")); if(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY) { UDFPrint((" media-ro\n")); try_return(RC = STATUS_MEDIA_WRITE_PROTECTED); } }
if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE)) && !(DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) && (ShareAccess & FILE_SHARE_READ) ) { // do nothing } else {
if(!(ShareAccess & FILE_SHARE_READ) || (DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) ) { // As soon as OpenVolume flushes the volume // we should complete all pending requests (Close)
UDFPrint((" set UDF_IRP_CONTEXT_FLUSH2_REQUIRED\n")); PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FLUSH2_REQUIRED;
/* UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); UDFReleaseResource(&(Vcb->VCBResource)); AcquiredVcb = FALSE;
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) { UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); }#ifdef UDF_DELAYED_CLOSE UDFCloseAllDelayed(Vcb);#endif //UDF_DELAYED_CLOSE
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); AcquiredVcb = TRUE; UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));*/ } }
// If the user does not want to share write or delete then we will try // and take out a lock on the volume. if(!(ShareAccess & (FILE_SHARE_WRITE | FILE_SHARE_DELETE))) { // Do a quick check here for handles on exclusive open. if ((Vcb->VCBHandleCount) && !(ShareAccess & FILE_SHARE_READ)) { // Sharing violation UDFPrint((" !FILE_SHARE_READ + open handles (%d)\n", Vcb->VCBHandleCount)); try_return(RC = STATUS_SHARING_VIOLATION); } if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_FLUSH2_REQUIRED) {
UDFPrint((" perform flush\n")); PtrIrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_FLUSH2_REQUIRED;
UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); UDFReleaseResource(&(Vcb->VCBResource)); AcquiredVcb = FALSE;
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)) { UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo); }#ifdef UDF_DELAYED_CLOSE UDFCloseAllDelayed(Vcb);#endif //UDF_DELAYED_CLOSE
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); AcquiredVcb = TRUE; UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
UDFFlushLogicalVolume(NULL, NULL, Vcb);
if((ShareAccess & FILE_SHARE_READ) && ((Vcb->VCBOpenCount - UDF_RESIDUAL_REFERENCE) != (Vcb->VCBOpenCountRO))) { UDFPrint((" FILE_SHARE_READ + R/W handles: %d(%d) -> STATUS_SHARING_VIOLATION ?\n", Vcb->VCBOpenCount - UDF_RESIDUAL_REFERENCE, Vcb->VCBOpenCountRO)); /* we shall not check it here, let System do it in IoCheckShareAccess() */ //try_return(RC = STATUS_SHARING_VIOLATION); } } // Lock the volume if(!(ShareAccess & FILE_SHARE_READ)) { UDFPrint((" set Lock\n")); Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_LOCKED; Vcb->VolumeLockFileObject = PtrNewFileObject; UndoLock = TRUE; } else if(DesiredAccess & ((GENERIC_WRITE | FILE_GENERIC_WRITE) & ~(SYNCHRONIZE | READ_CONTROL))) { UDFPrint((" set UDF_IRP_CONTEXT_FLUSH_REQUIRED\n")); PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_FLUSH_REQUIRED; } }
PtrNewFcb = (PtrUDFFCB)Vcb; ASSERT(!(PtrNewFcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE));
RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); if (!NT_SUCCESS(RC)) goto op_vol_accs_dnd;
PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); if(PtrNewCcb) PtrNewCcb->CCBFlags |= UDF_CCB_VOLUME_OPEN; // Check _Security_ RC = UDFCheckAccessRights(NULL, AccessState, Vcb->RootDirFCB, PtrNewCcb, DesiredAccess, ShareAccess); if (!NT_SUCCESS(RC)) { AdPrint((" Access violation (Volume)\n")); goto op_vol_accs_dnd; } // Check _ShareAccess_ RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); if(!NT_SUCCESS(RC)) { AdPrint((" Sharing violation (Volume)\n"));op_vol_accs_dnd: if(UndoLock) { Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED; Vcb->VolumeLockFileObject = NULL; } try_return(RC); }
// NoBufferingSpecified = TRUE; See #define above RequestedOptions |= FILE_NO_INTERMEDIATE_BUFFERING;
ReturnedInformation = FILE_OPENED; UDFNotifyVolumeEvent(PtrNewFileObject, FSRTL_VOLUME_LOCK); try_return(RC); }
if((Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) && (!(Vcb->CompatFlags & UDF_VCB_IC_SHOW_BLANK_CD) || UDFGlobalData.AutoFormatCount)) { ReturnedInformation = 0; AdPrint((" Can't open anything on blank volume ;)\n")); try_return(RC = STATUS_OBJECT_NAME_NOT_FOUND); }
if(UdfIllegalFcbAccess(Vcb,DesiredAccess)) { ReturnedInformation = 0; AdPrint((" Illegal share access\n")); try_return(RC = STATUS_ACCESS_DENIED); } // we could mount blank R/RW media in order to allow // user-mode applications to get access with Write privileges ASSERT(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED);
// we should check appropriate privilege if OpenForBackup requested if(OpenForBackup) { if (!SeSinglePrivilegeCheck(SeExports->SeBackupPrivilege, UserMode)) { try_return(RC = STATUS_PRIVILEGE_NOT_HELD); } }
// The FSD might wish to implement the open-by-id option. The "id" // is some unique numerical representation of the on-disk object. // The caller then therefore give us this file id and the FSD // should be completely capable of "opening" the object (it must // exist since the caller received an id for the object from the // FSD in a "query file" call ...
// If the file has been deleted in the meantime, we'll return // "not found"
// **************** // Open by FileID // **************** if (OpenByFileId) { // perform the open ... PUNICODE_STRING TmpPath; LONGLONG Id;
UDFPrint((" open by File ID\n")); if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { ReturnedInformation = 0; AdPrint((" Can't open by FileID on blank volume ;)\n")); try_return(RC = STATUS_OBJECT_NAME_NOT_FOUND); }
if (TargetObjectName.Length != sizeof(FILE_ID)) { AdPrint((" Invalid file ID\n")); try_return(RC = STATUS_INVALID_PARAMETER); } Id = *((FILE_ID*)(TargetObjectName.Buffer)); AdPrint((" Opening by ID %8.8x%8.8x\n", (ULONG)(Id>>32), (ULONG)Id)); if ((RequestedDisposition != FILE_OPEN) && (RequestedDisposition != FILE_OPEN_IF)) { AdPrint((" Illegal disposition for ID open\n")); try_return(RC = STATUS_ACCESS_DENIED); }
RC = UDFGetOpenParamsByFileId(Vcb, Id, &TmpPath, &IgnoreCase); if(!NT_SUCCESS(RC)) { AdPrint((" ID open failed\n")); try_return(RC); } // simulate absolute path open/* if(!NT_SUCCESS(RC = MyInitUnicodeString(&TargetObjectName, L"")) || !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&TargetObjectName, TmpPath, MEM_USABS_TAG))) {*/ if(!NT_SUCCESS(RC = MyCloneUnicodeString(&TargetObjectName, TmpPath))) { AdPrint((" Init String failed\n")); try_return(RC); } //ASSERT(TargetObjectName.Buffer); AbsolutePathName = TargetObjectName; PtrRelatedFileObject = NULL; } else // **************** // Relative open // **************** // Now determine the starting point from which to begin the parsing if (PtrRelatedFileObject) { // We have a user supplied related file object. // This implies a "relative" open i.e. relative to the directory // represented by the related file object ...
UDFPrint((" PtrRelatedFileObject %x, FCB %x\n", PtrRelatedFileObject, PtrRelatedFCB)); // Note: The only purpose FSD implementations ever have for // the related file object is to determine whether this // is a relative open or not. At all other times (including // during I/O operations), this field is meaningless from // the FSD's perspective. if (!(PtrRelatedFCB->FCBFlags & UDF_FCB_DIRECTORY)) { // we must have a directory as the "related" object RC = STATUS_INVALID_PARAMETER; AdPrint((" Related object must be a directory\n")); AdPrint((" Flags %x\n", PtrRelatedFCB->FCBFlags)); _SEH2_TRY { AdPrint((" ObjName %x, ", PtrRelatedFCB->FCBName->ObjectName)); AdPrint((" Name %S\n", PtrRelatedFCB->FCBName->ObjectName.Buffer)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { AdPrint((" exception when printing name\n")); } _SEH2_END; try_return(RC); }
// So we have a directory, ensure that the name begins with // a "\" i.e. begins at the root and does *not* begin with a "\\" // NOTE: This is just an example of the kind of path-name string // validation that a FSD must do. Although the remainder of // the code may not include such checks, any commercial // FSD *must* include such checking (no one else, including // the I/O Manager will perform checks on the FSD's behalf) if (!(RelatedObjectName.Length) || (RelatedObjectName.Buffer[0] != L'\\')) { AdPrint((" Wrong pathname (1)\n")); RC = STATUS_INVALID_PARAMETER; try_return(RC); } // similarly, if the target file name starts with a "\", it // is wrong since the target file name can no longer be absolute ASSERT(TargetObjectName.Buffer || !TargetObjectName.Length); if (TargetObjectName.Length && (TargetObjectName.Buffer[0] == L'\\')) { AdPrint((" Wrong pathname (2)\n")); RC = STATUS_INVALID_PARAMETER; try_return(RC); } // Create an absolute path-name. We could potentially use // the absolute path-name if we cache previously opened // file/directory object names./* if(!NT_SUCCESS(RC = MyInitUnicodeString(&AbsolutePathName, L"")) || !NT_SUCCESS(RC MyAppendUnicodeStringToStringTag(&AbsolutePathName, &RelatedObjectName, MEM_USABS_TAG)))*/ if(!NT_SUCCESS(RC = MyCloneUnicodeString(&AbsolutePathName, &RelatedObjectName))) try_return(RC); if(RelatedObjectName.Length && (RelatedObjectName.Buffer[ (RelatedObjectName.Length/sizeof(WCHAR)) - 1 ] != L'\\')) { RC = MyAppendUnicodeToString(&AbsolutePathName, L"\\"); if(!NT_SUCCESS(RC)) try_return(RC); } if(!AbsolutePathName.Length || (AbsolutePathName.Buffer[ (AbsolutePathName.Length/sizeof(WCHAR)) - 1 ] != L'\\')) { ASSERT(TargetObjectName.Buffer); if(TargetObjectName.Length && TargetObjectName.Buffer[0] != L'\\') { RC = MyAppendUnicodeToString(&AbsolutePathName, L"\\"); if(!NT_SUCCESS(RC)) try_return(RC); } } //ASSERT(TargetObjectName.Buffer); RC = MyAppendUnicodeStringToStringTag(&AbsolutePathName, &TargetObjectName, MEM_USABS_TAG); if(!NT_SUCCESS(RC)) try_return(RC);
} else { // **************** // Absolute open // **************** // The suplied path-name must be an absolute path-name i.e. // starting at the root of the file system tree UDFPrint((" Absolute open\n")); ASSERT(TargetObjectName.Buffer); if (!TargetObjectName.Length || TargetObjectName.Buffer[0] != L'\\') { AdPrint((" Wrong target name (1)\n")); try_return(RC = STATUS_INVALID_PARAMETER); }/* if(!NT_SUCCESS(RC = MyInitUnicodeString(&AbsolutePathName, L"")) || !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&AbsolutePathName, &TargetObjectName, MEM_USABS_TAG)))*/ ASSERT(TargetObjectName.Buffer); if(!NT_SUCCESS(RC = MyCloneUnicodeString(&AbsolutePathName, &TargetObjectName))) try_return(RC); } // Win 32 protection :) if ((AbsolutePathName.Length >= sizeof(WCHAR)*2) && (AbsolutePathName.Buffer[1] == L'\\') && (AbsolutePathName.Buffer[0] == L'\\')) {
// If there are still two beginning backslashes, the name is bogus. if ((AbsolutePathName.Length > 2*sizeof(WCHAR)) && (AbsolutePathName.Buffer[2] == L'\\')) { AdPrint((" Wrong target name (2)\n")); try_return (RC = STATUS_OBJECT_NAME_INVALID); } // Slide the name down in the buffer. RtlMoveMemory( AbsolutePathName.Buffer, AbsolutePathName.Buffer + 1, AbsolutePathName.Length ); // .Length includes // NULL-terminator AbsolutePathName.Length -= sizeof(WCHAR); } if ( (AbsolutePathName.Length > sizeof(WCHAR) ) && (AbsolutePathName.Buffer[ (AbsolutePathName.Length/sizeof(WCHAR)) - 1 ] == L'\\') ) {
AbsolutePathName.Length -= sizeof(WCHAR); } // TERMINATOR (2) ;) AbsolutePathName.Buffer[AbsolutePathName.Length/sizeof(WCHAR)] = 0;
// Sometimes W2000 decides to duplicate handle of // already opened File/Dir. In this case it sends us // RelatedFileObject & specifies zero-filled RelativePath if(!TargetObjectName.Length) { TargetObjectName = AbsolutePathName; OpenExisting = TRUE; } //ASSERT(TargetObjectName.Buffer);
// **************** // First, check if the caller simply wishes to open the Root // of the file system tree. // **************** if (AbsolutePathName.Length == sizeof(WCHAR)) { AdPrint((" Opening RootDir\n")); // this is an open of the root directory, ensure that the caller // has not requested a file only if (FileOnlyRequested || (RequestedDisposition == FILE_SUPERSEDE) || (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF)) { AdPrint((" Can't overwrite RootDir\n")); RC = STATUS_FILE_IS_A_DIRECTORY; try_return(RC); }
#if 0 CollectStatistics(Vcb, MetaDataReads);#endif
if (DeleteOnCloseSpecified) { // delete RootDir.... rather strange idea... I dislike it AdPrint((" Can't delete RootDir\n")); try_return(RC = STATUS_CANNOT_DELETE); }
PtrNewFcb = Vcb->RootDirFCB; RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); if(!NT_SUCCESS(RC)) try_return(RC);// DbgPrint("UDF: Open/Create RootDir : ReferenceCount %x\n",PtrNewFcb->ReferenceCount); UDFReferenceFile__(PtrNewFcb->FileInfo); PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); TreeLength = 1;
RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); if(!NT_SUCCESS(RC)) { AdPrint((" Access/Sharing violation (RootDir)\n")); try_return(RC); }
ReturnedInformation = FILE_OPENED;
try_return(RC); } // end of OpenRootDir
_SEH2_TRY { AdPrint((" Opening file %ws %8.8x\n",AbsolutePathName.Buffer, PtrNewFileObject)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { AdPrint((" Exception when printing FN\n")); } _SEH2_END; // **************** // Check if we have DuplicateHandle (or Reopen) request // **************** if(OpenExisting) {
// BrutePoint(); // We don't handle OpenTargetDirectory in this case if(OpenTargetDirectory) try_return(RC = STATUS_INVALID_PARAMETER);
// Init environment to simulate normal open procedure behavior/* if(!NT_SUCCESS(RC = MyInitUnicodeString(&LocalPath, L"")) || !NT_SUCCESS(RC = MyAppendUnicodeStringToStringTag(&LocalPath, &TargetObjectName, MEM_USLOC_TAG)))*/ ASSERT(TargetObjectName.Buffer); if(!NT_SUCCESS(RC = MyCloneUnicodeString(&LocalPath, &TargetObjectName))) try_return(RC);
ASSERT(PtrRelatedFCB); RelatedFileInfo = PtrRelatedFCB->FileInfo;
RC = STATUS_SUCCESS; NewFileInfo = LastGoodFileInfo = RelatedFileInfo;
RelatedFileInfo = OldRelatedFileInfo = RelatedFileInfo->ParentFile; PtrRelatedFCB = PtrRelatedFCB->ParentFcb; // prevent releasing parent structures UDFAcquireParent(RelatedFileInfo, &Res1, &Res2); TreeLength++;
if(Res1) UDFReleaseResource(Res1); if(Res2) UDFReleaseResource(Res2);
UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->NTRequiredFCB); UDFAcquireResourceExclusive(Res2 = &(RelatedFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); PtrNewFcb = NewFileInfo->Fcb;
UDF_CHECK_PAGING_IO_RESOURCE(PtrNewFcb->NTRequiredFCB); UDFAcquireResourceExclusive(Res1 = &(PtrNewFcb->NTRequiredFCB->MainResource),TRUE); UDFReferenceFile__(NewFileInfo); TreeLength++;
goto AlreadyOpened; }
if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { ReturnedInformation = 0; AdPrint((" Can't open File on blank volume ;)\n")); ReturnedInformation = FILE_DOES_NOT_EXIST; try_return(RC = STATUS_OBJECT_NAME_NOT_FOUND); }
//AdPrint((" Opening file %ws %8.8x\n",AbsolutePathName.Buffer, PtrNewFileObject));
if(AbsolutePathName.Length > UDF_X_PATH_LEN*sizeof(WCHAR)) { try_return(RC = STATUS_OBJECT_NAME_INVALID); }
// validate path specified // (sometimes we can see here very strange characters ;) if(!UDFIsNameValid(&AbsolutePathName, &StreamOpen, &SNameIndex)) { AdPrint((" Absolute path is not valid\n")); try_return(RC = STATUS_OBJECT_NAME_INVALID); } if(StreamOpen && !UDFStreamsSupported(Vcb)) { ReturnedInformation = FILE_DOES_NOT_EXIST; try_return(RC = STATUS_OBJECT_NAME_INVALID); }
RC = MyInitUnicodeString(&LocalPath, L""); if(!NT_SUCCESS(RC)) try_return(RC); if (PtrRelatedFileObject) { // Our "start directory" is the one identified // by the related file object RelatedFileInfo = PtrRelatedFCB->FileInfo; if(RelatedFileInfo != Vcb->RootDirFCB->FileInfo) { RC = MyAppendUnicodeStringToStringTag(&LocalPath, &(PtrRelatedFCB->FCBName->ObjectName), MEM_USLOC_TAG); if(!NT_SUCCESS(RC)) try_return(RC); } if(TargetObjectName.Buffer != AbsolutePathName.Buffer) { ASSERT(TargetObjectName.Buffer); if(!NT_SUCCESS(RC = MyCloneUnicodeString(&TailName, &TargetObjectName))) { AdPrint((" Init String 'TargetObjectName' failed\n")); try_return(RC); } TailNameBuffer = TailName.Buffer; } else { TailName = AbsolutePathName; } } else { // Start at the root of the file system RelatedFileInfo = Vcb->RootDirFCB->FileInfo; TailName = AbsolutePathName; }
if(StreamOpen) { StreamName = AbsolutePathName; StreamName.Buffer += SNameIndex; StreamName.Length -= (USHORT)SNameIndex*sizeof(WCHAR); // if StreamOpen specified & stream name starts with NULL character // we should create Stream Dir at first TailName.Length -= (AbsolutePathName.Length - (USHORT)SNameIndex*sizeof(WCHAR)); AbsolutePathName.Length = (USHORT)SNameIndex*sizeof(WCHAR); } CurName.MaximumLength = TailName.MaximumLength;
RC = STATUS_SUCCESS; LastGoodName.Length = 0; LastGoodFileInfo = RelatedFileInfo; // reference RelatedObject to prevent releasing parent structures UDFAcquireParent(RelatedFileInfo, &Res1, &Res2); TreeLength++;
// go into a loop parsing the supplied name
// Note that we may have to "open" intermediate directory objects // while traversing the path. We should __try to reuse existing code // whenever possible therefore we should consider using a common // open routine regardless of whether the open is on behalf of the // caller or an intermediate (internal) open performed by the driver.
// **************** // now we'll parse path to desired file // ****************
while (TRUE) {
// remember last 'good' ('good' means NO ERRORS before) path tail if(NT_SUCCESS(RC)) { LastGoodTail = TailName; while(LastGoodTail.Buffer[0] == L'\\') { LastGoodTail.Buffer++; LastGoodTail.Length -= sizeof(WCHAR); } } // get next path part... TmpBuffer = TailName.Buffer; TailName.Buffer = UDFDissectName(TailName.Buffer,&(CurName.Length) ); TailName.Length -= (USHORT)((ULONG_PTR)(TailName.Buffer) - (ULONG_PTR)TmpBuffer); CurName.Buffer = TailName.Buffer - CurName.Length; CurName.Length *= sizeof(WCHAR); CurName.MaximumLength = CurName.Length + sizeof(WCHAR); // check if we have already opened the component before last one // in this case OpenTargetDir request will be served in a special // way... if(OpenTargetDirectory && NT_SUCCESS(RC) && !TailName.Length) { // check if we should open SDir.. if(!StreamOpen || (TailName.Buffer[0]!=L':')) { // no, we should not. Continue with OpenTargetDir break; } }
if( CurName.Length && (NT_SUCCESS(RC) || !StreamOpen)) { // ...wow! non-zero! try to open! if(!NT_SUCCESS(RC)) { AdPrint((" Error opening path component\n")); // we haven't reached last name part... hm.. // probably, the path specified is invalid.. // or we had a hard error... What else can we do ? // Only say ..CK OFF !!!! if(RC == STATUS_OBJECT_NAME_NOT_FOUND) RC = STATUS_OBJECT_PATH_NOT_FOUND; ReturnedInformation = FILE_DOES_NOT_EXIST; try_return(RC); }
ASSERT_REF(RelatedFileInfo->Fcb->ReferenceCount >= RelatedFileInfo->RefCount);
if(RelatedFileInfo && (TreeLength>1)) { // it was an internal Open operation. Thus, assume // RelatedFileInfo's Fcb to be valid RelatedFileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; RelatedFileInfo->Fcb->FCBFlags |= UDF_FCB_VALID; } // check path fragment size if(CurName.Length > UDF_X_NAME_LEN * sizeof(WCHAR)) { AdPrint((" Path component is too long\n")); try_return(RC = STATUS_OBJECT_NAME_INVALID); } // ...and now release previously acquired objects, if(Res1) UDFReleaseResource(Res1); if(Res2) { UDFReleaseResource(Res2); Res2 = NULL; } // acquire new _parent_ directory & try to open what // we want.
UDF_CHECK_PAGING_IO_RESOURCE(RelatedFileInfo->Fcb->NTRequiredFCB); UDFAcquireResourceExclusive(Res1 = &(RelatedFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE);
// check traverse rights RC = UDFCheckAccessRights(NULL, NULL, RelatedFileInfo->Fcb, PtrRelatedCCB, FILE_TRAVERSE, 0); if(!NT_SUCCESS(RC)) { NewFileInfo = NULL; AdPrint((" Traverse check failed\n")); goto Skip_open_attempt; } // check if we should open normal File/Dir or SDir if(CurName.Buffer[0] != ':') { // standard open, nothing interesting.... RC = UDFOpenFile__(Vcb, IgnoreCase,TRUE,&CurName, RelatedFileInfo,&NewFileInfo,NULL); if(RC == STATUS_FILE_DELETED) { // file has gone, but system still remembers it... NewFileInfo = NULL; AdPrint((" File deleted\n")); RC = STATUS_ACCESS_DENIED;#ifdef UDF_DBG } else if(RC == STATUS_NOT_A_DIRECTORY) { AdPrint((" Not a directory\n"));#endif // UDF_DBG } else if(RC == STATUS_SHARING_PAUSED) { AdPrint((" Dloc is being initialized\n")); BrutePoint(); RC = STATUS_SHARING_VIOLATION; } } else { // And here we should open Stream Dir (if any, of cource) RC = UDFOpenStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo); if(NT_SUCCESS(RC)) {SuccessOpen_SDir: // this indicates that we needn't Stream Dir creation StreamExists = TRUE; StreamName.Buffer++; StreamName.Length-=sizeof(WCHAR); // update TailName TailName = StreamName; } else if(RC == STATUS_NOT_FOUND) {#ifndef UDF_READ_ONLY_BUILD // Stream Dir doesn't exist, but caller wants it to be // created. Lets try to help him... if((RequestedDisposition == FILE_CREATE) || (RequestedDisposition == FILE_OPEN_IF) || (RequestedDisposition == FILE_OVERWRITE_IF) || OpenTargetDirectory ) { RC = UDFCreateStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo); if(NT_SUCCESS(RC)) goto SuccessOpen_SDir; }#endif //UDF_READ_ONLY_BUILD }/* } else { AdPrint((" File deleted (2)\n")); RC = STATUS_ACCESS_DENIED;*/ }#if 0 CollectStatistics(Vcb, MetaDataReads);#endif
Skip_open_attempt:
// check if we have successfully opened path component if(NT_SUCCESS(RC)) { // Yesss !!! if (!(PtrNewFcb = NewFileInfo->Fcb)) { // It is a first open operation // Allocate new FCB // Here we set FileObject pointer to NULL to avoid // new CCB allocation RC = UDFFirstOpenFile(Vcb, NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo, &LocalPath, &CurName);
if(!NT_SUCCESS(RC)) { BrutePoint(); AdPrint((" Can't perform FirstOpen\n")); UDFCloseFile__(Vcb, NewFileInfo); if(PtrNewFcb) UDFCleanUpFCB(PtrNewFcb); PtrNewFcb = NULL; NewFileInfo->Fcb = NULL; if(UDFCleanUpFile__(Vcb, NewFileInfo)) { MyFreePool__(NewFileInfo); NewFileInfo = NULL; } try_return(RC); } } else { // It is not a first open operation // Validate Fcb. It is possible to get // not completly initialized Fcb here. if(!(PtrNewFcb->FCBFlags & UDF_FCB_VALID)) { BrutePoint(); AdPrint((" Fcb not valid\n")); UDFCloseFile__(Vcb, NewFileInfo); PtrNewFcb = NULL; if(UDFCleanUpFile__(Vcb, NewFileInfo)) { MyFreePool__(NewFileInfo); NewFileInfo = NULL; } try_return(RC = STATUS_ACCESS_DENIED); } } // Acquire newly opened File... Res2 = Res1; UDF_CHECK_PAGING_IO_RESOURCE(NewFileInfo->Fcb->NTRequiredFCB); UDFAcquireResourceExclusive(Res1 = &(NewFileInfo->Fcb->NTRequiredFCB->MainResource),TRUE); // ...and reference it UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount));
ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); // update unwind information LastGoodFileInfo = NewFileInfo; LastGoodName = CurName; TreeLength++; // update current path if(!StreamOpen || ((CurName.Buffer[0] != L':') && (!LocalPath.Length || (LocalPath.Buffer[LocalPath.Length/sizeof(WCHAR)-1] != L':'))) ) { // we should not insert '\' before or after ':' ASSERT(!LocalPath.Length || (LocalPath.Buffer[LocalPath.Length/2-1] != L'\\')); RC = MyAppendUnicodeToString(&LocalPath, L"\\"); if(!NT_SUCCESS(RC)) try_return(RC); } RC = MyAppendUnicodeStringToStringTag(&LocalPath, &CurName, MEM_USLOC_TAG); if(!NT_SUCCESS(RC)) try_return(RC);// DbgPrint("UDF: Open/Create File %ws : ReferenceCount %x\n",CurName.Buffer,PtrNewFcb->ReferenceCount); } else { AdPrint((" Can't open file\n")); // We have failed durring last Open attempt // Roll back to last good state PtrUDFNTRequiredFCB NtReqFcb = NULL; // Cleanup FileInfo if any if(NewFileInfo) { PtrNewFcb = NewFileInfo->Fcb; // acquire appropriate resource if possible if(PtrNewFcb && PtrNewFcb->NTRequiredFCB) { NtReqFcb = PtrNewFcb->NTRequiredFCB; Res2 = Res1; UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); UDFAcquireResourceExclusive(Res1 = &(NtReqFcb->MainResource),TRUE); } // cleanup pointer to Fcb in FileInfo to allow // UDF_INFO package release FileInfo if there are // no more references if(PtrNewFcb && !PtrNewFcb->ReferenceCount && !PtrNewFcb->OpenHandleCount) { NewFileInfo->Fcb = NULL; } // cleanup pointer to CommonFcb in Dloc to allow // UDF_INFO package release Dloc if there are // no more references if(NewFileInfo->Dloc && !NewFileInfo->Dloc->LinkRefCount && (!PtrNewFcb || !PtrNewFcb->ReferenceCount)) { NewFileInfo->Dloc->CommonFcb = NULL; } // try to release FileInfo if(UDFCleanUpFile__(Vcb, NewFileInfo)) { ASSERT(!PtrNewFcb); if(PtrNewFcb) { BrutePoint(); UDFCleanUpFCB(PtrNewFcb); } MyFreePool__(NewFileInfo); } else { // if we can't release FileInfo // restore pointers to Fcb & CommonFcb in // FileInfo & Dloc NewFileInfo->Fcb = PtrNewFcb; if(NtReqFcb) NewFileInfo->Dloc->CommonFcb = NtReqFcb; } // forget about last FileInfo & Fcb, // further unwind staff needs only last good // structures PtrNewFcb = NULL; NewFileInfo = NULL; } }
// should return error if 'delete in progress' if(LastGoodFileInfo->Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE | UDF_FCB_DELETED | UDF_FCB_POSTED_RENAME)) { AdPrint((" Return DeletePending (no err)\n")); try_return(RC = STATUS_DELETE_PENDING); } // update last good state information... OldRelatedFileInfo = RelatedFileInfo; RelatedFileInfo = NewFileInfo; // ...and go to the next open cycle } else { // ************ if(StreamOpen && (RC == STATUS_NOT_FOUND)) // handle SDir return code RC = STATUS_OBJECT_NAME_NOT_FOUND; if(RC == STATUS_OBJECT_NAME_NOT_FOUND) { // good path, but no such file.... Amen // break open loop and continue with Create break; } if (!NT_SUCCESS(RC)) { // Hard error or damaged data structures ...#ifdef UDF_DBG if((RC != STATUS_OBJECT_PATH_NOT_FOUND) && (RC != STATUS_ACCESS_DENIED) && (RC != STATUS_NOT_A_DIRECTORY)) { AdPrint((" Hard error or damaged data structures\n")); }#endif // UDF_DBG // ... and exit with error try_return(RC); } // discard changes for last successfully opened file UDFInterlockedDecrement((PLONG)&(PtrNewFcb->ReferenceCount)); UDFInterlockedDecrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); RC = STATUS_SUCCESS; ASSERT(!OpenTargetDirectory); // break open loop and continue with Open // (Create will be skipped) break; } } // end of while(TRUE)
// **************** // If "open target directory" was specified // **************** if(OpenTargetDirectory) {
if(!UDFIsADirectory(LastGoodFileInfo)) { AdPrint((" Not a directory (2)\n")); RC = STATUS_NOT_A_DIRECTORY; } if(!NT_SUCCESS(RC) || TailName.Length) { AdPrint((" Target name should not contain (back)slashes\n")); NewFileInfo = NULL; try_return(RC = STATUS_OBJECT_NAME_INVALID); }
NewFileInfo = LastGoodFileInfo; RtlCopyUnicodeString(&(PtrNewFileObject->FileName), &CurName);
// now we have to check if last component exists... if(NT_SUCCESS(RC = UDFFindFile__(Vcb, IgnoreCase, &CurName, RelatedFileInfo))) { // file exists, set this information in the Information field ReturnedInformation = FILE_EXISTS; AdPrint((" Open Target: FILE_EXISTS\n")); } else if(RC == STATUS_OBJECT_NAME_NOT_FOUND) {#ifdef UDF_DBG // check name. If there are '\\'s in TailName, some // directories in path specified do not exist for(TmpBuffer = LastGoodTail.Buffer; *TmpBuffer; TmpBuffer++) { if((*TmpBuffer) == L'\\') { ASSERT(FALSE); AdPrint((" Target name should not contain (back)slashes\n")); try_return(RC = STATUS_OBJECT_NAME_INVALID); } }#endif // UDF_DBG // Tell the I/O Manager that file does not exit ReturnedInformation = FILE_DOES_NOT_EXIST; AdPrint((" Open Target: FILE_DOES_NOT_EXIST\n")); RC = STATUS_SUCCESS; // is already set here } else { AdPrint((" Open Target: unexpected error\n")); NewFileInfo = NULL; ReturnedInformation = FILE_DOES_NOT_EXIST; try_return(RC = STATUS_OBJECT_NAME_INVALID); }
// RC = STATUS_SUCCESS; // is already set here
// Update the file object FsContext and FsContext2 fields // to reflect the fact that the parent directory of the // target has been opened PtrNewFcb = NewFileInfo->Fcb; UDFInterlockedDecrement((PLONG)&(PtrNewFcb->ReferenceCount)); UDFInterlockedDecrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); if (!NT_SUCCESS(RC)) { AdPrint((" Can't perform OpenFile operation for target\n")); try_return(RC); } PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2);
ASSERT(Res1); RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); if(!NT_SUCCESS(RC)) { AdPrint((" Access/Share access check failed (Open Target)\n")); }
try_return(RC); }
// **************** // should we CREATE a new file ? // **************** if (!NT_SUCCESS(RC)) { if (RC == STATUS_OBJECT_NAME_NOT_FOUND || RC == STATUS_OBJECT_PATH_NOT_FOUND) { if( ((RequestedDisposition == FILE_OPEN) || (RequestedDisposition == FILE_OVERWRITE)) /*&& (!StreamOpen || !StreamExists)*/ ){ ReturnedInformation = FILE_DOES_NOT_EXIST; AdPrint((" File doesn't exist\n")); try_return(RC); } } else { // Any other operation return STATUS_ACCESS_DENIED. AdPrint((" Can't create due to unexpected error\n")); try_return(RC); } // Object was not found, create if requested if ((RequestedDisposition != FILE_CREATE) && (RequestedDisposition != FILE_OPEN_IF) && (RequestedDisposition != FILE_OVERWRITE_IF) && (RequestedDisposition != FILE_SUPERSEDE)) { AdPrint((" File doesn't exist (2)\n")); ReturnedInformation = FILE_DOES_NOT_EXIST; try_return(RC); } // Check Volume ReadOnly attr#ifndef UDF_READ_ONLY_BUILD if((Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {#endif //UDF_READ_ONLY_BUILD ReturnedInformation = 0; AdPrint((" Write protected\n")); try_return(RC = STATUS_MEDIA_WRITE_PROTECTED);#ifndef UDF_READ_ONLY_BUILD } // Check r/o + delete on close if(DeleteOnCloseSpecified && (FileAttributes & FILE_ATTRIBUTE_READONLY)) { AdPrint((" Can't create r/o file marked for deletion\n")); try_return(RC = STATUS_CANNOT_DELETE); }
// Create a new file/directory here ... if(StreamOpen) StreamName.Buffer[StreamName.Length/sizeof(WCHAR)] = 0; for(TmpBuffer = LastGoodTail.Buffer; *TmpBuffer; TmpBuffer++) { if((*TmpBuffer) == L'\\') { AdPrint((" Target name should not contain (back)slashes\n")); try_return(RC = STATUS_OBJECT_NAME_INVALID); } } if( DirectoryOnlyRequested && ((IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_TEMPORARY) || StreamOpen || FALSE)) { AdPrint((" Creation of _temporary_ directory not permited\n")); try_return(RC = STATUS_INVALID_PARAMETER); } // check access rights ASSERT(Res1); RC = UDFCheckAccessRights(NULL, NULL, OldRelatedFileInfo->Fcb, PtrRelatedCCB, DirectoryOnlyRequested ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0); if(!NT_SUCCESS(RC)) { AdPrint((" Creation of File/Dir not permitted\n")); try_return(RC); } // Note that a FCB structure will be allocated at this time // and so will a CCB structure. Assume that these are called // PtrNewFcb and PtrNewCcb respectively. // Further, note that since the file is being created, no other // thread can have the file stream open at this time. RelatedFileInfo = OldRelatedFileInfo;
RC = UDFCreateFile__(Vcb, IgnoreCase, &LastGoodTail, 0, 0, Vcb->UseExtendedFE || (StreamOpen && !StreamExists), (RequestedDisposition == FILE_CREATE), RelatedFileInfo, &NewFileInfo); if(!NT_SUCCESS(RC)) { AdPrint((" Creation error\n"));Creation_Err_1: if(NewFileInfo) { PtrNewFcb = NewFileInfo->Fcb; ASSERT(!PtrNewFcb); if(PtrNewFcb && !PtrNewFcb->ReferenceCount && !PtrNewFcb->OpenHandleCount) { NewFileInfo->Fcb = NULL; } if(NewFileInfo->Dloc && !NewFileInfo->Dloc->LinkRefCount) { NewFileInfo->Dloc->CommonFcb = NULL; } if(UDFCleanUpFile__(Vcb, NewFileInfo)) { if(PtrNewFcb) { BrutePoint(); UDFCleanUpFCB(PtrNewFcb); } MyFreePool__(NewFileInfo); PtrNewFcb = PtrNewFcb; } else { NewFileInfo->Fcb = PtrNewFcb; } PtrNewFcb = NULL; } try_return(RC); } // Update parent object if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) && PtrRelatedFCB && PtrRelatedFileObject && (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) { PtrRelatedFileObject->Flags |= (FO_FILE_MODIFIED | FO_FILE_SIZE_CHANGED); }#if 0 CollectStatistics(Vcb, MetaDataWrites);#endif
if(DirectoryOnlyRequested) { // user wants the directory to be created RC = UDFRecordDirectory__(Vcb, NewFileInfo); if(!NT_SUCCESS(RC)) { AdPrint((" Can't transform to directory\n"));Undo_Create_1: if((RC != STATUS_FILE_IS_A_DIRECTORY) && (RC != STATUS_NOT_A_DIRECTORY) && (RC != STATUS_ACCESS_DENIED)) { UDFFlushFile__(Vcb, NewFileInfo); UDFUnlinkFile__(Vcb, NewFileInfo, TRUE); } UDFCloseFile__(Vcb, NewFileInfo); BrutePoint(); goto Creation_Err_1; }#if 0 CollectStatistics(Vcb, MetaDataWrites);#endif } else if(AllocationSize) { // set initial file size/* if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) { AdPrint((" Can't set initial file size\n")); goto Undo_Create_1; } CollectStatistics(Vcb, MetaDataWrites);*/ }
if(StreamOpen && !StreamExists) {
// PHASE 0
// Open the newly created object (file) if (!(PtrNewFcb = NewFileInfo->Fcb)) { // It is a first open operation // Allocate new FCB // Here we set FileObject pointer to NULL to avoid // new CCB allocation RC = UDFFirstOpenFile(Vcb, NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo, &LocalPath, &LastGoodTail); if(!NT_SUCCESS(RC)) { AdPrint((" Can't perform FirstOpenFile operation for file to contain stream\n")); BrutePoint(); UDFCleanUpFCB(NewFileInfo->Fcb); NewFileInfo->Fcb = NULL; goto Creation_Err_1; } } else { BrutePoint(); }
// Update unwind information TreeLength++; LastGoodFileInfo = NewFileInfo; // update FCB tree RC = MyAppendUnicodeToString(&LocalPath, L"\\"); if(!NT_SUCCESS(RC)) try_return(RC); RC = MyAppendUnicodeStringToStringTag(&LocalPath, &LastGoodTail, MEM_USLOC_TAG); if(!NT_SUCCESS(RC)) goto Creation_Err_1; UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; PtrNewFcb->FCBFlags |= UDF_FCB_VALID;
UDFNotifyFullReportChange( Vcb, NewFileInfo, UDFIsADirectory(NewFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED);
// PHASE 1
// we need to create Stream Dir RelatedFileInfo = NewFileInfo; RC = UDFCreateStreamDir__(Vcb, RelatedFileInfo, &NewFileInfo); if(!NT_SUCCESS(RC)) { AdPrint((" Can't create SDir\n")); BrutePoint(); goto Creation_Err_1; }#if 0 CollectStatistics(Vcb, MetaDataWrites);#endif
// normalize stream name StreamName.Buffer++; StreamName.Length-=sizeof(WCHAR); // Open the newly created object if (!(PtrNewFcb = NewFileInfo->Fcb)) { // It is a first open operation // Allocate new FCB // Here we set FileObject pointer to NULL to avoid // new CCB allocation RC = UDFFirstOpenFile(Vcb, NULL, &PtrNewFcb, RelatedFileInfo, NewFileInfo, &LocalPath, &(UDFGlobalData.UnicodeStrSDir)); } else { BrutePoint(); } if(!NT_SUCCESS(RC)) { AdPrint((" Can't perform OpenFile operation for SDir\n")); BrutePoint(); goto Creation_Err_1; }
// Update unwind information TreeLength++; LastGoodFileInfo = NewFileInfo; // update FCB tree RC = MyAppendUnicodeStringToStringTag(&LocalPath, &(UDFGlobalData.UnicodeStrSDir), MEM_USLOC_TAG); if(!NT_SUCCESS(RC)) { AdPrint((" Can't append UNC str\n")); BrutePoint(); goto Creation_Err_1; } UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); ASSERT_REF(PtrNewFcb->ReferenceCount >= NewFileInfo->RefCount); PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; PtrNewFcb->FCBFlags |= UDF_FCB_VALID;
// PHASE 2
// create stream RelatedFileInfo = NewFileInfo; RC = UDFCreateFile__(Vcb, IgnoreCase, &StreamName, 0, 0, Vcb->UseExtendedFE, (RequestedDisposition == FILE_CREATE), RelatedFileInfo, &NewFileInfo); if(!NT_SUCCESS(RC)) { AdPrint((" Can't create Stream\n")); BrutePoint(); goto Creation_Err_1; }#if 0 CollectStatistics(Vcb, MetaDataWrites);#endif
// Update unwind information LastGoodTail = StreamName; } // NT wants ARCHIVE bit to be set on Files if(!DirectoryOnlyRequested) FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; // Open the newly created object if (!(PtrNewFcb = NewFileInfo->Fcb)) { // It is a first open operation#ifndef IFS_40 // Set attributes for the file ... UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo),NewFileInfo->Index), NewFileInfo->Dloc->FileEntry, FileAttributes);#endif //IFS_40 // Allocate new FCB // Here we set FileObject pointer to NULL to avoid // new CCB allocation RC = UDFFirstOpenFile(Vcb, PtrNewFileObject, &PtrNewFcb, RelatedFileInfo, NewFileInfo, &LocalPath, &LastGoodTail); } else { BrutePoint(); }
if(!NT_SUCCESS(RC)) { AdPrint((" Can't perform OpenFile operation for file or stream\n")); BrutePoint(); goto Undo_Create_1; }
PtrNewFcb->NTRequiredFCB->CommonFCBHeader.FileSize.QuadPart = PtrNewFcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength.QuadPart = 0; if(AllocationSize) { // inform NT about size changes PtrNewFcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart = AllocationSize; MmPrint((" CcIsFileCached()\n")); if(CcIsFileCached(PtrNewFileObject)) { MmPrint((" CcSetFileSizes()\n")); BrutePoint(); CcSetFileSizes(PtrNewFileObject, (PCC_FILE_SIZES)&(PtrNewFcb->NTRequiredFCB->CommonFCBHeader.AllocationSize)); PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; } }
// Update unwind information TreeLength++; LastGoodFileInfo = NewFileInfo;
// Set the Share Access for the file stream. // The FCBShareAccess field will be set by the I/O Manager. PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2); RC = UDFSetAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess);
if(!NT_SUCCESS(RC)) { AdPrint((" Can't set Access Rights on Create\n")); BrutePoint(); UDFFlushFile__(Vcb, NewFileInfo); UDFUnlinkFile__(Vcb, NewFileInfo, TRUE); try_return(RC); }
#ifdef IFS_40 // Set attributes for the file ... UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo),NewFileInfo->Index), NewFileInfo->Dloc->FileEntry, FileAttributes); // It is rather strange for me, but NT requires us to allow // Create operation for r/o + WriteAccess, but denies all // the rest operations in this case. Thus, we should update // r/o flag in Fcb _after_ Access check :-/ if(FileAttributes & FILE_ATTRIBUTE_READONLY) PtrNewFcb->FCBFlags |= UDF_FCB_READ_ONLY;#endif //IFS_40 // We call the notify package to report that the // we have added a stream. if(UDFIsAStream(NewFileInfo)) { UDFNotifyFullReportChange( Vcb, NewFileInfo, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_ADDED_STREAM ); } else { UDFNotifyFullReportChange( Vcb, NewFileInfo, UDFIsADirectory(NewFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED); }/*#ifdef UDF_DBG { ULONG i; PDIR_INDEX_HDR hDirIndex = NewFileInfo->ParentFile->Dloc->DirIndex;
for(i=0;DirIndex[i].FName.Buffer;i++) { AdPrint(("%ws\n", DirIndex[i].FName.Buffer)); } }#endif*/ ReturnedInformation = FILE_CREATED;
try_return(RC);#endif //UDF_READ_ONLY_BUILD
}
AlreadyOpened:
// **************** // we have always STATUS_SUCCESS here // ****************
ASSERT(NewFileInfo != OldRelatedFileInfo); // A new CCB will be allocated. // Assume that this structure named PtrNewCcb RC = UDFOpenFile(Vcb, PtrNewFileObject, PtrNewFcb); if (!NT_SUCCESS(RC)) try_return(RC); PtrNewCcb = (PtrUDFCCB)(PtrNewFileObject->FsContext2);
if(RequestedDisposition == FILE_CREATE) { ReturnedInformation = FILE_EXISTS; AdPrint((" Object name collision\n")); try_return(RC = STATUS_OBJECT_NAME_COLLISION); }
NtReqFcb = PtrNewFcb->NTRequiredFCB; NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(PtrNewFcb);
// Check if caller wanted a directory only and target object // is not a directory, or caller wanted a file only and target // object is not a file ... if((PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY) && ((RequestedDisposition == FILE_SUPERSEDE) || (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF) || FileOnlyRequested)) { if(FileOnlyRequested) { AdPrint((" Can't open directory as a plain file\n")); } else { AdPrint((" Can't supersede directory\n")); } RC = STATUS_FILE_IS_A_DIRECTORY; try_return(RC); }
if(DirectoryOnlyRequested && !(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)) { AdPrint((" This is not a directory\n")); RC = STATUS_NOT_A_DIRECTORY; try_return(RC); }
if(DeleteOnCloseSpecified && (PtrNewFcb->FCBFlags & UDF_FCB_READ_ONLY)) { AdPrint((" Can't delete Read-Only file\n")); RC = STATUS_CANNOT_DELETE; try_return(RC); } // Check share access and fail if the share conflicts with an existing // open. ASSERT(Res1 != NULL); ASSERT(Res2 != NULL); RC = UDFCheckAccessRights(PtrNewFileObject, AccessState, PtrNewFcb, PtrNewCcb, DesiredAccess, ShareAccess); if(!NT_SUCCESS(RC)) { AdPrint((" Access/Share access check failed\n")); try_return(RC); }
RestoreShareAccess = TRUE;
if(FileOnlyRequested) { // If the user wants 'write access' access to the file make sure there // is not a process mapping this file as an image. Any attempt to // delete the file will be stopped in fileinfo.cpp // // If the user wants to delete on close, we must check at this // point though. if( (DesiredAccess & FILE_WRITE_DATA) || DeleteOnCloseSpecified ) { MmPrint((" MmFlushImageSection();\n")); NtReqFcb->AcqFlushCount++; if(!MmFlushImageSection( &(NtReqFcb->SectionObject), MmFlushForWrite )) {
NtReqFcb->AcqFlushCount--; RC = DeleteOnCloseSpecified ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION; AdPrint((" File is mapped or deletion in progress\n")); try_return (RC); } NtReqFcb->AcqFlushCount--; } if( NoBufferingSpecified && /* (PtrNewFileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) &&*/ !(PtrNewFcb->CachedOpenHandleCount) && (NtReqFcb->SectionObject.DataSectionObject) ) { // If this is a non-cached open, and there are no open cached // handles, but there is still a data section, attempt a flush // and purge operation to avoid cache coherency overhead later. // We ignore any I/O errors from the flush. MmPrint((" CcFlushCache()\n")); CcFlushCache( &(NtReqFcb->SectionObject), NULL, 0, NULL ); MmPrint((" CcPurgeCacheSection()\n")); CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE ); } }
if(DeleteOnCloseSpecified && UDFIsADirectory(NewFileInfo) && !UDFIsDirEmpty__(NewFileInfo)) { AdPrint((" Directory in not empry\n")); try_return (RC = STATUS_DIRECTORY_NOT_EMPTY); }
// Get attributes for the file ... TmpFileAttributes = (USHORT)UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index), NewFileInfo->Dloc->FileEntry);
if(DeleteOnCloseSpecified && (TmpFileAttributes & FILE_ATTRIBUTE_READONLY)) { ASSERT(Res1 != NULL); ASSERT(Res2 != NULL); RC = UDFCheckAccessRights(NULL, NULL, OldRelatedFileInfo->Fcb, PtrRelatedCCB, FILE_DELETE_CHILD, 0); if(!NT_SUCCESS(RC)) { AdPrint((" Read-only. DeleteOnClose attempt failed\n")); try_return (RC = STATUS_CANNOT_DELETE); } }
// If a supersede or overwrite was requested, do so now ... if((RequestedDisposition == FILE_SUPERSEDE) || (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF)) { // Attempt the operation here ...
#ifndef UDF_READ_ONLY_BUILD ASSERT(!UDFIsADirectory(NewFileInfo));
if(RequestedDisposition == FILE_SUPERSEDE) { BOOLEAN RestoreRO = FALSE;
ASSERT(Res1 != NULL); ASSERT(Res2 != NULL); // NT wants us to allow Supersede on RO files if(PtrNewFcb->FCBFlags & UDF_FCB_READ_ONLY) { // Imagine, that file is not RO and check other permissions RestoreRO = TRUE; PtrNewFcb->FCBFlags &= ~UDF_FCB_READ_ONLY; } RC = UDFCheckAccessRights(NULL, NULL, PtrNewFcb, PtrNewCcb, DELETE, 0); if(RestoreRO) { // Restore RO state if changed PtrNewFcb->FCBFlags |= UDF_FCB_READ_ONLY; } if(!NT_SUCCESS(RC)) { AdPrint((" Can't supersede. DELETE permission required\n")); try_return (RC); } } else { ASSERT(Res1 != NULL); ASSERT(Res2 != NULL); RC = UDFCheckAccessRights(NULL, NULL, PtrNewFcb, PtrNewCcb, FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES, 0); if(!NT_SUCCESS(RC)) { AdPrint((" Can't overwrite. Permission denied\n")); try_return (RC); } } // Existing & requested System and Hidden bits must match if( (TmpFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) & (FileAttributes ^ (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) ) { AdPrint((" The Hidden and/or System bits do not match\n")); try_return(RC = STATUS_ACCESS_DENIED); }
// Before we actually truncate, check to see if the purge // is going to fail. MmPrint((" MmCanFileBeTruncated()\n")); if (!MmCanFileBeTruncated( &NtReqFcb->SectionObject, &(UDFGlobalData.UDFLargeZero) )) { AdPrint((" Can't truncate. File is mapped\n")); try_return(RC = STATUS_USER_MAPPED_FILE); }
ASSERT(Res1 != NULL); ASSERT(Res2 != NULL);
#if 0 CollectStatistics(Vcb, MetaDataWrites);#endif // Synchronize with PagingIo UDFAcquireResourceExclusive(PagingIoRes = &(NtReqFcb->PagingIoResource),TRUE); // Set file sizes if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, 0))) { AdPrint((" Error during resize operation\n")); try_return(RC); }/* if(AllocationSize) { if(!NT_SUCCESS(RC = UDFResizeFile__(Vcb, NewFileInfo, AllocationSize))) { AdPrint((" Error during resize operation (2)\n")); try_return(RC); } }*/ NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = UDFSysGetAllocSize(Vcb, AllocationSize); NtReqFcb->CommonFCBHeader.FileSize.QuadPart = NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = 0 /*AllocationSize*/; PtrNewFcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE; MmPrint((" CcSetFileSizes()\n")); CcSetFileSizes(PtrNewFileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize)); NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED; // Release PagingIoResource UDFReleaseResource(PagingIoRes); PagingIoRes = NULL;
if(NT_SUCCESS(RC)) { FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; if (RequestedDisposition == FILE_SUPERSEDE) { // Set attributes for the file ... UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index), NewFileInfo->Dloc->FileEntry, FileAttributes); ReturnedInformation = FILE_SUPERSEDED; } else { // Get attributes for the file ... FileAttributes |= TmpFileAttributes; // Set attributes for the file ... UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(NewFileInfo), NewFileInfo->Index), NewFileInfo->Dloc->FileEntry, FileAttributes); ReturnedInformation = FILE_OVERWRITTEN; } } // notify changes UDFNotifyFullReportChange( Vcb, NewFileInfo, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED);
// Update parent object if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) && PtrRelatedFCB && PtrRelatedFileObject && (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) { PtrRelatedFileObject->Flags |= (FO_FILE_MODIFIED | FO_FILE_SIZE_CHANGED); }#else //UDF_READ_ONLY_BUILD try_return(RC = STATUS_ACCESS_DENIED);#endif //UDF_READ_ONLY_BUILD } else { ReturnedInformation = FILE_OPENED; }
// Update parent object if((Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_READ) && PtrRelatedFCB && PtrRelatedFileObject && (PtrRelatedFCB->FileInfo == NewFileInfo->ParentFile)) { PtrRelatedFileObject->Flags |= FO_FILE_FAST_IO_READ; }
try_exit: NOTHING;
} _SEH2_FINALLY { // Complete the request unless we are here as part of unwinding // when an exception condition was encountered, OR // if the request has been deferred (i.e. posted for later handling)
if(RestoreVCBOpenCounter) { UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); RestoreVCBOpenCounter = FALSE; }
if (RC != STATUS_PENDING) { // If any intermediate (directory) open operations were performed, // implement the corresponding close (do *not* however close // the target we have opened on behalf of the caller ...).
#if 0 if(NT_SUCCESS(RC)) { CollectStatistics2(Vcb, SuccessfulCreates); } else { CollectStatistics2(Vcb, FailedCreates); }#endif
if (NT_SUCCESS(RC) && PtrNewFcb) { // Update the file object such that: // (a) the FsContext field points to the NTRequiredFCB field // in the FCB // (b) the FsContext2 field points to the CCB created as a // result of the open operation
// If write-through was requested, then mark the file object // appropriately
// directories are not cached // so we should prevent flush attepmts on cleanup if(!(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)) {#ifndef UDF_READ_ONLY_BUILD if(WriteThroughRequested) { PtrNewFileObject->Flags |= FO_WRITE_THROUGH; PtrNewFcb->FCBFlags |= UDF_FCB_WRITE_THROUGH; MmPrint((" FO_WRITE_THROUGH\n")); }#endif //UDF_READ_ONLY_BUILD if(SequentialIoRequested && !(Vcb->CompatFlags & UDF_VCB_IC_IGNORE_SEQUENTIAL_IO)) { PtrNewFileObject->Flags |= FO_SEQUENTIAL_ONLY; MmPrint((" FO_SEQUENTIAL_ONLY\n"));#ifndef UDF_READ_ONLY_BUILD if(Vcb->TargetDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { PtrNewFileObject->Flags &= ~FO_WRITE_THROUGH; PtrNewFcb->FCBFlags &= ~UDF_FCB_WRITE_THROUGH; MmPrint((" FILE_REMOVABLE_MEDIA + FO_SEQUENTIAL_ONLY => ~FO_WRITE_THROUGH\n")); }#endif //UDF_READ_ONLY_BUILD if(PtrNewFcb->FileInfo) { UDFSetFileAllocMode__(PtrNewFcb->FileInfo, EXTENT_FLAG_ALLOC_SEQUENTIAL); } } if(NoBufferingSpecified) { PtrNewFileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; MmPrint((" FO_NO_INTERMEDIATE_BUFFERING\n")); } else { PtrNewFileObject->Flags |= FO_CACHE_SUPPORTED; MmPrint((" FO_CACHE_SUPPORTED\n")); } }
if((DesiredAccess & FILE_EXECUTE) /*&& !(PtrNewFcb->FCBFlags & UDF_FCB_DIRECTORY)*/) { MmPrint((" FO_FILE_FAST_IO_READ\n")); PtrNewFileObject->Flags |= FO_FILE_FAST_IO_READ; } // All right. Now we can safely increment OpenHandleCount UDFInterlockedIncrement((PLONG)&(Vcb->VCBHandleCount)); UDFInterlockedIncrement((PLONG)&(PtrNewFcb->OpenHandleCount));
if(PtrNewFileObject->Flags & FO_CACHE_SUPPORTED) UDFInterlockedIncrement((PLONG)&(PtrNewFcb->CachedOpenHandleCount)); // Store some flags in CCB if(PtrNewCcb) { PtrNewCcb->TreeLength = TreeLength; // delete on close#ifndef UDF_READ_ONLY_BUILD if(DeleteOnCloseSpecified) { ASSERT(!(PtrNewFcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)); PtrNewCcb->CCBFlags |= UDF_CCB_DELETE_ON_CLOSE; }#endif //UDF_READ_ONLY_BUILD // case sensetivity if(!IgnoreCase) { // remember this for possible Rename/Move operation PtrNewCcb->CCBFlags |= UDF_CCB_CASE_SENSETIVE; PtrNewFileObject->Flags |= FO_OPENED_CASE_SENSITIVE; } if(IsFileObjectReadOnly(PtrNewFileObject)) { UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCountRO)); PtrNewCcb->CCBFlags |= UDF_CCB_READ_ONLY; } } else { BrutePoint(); } // it was a stream... if(StreamOpen) PtrNewFileObject->Flags |= FO_STREAM_FILE;// PtrNewCcb->CCBFlags |= UDF_CCB_VALID; // increment the number of outstanding open operations on this // logical volume (i.e. volume cannot be dismounted) UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); PtrNewFcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; PtrNewFcb->FCBFlags |= UDF_FCB_VALID;#ifdef UDF_DBG // We have no FileInfo for Volume if(PtrNewFcb->FileInfo) { ASSERT_REF(PtrNewFcb->ReferenceCount >= PtrNewFcb->FileInfo->RefCount); }#endif // UDF_DBG AdPrint((" FCB %x, CCB %x, FO %x, Flags %x\n", PtrNewFcb, PtrNewCcb, PtrNewFileObject, PtrNewFcb->FCBFlags));
UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2);
} else if(!NT_SUCCESS(RC)) { // Perform failure related post-processing now if(RestoreShareAccess && NtReqFcb && PtrNewFileObject) { IoRemoveShareAccess(PtrNewFileObject, &(NtReqFcb->FCBShareAccess)); } UDFCleanUpCCB(PtrNewCcb); if(PtrNewFileObject) { PtrNewFileObject->FsContext2 = NULL; } // We have successfully opened LastGoodFileInfo, // so mark it as VALID to avoid future troubles... if(LastGoodFileInfo && LastGoodFileInfo->Fcb) { LastGoodFileInfo->Fcb->FCBFlags |= UDF_FCB_VALID; if(LastGoodFileInfo->Fcb->NTRequiredFCB) { LastGoodFileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_VALID; } } // Release resources... UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); ASSERT(AcquiredVcb); // close the chain UDFCloseFileInfoChain(Vcb, LastGoodFileInfo, TreeLength, TRUE); // cleanup FCBs (if any) if( Vcb && (PtrNewFcb != Vcb->RootDirFCB) && LastGoodFileInfo ) { UDFCleanUpFcbChain(Vcb, LastGoodFileInfo, TreeLength, TRUE); } else { ASSERT(!LastGoodFileInfo); } } else { UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); } // As long as this unwinding is not being performed as a result of // an exception condition, complete the IRP ... if (!_SEH2_AbnormalTermination()) { Irp->IoStatus.Status = RC; Irp->IoStatus.Information = ReturnedInformation;
// complete the IRP IoCompleteRequest(Irp, IO_DISK_INCREMENT); // Free up the Irp Context UDFReleaseIrpContext(PtrIrpContext); } } else { UDFReleaseResFromCreate(&PagingIoRes, &Res1, &Res2); }
if(AcquiredVcb) { UDFReleaseResource(&(Vcb->VCBResource)); } // free allocated tmp buffers (if any) if(AbsolutePathName.Buffer) MyFreePool__(AbsolutePathName.Buffer); if(LocalPath.Buffer) MyFreePool__(LocalPath.Buffer); if(TailNameBuffer) MyFreePool__(TailNameBuffer); } _SEH2_END;
return(RC);} // end UDFCommonCreate()
/*************************************************************************** Function: UDFFirstOpenFile()** Description:* Perform first Open/Create initialization.** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL** Return Value: STATUS_SUCCESS/Error**************************************************************************/NTSTATUSUDFFirstOpenFile( IN PVCB Vcb, // volume control block IN PFILE_OBJECT PtrNewFileObject, // I/O Mgr. created file object OUT PtrUDFFCB* PtrNewFcb, IN PUDF_FILE_INFO RelatedFileInfo, IN PUDF_FILE_INFO NewFileInfo, IN PUNICODE_STRING LocalPath, IN PUNICODE_STRING CurName ){// DIR_INDEX NewFileIndex; PtrUDFObjectName NewFCBName; PtrUDFNTRequiredFCB NtReqFcb; NTSTATUS RC; BOOLEAN Linked = TRUE; PDIR_INDEX_HDR hDirIndex; PDIR_INDEX_ITEM DirIndex;
AdPrint(("UDFFirstOpenFile\n"));
if(!((*PtrNewFcb) = UDFAllocateFCB())) { AdPrint(("Can't allocate FCB\n")); return STATUS_INSUFFICIENT_RESOURCES; }
// Allocate and set new FCB unique name (equal to absolute path name) if(!(NewFCBName = UDFAllocateObjectName())) return STATUS_INSUFFICIENT_RESOURCES;
if(RelatedFileInfo && RelatedFileInfo->Fcb && !(RelatedFileInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)) { RC = MyCloneUnicodeString(&(NewFCBName->ObjectName), &(RelatedFileInfo->Fcb->FCBName->ObjectName)); } else { RC = MyInitUnicodeString(&(NewFCBName->ObjectName), L""); } if(!NT_SUCCESS(RC)) return STATUS_INSUFFICIENT_RESOURCES; if( (CurName->Buffer[0] != L':') && (!LocalPath->Length || ((LocalPath->Buffer[LocalPath->Length/sizeof(WCHAR)-1] != L':') /*&& (LocalPath->Buffer[LocalPath->Length/sizeof(WCHAR)-1] != L'\\')*/) )) { RC = MyAppendUnicodeToString(&(NewFCBName->ObjectName), L"\\"); if(!NT_SUCCESS(RC)) { UDFReleaseObjectName(NewFCBName); return STATUS_INSUFFICIENT_RESOURCES; } }
// Make link between Fcb and FileInfo (*PtrNewFcb)->FileInfo = NewFileInfo; NewFileInfo->Fcb = (*PtrNewFcb); (*PtrNewFcb)->ParentFcb = RelatedFileInfo->Fcb;
if(!((*PtrNewFcb)->NTRequiredFCB = NewFileInfo->Dloc->CommonFcb)) { (*PtrNewFcb)->NTRequiredFCB = (PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB))); if(!((*PtrNewFcb)->NTRequiredFCB)) { UDFReleaseObjectName(NewFCBName); return STATUS_INSUFFICIENT_RESOURCES; }
UDFPrint(("UDFAllocateNtReqFCB: %x\n", (*PtrNewFcb)->NTRequiredFCB)); RtlZeroMemory((*PtrNewFcb)->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB))); (*PtrNewFcb)->FileInfo->Dloc->CommonFcb = (*PtrNewFcb)->NTRequiredFCB; Linked = FALSE; } else { if(!(NewFileInfo->Dloc->CommonFcb->NtReqFCBFlags & UDF_NTREQ_FCB_VALID)) { (*PtrNewFcb)->NTRequiredFCB = NULL; BrutePoint(); UDFReleaseObjectName(NewFCBName); return STATUS_ACCESS_DENIED; } }
NtReqFcb = (*PtrNewFcb)->NTRequiredFCB; // Set times if(!Linked) { UDFGetFileXTime((*PtrNewFcb)->FileInfo, &(NtReqFcb->CreationTime.QuadPart), &(NtReqFcb->LastAccessTime.QuadPart), &(NtReqFcb->ChangeTime.QuadPart), &(NtReqFcb->LastWriteTime.QuadPart) );
// Set the allocation size for the object is specified NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = UDFSysGetAllocSize(Vcb, NewFileInfo->Dloc->DataLoc.Length);// NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart = UDFGetFileAllocationSize(Vcb, NewFileInfo); NtReqFcb->CommonFCBHeader.FileSize.QuadPart = NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = NewFileInfo->Dloc->DataLoc.Length; } // begin transaction UDFAcquireResourceExclusive(&(Vcb->FcbListResource), TRUE);
RC = UDFInitializeFCB(*PtrNewFcb, Vcb, NewFCBName, UDFIsADirectory(NewFileInfo) ? UDF_FCB_DIRECTORY : 0, PtrNewFileObject); if(!NT_SUCCESS(RC)) { if(!Linked) { MyFreePool__((*PtrNewFcb)->NTRequiredFCB); (*PtrNewFcb)->NTRequiredFCB = NULL; } UDFReleaseResource(&(Vcb->FcbListResource)); return RC; } // set Read-only attribute if(!UDFIsAStreamDir(NewFileInfo)) { hDirIndex = UDFGetDirIndexByFileInfo(NewFileInfo);#ifdef UDF_DBG if(!hDirIndex) { BrutePoint(); } else {#endif // UDF_DBG if(UDFAttributesToNT(DirIndex = UDFDirIndex(hDirIndex, NewFileInfo->Index),NULL) & FILE_ATTRIBUTE_READONLY) { (*PtrNewFcb)->FCBFlags |= UDF_FCB_READ_ONLY; } MyAppendUnicodeStringToStringTag(&(NewFCBName->ObjectName), &(DirIndex->FName), MEM_USOBJ_TAG);#ifdef UDF_DBG }#endif // UDF_DBG } else if (RelatedFileInfo->ParentFile) { hDirIndex = UDFGetDirIndexByFileInfo(RelatedFileInfo); if(UDFAttributesToNT(DirIndex = UDFDirIndex(hDirIndex, RelatedFileInfo->Index),NULL) & FILE_ATTRIBUTE_READONLY) { (*PtrNewFcb)->FCBFlags |= UDF_FCB_READ_ONLY; } RC = MyAppendUnicodeStringToStringTag(&(NewFCBName->ObjectName), CurName, MEM_USOBJ_TAG);// } else {// BrutePoint(); } // do not allocate CCB if it is internal Create/Open if(NT_SUCCESS(RC)) { if(PtrNewFileObject) { RC = UDFOpenFile(Vcb, PtrNewFileObject, *PtrNewFcb); } else { RC = STATUS_SUCCESS; } } UDFReleaseResource(&(Vcb->FcbListResource)); // end transaction
// if(!NT_SUCCESS(RC)) return RC;
return RC;} // end UDFFirstOpenFile()
/*************************************************************************** Function: UDFOpenFile()** Description:* Open a file/dir for the caller.** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL** Return Value: STATUS_SUCCESS/Error**************************************************************************/NTSTATUSUDFOpenFile( PVCB Vcb, // volume control block PFILE_OBJECT PtrNewFileObject, // I/O Mgr. created file object PtrUDFFCB PtrNewFcb ){ NTSTATUS RC = STATUS_SUCCESS; PtrUDFCCB Ccb = NULL; PtrUDFNTRequiredFCB NtReqFcb;
AdPrint(("UDFOpenFile\n")); ASSERT((PtrNewFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB) ||(PtrNewFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB));
_SEH2_TRY {
#if 0 CollectStatistics2(Vcb, CreateHits);#endif // create a new CCB structure if (!(Ccb = UDFAllocateCCB())) { AdPrint(("Can't allocate CCB\n")); PtrNewFileObject->FsContext2 = NULL; // UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); RC = STATUS_INSUFFICIENT_RESOURCES; try_return(RC); } // initialize the CCB Ccb->Fcb = PtrNewFcb; // initialize the CCB to point to the file object Ccb->FileObject = PtrNewFileObject;
// initialize the file object appropriately PtrNewFileObject->FsContext2 = (PVOID)(Ccb); PtrNewFileObject->Vpb = Vcb->Vpb; PtrNewFileObject->FsContext = (PVOID)(NtReqFcb = PtrNewFcb->NTRequiredFCB); PtrNewFileObject->SectionObjectPointer = &(NtReqFcb->SectionObject);#ifdef DBG// NtReqFcb ->FileObject = PtrNewFileObject;#endif //DBG
#ifdef UDF_DELAYED_CLOSE PtrNewFcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE;#endif //UDF_DELAYED_CLOSE
UDFAcquireResourceExclusive(&(PtrNewFcb->CcbListResource),TRUE); // insert CCB into linked list of open file object to Fcb or // to Vcb and do other intialization InsertTailList(&(PtrNewFcb->NextCCB), &(Ccb->NextCCB)); UDFInterlockedIncrement((PLONG)&(PtrNewFcb->ReferenceCount)); UDFInterlockedIncrement((PLONG)&(PtrNewFcb->NTRequiredFCB->CommonRefCount)); UDFReleaseResource(&(PtrNewFcb->CcbListResource));
try_exit: NOTHING; } _SEH2_FINALLY { NOTHING; } _SEH2_END;
return(RC);} // end UDFOpenFile()
/*************************************************************************** Function: UDFInitializeFCB()** Description:* Initialize a new FCB structure and also the sent-in file object* (if supplied)** Expected Interrupt Level (for execution) :** IRQL_PASSIVE_LEVEL** Return Value: None**************************************************************************/NTSTATUSUDFInitializeFCB( IN PtrUDFFCB PtrNewFcb, // FCB structure to be initialized IN PVCB Vcb, // logical volume (VCB) pointer IN PtrUDFObjectName PtrObjectName, // name of the object IN ULONG Flags, // is this a file/directory, etc. IN PFILE_OBJECT FileObject) // optional file object to be initialized{ AdPrint(("UDFInitializeFCB\n")); NTSTATUS status; BOOLEAN Linked = TRUE;
if(!PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource) { // record signature PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode = UDF_NODE_TYPE_NT_REQ_FCB; PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeByteSize = sizeof(UDFNTRequiredFCB); // Initialize the ERESOURCE objects if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->NTRequiredFCB->MainResource)))) { AdPrint((" Can't init resource\n")); return status; } if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->NTRequiredFCB->PagingIoResource)))) { AdPrint((" Can't init resource (2)\n")); UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->MainResource)); return status; } // Fill NT required Fcb part PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource = &(PtrNewFcb->NTRequiredFCB->MainResource); PtrNewFcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource = &(PtrNewFcb->NTRequiredFCB->PagingIoResource); // Itialize byte-range locks support structure FsRtlInitializeFileLock(&(PtrNewFcb->NTRequiredFCB->FileLock),NULL,NULL); // Init reference counter PtrNewFcb->NTRequiredFCB->CommonRefCount = 0; Linked = FALSE; } else { ASSERT(PtrNewFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB); } if(!NT_SUCCESS(status = UDFInitializeResourceLite(&(PtrNewFcb->CcbListResource)))) { AdPrint((" Can't init resource (3)\n")); BrutePoint(); if(!Linked) { UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->PagingIoResource)); UDFDeleteResource(&(PtrNewFcb->NTRequiredFCB->MainResource)); PtrNewFcb->NTRequiredFCB->CommonFCBHeader.Resource = PtrNewFcb->NTRequiredFCB->CommonFCBHeader.PagingIoResource = NULL; FsRtlUninitializeFileLock(&(PtrNewFcb->NTRequiredFCB->FileLock)); } return status; }
// caller MUST ensure that VCB has been acquired exclusively InsertTailList(&(Vcb->NextFCB), &(PtrNewFcb->NextFCB));
// initialize the various list heads InitializeListHead(&(PtrNewFcb->NextCCB));
PtrNewFcb->ReferenceCount = 0; PtrNewFcb->OpenHandleCount = 0;
PtrNewFcb->FCBFlags = Flags | UDF_FCB_INITIALIZED_CCB_LIST_RESOURCE;
PtrNewFcb->FCBName = PtrObjectName;
PtrNewFcb->Vcb = Vcb;
return STATUS_SUCCESS;} // end UDFInitializeFCB()