create.c

来自「winNT技术操作系统,国外开放的原代码和LIUX一样」· C语言 代码 · 共 805 行 · 第 1/2 页

C
805
字号

	/*  try first to find an existing FCB in memory  */
	DPRINT ("Checking for existing FCB in memory\n");

	Status = vfatGetFCBForFile (DeviceExt, ParentFcb, &Fcb, PathNameU);
	if (!NT_SUCCESS (Status))
	{
		DPRINT ("Could not make a new FCB, status: %x\n", Status);
		return  Status;
	}
	if (Fcb->Flags & FCB_DELETE_PENDING)
	{
		vfatReleaseFCB (DeviceExt, Fcb);
		return STATUS_DELETE_PENDING;
	}
	DPRINT ("Attaching FCB to fileObject\n");
	Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
	if (!NT_SUCCESS(Status))
	{
		vfatReleaseFCB (DeviceExt, Fcb);
	}
	return  Status;
}

static NTSTATUS
VfatCreateFile ( PDEVICE_OBJECT DeviceObject, PIRP Irp )
/*
 * FUNCTION: Create or open a file
 */
{
	PIO_STACK_LOCATION Stack;
	PFILE_OBJECT FileObject;
	NTSTATUS Status = STATUS_SUCCESS;
	PDEVICE_EXTENSION DeviceExt;
	ULONG RequestedDisposition, RequestedOptions;
	PVFATCCB pCcb;
	PVFATFCB pFcb = NULL;
	PVFATFCB ParentFcb = NULL;
	PWCHAR c, last;
	BOOLEAN PagingFileCreate = FALSE;
	BOOLEAN Dots;
	UNICODE_STRING FileNameU;
        UNICODE_STRING PathNameU;

	/* Unpack the various parameters. */
	Stack = IoGetCurrentIrpStackLocation (Irp);
	RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
	RequestedOptions =
		Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
	PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
	FileObject = Stack->FileObject;
	DeviceExt = DeviceObject->DeviceExtension;

	/* Check their validity. */
	if (RequestedOptions & FILE_DIRECTORY_FILE &&
		RequestedDisposition == FILE_SUPERSEDE)
	{
		return(STATUS_INVALID_PARAMETER);
	}

        if (RequestedOptions & FILE_DIRECTORY_FILE &&
            RequestedOptions & FILE_NON_DIRECTORY_FILE)
        {
		return(STATUS_INVALID_PARAMETER);
        }

	/* This a open operation for the volume itself */
	if (FileObject->FileName.Length == 0 &&
		FileObject->RelatedFileObject == NULL)
	{
		if (RequestedDisposition == FILE_CREATE ||
			RequestedDisposition == FILE_OVERWRITE_IF ||
			RequestedDisposition == FILE_SUPERSEDE)
		{
			return(STATUS_ACCESS_DENIED);
		}
		if (RequestedOptions & FILE_DIRECTORY_FILE)
		{
			return(STATUS_NOT_A_DIRECTORY);
		}
		pFcb = DeviceExt->VolumeFcb;
		pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
		if (pCcb == NULL)
		{
			return (STATUS_INSUFFICIENT_RESOURCES);
		}
		RtlZeroMemory(pCcb, sizeof(VFATCCB));
		FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers;
		FileObject->FsContext = pFcb;
		FileObject->FsContext2 = pCcb;
		pFcb->RefCount++;

		Irp->IoStatus.Information = FILE_OPENED;
		return(STATUS_SUCCESS);
	}

	/*
	 * Check for illegal characters and illegale dot sequences in the file name
	 */
        PathNameU = FileObject->FileName;
	c = PathNameU.Buffer + PathNameU.Length / sizeof(WCHAR);
	last = c - 1;
	Dots = TRUE;
	while (c-- > PathNameU.Buffer)
	{
		if (*c == L'\\' || c == PathNameU.Buffer)
		{
			if (Dots && last > c)
			{
				return(STATUS_OBJECT_NAME_INVALID);
			}
			last = c - 1;
			Dots = TRUE;
		}
		else if (*c != L'.')
		{
			Dots = FALSE;
		}

		if (*c != '\\' && vfatIsLongIllegal(*c))
		{
			return(STATUS_OBJECT_NAME_INVALID);
		}
	}
        if (FileObject->RelatedFileObject && PathNameU.Buffer[0] == L'\\')
        {
            return(STATUS_OBJECT_NAME_INVALID);
        }
        if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\')
        {
            PathNameU.Length -= sizeof(WCHAR);
        }

	/* Try opening the file. */
	Status = VfatOpenFile (DeviceExt, &PathNameU, FileObject, &ParentFcb);

	/*
	 * If the directory containing the file to open doesn't exist then
	 * fail immediately
	 */
	if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
            Status == STATUS_INVALID_PARAMETER ||
	    Status == STATUS_DELETE_PENDING)
	{
		if (ParentFcb)
		{
			vfatReleaseFCB (DeviceExt, ParentFcb);
		}
		return(Status);
	}
        if (!NT_SUCCESS(Status) && ParentFcb == NULL)
        {
                DPRINT1("VfatOpenFile faild for '%wZ', status %x\n", &PathNameU, Status);
                return Status;
        }

	/*
	 * If the file open failed then create the required file
	 */
	if (!NT_SUCCESS (Status))
	{
		if (RequestedDisposition == FILE_CREATE ||
		    RequestedDisposition == FILE_OPEN_IF ||
		    RequestedDisposition == FILE_OVERWRITE_IF ||
		    RequestedDisposition == FILE_SUPERSEDE)
		{
			ULONG Attributes;
			Attributes = Stack->Parameters.Create.FileAttributes;

			vfatSplitPathName(&PathNameU, NULL, &FileNameU);
			Status = VfatAddEntry (DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
				(UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
			vfatReleaseFCB (DeviceExt, ParentFcb);
			if (NT_SUCCESS (Status))
			{
				Status = vfatAttachFCBToFileObject (DeviceExt, pFcb, FileObject);
				if ( !NT_SUCCESS(Status) )
				{
					vfatReleaseFCB (DeviceExt, pFcb);
					return Status;
				}

				Irp->IoStatus.Information = FILE_CREATED;
				VfatSetAllocationSizeInformation(FileObject,
					pFcb,
					DeviceExt,
					&Irp->Overlay.AllocationSize);
				VfatSetExtendedAttributes(FileObject,
					Irp->AssociatedIrp.SystemBuffer,
					Stack->Parameters.Create.EaLength);

				if (PagingFileCreate)
				{
					pFcb->Flags |= FCB_IS_PAGE_FILE;
				}
			}
			else
			{
				return(Status);
			}
		}
		else
		{
			if (ParentFcb)
			{
				vfatReleaseFCB (DeviceExt, ParentFcb);
			}
			return(Status);
		}
	}
	else
	{
		if (ParentFcb)
		{
			vfatReleaseFCB (DeviceExt, ParentFcb);
		}
		/* Otherwise fail if the caller wanted to create a new file  */
		if (RequestedDisposition == FILE_CREATE)
		{
			Irp->IoStatus.Information = FILE_EXISTS;
			VfatCloseFile (DeviceExt, FileObject);
			return(STATUS_OBJECT_NAME_COLLISION);
		}

		pFcb = FileObject->FsContext;

		if (pFcb->OpenHandleCount != 0)
		{
			Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
				Stack->Parameters.Create.ShareAccess,
				FileObject,
				&pFcb->FCBShareAccess,
				FALSE);
			if (!NT_SUCCESS(Status))
			{
				VfatCloseFile (DeviceExt, FileObject);
				return(Status);
			}
		}

		/*
		 * Check the file has the requested attributes
		 */
		if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
			*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
		{
			VfatCloseFile (DeviceExt, FileObject);
			return(STATUS_FILE_IS_A_DIRECTORY);
		}
		if (RequestedOptions & FILE_DIRECTORY_FILE &&
			!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
		{
			VfatCloseFile (DeviceExt, FileObject);
			return(STATUS_NOT_A_DIRECTORY);
		}
#ifndef USE_ROS_CC_AND_FS
		if (!(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
		{
			if (Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA || 
				RequestedDisposition == FILE_OVERWRITE ||
				RequestedDisposition == FILE_OVERWRITE_IF)
			{
				if (!MmFlushImageSection(&pFcb->SectionObjectPointers, MmFlushForWrite))
				{
					DPRINT1("%wZ\n", &pFcb->PathNameU);
					DPRINT1("%d %d %d\n", Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA, 
							RequestedDisposition == FILE_OVERWRITE, RequestedDisposition == FILE_OVERWRITE_IF);
					VfatCloseFile (DeviceExt, FileObject);
					return STATUS_SHARING_VIOLATION;
				}
			}
		}
#endif
		if (PagingFileCreate)
		{
			/* FIXME:
			 *   Do more checking for page files. It is possible,
			 *   that the file was opened and closed previously
			 *   as a normal cached file. In this case, the cache
			 *   manager has referenced the fileobject and the fcb
			 *   is held in memory. Try to remove the fileobject
			 *   from cache manager and use the fcb.
			 */
			if (pFcb->RefCount > 1)
			{
				if(!(pFcb->Flags & FCB_IS_PAGE_FILE))
				{
					VfatCloseFile(DeviceExt, FileObject);
					return(STATUS_INVALID_PARAMETER);
				}
			}
			else
			{
				pFcb->Flags |= FCB_IS_PAGE_FILE;
			}
		}
		else
		{
			if (pFcb->Flags & FCB_IS_PAGE_FILE)
			{
				VfatCloseFile(DeviceExt, FileObject);
				return(STATUS_INVALID_PARAMETER);
			}
		}


		if (RequestedDisposition == FILE_OVERWRITE ||
		    RequestedDisposition == FILE_OVERWRITE_IF ||
		    RequestedDisposition == FILE_SUPERSEDE)
		{
                        ExAcquireResourceExclusiveLite(&(pFcb->MainResource), TRUE);
			Status = VfatSetAllocationSizeInformation (FileObject,
				                                   pFcb,
				                                   DeviceExt,
				                                   &Irp->Overlay.AllocationSize);
                        ExReleaseResourceLite(&(pFcb->MainResource));
			if (!NT_SUCCESS (Status))
			{
				VfatCloseFile (DeviceExt, FileObject);
				return(Status);
			}
		}

		if (RequestedDisposition == FILE_SUPERSEDE)
		{
			Irp->IoStatus.Information = FILE_SUPERSEDED;
		}
		else if (RequestedDisposition == FILE_OVERWRITE || 
		         RequestedDisposition == FILE_OVERWRITE_IF)
		{
			Irp->IoStatus.Information = FILE_OVERWRITTEN;
		}
		else
		{
			Irp->IoStatus.Information = FILE_OPENED;
		}
	}

	if (pFcb->OpenHandleCount == 0)
	{
		IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
			Stack->Parameters.Create.ShareAccess,
			FileObject,
			&pFcb->FCBShareAccess);
	}
	else
	{
		IoUpdateShareAccess(
			FileObject,
			&pFcb->FCBShareAccess
			);

	}

	pFcb->OpenHandleCount++;

	/* FIXME : test write access if requested */

	return(Status);
}


NTSTATUS
VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
/*
 * FUNCTION: Create or open a file
 */
{
	NTSTATUS Status;

	ASSERT(IrpContext);

	if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
	{
		/* DeviceObject represents FileSystem instead of logical volume */
		DPRINT ("FsdCreate called with file system\n");
		IrpContext->Irp->IoStatus.Information = FILE_OPENED;
		IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
		IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT);
		VfatFreeIrpContext(IrpContext);
		return(STATUS_SUCCESS);
	}

	if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
	{
		return(VfatQueueRequest (IrpContext));
	}

	IrpContext->Irp->IoStatus.Information = 0;
	ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
	Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
	ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);

	IrpContext->Irp->IoStatus.Status = Status;
	IoCompleteRequest (IrpContext->Irp,
		(CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
	VfatFreeIrpContext(IrpContext);
	return(Status);
}

/* EOF */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?