Mount archives using archivemount

This commit is contained in:
Arun Prakash Jana 2019-10-12 02:13:08 +05:30
parent c54f50cf4f
commit 19df7777db
No known key found for this signature in database
GPG key ID: A75979F35C080412
3 changed files with 84 additions and 15 deletions

View file

@ -44,7 +44,7 @@ Add to that an awesome [Wiki](https://github.com/jarun/nnn/wiki)!
- Subtree search to open or edit files (using plugin) - Subtree search to open or edit files (using plugin)
- Mimes - Mimes
- Open with desktop opener or specify a custom app - 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 - Option to open all text files in EDITOR
- Information - Information
- Detailed file information - Detailed file information
@ -90,6 +90,7 @@ A curses library with wide char support (e.g. ncursesw), libreadline (`make O_NO
| xdg-open (Linux), open(1) (macOS), cygstart (Cygwin) | base | desktop opener | | 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 | | 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 | | 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 | | sshfs, fusermount(3) | optional | mount, unmount over SSHFS |
| trash-cli | optional | trash files (default action: delete) | | 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)) | | vlock (Linux), bashlock (macOS), lock(1) (BSD) | optional | terminal locker (fallback: [cmatrix](https://github.com/abishekvashok/cmatrix)) |
@ -211,14 +212,14 @@ The list below is from the **dev branch**. Press <kbd>?</kbd> in `nnn` to see th
a Select all K Edit selection a Select all K Edit selection
P Copy selection X Delete selection P Copy selection X Delete selection
V Move selection ^X Delete entry V Move selection ^X Delete entry
f Create archive C Execute entry f Create archive T Mount archive
^F Extract archive F List archive ^F Extract archive F List archive
e Edit in EDITOR p Open in PAGER e Edit in EDITOR p Open in PAGER
ORDER TOGGLES ORDER TOGGLES
A Apparent du S du A Apparent du S du
s Size E Extn t Time s Size E Extn t Time
MISC MISC
! ^] Shell = Launcher ! ^] Shell = Launch C Execute entry
R ^V Pick plugin :K xK Execute plugin K R ^V Pick plugin :K xK Execute plugin K
c SSHFS mount u Unmount c SSHFS mount u Unmount
^P Prompt/run cmd L Lock ^P Prompt/run cmd L Lock

View file

@ -383,6 +383,7 @@ static char mv[] = "mvg -gi";
#define STR_TMPFILE 3 #define STR_TMPFILE 3
#define NONE_SELECTED 4 #define NONE_SELECTED 4
#define UTIL_MISSING 5 #define UTIL_MISSING 5
#define MOUNT_FAILED 6
static const char * const messages[] = { static const char * const messages[] = {
"no traversal", "no traversal",
@ -391,6 +392,7 @@ static const char * const messages[] = {
"/.nnnXXXXXX", "/.nnnXXXXXX",
"0 selected", "0 selected",
"missing dep", "missing dep",
"mount failed",
}; };
/* Supported configuration environment variables */ /* Supported configuration environment variables */
@ -2793,6 +2795,50 @@ static bool create_dir(const char *path)
return TRUE; 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) static bool sshfs_mount(char *newpath, int *presel)
{ {
uchar flag = F_NORMAL; uchar flag = F_NORMAL;
@ -2828,18 +2874,23 @@ static bool sshfs_mount(char *newpath, int *presel)
/* Connect to remote */ /* Connect to remote */
if (spawn(env, tmp, newpath, NULL, flag)) { if (spawn(env, tmp, newpath, NULL, flag)) {
printwait("mount failed", presel); printwait(messages[MOUNT_FAILED], presel);
return FALSE; return FALSE;
} }
return TRUE; 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 char cmd[] = "fusermount3"; /* Arch Linux utility */
static bool found = FALSE; static bool found = FALSE;
char *tmp; char *tmp = name;
struct stat sb, psb;
/* On Ubuntu it's fusermount */ /* On Ubuntu it's fusermount */
if (!found && !getutil(cmd)) { if (!found && !getutil(cmd)) {
@ -2847,9 +2898,19 @@ static bool sshfs_unmount(char *newpath, int *presel)
found = TRUE; found = TRUE;
} }
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: "); tmp = xreadline(NULL, "host: ");
if (!tmp[0]) if (!tmp[0])
return FALSE; return FALSE;
}
/* Create the mount point */ /* Create the mount point */
mkpath(cfgdir, tmp, newpath); mkpath(cfgdir, tmp, newpath);
@ -2919,14 +2980,14 @@ static void show_help(const char *path)
"ca Select all K Edit selection\n" "ca Select all K Edit selection\n"
"cP Copy selection X Delete selection\n" "cP Copy selection X Delete selection\n"
"cV Move selection ^X Delete entry\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" "b^F Extract archive F List archive\n"
"ce Edit in EDITOR p Open in PAGER\n" "ce Edit in EDITOR p Open in PAGER\n"
"1ORDER TOGGLES\n" "1ORDER TOGGLES\n"
"cA Apparent du S du\n" "cA Apparent du S du\n"
"cs Size E Extn t Time\n" "cs Size E Extn t Time\n"
"1MISC\n" "1MISC\n"
"9! ^] Shell = Launcher\n" "9! ^] Shell = Launch C Execute entry\n"
"9R ^V Pick plugin :K xK Execute plugin K\n" "9R ^V Pick plugin :K xK Execute plugin K\n"
"cc SSHFS mount u Unmount\n" "cc SSHFS mount u Unmount\n"
"b^P Prompt/run cmd L Lock\n"}; "b^P Prompt/run cmd L Lock\n"};
@ -4577,8 +4638,11 @@ nochange:
/* Repopulate as directory content may have changed */ /* Repopulate as directory content may have changed */
goto begin; goto begin;
case SEL_ARCHIVEMNT:
if (!ndents || !archive_mount(dents[cur].name, path, newpath, &presel))
goto nochange; // fallthrough
case SEL_SSHFS: case SEL_SSHFS:
if (!sshfs_mount(newpath, &presel)) if (sel == SEL_SSHFS && !sshfs_mount(newpath, &presel))
goto nochange; goto nochange;
lastname[0] = '\0'; lastname[0] = '\0';
@ -4592,7 +4656,8 @@ nochange:
setdirwatch(); setdirwatch();
goto begin; goto begin;
case SEL_UMOUNT: case SEL_UMOUNT:
sshfs_unmount(newpath, &presel); tmp = ndents ? dents[cur].name : NULL;
unmount(tmp, newpath, &presel);
goto nochange; goto nochange;
case SEL_QUITCD: // fallthrough case SEL_QUITCD: // fallthrough
case SEL_QUIT: case SEL_QUIT:

View file

@ -88,6 +88,7 @@ enum action {
SEL_NEW, SEL_NEW,
SEL_RENAME, SEL_RENAME,
SEL_RENAMEMUL, SEL_RENAMEMUL,
SEL_ARCHIVEMNT,
SEL_SSHFS, SEL_SSHFS,
SEL_UMOUNT, SEL_UMOUNT,
SEL_HELP, SEL_HELP,
@ -229,6 +230,8 @@ static struct key bindings[] = {
{ KEY_F(2), SEL_RENAME }, { KEY_F(2), SEL_RENAME },
/* Rename contents of current dir */ /* Rename contents of current dir */
{ 'r', SEL_RENAMEMUL }, { 'r', SEL_RENAMEMUL },
/* Mount an archive */
{ 'T', SEL_ARCHIVEMNT },
/* Connect to server over SSHFS */ /* Connect to server over SSHFS */
{ 'c', SEL_SSHFS }, { 'c', SEL_SSHFS },
/* Disconnect a SSHFS mount point */ /* Disconnect a SSHFS mount point */