]> Sergey Matveev's repositories - nnn.git/commitdiff
Mount archives using archivemount
authorArun Prakash Jana <engineerarun@gmail.com>
Fri, 11 Oct 2019 20:43:08 +0000 (02:13 +0530)
committerArun Prakash Jana <engineerarun@gmail.com>
Fri, 11 Oct 2019 20:43:08 +0000 (02:13 +0530)
README.md
src/nnn.c
src/nnn.h

index cf762f096ad1c3909aa167138fed45f001e5f1f4..11f8e46bcde26093fcbc63b1022b664187ebde8b 100644 (file)
--- a/README.md
+++ b/README.md
@@ -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)
 - 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
@@ -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 |
 | 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)) |
@@ -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
             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
index b2342d4437cba67b2d4bbf379416387512de1039..7f2cd5d452229a4bf715e71ebdff6962a7aa3b8c 100644 (file)
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -383,6 +383,7 @@ static char mv[] = "mvg -gi";
 #define STR_TMPFILE 3
 #define NONE_SELECTED 4
 #define UTIL_MISSING 5
+#define MOUNT_FAILED 6
 
 static const char * const messages[] = {
        "no traversal",
@@ -391,6 +392,7 @@ static const char * const messages[] = {
        "/.nnnXXXXXX",
        "0 selected",
        "missing dep",
+       "mount failed",
 };
 
 /* Supported configuration environment variables */
@@ -2793,6 +2795,50 @@ static bool create_dir(const char *path)
        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;
@@ -2828,18 +2874,23 @@ static bool sshfs_mount(char *newpath, int *presel)
 
        /* 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)) {
@@ -2847,9 +2898,19 @@ static bool sshfs_unmount(char *newpath, int *presel)
                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);
@@ -2919,14 +2980,14 @@ static void show_help(const char *path)
                  "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"};
@@ -4577,8 +4638,11 @@ nochange:
 
                        /* 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';
@@ -4592,7 +4656,8 @@ nochange:
                        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:
index 241e16e98a8907f421bef1823d26da05e2cafa25..2933d26437bf46eeb27a16a5dc7a6934e85de644 100644 (file)
--- a/src/nnn.h
+++ b/src/nnn.h
@@ -88,6 +88,7 @@ enum action {
        SEL_NEW,
        SEL_RENAME,
        SEL_RENAMEMUL,
+       SEL_ARCHIVEMNT,
        SEL_SSHFS,
        SEL_UMOUNT,
        SEL_HELP,
@@ -229,6 +230,8 @@ static struct key bindings[] = {
        { KEY_F(2),       SEL_RENAME },
        /* Rename contents of current dir */
        { 'r',            SEL_RENAMEMUL },
+       /* Mount an archive */
+       { 'T',            SEL_ARCHIVEMNT },
        /* Connect to server over SSHFS */
        { 'c',            SEL_SSHFS },
        /* Disconnect a SSHFS mount point */