From f06a879b40590614fced0d4833a911e69c983b93 Mon Sep 17 00:00:00 2001 From: human Date: Sat, 22 May 2021 03:57:58 +0300 Subject: [PATCH] cygwin support --- fs/Makefile | 4 ++++ fs/tabfs.c | 34 ++++++++++++++++++++++++++++++++-- install.sh | 16 ++++++++++++++++ test/test.c | 11 +++++++++-- test/test.js | 2 +- 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/fs/Makefile b/fs/Makefile index 622c2df..4f11d01 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -22,6 +22,10 @@ ifeq ($(shell uname -s),FreeBSD) CFLAGS += -L$(FREEBSD_ROOT)/lib -I$(FREEBSD_ROOT)/include $(CFLAGS_EXTRA) LIBS = -lfuse -pthread endif +ifeq ($(shell uname -o),Cygwin) + CFLAGS += $(shell pkg-config --cflags fuse) + LIBS = $(shell pkg-config --libs fuse) +endif all: $(TARGETS) diff --git a/fs/tabfs.c b/fs/tabfs.c index c74becf..c57ed07 100644 --- a/fs/tabfs.c +++ b/fs/tabfs.c @@ -18,6 +18,16 @@ #include "vendor/frozen.h" #include "vendor/frozen.c" +static unsigned int get_thread_id(void) { +#if defined(__CYGWIN__) + // note: using this because pthread_self() didn't seem to be unique under cygwin + extern int GetCurrentThreadId(void); + return GetCurrentThreadId(); +#else + return (uintptr_t)pthread_self(); +#endif +} + #define eprintln(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__) // protects: @@ -115,8 +125,11 @@ static int do_exchange(unsigned int id, char c; read_or_die(mydata.msgpipe[0], &c, 1); + // note: protecting this with the same lock fixes random fd-related crashes under cygwin + pthread_mutex_lock(&write_lock); close(mydata.msgpipe[0]); close(mydata.msgpipe[1]); + pthread_mutex_unlock(&write_lock); int err; if (1 == json_scanf(mydata.data, mydata.size, "{error: %d}", &err)) { @@ -185,7 +198,7 @@ static int count_fmt_args(const char *s) { #define exchange_json(datap, sizep, keys_fmt, ...) \ do { \ - unsigned int id = (uintptr_t)pthread_self(); \ + unsigned int id = get_thread_id(); \ int req_rv = do_exchange(id, datap, sizep, \ "{id: %u, " keys_fmt "}", \ id, ##__VA_ARGS__); \ @@ -206,7 +219,7 @@ static int count_fmt_args(const char *s) { free(data); data = NULL; \ } else { \ eprintln("%s: could only parse %d of %d keys!", \ - __func__, num_expected, num_scanned); \ + __func__, num_scanned, num_expected); \ free(data); data = NULL; \ return -EIO; \ } \ @@ -225,6 +238,11 @@ static int tabfs_getattr(const char *path, struct stat *stbuf) { "st_mode: %d, st_nlink: %d, st_size: %d", &stbuf->st_mode, &stbuf->st_nlink, &stbuf->st_size); +#if defined(CYGFUSE) + // user must be set for writing files to work under cygwin + stbuf->st_uid = geteuid(); +#endif + return 0; } @@ -452,6 +470,7 @@ int main(int argc, char **argv) { freopen("log.txt", "a", stderr); setvbuf(stderr, NULL, _IONBF, 0); +#if !defined(CYGFUSE) char killcmd[128]; sprintf(killcmd, "pgrep tabfs | grep -v %d | xargs kill -9 2>/dev/null", getpid()); system(killcmd); @@ -465,6 +484,17 @@ int main(int argc, char **argv) { #endif system("mkdir -p \"$TABFS_MOUNT_DIR\""); +#endif + +#if defined(CYGFUSE) + // winfsp-fuse needs to create the mount directory itself + // try to remove it using rmdir (will work if it's empty) + if (0 == access(getenv("TABFS_MOUNT_DIR"), R_OK) && + 0 != rmdir(getenv("TABFS_MOUNT_DIR"))) { + eprintln("error: the mount directory \"%s\" already exists!", getenv("TABFS_MOUNT_DIR")); + return 1; + } +#endif pthread_t thread; int err = pthread_create(&thread, NULL, reader_main, NULL); diff --git a/install.sh b/install.sh index b6bfa36..af6ab28 100755 --- a/install.sh +++ b/install.sh @@ -49,12 +49,18 @@ case "$OS $BROWSER" in MANIFEST_LOCATION="$HOME/Library/Application Support/Chromium/NativeMessagingHosts";; "Darwin vivaldi") MANIFEST_LOCATION="$HOME/Library/Application Support/Vivaldi/NativeMessagingHosts";; + "CYGWIN_NT"*) + MANIFEST_LOCATION="$PWD/fs";; esac mkdir -p "$MANIFEST_LOCATION" APP_NAME="com.rsnous.tabfs" EXE_PATH=$(pwd)/fs/tabfs +if [[ "$OS" == CYGWIN_NT* ]]; then + # convert to native path and json-escape backslashes + EXE_PATH="$(cygpath -w "$EXE_PATH" | sed 's:\\:\\\\:g')" +fi case "$BROWSER" in chrome | chromium | chromebeta | brave | vivaldi | edgedev) @@ -83,4 +89,14 @@ EOF );; esac +if [[ "$OS" == CYGWIN_NT* ]]; then + case "$BROWSER" in + chrome | chromium | chromebeta | brave | vivaldi | edgedev) + REGKEY="HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\$APP_NAME";; + firefox) + REGKEY="HKCU\\Software\\Mozilla\\NativeMessagingHosts\\$APP_NAME";; + esac + reg add "$REGKEY" /ve /t REG_SZ /d "$(cygpath -w "$MANIFEST_LOCATION")\\$APP_NAME.json" /f +fi + echo "$MANIFEST" > "$MANIFEST_LOCATION/$APP_NAME.json" diff --git a/test/test.c b/test/test.c index b463f89..28e4e9f 100644 --- a/test/test.c +++ b/test/test.c @@ -9,6 +9,13 @@ #include #include +#if defined(__CYGWIN__) + // needs to be the native path for file:// urls to work + #define PWD "$(cygpath -w \"$(pwd)\")" +#else + #define PWD "$(pwd)" +#endif + int file_contents_equal(char* path, char* contents) { // hehe: https://twitter.com/ianh_/status/1340450349065244675 setenv("path", path, 1); @@ -55,7 +62,7 @@ int main() { } { - assert(system("echo file://$(pwd)/test-resources/test-page.html > ../fs/mnt/tabs/create") == 0); + assert(system("echo file://" PWD "/test-resources/test-page.html > ../fs/mnt/tabs/create") == 0); assert(file_contents_equal("../fs/mnt/tabs/last-focused/title.txt", "Title of Test Page")); assert(file_contents_equal("../fs/mnt/tabs/last-focused/text.txt", "Body Text of Test Page")); @@ -87,7 +94,7 @@ int main() { } { - assert(system("echo file://$(pwd)/test-resources/test-textarea.html > ../fs/mnt/tabs/create") == 0); + assert(system("echo file://" PWD "/test-resources/test-textarea.html > ../fs/mnt/tabs/create") == 0); { assert(system("echo \"document.getElementById('ta').value\" > ../fs/mnt/tabs/last-focused/evals/ta.js") == 0); diff --git a/test/test.js b/test/test.js index 228df67..a1d2dad 100644 --- a/test/test.js +++ b/test/test.js @@ -15,7 +15,7 @@ const {Routes, tryMatchRoute} = require('../extension/background'); { entries: ['.', '..', 'windows', 'extensions', 'tabs', 'runtime'] }); assert.deepEqual(await Routes['/tabs'].readdir(), { entries: ['.', '..', 'create', - 'by-id', 'by-title', 'last-focused'] }); + 'by-title', 'last-focused', 'by-id'] }); assert.deepEqual(tryMatchRoute('/'), [Routes['/'], {}]);