diff --git a/build/VStudio/testing/winfsp-tests.vcxproj b/build/VStudio/testing/winfsp-tests.vcxproj
index 3447dde0..c1cb3345 100644
--- a/build/VStudio/testing/winfsp-tests.vcxproj
+++ b/build/VStudio/testing/winfsp-tests.vcxproj
@@ -177,6 +177,7 @@
TurnOffAllWarnings
+
diff --git a/build/VStudio/testing/winfsp-tests.vcxproj.filters b/build/VStudio/testing/winfsp-tests.vcxproj.filters
index d017e9d8..47ab4f4b 100644
--- a/build/VStudio/testing/winfsp-tests.vcxproj.filters
+++ b/build/VStudio/testing/winfsp-tests.vcxproj.filters
@@ -22,6 +22,9 @@
Source
+
+ Source
+
diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj
index 0384b7ed..3ca1fa0a 100644
--- a/build/VStudio/winfsp_dll.vcxproj
+++ b/build/VStudio/winfsp_dll.vcxproj
@@ -24,11 +24,14 @@
+
+
+
diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters
index a868f31b..878ca2ac 100644
--- a/build/VStudio/winfsp_dll.vcxproj.filters
+++ b/build/VStudio/winfsp_dll.vcxproj.filters
@@ -40,6 +40,15 @@
Source
+
+ Source
+
+
+ Source
+
+
+ Source
+
diff --git a/inc/winfsp/fsctl.h b/inc/winfsp/fsctl.h
index 625657b8..60906990 100644
--- a/inc/winfsp/fsctl.h
+++ b/inc/winfsp/fsctl.h
@@ -110,7 +110,6 @@ typedef struct
UINT32 FileAttributes; /* FILE_ATTRIBUTE_{NORMAL,DIRECTORY,etc.} */
FSP_FSCTL_TRANSACT_BUF SecurityDescriptor; /* security descriptor for new files */
UINT64 AllocationSize; /* initial allocation size */
- UINT64 AccessToken; /* (HANDLE); request access token; sent if NoAccessCheck is 0 */
UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */
FSP_FSCTL_TRANSACT_BUF Ea; /* reserved; not currently implemented */
@@ -214,6 +213,8 @@ FSP_API NTSTATUS FspFsctlCreateVolume(PWSTR DevicePath,
FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
PVOID ResponseBuf, SIZE_T ResponseBufSize,
PVOID RequestBuf, SIZE_T *PRequestBufSize);
+FSP_API NTSTATUS FspFsctlOpenAccessToken(HANDLE VolumeHandle,
+ UINT64 Hint, PHANDLE PAccessToken);
#endif
#endif
diff --git a/inc/winfsp/winfsp.h b/inc/winfsp/winfsp.h
index 61b84482..ec63a0d0 100644
--- a/inc/winfsp/winfsp.h
+++ b/inc/winfsp/winfsp.h
@@ -21,6 +21,9 @@
#include
+/*
+ * File System
+ */
typedef struct _FSP_FILE_SYSTEM FSP_FILE_SYSTEM;
typedef VOID FSP_FILE_SYSTEM_DISPATCHER(FSP_FILE_SYSTEM *, FSP_FSCTL_TRANSACT_REQ *);
typedef NTSTATUS FSP_FILE_SYSTEM_OPERATION(FSP_FILE_SYSTEM *, FSP_FSCTL_TRANSACT_REQ *);
@@ -34,6 +37,10 @@ typedef struct _FSP_FILE_SYSTEM
FSP_FILE_SYSTEM_DISPATCHER *Dispatcher;
FSP_FILE_SYSTEM_DISPATCHER *EnterOperation, *LeaveOperation;
FSP_FILE_SYSTEM_OPERATION *Operations[FspFsctlTransactKindCount];
+ NTSTATUS (*AccessCheck)(FSP_FILE_SYSTEM *, FSP_FSCTL_TRANSACT_REQ *,
+ PDWORD);
+ NTSTATUS (*QuerySecurity)(FSP_FILE_SYSTEM *, FSP_FSCTL_TRANSACT_REQ *,
+ SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, SIZE_T *);
} FSP_FILE_SYSTEM;
FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath,
@@ -80,6 +87,17 @@ FSP_API NTSTATUS FspSendResponse(FSP_FILE_SYSTEM *FileSystem,
FSP_API NTSTATUS FspSendResponseWithStatus(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, NTSTATUS Result);
+/*
+ * Path Handling
+ */
+FSP_API VOID FspPathPrefix(PWSTR Path, PWSTR *PPrefix, PWSTR *PRemain);
+FSP_API VOID FspPathSuffix(PWSTR Path, PWSTR *PRemain, PWSTR *PSuffix);
+FSP_API VOID FspPathCombine(PWSTR Prefix, PWSTR Suffix);
+
+/*
+ * Utility
+ */
+FSP_API PGENERIC_MAPPING FspGetFileGenericMapping(VOID);
FSP_API NTSTATUS FspNtStatusFromWin32(DWORD Error);
FSP_API VOID FspDebugLog(const char *format, ...);
diff --git a/src/dll/access.c b/src/dll/access.c
new file mode 100644
index 00000000..2969c67a
--- /dev/null
+++ b/src/dll/access.c
@@ -0,0 +1,70 @@
+/**
+ * @file dll/access.c
+ *
+ * @copyright 2015 Bill Zissimopoulos
+ */
+
+#include
+
+static GENERIC_MAPPING FspFileGenericMapping =
+{
+ .GenericRead = FILE_GENERIC_READ,
+ .GenericWrite = FILE_GENERIC_WRITE,
+ .GenericExecute = FILE_GENERIC_EXECUTE,
+ .GenericAll = FILE_ALL_ACCESS,
+};
+
+FSP_API PGENERIC_MAPPING FspGetFileGenericMapping(VOID)
+{
+ return &FspFileGenericMapping;
+}
+
+FSP_API NTSTATUS FspOpenAccessToken(FSP_FILE_SYSTEM *FileSystem,
+ FSP_FSCTL_TRANSACT_REQ *Request, PHANDLE PAccessToken)
+{
+ return FspFsctlOpenAccessToken(FileSystem->VolumeHandle, Request->Hint, PAccessToken);
+}
+
+#if 0
+FSP_API NTSTATUS FspAccessCheck(FSP_FILE_SYSTEM *FileSystem,
+ FSP_FSCTL_TRANSACT_REQ *Request, PUINT32 PGrantedAccess)
+{
+ if (0 != FileSystem->AccessCheck)
+ return FileSystem->AccessCheck(FileSystem, Request, PGrantedAccess);
+
+ NTSTATUS Result;
+ PWSTR FileName = (PVOID)Request->Buffer;
+ PSECURITY_DESCRIPTOR SecurityDescriptor = 0;
+ HANDLE AccessToken = 0;
+ DWORD PrivilegeSetLength;
+ BOOLEAN AccessStatus;
+ s
+ *PGrantedAccess = 0;
+
+ SecurityDescriptor = MemAlloc(1024);
+ if (0 == SecurityDescriptor)
+ {
+ Result = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
+ }
+
+ Result = FspGetSecurityDescriptor();
+
+ Result = FspOpenAccessToken(FileSystem, Request, &AccessToken);
+ if (!NT_SUCCESS(Result))
+ goto exit;
+
+ if (AccessCheck(&SecurityDescriptor, AccessToken, Request->Req.Create.DesiredAccess,
+ &FspFileGenericMapping, 0, &PrivilegeSetLength, PGrantedAccess, &AccessStatus))
+ Result = AccessStatus ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
+ else
+ Result = FspNtStatusFromWin32(GetLastError());
+
+exit:
+ if (0 != AccessToken)
+ CloseHandle(AccessToken);
+ MemFree(SecurityDescriptor);
+
+ return Result;
+}
+#endif
diff --git a/src/dll/create.c b/src/dll/create.c
new file mode 100644
index 00000000..a831eb06
--- /dev/null
+++ b/src/dll/create.c
@@ -0,0 +1,112 @@
+/**
+ * @file dll/create.c
+ *
+ * @copyright 2015 Bill Zissimopoulos
+ */
+
+#include
+
+#if 0
+static NTSTATUS FspFileSystemOpCreate_FileCreate(FSP_FILE_SYSTEM *FileSystem,
+ FSP_FSCTL_TRANSACT_REQ *Request)
+{
+ NTSTATUS Result;
+ DWORD GrantedAccess;
+ PVOID File;
+ FSP_FSCTL_TRANSACT_RSP Response;
+
+ Result = FspAccessCheck(FileSystem, Request, TRUE, &GrantedAccess);
+ if (!NT_SUCCESS(Result))
+ return FspSendResponseWithStatus(FileSystem, Request, Result);
+
+ Result = FileSystem->FileCreate(FileSystem, Request, &File);
+ if (!NT_SUCCESS(Result))
+ return FspSendResponseWithStatus(FileSystem, Request, Result);
+
+ /* !!!: set share access */
+
+ memset(&Response, 0, sizeof Response);
+ Response.Size = sizeof Response;
+ Response.Kind = Request->Kind;
+ Response.Hint = Request->Hint;
+ Response.IoStatus.Status = STATUS_SUCCESS;
+ Response.IoStatus.Information = FILE_CREATED;
+ Response.Rsp.Create.Opened.UserContext = (UINT_PTR)File;
+ Response.Rsp.Create.Opened.GrantedAccess = GrantedAccess;
+ return FspSendResponse(FileSystem, &Response);
+}
+
+static NTSTATUS FspFileSystemOpCreate_FileOpen(FSP_FILE_SYSTEM *FileSystem,
+ FSP_FSCTL_TRANSACT_REQ *Request)
+{
+ NTSTATUS Result;
+ DWORD GrantedAccess;
+ PVOID File;
+ FSP_FSCTL_TRANSACT_RSP Response;
+
+ Result = FspAccessCheck(FileSystem, Request, FALSE, &GrantedAccess);
+ if (!NT_SUCCESS(Result))
+ return FspSendResponseWithStatus(FileSystem, Request, Result);
+
+ Result = FileSystem->FileOpen(FileSystem, Request, &File);
+ if (!NT_SUCCESS(Result))
+ return FspSendResponseWithStatus(FileSystem, Request, Result);
+
+ Result = FspShareCheck(FileSystem, Request, GrantedAccess, File);
+ if (!NT_SUCCESS(Result))
+ {
+ FileSystem->FileCleanupClose(FileSystem, Request, File);
+ return FspSendResponseWithStatus(FileSystem, Request, Result);
+ }
+
+ memset(&Response, 0, sizeof Response);
+ Response.Size = sizeof Response;
+ Response.Kind = Request->Kind;
+ Response.Hint = Request->Hint;
+ Response.IoStatus.Status = STATUS_SUCCESS;
+ Response.IoStatus.Information = FILE_CREATED;
+ Response.Rsp.Create.Opened.UserContext = (UINT_PTR)File;
+ Response.Rsp.Create.Opened.GrantedAccess = GrantedAccess;
+ return FspSendResponse(FileSystem, &Response);
+}
+
+static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
+ FSP_FSCTL_TRANSACT_REQ *Request)
+{
+ return STATUS_INVALID_PARAMETER;
+}
+
+static NTSTATUS FspFileSystemOpCreate_FileOverwrite(FSP_FILE_SYSTEM *FileSystem,
+ FSP_FSCTL_TRANSACT_REQ *Request, BOOLEAN Supersede)
+{
+ return STATUS_INVALID_PARAMETER;
+}
+
+static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSystem,
+ FSP_FSCTL_TRANSACT_REQ *Request)
+{
+ return STATUS_INVALID_PARAMETER;
+}
+
+FSP_API NTSTATUS FspFileSystemOpCreate(FSP_FILE_SYSTEM *FileSystem,
+ FSP_FSCTL_TRANSACT_REQ *Request)
+{
+ switch ((Request->Req.Create.CreateOptions >> 24) & 0xff)
+ {
+ case FILE_CREATE:
+ return FspFileSystemOpCreate_FileCreate(FileSystem, Request);
+ case FILE_OPEN:
+ return FspFileSystemOpCreate_FileOpen(FileSystem, Request);
+ case FILE_OPEN_IF:
+ return FspFileSystemOpCreate_FileOpenIf(FileSystem, Request);
+ case FILE_OVERWRITE:
+ return FspFileSystemOpCreate_FileOverwrite(FileSystem, Request, FALSE);
+ case FILE_SUPERSEDE:
+ return FspFileSystemOpCreate_FileOverwrite(FileSystem, Request, TRUE);
+ case FILE_OVERWRITE_IF:
+ return FspFileSystemOpCreate_FileOverwriteIf(FileSystem, Request);
+ default:
+ return FspSendResponseWithStatus(FileSystem, Request, STATUS_INVALID_PARAMETER);
+ }
+}
+#endif
diff --git a/src/dll/fsctl.c b/src/dll/fsctl.c
index 8bc56ece..81be2cbf 100644
--- a/src/dll/fsctl.c
+++ b/src/dll/fsctl.c
@@ -109,3 +109,11 @@ FSP_API NTSTATUS FspFsctlTransact(HANDLE VolumeHandle,
exit:
return Result;
}
+
+FSP_API NTSTATUS FspFsctlOpenAccessToken(HANDLE VolumeHandle,
+ UINT64 Hint, PHANDLE PAccessToken)
+{
+ *PAccessToken = 0;
+
+ return STATUS_NOT_IMPLEMENTED;
+}
diff --git a/src/dll/path.c b/src/dll/path.c
new file mode 100644
index 00000000..1e100506
--- /dev/null
+++ b/src/dll/path.c
@@ -0,0 +1,56 @@
+/**
+ * @file dll/path.c
+ *
+ * @copyright 2015 Bill Zissimopoulos
+ */
+
+#include
+
+FSP_API VOID FspPathPrefix(PWSTR Path, PWSTR *PPrefix, PWSTR *PRemain)
+{
+ PWSTR Pointer;
+
+ for (Pointer = Path; *Pointer; Pointer++)
+ if (L'\\' == *Pointer)
+ {
+ *Pointer++ = L'\0';
+ for (; L'\\' == *Pointer; Pointer++)
+ ;
+ break;
+ }
+
+ *PPrefix = Path;
+ *PRemain = Pointer;
+}
+
+FSP_API VOID FspPathSuffix(PWSTR Path, PWSTR *PRemain, PWSTR *PSuffix)
+{
+ PWSTR Pointer, RemainEnd, Suffix = 0;
+
+ for (Pointer = Path; *Pointer;)
+ if (L'\\' == *Pointer)
+ {
+ RemainEnd = Pointer++;
+ for (; L'\\' == *Pointer; Pointer++)
+ ;
+ Suffix = Pointer;
+ }
+ else
+ Pointer++;
+
+ *PRemain = Path;
+ if (Path < Suffix)
+ {
+ *RemainEnd = L'\0';
+ *PSuffix = Suffix;
+ }
+ else
+ *PSuffix = Pointer;
+}
+
+FSP_API VOID FspPathCombine(PWSTR Prefix, PWSTR Suffix)
+{
+ for (; Prefix < Suffix; Prefix++)
+ if (L'\0' == *Prefix)
+ *Prefix = L'\\';
+}
diff --git a/src/sys/create.c b/src/sys/create.c
index ca142995..2cc7b336 100644
--- a/src/sys/create.c
+++ b/src/sys/create.c
@@ -256,7 +256,6 @@ static NTSTATUS FspFsvolCreate(
FSP_FSCTL_DEFAULT_ALIGN_UP(Request->FileName.Size);
Request->Req.Create.SecurityDescriptor.Size = (UINT16)SecurityDescriptorSize;
Request->Req.Create.AllocationSize = AllocationSize.QuadPart;
- Request->Req.Create.AccessToken = 0;
Request->Req.Create.DesiredAccess = DesiredAccess;
Request->Req.Create.ShareAccess = ShareAccess;
Request->Req.Create.Ea.Offset = 0;
diff --git a/tst/winfsp-tests/path-test.c b/tst/winfsp-tests/path-test.c
new file mode 100644
index 00000000..a65df42d
--- /dev/null
+++ b/tst/winfsp-tests/path-test.c
@@ -0,0 +1,108 @@
+#include
+#include
+
+void path_prefix_test(void)
+{
+ PWSTR ipaths[] =
+ {
+ L"",
+ L"\\",
+ L"\\\\",
+ L"\\a",
+ L"\\\\a",
+ L"\\\\a\\",
+ L"\\\\a\\\\",
+ L"a\\",
+ L"a\\\\",
+ L"a\\b",
+ L"a\\\\b",
+ L"foo\\\\\\bar\\\\baz",
+ L"foo\\\\\\bar\\\\baz\\",
+ L"foo\\\\\\bar\\\\baz\\\\",
+ };
+ PWSTR opaths[] =
+ {
+ L"", L"",
+ L"", L"",
+ L"", L"",
+ L"", L"a",
+ L"", L"a",
+ L"", L"a\\",
+ L"", L"a\\\\",
+ L"a", L"",
+ L"a", L"",
+ L"a", L"b",
+ L"a", L"b",
+ L"foo", L"bar\\\\baz",
+ L"foo", L"bar\\\\baz\\",
+ L"foo", L"bar\\\\baz\\\\",
+ };
+
+ for (size_t i = 0; sizeof ipaths / sizeof ipaths[0] > i; i++)
+ {
+ PWSTR Prefix, Remain;
+ WCHAR buf[32];
+ wcscpy_s(buf, 32, ipaths[i]);
+ FspPathPrefix(buf, &Prefix, &Remain);
+ ASSERT(0 == wcscmp(opaths[2 * i + 0], Prefix));
+ ASSERT(0 == wcscmp(opaths[2 * i + 1], Remain));
+ FspPathCombine(Prefix, Remain);
+ ASSERT(0 == wcscmp(ipaths[i], buf));
+ }
+}
+
+void path_suffix_test(void)
+{
+ PWSTR ipaths[] =
+ {
+ L"",
+ L"\\",
+ L"\\\\",
+ L"\\a",
+ L"\\\\a",
+ L"\\\\a\\",
+ L"\\\\a\\\\",
+ L"a\\",
+ L"a\\\\",
+ L"a\\b",
+ L"a\\\\b",
+ L"foo\\\\\\bar\\\\baz",
+ L"foo\\\\\\bar\\\\baz\\",
+ L"foo\\\\\\bar\\\\baz\\\\",
+ };
+ PWSTR opaths[] =
+ {
+ L"", L"",
+ L"", L"",
+ L"", L"",
+ L"", L"a",
+ L"", L"a",
+ L"\\\\a", L"",
+ L"\\\\a", L"",
+ L"a", L"",
+ L"a", L"",
+ L"a", L"b",
+ L"a", L"b",
+ L"foo\\\\\\bar", L"baz",
+ L"foo\\\\\\bar\\\\baz", L"",
+ L"foo\\\\\\bar\\\\baz", L"",
+ };
+
+ for (size_t i = 0; sizeof ipaths / sizeof ipaths[0] > i; i++)
+ {
+ PWSTR Remain, Suffix;
+ WCHAR buf[32];
+ wcscpy_s(buf, 32, ipaths[i]);
+ FspPathSuffix(buf, &Remain, &Suffix);
+ ASSERT(0 == wcscmp(opaths[2 * i + 0], Remain));
+ ASSERT(0 == wcscmp(opaths[2 * i + 1], Suffix));
+ FspPathCombine(Remain, Suffix);
+ ASSERT(0 == wcscmp(ipaths[i], buf));
+ }
+}
+
+void path_tests(void)
+{
+ TEST(path_prefix_test);
+ TEST(path_suffix_test);
+}
diff --git a/tst/winfsp-tests/winfsp-tests.c b/tst/winfsp-tests/winfsp-tests.c
index 848a4bca..cde6c340 100644
--- a/tst/winfsp-tests/winfsp-tests.c
+++ b/tst/winfsp-tests/winfsp-tests.c
@@ -5,6 +5,7 @@ int WinFspNetTests = 1;
int main(int argc, char *argv[])
{
+ TESTSUITE(path_tests);
TESTSUITE(mount_tests);
TESTSUITE(timeout_tests);