diff --git a/build/VStudio/winfsp_dll.vcxproj b/build/VStudio/winfsp_dll.vcxproj
index 2965d711..67346b30 100644
--- a/build/VStudio/winfsp_dll.vcxproj
+++ b/build/VStudio/winfsp_dll.vcxproj
@@ -74,7 +74,6 @@ copy /b $(OutDir)fuse-$(PlatformTarget).pc + %(FullPath) $(OutDir)fuse-$(Platfor
false
-
diff --git a/build/VStudio/winfsp_dll.vcxproj.filters b/build/VStudio/winfsp_dll.vcxproj.filters
index 6782b92e..8e5d8446 100644
--- a/build/VStudio/winfsp_dll.vcxproj.filters
+++ b/build/VStudio/winfsp_dll.vcxproj.filters
@@ -105,9 +105,6 @@
-
- Source
-
Source
diff --git a/inc/fuse/fuse_common.h b/inc/fuse/fuse_common.h
index c88a700c..14aae05c 100644
--- a/inc/fuse/fuse_common.h
+++ b/inc/fuse/fuse_common.h
@@ -85,6 +85,8 @@ FSP_FUSE_API void fsp_fuse_unmount(struct fsp_fuse_env *env,
FSP_FUSE_API int fsp_fuse_parse_cmdline(struct fsp_fuse_env *env,
struct fuse_args *args,
char **mountpoint, int *multithreaded, int *foreground);
+FSP_FUSE_API NTSTATUS fsp_fuse_ntstatus_from_errno(struct fsp_fuse_env *env,
+ int err);
static inline int fuse_version(void)
{
diff --git a/src/dll/fuse/errno.i b/src/dll/fuse/errno.i
new file mode 100644
index 00000000..1d471876
--- /dev/null
+++ b/src/dll/fuse/errno.i
@@ -0,0 +1,113 @@
+#if FSP_FUSE_ERRNO == 87 /* Windows */
+
+case 1: return STATUS_ACCESS_DENIED;
+case 2: return STATUS_OBJECT_NAME_NOT_FOUND;
+case 3: return STATUS_PROCEDURE_NOT_FOUND;
+case 4: return STATUS_CANCELLED;
+case 5: return STATUS_IO_DEVICE_ERROR;
+case 6: return STATUS_FILE_INVALID;
+case 7: return STATUS_INSUFFICIENT_RESOURCES;
+case 8: return STATUS_INVALID_IMAGE_FORMAT;
+case 9: return STATUS_INVALID_HANDLE;
+case 12: return STATUS_INSUFFICIENT_RESOURCES;
+case 13: return STATUS_ACCESS_DENIED;
+case 14: return STATUS_ACCESS_VIOLATION;
+case 16: return STATUS_DEVICE_BUSY;
+case 17: return STATUS_OBJECT_NAME_COLLISION;
+case 18: return STATUS_NOT_SAME_DEVICE;
+case 19: return STATUS_NO_SUCH_DEVICE;
+case 20: return STATUS_NOT_A_DIRECTORY;
+case 21: return STATUS_FILE_IS_A_DIRECTORY;
+case 22: return STATUS_INVALID_PARAMETER;
+case 23: return STATUS_TOO_MANY_OPENED_FILES;
+case 24: return STATUS_TOO_MANY_OPENED_FILES;
+case 27: return STATUS_DISK_FULL;
+case 28: return STATUS_DISK_FULL;
+case 29: return STATUS_INVALID_PARAMETER;
+case 30: return STATUS_MEDIA_WRITE_PROTECTED;
+case 31: return STATUS_TOO_MANY_LINKS;
+case 32: return STATUS_PIPE_BROKEN;
+case 33: return STATUS_INVALID_PARAMETER;
+case 34: return STATUS_INVALID_PARAMETER;
+case 36: return STATUS_POSSIBLE_DEADLOCK;
+case 38: return STATUS_NAME_TOO_LONG;
+case 39: return STATUS_LOCK_NOT_GRANTED;
+case 40: return STATUS_INVALID_DEVICE_REQUEST;
+case 41: return STATUS_DIRECTORY_NOT_EMPTY;
+case 42: return STATUS_INVALID_PARAMETER;
+case 100: return STATUS_ADDRESS_ALREADY_ASSOCIATED;
+case 103: return STATUS_CONNECTION_ACTIVE;
+case 105: return STATUS_CANCELLED;
+case 106: return STATUS_CONNECTION_ABORTED;
+case 107: return STATUS_CONNECTION_REFUSED;
+case 108: return STATUS_CONNECTION_RESET;
+case 110: return STATUS_HOST_UNREACHABLE;
+case 113: return STATUS_CONNECTION_ACTIVE;
+case 114: return STATUS_REPARSE_POINT_NOT_RESOLVED;
+case 116: return STATUS_HOST_DOWN;
+case 117: return STATUS_CONNECTION_RESET;
+case 118: return STATUS_NETWORK_UNREACHABLE;
+case 119: return STATUS_INSUFFICIENT_RESOURCES;
+case 120: return STATUS_END_OF_FILE;
+case 121: return STATUS_CONNECTION_INVALID;
+case 126: return STATUS_CONNECTION_INVALID;
+case 128: return STATUS_INVALID_HANDLE;
+case 138: return STATUS_TRANSACTION_TIMED_OUT;
+
+#elif FSP_FUSE_ERRNO == 67 /* Cygwin */
+
+case 1: return STATUS_ACCESS_DENIED;
+case 2: return STATUS_OBJECT_NAME_NOT_FOUND;
+case 3: return STATUS_PROCEDURE_NOT_FOUND;
+case 4: return STATUS_CANCELLED;
+case 5: return STATUS_IO_DEVICE_ERROR;
+case 6: return STATUS_FILE_INVALID;
+case 7: return STATUS_INSUFFICIENT_RESOURCES;
+case 8: return STATUS_INVALID_IMAGE_FORMAT;
+case 9: return STATUS_INVALID_HANDLE;
+case 12: return STATUS_INSUFFICIENT_RESOURCES;
+case 13: return STATUS_ACCESS_DENIED;
+case 14: return STATUS_ACCESS_VIOLATION;
+case 16: return STATUS_DEVICE_BUSY;
+case 17: return STATUS_OBJECT_NAME_COLLISION;
+case 18: return STATUS_NOT_SAME_DEVICE;
+case 19: return STATUS_NO_SUCH_DEVICE;
+case 20: return STATUS_NOT_A_DIRECTORY;
+case 21: return STATUS_FILE_IS_A_DIRECTORY;
+case 22: return STATUS_INVALID_PARAMETER;
+case 23: return STATUS_TOO_MANY_OPENED_FILES;
+case 24: return STATUS_TOO_MANY_OPENED_FILES;
+case 27: return STATUS_DISK_FULL;
+case 28: return STATUS_DISK_FULL;
+case 29: return STATUS_INVALID_PARAMETER;
+case 30: return STATUS_MEDIA_WRITE_PROTECTED;
+case 31: return STATUS_TOO_MANY_LINKS;
+case 32: return STATUS_PIPE_BROKEN;
+case 33: return STATUS_INVALID_PARAMETER;
+case 34: return STATUS_INVALID_PARAMETER;
+case 45: return STATUS_POSSIBLE_DEADLOCK;
+case 91: return STATUS_NAME_TOO_LONG;
+case 46: return STATUS_LOCK_NOT_GRANTED;
+case 88: return STATUS_INVALID_DEVICE_REQUEST;
+case 90: return STATUS_DIRECTORY_NOT_EMPTY;
+case 138: return STATUS_INVALID_PARAMETER;
+case 112: return STATUS_ADDRESS_ALREADY_ASSOCIATED;
+case 120: return STATUS_CONNECTION_ACTIVE;
+case 140: return STATUS_CANCELLED;
+case 113: return STATUS_CONNECTION_ABORTED;
+case 111: return STATUS_CONNECTION_REFUSED;
+case 104: return STATUS_CONNECTION_RESET;
+case 118: return STATUS_HOST_UNREACHABLE;
+case 127: return STATUS_CONNECTION_ACTIVE;
+case 92: return STATUS_REPARSE_POINT_NOT_RESOLVED;
+case 115: return STATUS_HOST_DOWN;
+case 126: return STATUS_CONNECTION_RESET;
+case 114: return STATUS_NETWORK_UNREACHABLE;
+case 105: return STATUS_INSUFFICIENT_RESOURCES;
+case 61: return STATUS_END_OF_FILE;
+case 67: return STATUS_CONNECTION_INVALID;
+case 128: return STATUS_CONNECTION_INVALID;
+case 108: return STATUS_INVALID_HANDLE;
+case 116: return STATUS_TRANSACTION_TIMED_OUT;
+
+#endif
diff --git a/src/dll/fuse/fuse.c b/src/dll/fuse/fuse.c
index 479fc194..ce51a20b 100644
--- a/src/dll/fuse/fuse.c
+++ b/src/dll/fuse/fuse.c
@@ -645,3 +645,26 @@ FSP_FUSE_API struct fuse_context *fsp_fuse_get_context(struct fsp_fuse_env *env)
return context;
}
+
+FSP_FUSE_API NTSTATUS fsp_fuse_ntstatus_from_errno(struct fsp_fuse_env *env,
+ int err)
+{
+ if ('C' == env->environment)
+ switch (err)
+ {
+ #undef FSP_FUSE_ERRNO
+ #define FSP_FUSE_ERRNO 67
+ #include "errno.i"
+ default:
+ return STATUS_ACCESS_DENIED;
+ }
+ else
+ switch (err)
+ {
+ #undef FSP_FUSE_ERRNO
+ #define FSP_FUSE_ERRNO 87
+ #include "errno.i"
+ default:
+ return STATUS_ACCESS_DENIED;
+ }
+}
diff --git a/tools/gensrc/errno.sh b/tools/gensrc/errno.sh
new file mode 100644
index 00000000..caf030a4
--- /dev/null
+++ b/tools/gensrc/errno.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+cd $(dirname "$0")
+
+(
+echo '#include '
+echo '/*beginbeginbeginbegin*/'
+awk '{ printf "case %s: return %s;\n", $1, $2 }' errno.txt
+) > errno.src
+
+echo "#if FSP_FUSE_ERRNO == 87 /* Windows */"
+echo
+vcvars="$(cygpath -aw "$VS140COMNTOOLS/../../VC/vcvarsall.bat")"
+cmd /c "call" "$vcvars" "x64" "&&" cl /nologo /EP /C errno.src 2>/dev/null | sed -e '1,/beginbeginbeginbegin/d'
+echo
+echo "#elif FSP_FUSE_ERRNO == 67 /* Cygwin */"
+echo
+cpp -C -P errno.src | sed -e '1,/beginbeginbeginbegin/d'
+echo
+echo "#endif"
+
+rm errno.src
diff --git a/tools/gensrc/errno.txt b/tools/gensrc/errno.txt
new file mode 100644
index 00000000..f694a02a
--- /dev/null
+++ b/tools/gensrc/errno.txt
@@ -0,0 +1,53 @@
+EPERM STATUS_ACCESS_DENIED
+ENOENT STATUS_OBJECT_NAME_NOT_FOUND
+ESRCH STATUS_PROCEDURE_NOT_FOUND
+EINTR STATUS_CANCELLED
+EIO STATUS_IO_DEVICE_ERROR
+ENXIO STATUS_FILE_INVALID
+E2BIG STATUS_INSUFFICIENT_RESOURCES
+ENOEXEC STATUS_INVALID_IMAGE_FORMAT
+EBADF STATUS_INVALID_HANDLE
+ENOMEM STATUS_INSUFFICIENT_RESOURCES
+EACCES STATUS_ACCESS_DENIED
+EFAULT STATUS_ACCESS_VIOLATION
+EBUSY STATUS_DEVICE_BUSY
+EEXIST STATUS_OBJECT_NAME_COLLISION
+EXDEV STATUS_NOT_SAME_DEVICE
+ENODEV STATUS_NO_SUCH_DEVICE
+ENOTDIR STATUS_NOT_A_DIRECTORY
+EISDIR STATUS_FILE_IS_A_DIRECTORY
+EINVAL STATUS_INVALID_PARAMETER
+ENFILE STATUS_TOO_MANY_OPENED_FILES
+EMFILE STATUS_TOO_MANY_OPENED_FILES
+EFBIG STATUS_DISK_FULL
+ENOSPC STATUS_DISK_FULL
+ESPIPE STATUS_INVALID_PARAMETER
+EROFS STATUS_MEDIA_WRITE_PROTECTED
+EMLINK STATUS_TOO_MANY_LINKS
+EPIPE STATUS_PIPE_BROKEN
+EDOM STATUS_INVALID_PARAMETER
+ERANGE STATUS_INVALID_PARAMETER
+EDEADLK STATUS_POSSIBLE_DEADLOCK
+ENAMETOOLONG STATUS_NAME_TOO_LONG
+ENOLCK STATUS_LOCK_NOT_GRANTED
+ENOSYS STATUS_INVALID_DEVICE_REQUEST
+ENOTEMPTY STATUS_DIRECTORY_NOT_EMPTY
+EILSEQ STATUS_INVALID_PARAMETER
+EADDRINUSE STATUS_ADDRESS_ALREADY_ASSOCIATED
+EALREADY STATUS_CONNECTION_ACTIVE
+ECANCELED STATUS_CANCELLED
+ECONNABORTED STATUS_CONNECTION_ABORTED
+ECONNREFUSED STATUS_CONNECTION_REFUSED
+ECONNRESET STATUS_CONNECTION_RESET
+EHOSTUNREACH STATUS_HOST_UNREACHABLE
+EISCONN STATUS_CONNECTION_ACTIVE
+ELOOP STATUS_REPARSE_POINT_NOT_RESOLVED
+ENETDOWN STATUS_HOST_DOWN
+ENETRESET STATUS_CONNECTION_RESET
+ENETUNREACH STATUS_NETWORK_UNREACHABLE
+ENOBUFS STATUS_INSUFFICIENT_RESOURCES
+ENODATA STATUS_END_OF_FILE
+ENOLINK STATUS_CONNECTION_INVALID
+ENOTCONN STATUS_CONNECTION_INVALID
+ENOTSOCK STATUS_INVALID_HANDLE
+ETIMEDOUT STATUS_TRANSACTION_TIMED_OUT
diff --git a/tools/ntstatus.py b/tools/gensrc/ntstatus.py
similarity index 100%
rename from tools/ntstatus.py
rename to tools/gensrc/ntstatus.py
diff --git a/tools/ntstatus.txt b/tools/gensrc/ntstatus.txt
similarity index 100%
rename from tools/ntstatus.txt
rename to tools/gensrc/ntstatus.txt