From 89215f16c5ba3dbdd3a06844988f7439d4379dd4 Mon Sep 17 00:00:00 2001 From: benrubson Date: Mon, 26 Mar 2018 22:09:57 +0200 Subject: [PATCH 1/9] Cygwin, configure cmake --- CMakeLists.txt | 8 +++++++- encfs/FileUtils.cpp | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f7c88b0..bd90490 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,5 @@ +set(CMAKE_LEGACY_CYGWIN_WIN32 0) + # 3.0.2 preferred, but we can often get by with 2.8. cmake_minimum_required(VERSION 2.8) if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} LESS 3.0.2) @@ -73,7 +75,7 @@ if (APPLE) endif() endif() -if (WIN32 OR APPLE) +if (CYGWIN OR WIN32 OR APPLE) set(DEFAULT_CASE_INSENSITIVE TRUE) else() set(DEFAULT_CASE_INSENSITIVE FALSE) @@ -83,6 +85,10 @@ endif() find_package (FUSE REQUIRED) include_directories (SYSTEM ${FUSE_INCLUDE_DIR}) add_definitions (-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=29) +if (CYGWIN) + # Cygwin build is intended to use WinFsp + add_definitions(-DCYGFUSE) +endif() # Check for OpenSSL. find_package (OpenSSL REQUIRED) diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 8f067f2..87a0ed4 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -1089,7 +1089,7 @@ RootPtr createV6Config(EncFS_Context *ctx, alg = findCipherAlgorithm("AES", keySize); // If case-insensitive system, opt for Block32 filename encoding -#if defined(__APPLE__) || defined(WIN32) +#if defined(DEFAULT_CASE_INSENSITIVE) nameIOIface = BlockNameIO::CurrentInterface(true); #else nameIOIface = BlockNameIO::CurrentInterface(); From be0c616d38a471ce8aa7aeb6ee6531b5dc538ccc Mon Sep 17 00:00:00 2001 From: benrubson Date: Mon, 26 Mar 2018 22:19:06 +0200 Subject: [PATCH 2/9] Cygwin, correct delete When deleting a file, Windows first opens it, deletes it, and closes it. But Windows does not allow deleting opened files, so no need to check before deletion. --- encfs/DirNode.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/encfs/DirNode.cpp b/encfs/DirNode.cpp index 58e7ab7..649681e 100644 --- a/encfs/DirNode.cpp +++ b/encfs/DirNode.cpp @@ -739,7 +739,9 @@ int DirNode::unlink(const char *plaintextName) { Lock _lock(mutex); - int res = 0; +// Windows does not allow deleting opened files, so no need to check +// There is this "issue" however : https://github.com/billziss-gh/winfsp/issues/157 +#ifndef __CYGWIN__ if ((ctx != nullptr) && ctx->lookupNode(plaintextName)) { // If FUSE is running with "hard_remove" option where it doesn't // hide open files for us, then we can't allow an unlink of an open @@ -747,14 +749,16 @@ int DirNode::unlink(const char *plaintextName) { RLOG(WARNING) << "Refusing to unlink open file: " << cyName << ", hard_remove option " "is probably in effect"; - res = -EBUSY; - } else { - string fullName = rootDir + cyName; - res = ::unlink(fullName.c_str()); - if (res == -1) { - res = -errno; - VLOG(1) << "unlink error: " << strerror(-res); - } + return -EBUSY; + } +#endif + + int res = 0; + string fullName = rootDir + cyName; + res = ::unlink(fullName.c_str()); + if (res == -1) { + res = -errno; + VLOG(1) << "unlink error: " << strerror(-res); } return res; From 27394cd1982ae499af340808f4c2efdf519dd033 Mon Sep 17 00:00:00 2001 From: benrubson Date: Mon, 26 Mar 2018 22:23:09 +0200 Subject: [PATCH 3/9] Cygwin, correct rename When renaming a file, Windows first opens it, renames it and then closes it. We then must decrease the target openFiles count. --- encfs/Context.cpp | 9 +++++++++ encfs/DirNode.cpp | 25 ++++++++++++++++++++----- encfs/encfs.cpp | 7 +++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/encfs/Context.cpp b/encfs/Context.cpp index 7ebebaa..61ab7ed 100644 --- a/encfs/Context.cpp +++ b/encfs/Context.cpp @@ -171,6 +171,15 @@ void EncFS_Context::eraseNode(const char *path, Lock lock(contextMutex); auto it = openFiles.find(std::string(path)); +#ifdef __CYGWIN__ + // When renaming a file, Windows first opens it, renames it and then closes it + // Filenode may have then been renamed too + if (it == openFiles.end()) { + RLOG(WARNING) << "Filenode to erase not found, file has certainly be renamed: " + << path; + return; + } +#endif rAssert(it != openFiles.end()); auto &list = it->second; diff --git a/encfs/DirNode.cpp b/encfs/DirNode.cpp index 649681e..ff71f18 100644 --- a/encfs/DirNode.cpp +++ b/encfs/DirNode.cpp @@ -599,11 +599,26 @@ int DirNode::rename(const char *fromPlaintext, const char *toPlaintext) { if (renameOp) { renameOp->undo(); } - } else if (preserve_mtime) { - struct utimbuf ut; - ut.actime = st.st_atime; - ut.modtime = st.st_mtime; - ::utime(toCName.c_str(), &ut); + } + else { +#ifdef __CYGWIN__ + // When renaming a file, Windows first opens it, renames it and then closes it + // We then must decrease the target openFiles count + // We could recreate the source so that close will not (silently) fails, + // however it will update modification time of the file, so break what we do below. + // Let's simply warn in eraseNode(). + if (!isDirectory(toCName.c_str())) { + std::shared_ptr toNode = findOrCreate(toPlaintext); + ctx->eraseNode(toPlaintext, toNode); + //ctx->putNode(fromPlaintext, toNode); + } +#endif + if (preserve_mtime) { + struct utimbuf ut; + ut.actime = st.st_atime; + ut.modtime = st.st_mtime; + ::utime(toCName.c_str(), &ut); + } } } catch (encfs::Error &err) { // exception from renameNode, just show the error and continue.. diff --git a/encfs/encfs.cpp b/encfs/encfs.cpp index 38eec09..a7c9c34 100644 --- a/encfs/encfs.cpp +++ b/encfs/encfs.cpp @@ -167,6 +167,13 @@ static int withFileNode(const char *opName, const char *path, if (fi != nullptr && fi->fh != 0) { auto node = ctx->lookupFuseFh(fi->fh); if (node == nullptr) { +#ifdef __CYGWIN__ + if (strcmp(opName, "flush") == 0) { + RLOG(WARNING) << "Filenode to flush not found, file has certainly be renamed: " + << path; + return 0; + } +#endif auto msg = "fh=" + std::to_string(fi->fh) + " not found in fuseFhMap"; throw Error(msg.c_str()); } From e8e1dc35955c7fcaf7e5b77bf2d803e35772b8eb Mon Sep 17 00:00:00 2001 From: benrubson Date: Mon, 26 Mar 2018 22:26:44 +0200 Subject: [PATCH 4/9] Cygwin, use correct mount point --- encfs/FileUtils.h | 1 + encfs/main.cpp | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/encfs/FileUtils.h b/encfs/FileUtils.h index 1406915..7e6aa1f 100644 --- a/encfs/FileUtils.h +++ b/encfs/FileUtils.h @@ -72,6 +72,7 @@ enum ConfigMode { Config_Prompt, Config_Standard, Config_Paranoia }; struct EncFS_Opts { std::string rootDir; std::string mountPoint; // where to make filesystem visible + std::string cygDrive; // Cygwin mount drive bool createIfNotFound; // create filesystem if not found bool idleTracking; // turn on idle monitoring of filesystem bool mountOnDemand; // mounting on-demand diff --git a/encfs/main.cpp b/encfs/main.cpp index c79cada..c624341 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -542,18 +542,38 @@ static bool processArgs(int argc, char *argv[], if (!isDirectory(out->opts->rootDir.c_str()) && !userAllowMkdir(out->opts->annotate ? 1 : 0, out->opts->rootDir.c_str(), 0700)) { - cerr << _("Unable to locate root directory, aborting."); + cerr << _("Unable to locate root directory, aborting.") << endl; return false; } +#ifdef __CYGWIN__ + if (isDirectory(out->opts->mountPoint.c_str())) { + cerr << _("Mount point must not exist before mouting, aborting.") << endl; + return false; + } + if ((strncmp(out->opts->mountPoint.c_str(), "/cygdrive/", 10) != 0) || + (out->opts->mountPoint.length() != 12)) { + cerr << _("A drive is prefered for mouting, ") + << _("so a path like /cygdrive/x should rather be used. ") + << _("Mounting anyway.") << endl; + } +#else if (!isDirectory(out->opts->mountPoint.c_str()) && !userAllowMkdir(out->opts->annotate ? 2 : 0, out->opts->mountPoint.c_str(), 0700)) { - cerr << _("Unable to locate mount point, aborting."); + cerr << _("Unable to locate mount point, aborting.") << endl; return false; } +#endif // fill in mount path for fuse out->fuseArgv[1] = out->opts->mountPoint.c_str(); +#ifdef __CYGWIN__ + if ((strncmp(out->opts->mountPoint.c_str(), "/cygdrive/", 10) == 0) && + (out->opts->mountPoint.length() == 12)) { + out->opts->cygDrive = out->opts->mountPoint.substr(10,1).append(":"); + out->fuseArgv[1] = out->opts->cygDrive.c_str(); + } +#endif return true; } From 1a8a5e02465af7dd7a863edfc185060614bcda30 Mon Sep 17 00:00:00 2001 From: benrubson Date: Mon, 26 Mar 2018 23:19:52 +0200 Subject: [PATCH 5/9] Cygwin, unmount --- CMakeLists.txt | 7 +++++++ encfs/FileUtils.cpp | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd90490..ff68afb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,6 +81,13 @@ else() set(DEFAULT_CASE_INSENSITIVE FALSE) endif() +if (CYGWIN) + find_program(PKILL NAMES "pkill") + if(NOT PKILL) + message(FATAL_ERROR "pkill not found, please install procps-ng package.") + endif() +endif() + # Check for FUSE. find_package (FUSE REQUIRED) include_directories (SYSTEM ${FUSE_INCLUDE_DIR}) diff --git a/encfs/FileUtils.cpp b/encfs/FileUtils.cpp index 87a0ed4..ca3db78 100644 --- a/encfs/FileUtils.cpp +++ b/encfs/FileUtils.cpp @@ -1739,6 +1739,14 @@ void unmountFS(const char *mountPoint) { // fuse_unmount does not work on Mac OS, see #428 unmount(mountPoint, MNT_FORCE); #endif +#ifdef __CYGWIN__ + if(fork() == 0) + { + execl("/usr/bin/pkill", "/usr/bin/pkill", "-f", string("(^|/)encfs .*/.* ").append(mountPoint).append("?( |$)").c_str(), (char *)0); + } + int status; + wait(&status); +#endif } int remountFS(EncFS_Context *ctx) { From 9495f6f7aa7cc187b1413709a43f4a5e3612f832 Mon Sep 17 00:00:00 2001 From: benrubson Date: Mon, 26 Mar 2018 23:20:32 +0200 Subject: [PATCH 6/9] Cygwin, disable xattr support --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff68afb..6eee2df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,8 +105,10 @@ find_program (POD2MAN pod2man) # Check for include files and stdlib properties. include (CheckIncludeFileCXX) -check_include_file_cxx (attr/xattr.h HAVE_ATTR_XATTR_H) -check_include_file_cxx (sys/xattr.h HAVE_SYS_XATTR_H) +if (NOT CYGWIN) + check_include_file_cxx (attr/xattr.h HAVE_ATTR_XATTR_H) + check_include_file_cxx (sys/xattr.h HAVE_SYS_XATTR_H) +endif() include(CheckStructHasMember) check_struct_has_member("struct dirent" d_type dirent.h HAVE_DIRENT_D_TYPE LANGUAGE CXX) From daedfbc86197f4f12e350d785cbbd899b6e47448 Mon Sep 17 00:00:00 2001 From: benrubson Date: Mon, 26 Mar 2018 23:22:00 +0200 Subject: [PATCH 7/9] Cygwin, update normal tests --- encfs/Error.h | 7 +++++++ integration/normal.t.pl | 30 ++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/encfs/Error.h b/encfs/Error.h index 50cabdf..d03e428 100644 --- a/encfs/Error.h +++ b/encfs/Error.h @@ -6,6 +6,13 @@ #include "easylogging++.h" #include +// Cygwin / WinFsp does not support EBADMSG yet +// https://github.com/billziss-gh/winfsp/issues/156 +#ifdef __CYGWIN__ +#undef EBADMSG +#define EBADMSG EINVAL +#endif + namespace encfs { class Error : public std::runtime_error { diff --git a/integration/normal.t.pl b/integration/normal.t.pl index 6c5fadf..3f2ce3e 100755 --- a/integration/normal.t.pl +++ b/integration/normal.t.pl @@ -107,6 +107,10 @@ sub newWorkingDir our $raw = "$workingDir/raw"; our $crypt = "$workingDir/crypt"; + if ($^O eq "cygwin") + { + $crypt = "/cygdrive/x"; + } } # Test Corruption @@ -124,7 +128,8 @@ sub corruption ok( open(IN, "< $crypt/corrupt"), "open corrupted file"); my $content; $result = read(IN, $content, 20); - ok($!{EBADMSG} && (! defined $result), "corrupted file with MAC returns read error: $!"); + # Cygwin returns EINVAL for now + ok(($!{EBADMSG} || $!{EINVAL}) && (! defined $result), "corrupted file with MAC returns read error: $!"); } # Test internal modification @@ -363,7 +368,10 @@ sub mount # When these fail, the rest of the tests makes no sense mkdir($raw) || BAIL_OUT("Could not create $raw: $!"); - mkdir($crypt) || BAIL_OUT("Could not create $crypt: $!"); + if ($^O ne "cygwin") + { + mkdir($crypt) || BAIL_OUT("Could not create $crypt: $!"); + } delete $ENV{"ENCFS6_CONFIG"}; remount($args); @@ -425,8 +433,15 @@ sub create_unmount_remount { my $crypt = "$workingDir/create_remount.crypt"; my $mnt = "$workingDir/create_remount.mnt"; + if ($^O eq "cygwin") + { + $mnt = "/cygdrive/y"; + } mkdir($crypt) || BAIL_OUT($!); - mkdir($mnt) || BAIL_OUT($!); + if ($^O ne "cygwin") + { + mkdir($mnt) || BAIL_OUT($!); + } system("./build/encfs --standard --extpass=\"echo test\" $crypt $mnt 2>&1"); ok( $? == 0, "encfs command returns 0") || return; @@ -472,8 +487,15 @@ sub checkWriteError else { my $crypt = "$workingDir/checkWriteError.crypt"; my $mnt = "$workingDir/checkWriteError.mnt"; + if ($^O eq "cygwin") + { + $mnt = "/cygdrive/z"; + } mkdir($crypt) || BAIL_OUT($!); - mkdir($mnt) || BAIL_OUT($!); + if ($^O ne "cygwin") + { + mkdir($mnt) || BAIL_OUT($!); + } system("$sudo_cmd mount -t tmpfs -o size=1m tmpfs $crypt"); ok( $? == 0, "mount command returns 0") || return; system("./build/encfs --standard --extpass=\"echo test\" $crypt $mnt 2>&1"); From 4399676ec724168a3482a60cd3f53b601d284432 Mon Sep 17 00:00:00 2001 From: benrubson Date: Mon, 26 Mar 2018 23:24:07 +0200 Subject: [PATCH 8/9] Cygwin, update reverse tests --- encfs/main.cpp | 5 +++++ integration/reverse.t.pl | 27 ++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/encfs/main.cpp b/encfs/main.cpp index c624341..93925ee 100644 --- a/encfs/main.cpp +++ b/encfs/main.cpp @@ -380,6 +380,11 @@ static bool processArgs(int argc, char *argv[], /* Disable kernel dentry cache * Fallout unknown, disabling for safety */ PUSHARG("-oentry_timeout=0"); +#ifdef __CYGWIN__ + // Should be enforced due to attr_timeout=0, but does not seem to work correctly + // https://github.com/billziss-gh/winfsp/issues/155 + PUSHARG("-oFileInfoTimeout=0"); +#endif break; case 'm': out->opts->mountOnDemand = true; diff --git a/integration/reverse.t.pl b/integration/reverse.t.pl index 9acf7cd..ce73d14 100755 --- a/integration/reverse.t.pl +++ b/integration/reverse.t.pl @@ -49,9 +49,23 @@ sub newWorkingDir our $plain = "$workingDir/plain"; mkdir($plain); our $ciphertext = "$workingDir/ciphertext"; - mkdir($ciphertext); + if ($^O ne "cygwin") + { + mkdir($ciphertext); + } + else + { + $ciphertext = "/cygdrive/x"; + } our $decrypted = "$workingDir/decrypted"; - mkdir($decrypted); + if ($^O ne "cygwin") + { + mkdir($decrypted); + } + else + { + $decrypted = "/cygdrive/y"; + } } # Helper function @@ -231,7 +245,14 @@ encfsctl_cat_test(); symlink_test("/"); # absolute symlink_test("foo"); # relative symlink_test("/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/15/17/18"); # long -symlink_test("!§\$%&/()\\<>#+="); # special characters +if ($^O ne "cygwin") +{ + symlink_test("!§\$%&/()\\<>#+="); # special characters +} +else +{ + symlink_test("!§\$%&/()//<>#+="); # special characters but without \ which is not Windows compliant +} # Absolute symlinks may failed on Windows : https://github.com/billziss-gh/winfsp/issues/153 symlink_test("$plain/foo"); writesDenied(); From d58d9fa5b46ff7ba6d07dd5fc2ff53417d027795 Mon Sep 17 00:00:00 2001 From: benrubson Date: Mon, 26 Mar 2018 23:25:19 +0200 Subject: [PATCH 9/9] Cygwin, documention links --- README.md | 5 ++++- encfs/encfs.pod | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aa88c33..efa161e 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,10 @@ How about a nice email instead? ## Windows -A Windows port exists and is maintained by JetWhiz in the GitHub +EncFS works on Cygwin, see [the wiki](https://github.com/vgough/encfs/wiki) +for additional info. + +A Windows port also exists and is maintained by JetWhiz in the GitHub [jetwhiz/encfs4win](https://github.com/jetwhiz/encfs4win) repository. ## FAQ diff --git a/encfs/encfs.pod b/encfs/encfs.pod index e5b0817..7e3a48f 100644 --- a/encfs/encfs.pod +++ b/encfs/encfs.pod @@ -649,6 +649,8 @@ Support, bug reports... : B. Mailing list : none. +Cygwin : B. + Windows port : B. =head1 SEE ALSO