diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj
index 58d10448..b20b231b 100644
--- a/build/VStudio/winfsp_sys.vcxproj
+++ b/build/VStudio/winfsp_sys.vcxproj
@@ -145,6 +145,7 @@
+
diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters
index cf1748c9..07e25c08 100644
--- a/build/VStudio/winfsp_sys.vcxproj.filters
+++ b/build/VStudio/winfsp_sys.vcxproj.filters
@@ -83,6 +83,9 @@
Source
+
+ Source
+
diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h
index 9b2b27d4..3ccd1a7b 100644
--- a/inc/winfsp/fsctl.h
+++ b/inc/winfsp/fsctl.h
@@ -62,7 +62,11 @@ typedef struct
UINT8 Kind;
union
{
- UINT8 Placeholder; // !!!: REMOVE
+ struct
+ {
+ UINT8 Placeholder;
+ WCHAR FileName[];
+ } Create;
} Req;
} FSP_FSCTL_TRANSACT_REQ;
typedef struct
diff --git a/src/sys/create.c b/src/sys/create.c
index c181cc33..cd8efe23 100644
--- a/src/sys/create.c
+++ b/src/sys/create.c
@@ -48,6 +48,7 @@ static NTSTATUS FspFsvolCreate(
{
PAGED_CODE();
+ NTSTATUS Result;
FSP_FSVOL_DEVICE_EXTENSION *FsvolDeviceExtension = FspFsvolDeviceExtension(DeviceObject);
FSP_FSVRT_DEVICE_EXTENSION *FsvrtDeviceExtension =
FspFsvrtDeviceExtension(FsvolDeviceExtension->FsvrtDeviceObject);
@@ -67,12 +68,14 @@ static NTSTATUS FspFsvolCreate(
PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer;
ULONG EaLength = IrpSp->Parameters.Create.EaLength;
BOOLEAN HasTraversePrivilege = BooleanFlagOn(AccessState->Flags, TOKEN_HAS_TRAVERSE_PRIVILEGE);
+ BOOLEAN HasTrailingBackslash = FALSE;
+ FSP_FILE_CONTEXT *FsContext = 0;
/* cannot open the volume object */
if (0 == RelatedFileObject && 0 == FileName.Length)
- return STATUS_ACCESS_DENIED; // need error code like UNIX EPERM (STATUS_NOT_SUPPORTED?)
+ return STATUS_ACCESS_DENIED; /* need error code like UNIX EPERM (STATUS_NOT_SUPPORTED?) */
- /* cannot open paging file */
+ /* cannot open a paging file */
if (FlagOn(Flags, SL_OPEN_PAGING_FILE))
return STATUS_ACCESS_DENIED;
@@ -97,6 +100,66 @@ static NTSTATUS FspFsvolCreate(
return STATUS_OBJECT_NAME_INVALID;
}
+ /* check for trailing backslash */
+ if (sizeof(WCHAR) * 2/* root can have trailing backslash */ <= FileName.Length &&
+ L'\\' == FileName.Buffer[FileName.Length / 2 - 1])
+ {
+ FileName.Length -= sizeof(WCHAR);
+ HasTrailingBackslash = TRUE;
+
+ if (sizeof(WCHAR) * 2 <= FileName.Length && L'\\' == FileName.Buffer[FileName.Length / 2 - 1])
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ /* is this a relative or absolute open? */
+ if (0 != RelatedFileObject)
+ {
+ /* must be a relative path */
+ if (sizeof(WCHAR) <= FileName.Length && L'\\' == FileName.Buffer[0])
+ return STATUS_OBJECT_NAME_INVALID;
+
+ FSP_FILE_CONTEXT *RelatedFsContext = RelatedFileObject->FsContext;
+ ASSERT(0 != RelatedFsContext);
+
+ /*
+ * There is no need to lock our accesses of RelatedFileObject->FsContext->FileName,
+ * because RelatedFileObject->FsContext->Filename is read-only (after creation) and
+ * because RelatedFileObject->FsContext is guaranteed to exist while RelatedFileObject
+ * exists.
+ */
+ Result = FspFileContextCreate(
+ RelatedFsContext->FileName.Length + sizeof(WCHAR)/* backslash */ + FileName.Length,
+ &FsContext);
+ if (!NT_SUCCESS(Result))
+ return Result;
+
+ Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &RelatedFsContext->FileName);
+ ASSERT(NT_SUCCESS(Result));
+ if (HasTrailingBackslash)
+ {
+ Result = RtlAppendUnicodeToString(&FsContext->FileName, L"\\");
+ ASSERT(NT_SUCCESS(Result));
+ }
+ Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &FileName);
+ ASSERT(NT_SUCCESS(Result));
+ }
+ else
+ {
+ /* absolute open */
+ Result = FspFileContextCreate(
+ FileName.Length,
+ &FsContext);
+ if (!NT_SUCCESS(Result))
+ return Result;
+
+ Result = RtlAppendUnicodeStringToString(&FsContext->FileName, &FileName);
+ ASSERT(NT_SUCCESS(Result));
+ }
+
+ /*
+ * From this point forward we MUST remember to delete the FsContext on error.
+ */
+
return STATUS_PENDING;
}
diff --git a/src/sys/driver.h b/src/sys/driver.h
index 0969a99f..1acf6109 100644
--- a/src/sys/driver.h
+++ b/src/sys/driver.h
@@ -192,7 +192,7 @@ _Dispatch_type_(IRP_MJ_SET_VOLUME_INFORMATION) FSP_DRIVER_DISPATCH FspSetVolumeI
_Dispatch_type_(IRP_MJ_SHUTDOWN) FSP_DRIVER_DISPATCH FspShutdown;
_Dispatch_type_(IRP_MJ_WRITE) FSP_DRIVER_DISPATCH FspWrite;
-/* I/O process functions */
+/* I/O processing functions */
_IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_same_
typedef VOID FSP_IOCMPL_DISPATCH(
@@ -245,6 +245,10 @@ PIRP FspIoqNextPendingIrp(FSP_IOQ *Ioq, ULONG millis);
BOOLEAN FspIoqStartProcessingIrp(FSP_IOQ *Ioq, PIRP Irp);
PIRP FspIoqEndProcessingIrp(FSP_IOQ *Ioq, UINT_PTR IrpHint);
+/* I/O processing */
+VOID FspIopCompleteRequest(PIRP Irp, NTSTATUS Result);
+VOID FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
+
/* device management */
enum
{
@@ -321,9 +325,21 @@ VOID FspDeviceDeleteList(
PDEVICE_OBJECT *DeviceObjects, ULONG DeviceObjectCount);
VOID FspDeviceDeleteAll(VOID);
-/* I/O processing */
-VOID FspIopCompleteRequest(PIRP Irp, NTSTATUS Result);
-VOID FspIopDispatchComplete(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response);
+/* file objects */
+typedef struct
+{
+ FAST_MUTEX HeaderFastMutex;
+} FSP_FILE_CONTEXT_NONPAGED;
+typedef struct
+{
+ FSRTL_ADVANCED_FCB_HEADER Header;
+ FSP_FILE_CONTEXT_NONPAGED *NonPaged;
+ BOOLEAN HasTrailingBackslash;
+ UNICODE_STRING FileName;
+ WCHAR FileNameBuf[];
+} FSP_FILE_CONTEXT;
+NTSTATUS FspFileContextCreate(SIZE_T ExtraSize, FSP_FILE_CONTEXT **PContext);
+VOID FspFileContextDelete(FSP_FILE_CONTEXT *Context);
/* misc */
NTSTATUS FspCreateGuid(GUID *Guid);
diff --git a/src/sys/fileobj.c b/src/sys/fileobj.c
new file mode 100644
index 00000000..5d83ec36
--- /dev/null
+++ b/src/sys/fileobj.c
@@ -0,0 +1,56 @@
+/**
+ * @file sys/fileobj.c
+ *
+ * @copyright 2015 Bill Zissimopoulos
+ */
+
+#include
+
+NTSTATUS FspFileContextCreate(SIZE_T ExtraSize, FSP_FILE_CONTEXT **PContext);
+VOID FspFileContextDelete(FSP_FILE_CONTEXT *Context);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, FspFileContextCreate)
+#pragma alloc_text(PAGE, FspFileContextDelete)
+#endif
+
+NTSTATUS FspFileContextCreate(SIZE_T ExtraSize, FSP_FILE_CONTEXT **PFsContext)
+{
+ PAGED_CODE();
+
+ *PFsContext = 0;
+
+ FSP_FILE_CONTEXT_NONPAGED *NonPaged = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof *NonPaged, FSP_TAG);
+ if (0 == NonPaged)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ FSP_FILE_CONTEXT *FsContext = ExAllocatePoolWithTag(PagedPool,
+ sizeof *FsContext + ExtraSize, FSP_TAG);
+ if (0 == FsContext)
+ {
+ ExFreePoolWithTag(NonPaged, FSP_TAG);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(NonPaged, sizeof *NonPaged);
+ ExInitializeFastMutex(&NonPaged->HeaderFastMutex);
+
+ RtlZeroMemory(FsContext, sizeof *FsContext + ExtraSize);
+ FsRtlSetupAdvancedHeader(&FsContext->Header, &NonPaged->HeaderFastMutex);
+ FsContext->NonPaged = NonPaged;
+ RtlInitEmptyUnicodeString(&FsContext->FileName, FsContext->FileNameBuf, (USHORT)ExtraSize);
+
+ *PFsContext = FsContext;
+
+ return STATUS_SUCCESS;
+}
+
+VOID FspFileContextDelete(FSP_FILE_CONTEXT *FsContext)
+{
+ PAGED_CODE();
+
+ FsRtlTeardownPerStreamContexts(&FsContext->Header);
+ ExFreePoolWithTag(FsContext->NonPaged, FSP_TAG);
+ ExFreePoolWithTag(FsContext, FSP_TAG);
+}