- Subtree search to open or edit files (using plugin)
- Mimes
- Open with desktop opener or specify a custom app
- - Create, list, extract archives
+ - Create, list, extract, mount (FUSE based) archives
- Option to open all text files in EDITOR
- Information
- Detailed file information
| xdg-open (Linux), open(1) (macOS), cygstart (Cygwin) | base | desktop opener |
| file, coreutils (cp, mv, rm), findutils (xargs) | base | file type, copy, move and remove |
| tar, (un)zip [atool/bsdtar for more formats] | base | create, list, extract tar, gzip, bzip2, zip |
+| archivemount | optional | mount archives over FUSE |
| sshfs, fusermount(3) | optional | mount, unmount over SSHFS |
| trash-cli | optional | trash files (default action: delete) |
| vlock (Linux), bashlock (macOS), lock(1) (BSD) | optional | terminal locker (fallback: [cmatrix](https://github.com/abishekvashok/cmatrix)) |
a Select all K Edit selection
P Copy selection X Delete selection
V Move selection ^X Delete entry
- f Create archive C Execute entry
+ f Create archive T Mount archive
^F Extract archive F List archive
e Edit in EDITOR p Open in PAGER
ORDER TOGGLES
A Apparent du S du
- s Size E Extn t Time
+ s Size E Extn t Time
MISC
- ! ^] Shell = Launcher
+ ! ^] Shell = Launch C Execute entry
R ^V Pick plugin :K xK Execute plugin K
c SSHFS mount u Unmount
^P Prompt/run cmd L Lock
#define STR_TMPFILE 3
#define NONE_SELECTED 4
#define UTIL_MISSING 5
+#define MOUNT_FAILED 6
static const char * const messages[] = {
"no traversal",
"/.nnnXXXXXX",
"0 selected",
"missing dep",
+ "mount failed",
};
/* Supported configuration environment variables */
return TRUE;
}
+static bool archive_mount(char *name, char *path, char *newpath, int *presel)
+{
+ char *dir, *cmd = "archivemount";
+ size_t len;
+
+ if (!getutil(cmd)) {
+ printwait(messages[UTIL_MISSING], presel);
+ return FALSE;
+ }
+
+ dir = strdup(name);
+ if (!dir)
+ return FALSE;
+
+ len = strlen(dir);
+
+ while (len > 1)
+ if (dir[--len] == '.') {
+ dir[len] = '\0';
+ break;
+ }
+
+ DPRINTF_S(dir);
+
+ /* Create the mount point */
+ mkpath(cfgdir, dir, newpath);
+ free(dir);
+
+ if (!create_dir(newpath)) {
+ printwait(strerror(errno), presel);
+ return FALSE;
+ }
+
+ /* Mount archive */
+ DPRINTF_S(name);
+ DPRINTF_S(newpath);
+ if (spawn(cmd, name, newpath, path, F_NORMAL)) {
+ printwait(messages[MOUNT_FAILED], presel);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static bool sshfs_mount(char *newpath, int *presel)
{
uchar flag = F_NORMAL;
/* Connect to remote */
if (spawn(env, tmp, newpath, NULL, flag)) {
- printwait("mount failed", presel);
+ printwait(messages[MOUNT_FAILED], presel);
return FALSE;
}
return TRUE;
}
-static bool sshfs_unmount(char *newpath, int *presel)
+/*
+ * Unmounts if the directory represented by name is a mount point.
+ * Otherwise, asks for hostname
+ */
+static bool unmount(char *name, char *newpath, int *presel)
{
static char cmd[] = "fusermount3"; /* Arch Linux utility */
static bool found = FALSE;
- char *tmp;
+ char *tmp = name;
+ struct stat sb, psb;
/* On Ubuntu it's fusermount */
if (!found && !getutil(cmd)) {
found = TRUE;
}
- tmp = xreadline(NULL, "host: ");
- if (!tmp[0])
- return FALSE;
+ if (tmp) {
+ mkpath(cfgdir, tmp, newpath);
+ if ((lstat(newpath, &sb) == -1) || (lstat(dirname(newpath), &psb) == -1)) {
+ *presel = MSGWAIT;
+ return FALSE;
+ }
+ }
+
+ if (!tmp || (sb.st_dev == psb.st_dev)) {
+ tmp = xreadline(NULL, "host: ");
+ if (!tmp[0])
+ return FALSE;
+ }
/* Create the mount point */
mkpath(cfgdir, tmp, newpath);
"ca Select all K Edit selection\n"
"cP Copy selection X Delete selection\n"
"cV Move selection ^X Delete entry\n"
- "cf Create archive C Execute entry\n"
+ "cf Create archive T Mount archive\n"
"b^F Extract archive F List archive\n"
"ce Edit in EDITOR p Open in PAGER\n"
"1ORDER TOGGLES\n"
"cA Apparent du S du\n"
- "cs Size E Extn t Time\n"
+ "cs Size E Extn t Time\n"
"1MISC\n"
- "9! ^] Shell = Launcher\n"
+ "9! ^] Shell = Launch C Execute entry\n"
"9R ^V Pick plugin :K xK Execute plugin K\n"
"cc SSHFS mount u Unmount\n"
"b^P Prompt/run cmd L Lock\n"};
/* Repopulate as directory content may have changed */
goto begin;
+ case SEL_ARCHIVEMNT:
+ if (!ndents || !archive_mount(dents[cur].name, path, newpath, &presel))
+ goto nochange; // fallthrough
case SEL_SSHFS:
- if (!sshfs_mount(newpath, &presel))
+ if (sel == SEL_SSHFS && !sshfs_mount(newpath, &presel))
goto nochange;
lastname[0] = '\0';
setdirwatch();
goto begin;
case SEL_UMOUNT:
- sshfs_unmount(newpath, &presel);
+ tmp = ndents ? dents[cur].name : NULL;
+ unmount(tmp, newpath, &presel);
goto nochange;
case SEL_QUITCD: // fallthrough
case SEL_QUIT: