Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cygwin support #499

Merged
merged 9 commits into from
Mar 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -73,16 +75,27 @@ 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)
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})
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)
Expand All @@ -92,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)
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions encfs/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
47 changes: 33 additions & 14 deletions encfs/DirNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<FileNode> 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..
Expand Down Expand Up @@ -739,22 +754,26 @@ 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
// file..
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;
Expand Down
7 changes: 7 additions & 0 deletions encfs/Error.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
#include "easylogging++.h"
#include <stdexcept>

// 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 {
Expand Down
10 changes: 9 additions & 1 deletion encfs/FileUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions encfs/FileUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions encfs/encfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down
2 changes: 2 additions & 0 deletions encfs/encfs.pod
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,8 @@ Support, bug reports... : B<https://github.com/vgough/encfs>.

Mailing list : none.

Cygwin : B<https://github.com/vgough/encfs/wiki>.

Windows port : B<https://github.com/jetwhiz/encfs4win>.

=head1 SEE ALSO
Expand Down
29 changes: 27 additions & 2 deletions encfs/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -542,18 +547,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;
}
Expand Down
30 changes: 26 additions & 4 deletions integration/normal.t.pl
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ sub newWorkingDir

our $raw = "$workingDir/raw";
our $crypt = "$workingDir/crypt";
if ($^O eq "cygwin")
{
$crypt = "/cygdrive/x";
}
}

# Test Corruption
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down
27 changes: 24 additions & 3 deletions integration/reverse.t.pl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -231,7 +245,14 @@ sub writesDenied {
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();

Expand Down