www.pudn.com > filesys.rar > create.c


/************************************************************************* 
* 
* File: create.c 
* 
* Module: Sample File System Driver (Kernel mode execution only) 
* 
* Description: 
*	Contains code to handle the "Create"/"Open" dispatch entry point. 
* 
* Author: R. Nagar 
* 
* (c) 1996-97 Rajeev Nagar, All Rights Reserved 
* 
*************************************************************************/ 
 
#include			"sfsd.h" 
 
// define the file specific bug-check id 
#define			SFSD_BUG_CHECK_ID				SFSD_FILE_CREATE 
 
 
 
/************************************************************************* 
* 
* Function: SFsdCreate() 
* 
* 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 
* 
*************************************************************************/ 
NTSTATUS SFsdCreate( 
PDEVICE_OBJECT		DeviceObject,		// the logical volume device object 
PIRP					Irp)					// I/O Request Packet 
{ 
	NTSTATUS				RC = STATUS_SUCCESS; 
   PtrSFsdIrpContext	PtrIrpContext; 
	BOOLEAN				AreWeTopLevel = FALSE; 
 
	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 (DeviceObject->Size == (unsigned short)(sizeof(DEVICE_OBJECT))) { 
		// this is an open of the FSD itself 
		Irp->IoStatus.Status = RC; 
		Irp->IoStatus.Information = FILE_OPENED; 
 
		IoCompleteRequest(Irp, IO_NO_INCREMENT); 
		return(RC); 
	} 
 
	// set the top level context 
	AreWeTopLevel = SFsdIsIrpTopLevel(Irp); 
 
	try { 
 
		// get an IRP context structure and issue the request 
		PtrIrpContext = SFsdAllocateIrpContext(Irp, DeviceObject); 
		ASSERT(PtrIrpContext); 
 
		RC = SFsdCommonCreate(PtrIrpContext, Irp); 
 
	} except (SFsdExceptionFilter(PtrIrpContext, GetExceptionInformation())) { 
 
		RC = SFsdExceptionHandler(PtrIrpContext, Irp); 
 
		SFsdLogEvent(SFSD_ERROR_INTERNAL_ERROR, RC); 
	} 
 
	if (AreWeTopLevel) { 
		IoSetTopLevelIrp(NULL); 
	} 
 
	FsRtlExitFileSystem(); 
 
	return(RC); 
} 
 
 
 
/************************************************************************* 
* 
* Function: SFsdCommonCreate() 
* 
* 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 
* 
*************************************************************************/ 
NTSTATUS SFsdCommonCreate( 
PtrSFsdIrpContext			PtrIrpContext, 
PIRP							PtrIrp) 
{ 
	NTSTATUS					RC = STATUS_SUCCESS; 
	PIO_STACK_LOCATION	PtrIoStackLocation = NULL; 
   PIO_SECURITY_CONTEXT	PtrSecurityContext = NULL; 
	PFILE_OBJECT			PtrNewFileObject = NULL; 
	PFILE_OBJECT			PtrRelatedFileObject = NULL; 
	uint32					AllocationSize = 0; 	// if we create a new file 
	PFILE_FULL_EA_INFORMATION	PtrExtAttrBuffer = NULL; 
	unsigned long			RequestedOptions = 0; 
	unsigned long			RequestedDisposition = 0; 
	uint8						FileAttributes = 0; 
	unsigned short			ShareAccess = 0; 
	unsigned long			ExtAttrLength = 0; 
	ACCESS_MASK				DesiredAccess; 
 
	BOOLEAN					DeferredProcessing = FALSE; 
 
   PtrSFsdVCB				PtrVCB = NULL; 
	BOOLEAN					AcquiredVCB = FALSE; 
 
	BOOLEAN					DirectoryOnlyRequested = FALSE; 
	BOOLEAN					FileOnlyRequested = FALSE; 
	BOOLEAN					NoBufferingSpecified = FALSE; 
	BOOLEAN					WriteThroughRequested = FALSE; 
	BOOLEAN					DeleteOnCloseSpecified = FALSE; 
	BOOLEAN					NoExtAttrKnowledge = FALSE; 
	BOOLEAN					CreateTreeConnection = FALSE; 
	BOOLEAN					OpenByFileId = FALSE; 
 
	// Are we dealing with a page file? 
	BOOLEAN					PageFileManipulation = FALSE; 
 
	// Is this open for a target directory (used in rename operations)? 
	BOOLEAN					OpenTargetDirectory = FALSE; 
 
	// Should we ignore case when attempting to locate the object? 
	BOOLEAN					IgnoreCaseWhenChecking = FALSE; 
 
	PtrSFsdCCB				PtrRelatedCCB = NULL, PtrNewCCB = NULL; 
	PtrSFsdFCB				PtrRelatedFCB = NULL, PtrNewFCB = NULL; 
 
	unsigned long			ReturnedInformation; 
 
	UNICODE_STRING			TargetObjectName; 
	UNICODE_STRING			RelatedObjectName; 
 
	UNICODE_STRING			AbsolutePathName; 
 
	LARGE_INTEGER			FileAllocationSize, FileEndOfFile; 
 
 
	ASSERT(PtrIrpContext); 
	ASSERT(PtrIrp); 
 
	try { 
 
		AbsolutePathName.Buffer = NULL; 
		AbsolutePathName.Length = AbsolutePathName.MaximumLength = 0; 
 
		// First, get a pointer to the current I/O stack location 
		PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); 
		ASSERT(PtrIoStackLocation); 
 
		// If the caller cannot block, post the request to be handled 
		//	asynchronously 
		if (!(PtrIrpContext->IrpContextFlags & SFSD_IRP_CONTEXT_CAN_BLOCK)) { 
			// We must defer processing of this request since we could 
			//	block anytime while performing the create/open ... 
			RC = SFsdPostRequest(PtrIrpContext, PtrIrp); 
         DeferredProcessing = TRUE; 
			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	= PtrIoStackLocation->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 = (PtrSFsdCCB)(PtrRelatedFileObject->FsContext2); 
			ASSERT(PtrRelatedCCB); 
			ASSERT(PtrRelatedCCB->NodeIdentifier.NodeType == SFSD_NODE_TYPE_CCB); 
			// each CCB in turn points to a FCB 
			PtrRelatedFCB = PtrRelatedCCB->PtrFCB; 
			ASSERT(PtrRelatedFCB); 
			ASSERT((PtrRelatedFCB->NodeIdentifier.NodeType == SFSD_NODE_TYPE_FCB) 
					 || 
  					 (PtrRelatedFCB->NodeIdentifier.NodeType == SFSD_NODE_TYPE_VCB)); 
			RelatedObjectName = PtrRelatedFileObject->FileName; 
		} 
 
		// Allocation size is only used if a new file is created 
		//	or a file is superseded. 
		AllocationSize    = PtrIrp->Overlay.AllocationSize.LowPart; 
		// Note: Some FSD implementations support file sizes > 2 GB. 
		//	The following check is only valid if your FSD does not support 
		//	a large file size. With NT version 5.0, 64 bit support will 
		//	become available and your FSD should ideally support large files ... 
		if (PtrIrp->Overlay.AllocationSize.HighPart) { 
			RC = STATUS_INVALID_PARAMETER; 
			try_return(RC); 
		} 
 
		// Get a ptr to the supplied security context 
		PtrSecurityContext = PtrIoStackLocation->Parameters.Create.SecurityContext; 
 
		// 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 = (PtrIoStackLocation->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 = ((PtrIoStackLocation->Parameters.Create.Options >> 24) && 0xFF); 
 
		FileAttributes	= (uint8)(PtrIoStackLocation->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS); 
		ShareAccess	= PtrIoStackLocation->Parameters.Create.ShareAccess; 
 
		// If your FSD does not support EA manipulation, you 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 
		PtrExtAttrBuffer	= PtrIrp->AssociatedIrp.SystemBuffer; 
		ExtAttrLength		= PtrIoStackLocation->Parameters.Create.EaLength; 
 
		// Get the options supplied by the user 
 
		// 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. 
		DirectoryOnlyRequested = ((RequestedOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE); 
 
		// 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. 
		FileOnlyRequested = ((RequestedOptions & FILE_NON_DIRECTORY_FILE) ? TRUE : FALSE); 
 
		// 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) 
		NoBufferingSpecified = ((RequestedOptions & FILE_NO_INTERMEDIATE_BUFFERING) ? TRUE : FALSE); 
	 
		// 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); 
 
		// 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, your 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 you 
		//	could create such "delete-on-close" marked files under directories 
		//	marked for deletion. Ordinarily, a FSD will not allow you to create 
		//	a new file under a directory that has been marked for deletion. 
		DeleteOnCloseSpecified = ((RequestedOptions & FILE_DELETE_ON_CLOSE) ? TRUE : FALSE); 
 
		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. 
		//	Your 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 your FSD with the file identifier instead of 
		//	a file/path name. 
		OpenByFileId = ((RequestedOptions & FILE_OPEN_BY_FILE_ID) ? TRUE : FALSE); 
 
		// Are we dealing with a page file? 
		PageFileManipulation = ((PtrIoStackLocation->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 = ((PtrIoStackLocation->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE); 
 
		// If your FSD supports case-sensitive file name checks, you may 
		//	choose to honor the following flag ... 
      IgnoreCaseWhenChecking = ((PtrIoStackLocation->Flags & SL_CASE_SENSITIVE) ? TRUE : FALSE); 
 
		// Ensure that the operation has been directed to a valid VCB ... 
		PtrVCB =	(PtrSFsdVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); 
		ASSERT(PtrVCB); 
		ASSERT(PtrVCB->NodeIdentifier.NodeType == SFSD_NODE_TYPE_VCB); 
 
		// Use coarse grained locking and acquire the VCB exclusively. This 
		//	will lock out all other concurrent create/open requests 
		// If the VCB is also acquired by the cleanup/close dispatch routines, 
		// you can count on create/opens being synchronized with these functions 
		// as well. 
		ExAcquireResourceExclusiveLite(&(PtrVCB->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 
 
		//	Implement your own volume verification routine ... 
		//	Read the DDK for more information on when a FSD must verify a 
		//	volume ... 
		//	if (!NT_SUCCESS(RC = SFsdVerifyVolume(PtrVCB))) { 
		//		try_return(RC); 
		//	} 
 
		// If the volume has been locked, fail the request 
		if (PtrVCB->VCBFlags & SFSD_VCB_FLAGS_VOLUME_LOCKED) { 
			RC = STATUS_ACCESS_DENIED; 
			try_return(RC); 
		} 
 
		// If a volume open is requested, satisfy it now 
		if ((PtrNewFileObject->FileName.Length == 0) && ((PtrRelatedFileObject == NULL) || 
			  (PtrRelatedFCB->NodeIdentifier.NodeType == SFSD_NODE_TYPE_VCB))) { 
			// 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: your 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)) { 
				RC = STATUS_INVALID_PARAMETER; 
				try_return(RC); 
			} 
 
			if (DirectoryOnlyRequested) { 
				// a volume is not a directory 
				RC = STATUS_NOT_A_DIRECTORY; 
				try_return(RC); 
			} 
 
			if ((RequestedDisposition != FILE_OPEN) && (RequestedDisposition != FILE_OPEN_IF)) { 
				// cannot create a new volume, I'm afraid ... 
				RC = STATUS_ACCESS_DENIED; 
				try_return(RC); 
			} 
 
			RC = SFsdOpenVolume(PtrVCB, PtrIrpContext, PtrIrp, ShareAccess, PtrSecurityContext, PtrNewFileObject); 
			ReturnedInformation = PtrIrp->IoStatus.Information; 
 
			try_return(RC); 
		} 
 
		// Your 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 you this file id and your FSD 
		//	should be completely capable of "opening" the object (it must 
		//	exist since the caller received an id for the object from your 
		//	FSD in a "query file" call ... 
 
		//	If the file has been deleted in the meantime, you can return 
		//	"not found" 
		if (OpenByFileId) { 
			// perform the open ... 
			// RC = SFsdOpenByFileId(PtrIrpContext, PtrIrp ....); 
			// try_return(RC); 
		} 
 
		// 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 ... 
 
			//	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 & SFSD_FCB_DIRECTORY)) { 
				// we must have a directory as the "related" object 
				RC = STATUS_INVALID_PARAMETER; 
				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 your FSD's behalf) 
			if ((RelatedObjectName.Length == 0) || (RelatedObjectName.Buffer[0] != L'\\')) { 
				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 
			if ((TargetObjectName.Length != 0) && (TargetObjectName.Buffer[0] == L'\\')) { 
				RC = STATUS_INVALID_PARAMETER; 
				try_return(RC); 
			} 
 
			// Create an absolute path-name. You could potentially use 
			//	the absolute path-name if you cache previously opened 
			//	file/directory object names. 
			{ 
				AbsolutePathName.MaximumLength = TargetObjectName.Length + RelatedObjectName.Length + sizeof(WCHAR); 
				if (!(AbsolutePathName.Buffer = ExAllocatePool(PagedPool, AbsolutePathName.MaximumLength))) { 
					RC = STATUS_INSUFFICIENT_RESOURCES; 
					try_return(RC); 
				} 
 
				RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength); 
 
				RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(RelatedObjectName.Buffer), RelatedObjectName.Length); 
				AbsolutePathName.Length = RelatedObjectName.Length; 
				RtlAppendUnicodeToString(&AbsolutePathName, L"\\"); 
				RtlAppendUnicodeToString(&AbsolutePathName, TargetObjectName.Buffer); 
			} 
 
		} else { 
 
			// The suplied path-name must be an absolute path-name i.e. 
			//	starting at the root of the file system tree 
         if (TargetObjectName.Buffer[0] != L'\\') { 
				RC = STATUS_INVALID_PARAMETER; 
				try_return(RC); 
			} 
 
			{ 
				AbsolutePathName.MaximumLength = TargetObjectName.Length; 
				if (!(AbsolutePathName.Buffer = ExAllocatePool(PagedPool, AbsolutePathName.MaximumLength))) { 
					RC = STATUS_INSUFFICIENT_RESOURCES; 
					try_return(RC); 
				} 
 
				RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength); 
 
				RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(TargetObjectName.Buffer), TargetObjectName.Length); 
				AbsolutePathName.Length = TargetObjectName.Length; 
			} 
		} 
 
		// go into a loop parsing the supplied name 
 
		//	Use the algorithm supplied in the book to implement this 
		//	loop. 
 
		//	Note that you may have to "open" intermediate directory objects 
		//	while traversing the path. You should try to reuse existing code 
		//	whenever possible therefore you 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 your driver. 
 
		//	But first, check if the caller simply wishes to open the root 
		//	of the file system tree. 
		if (AbsolutePathName.Length == 2) { 
			// 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)) { 
				RC = STATUS_FILE_IS_A_DIRECTORY; 
				try_return(RC); 
			} 
 
			// Insert code to open root directory here. Include creation of a new CCB structure. 
			//	e.g. RC = SFsdOpenRootDirectory(...); 
 
			try_return(RC); 
		} 
 
		if (PtrRelatedFileObject) { 
			// Insert code such that your "start directory" is 
			//	the one identified by the related file object 
		} else { 
			// Insert code to start at the root of the file system 
		} 
 
		// NOTE: If your FSD does not support access checking i.e. 
		//	your FSD does not check "traversal" privileges, 
		//	you could easily maintain a "prefix" cache containing 
		//	path-names and open FCB pointers. Then, if the requested 
		//	path-name is already present in the cache i.e. someone 
		//	had opened it earlier, you can avoid the tedious traversal 
		//	of the entire path-name performed below and described in 
		//	the book ... 
 
		//	If you do not maintain such a prefix table cache of previously 
		//	opened object names or if you do not find the name to be opened 
		//	in the cache, then: 
 
		//	Get the "next" component in the name to be parsed. Note that 
		//	obtaining the next string component is similar to the strtok 
		//	library routine where the separator is a "\" 
 
		//	Your FSD should also always check the validity of the token 
		//	to ensure that only valid characters comprise the path/file name 
 
		//	Insert code to open the starting directory here. 
 
		while (TRUE) { 
			// Insert code to perform the following tasks here: 
 
			//	(a) acquire the parent directory FCB MainResource exclusively 
			//	(b) ensure that the parent directory in which you will perform 
			//		 a lookup operation is indeed a directory 
			//	(c) if there are no more components left after this one in the 
			//		 pathname supplied by the user, break; 
			//	(d) attempt to lookup the sub-directory in the parent 
			//	(e) if not found, return STATUS_OBJECT_PATH_NOT_FOUND 
			//	(f) Otherwise, open the new sub-directory and make it 
			//		 the "parent" 
			//	(g) go back and repeat the loop for the next component in 
			//		 the path 
 
			//	NOTE: If your FSD supports it, you should always check 
			//	that the caller has appropriate privileges to traverse 
			//	the directories being searched. 
		} 
 
		// Now we are down to the last component, check it out to see if it exists ... 
 
		// If "open target directory" was specified 
		if (OpenTargetDirectory) { 
			if (NT_SUCCESS(RC)) { 
				// file exists, set this information in the Information field 
				ReturnedInformation = FILE_EXISTS; 
			} else { 
				RC = STATUS_SUCCESS; 
 
				// Tell the I/O Manager that file does not exit 
				ReturnedInformation = FILE_DOES_NOT_EXIST; 
			} 
 
			// Now, do the following: 
 
			//	(a) Replace the string in the FileName field in the 
			//		 PtrNewFileObject to identify the "target name" 
			//		 only (sans the path leading to the object) 
				{ 
					unsigned int	Index = (AbsolutePathName.Length - 1); 
 
					// Back up until we come to the last '\' 
					// But first, skip any trailing '\' characters 
 
					while (AbsolutePathName.Buffer[Index] == L'\\') { 
						ASSERT(Index >= sizeof(WCHAR)); 
						Index -= sizeof(WCHAR); 
						// Skip this length also 
						PtrNewFileObject->FileName.Length -= sizeof(WCHAR); 
					} 
 
					while (AbsolutePathName.Buffer[Index] != L'\\') { 
						// Keep backing up until we hit one 
						ASSERT(Index >= sizeof(WCHAR)); 
						Index -= sizeof(WCHAR); 
					} 
 
					// We must be at a '\' character 
					ASSERT(AbsolutePathName.Buffer[Index] == L'\\'); 
					Index++; 
 
					// We can now determine the new length of the filename 
					// and copy the name over 
					PtrNewFileObject->FileName.Length -= (unsigned short)(Index*sizeof(WCHAR)); 
					RtlCopyMemory(&(PtrNewFileObject->FileName.Buffer[0]), 
									  &(PtrNewFileObject->FileName.Buffer[Index]), 
                             PtrNewFileObject->FileName.Length); 
				} 
 
			//	(b) Return with the target's parent directory opened 
			//	(c) Update the file object FsContext and FsContext2 fields 
			//		 to reflect the fact that the parent directory of the 
			//		 target has been opened 
 
			try_return(RC); 
		} 
 
		if (!NT_SUCCESS(RC)) { 
			// Object was not found, create if requested 
			if ((RequestedDisposition == FILE_CREATE) || (RequestedDisposition == FILE_OPEN_IF) || 
				 (RequestedDisposition == FILE_OVERWRITE_IF)) { 
				// Create a new file/directory here ... 
				// 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. 
 
				// Open the newly created object 
 
				// Set the allocation size for the object is specified 
	 
				// Set extended attributes for the file ... 
 
				// Set the Share Access for the file stream. 
				// The FCBShareAccess field will be set by the I/O Manager. 
				IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess)); 
 
				RC = STATUS_SUCCESS; 
				ReturnedInformation = FILE_CREATED; 
			} 
 
			try_return(RC); 
 
		} else { 
			if (RequestedDisposition == FILE_CREATE) { 
				ReturnedInformation = FILE_EXISTS; 
				RC = STATUS_OBJECT_NAME_COLLISION; 
				try_return(RC); 
			} 
 
			// Insert code to open the target here, return if failed 
 
			// The FSD will allocate a new FCB structure if no such structure 
			// currently exists in memory for the file stream. 
			// A new CCB will always be allocated. 
			// Assume that these structures are named PtrNewFCB and PtrNewCCB 
			// respectively. 
			// Further, you should obtain the FCB MainResource exclusively 
			// at this time. 
 
			// Check if caller wanted a directory only and target object 
			//	not a directory, or caller wanted a file only and target 
			//	object not a file ... 
			if (FileOnlyRequested && (PtrNewFCB->FCBFlags & SFSD_FCB_DIRECTORY)) { 
				// Close the new FCB and leave. 
				//	SFsdCloseCCB(PtrNewCCB); 
				RC = STATUS_FILE_IS_A_DIRECTORY; 
				try_return(RC); 
			} 
 
			if ((PtrNewFCB->FCBFlags & SFSD_FCB_DIRECTORY) && ((RequestedDisposition == FILE_SUPERSEDE) || 
				  (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF))) { 
				RC = STATUS_FILE_IS_A_DIRECTORY; 
				try_return(RC); 
			} 
 
			if (DirectoryOnlyRequested && !(PtrNewFCB->FCBFlags & SFSD_FCB_DIRECTORY)) { 
				// Close the new FCB and leave. 
				//	SFsdCloseCCB(PtrNewCCB); 
				RC = STATUS_NOT_A_DIRECTORY; 
				try_return(RC); 
			} 
 
			// Check share access and fail if the share conflicts with an existing 
			// open. 
			if (PtrNewFCB->OpenHandleCount > 0) { 
				// The FCB is currently in use by some thread. 
				// We must check whether the requested access/share access 
				// conflicts with the existing open operations. 
 
				if (!NT_SUCCESS(RC = IoCheckShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, 
												&(PtrNewFCB->FCBShareAccess), TRUE))) { 
					// SFsdCloseCCB(PtrNewCCB); 
					try_return(RC); 
				} 
			} else { 
					IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess)); 
			} 
 
			ReturnedInformation = FILE_OPENED; 
 
			// If a supersede or overwrite was requested, do so now ... 
			if (RequestedDisposition == FILE_SUPERSEDE) { 
				// Attempt the operation here ... 
				//	RC = SFsdSupersede(...); 
				if (NT_SUCCESS(RC)) { 
					ReturnedInformation = FILE_SUPERSEDED; 
				} 
			} else if ((RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF)){ 
				// Attempt the operation here ... 
				//	RC = SFsdOverwrite(...); 
				if (NT_SUCCESS(RC)) { 
					ReturnedInformation = FILE_OVERWRITTEN; 
				} 
			} 
		} 
 
		try_exit:	NOTHING; 
 
	} 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 (RC != STATUS_PENDING) { 
			// If we acquired any FCB resources, release them now ... 
 
			// If any intermediate (directory) open operations were performed, 
			//	implement the corresponding close (do *not* however close 
			//	the target you have opened on behalf of the caller ...). 
 
			if (NT_SUCCESS(RC)) { 
				// 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 
				if (WriteThroughRequested) { 
               PtrNewFileObject->Flags |= FO_WRITE_THROUGH; 
				} 
 
			} else { 
				// Perform failure related post-processing now 
			} 
 
			// As long as this unwinding is not being performed as a result of 
			//	an exception condition, complete the IRP ... 
			if (!(PtrIrpContext->IrpContextFlags & SFSD_IRP_CONTEXT_EXCEPTION)) { 
				PtrIrp->IoStatus.Status = RC; 
				PtrIrp->IoStatus.Information = ReturnedInformation; 
 
				// Free up the Irp Context 
				SFsdReleaseIrpContext(PtrIrpContext); 
	 
				// complete the IRP 
				IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT); 
			} 
		} 
 
		if (AcquiredVCB) { 
			ASSERT(PtrVCB); 
         SFsdReleaseResource(&(PtrVCB->VCBResource)); 
			AcquiredVCB = FALSE; 
		} 
 
		if (AbsolutePathName.Buffer != NULL) { 
			ExFreePool(AbsolutePathName.Buffer); 
		} 
	} 
 
	return(RC); 
} 
 
 
/************************************************************************* 
* 
* Function: SFsdOpenVolume() 
* 
* Description: 
*	Open a logical volume for the caller. 
* 
* Expected Interrupt Level (for execution) : 
* 
*  IRQL_PASSIVE_LEVEL 
* 
* Return Value: STATUS_SUCCESS/Error 
* 
*************************************************************************/ 
NTSTATUS SFsdOpenVolume( 
PtrSFsdVCB				PtrVCB,					// volume to be opened 
PtrSFsdIrpContext		PtrIrpContext,			// IRP context 
PIRP						PtrIrp,					// original/user IRP 
unsigned short			ShareAccess,			// share access 
PIO_SECURITY_CONTEXT	PtrSecurityContext,	// caller's context (incl access) 
PFILE_OBJECT			PtrNewFileObject)		// I/O Mgr. created file object 
{ 
	NTSTATUS				RC = STATUS_SUCCESS; 
	PtrSFsdCCB			PtrCCB = NULL; 
 
	try { 
		// check for exclusive open requests (using share modes supplied) 
		//	and determine whether it is even possible to open the volume 
		//	with the specified share modes (e.g. if caller does not 
		//	wish to share read or share write ...) 
	 
		//	Use IoCheckShareAccess() and IoSetShareAccess() here ...	 
		//	They are defined in the DDK. 
 
		//	You might also wish to check the caller's security context 
		//	to see whether you wish to allow the volume open or not. 
		//	Use the SeAccessCheck() routine described in the DDK for	this purpose. 
	 
		// create a new CCB structure 
		if (!(PtrCCB = SFsdAllocateCCB())) { 
			RC = STATUS_INSUFFICIENT_RESOURCES; 
			try_return(RC); 
		} 
 
		// initialize the CCB 
		PtrCCB->PtrFCB = (PtrSFsdFCB)(PtrVCB); 
		InsertTailList(&(PtrVCB->VolumeOpenListHead), &(PtrCCB->NextCCB)); 
 
		// initialize the CCB to point to the file object 
		PtrCCB->PtrFileObject = PtrNewFileObject; 
 
		SFsdSetFlag(PtrCCB->CCBFlags, SFSD_CCB_VOLUME_OPEN); 
 
		// initialize the file object appropriately 
		PtrNewFileObject->FsContext = (void *)(PtrVCB); 
		PtrNewFileObject->FsContext2 = (void *)(PtrCCB); 
 
		// increment the number of outstanding open operations on this 
		//	logical volume (i.e. volume cannot be dismounted) 
 
		//	You might be concerned about 32 bit wrap-around though I would 
		//	argue that it is unlikely ... :-) 
		(PtrVCB->VCBOpenCount)++; 
	 
		// now set the IoStatus Information value correctly in the IRP 
		//	(caller will set the status field) 
		PtrIrp->IoStatus.Information = FILE_OPENED; 
	 
		try_exit:	NOTHING; 
	} finally { 
		NOTHING; 
	} 
 
	return(RC); 
} 
 
 
/************************************************************************* 
* 
* Function: SFsdInitializeFCB() 
* 
* 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 
* 
*************************************************************************/ 
void SFsdInitializeFCB( 
PtrSFsdFCB				PtrNewFCB,		// FCB structure to be initialized 
PtrSFsdVCB				PtrVCB,			// logical volume (VCB) pointer 
PtrSFsdObjectName		PtrObjectName,	// name of the object 
uint32					Flags,			// is this a file/directory, etc. 
PFILE_OBJECT			PtrFileObject)	// optional file object to be initialized 
{ 
	// Initialize the disk dependent portion as you see fit 
 
	// Initialize the two ERESOURCE objects 
	ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.MainResource)); 
	ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.PagingIoResource)); 
 
	PtrNewFCB->PtrVCB = PtrVCB; 
 
	// caller MUST ensure that VCB has been acquired exclusively 
	InsertTailList(&(PtrVCB->NextFCB), &(PtrNewFCB->NextFCB)); 
 
	// initialize the various list heads 
	InitializeListHead(&(PtrNewFCB->NextCCB)); 
 
	PtrNewFCB->ReferenceCount = 1; 
	PtrNewFCB->OpenHandleCount = 1; 
 
	PtrNewFCB->FCBFlags = Flags; 
 
	PtrNewFCB->FCBName = PtrObjectName; 
 
	if (PtrFileObject) { 
		PtrFileObject->FsContext = (void *)(&(PtrNewFCB->NTRequiredFCB)); 
	} 
 
	return; 
}