README.md | 2 +- src/nnn.c | 164 ++++++++++++++++++++++++++++++----------------------- diff --git a/README.md b/README.md index cd1d9ea029009f63980d4053151f95d0644ab7a4..2f9a057ac878359c9c7a6d3c544effd9f9d4cf31 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ - Open with desktop opener or specify a custom opener - File-specific colors (or minimal _dirs in context color_) - Icons (customize and compile-in) - Plugin for image, video and audio thumbnails - - Create, list, extract, mount (FUSE based) archives + - Create, list, extract (to), mount (FUSE based) archives - Option to open all text files in `$EDITOR` - Information - Detailed file information diff --git a/src/nnn.c b/src/nnn.c index fde166cf7c8612a418e9896d2fe1b89d2e58d714..1080d84af5e64a670c28748d31162782ed1c4720 100644 --- a/src/nnn.c +++ b/src/nnn.c @@ -4187,11 +4187,90 @@ return (size_t)svb.f_bavail << ffs((int)(svb.f_frsize >> 1)); } +/* Create non-existent parents and a file or dir */ +static bool xmktree(char *path, bool dir) +{ + char *p = path; + char *slash = path; + + if (!p || !*p) + return FALSE; + + /* Skip the first '/' */ + ++p; + + while (*p != '\0') { + if (*p == '/') { + slash = p; + *p = '\0'; + } else { + ++p; + continue; + } + + /* Create folder from path to '\0' inserted at p */ + if (mkdir(path, 0777) == -1 && errno != EEXIST) { +#ifdef __HAIKU__ + // XDG_CONFIG_HOME contains a directory + // that is read-only, but the full path + // is writeable. + // Try to continue and see what happens. + // TODO: Find a more robust solution. + if (errno == B_READ_ONLY_DEVICE) + goto next; +#endif + DPRINTF_S("mkdir1!"); + DPRINTF_S(strerror(errno)); + *slash = '/'; + return FALSE; + } + +#ifdef __HAIKU__ +next: +#endif + /* Restore path */ + *slash = '/'; + ++p; + } + + if (dir) { + if (mkdir(path, 0777) == -1 && errno != EEXIST) { + DPRINTF_S("mkdir2!"); + DPRINTF_S(strerror(errno)); + return FALSE; + } + } else { + int fd = open(path, O_CREAT, 0666); + + if (fd == -1 && errno != EEXIST) { + DPRINTF_S("open!"); + DPRINTF_S(strerror(errno)); + return FALSE; + } + + close(fd); + } + + return TRUE; +} + /* List or extract archive */ -static void handle_archive(char *fpath, char op) +static bool handle_archive(char *fpath, char op) { char arg[] = "-tvf"; /* options for tar/bsdtar to list files */ - char *util; + char *util, *outdir; + bool x_to = FALSE; + + if (op == 'x') { + outdir = xreadline(NULL, messages[MSG_NEW_PATH]); + if (outdir && *outdir && !(*outdir == '.' && outdir[1] == '\0')) { + if (!xmktree(outdir, TRUE) || (chdir(outdir) == -1)) { + printwarn(NULL); + return FALSE; + } + x_to = TRUE; + } + } if (getutil(utils[UTIL_ATOOL])) { util = utils[UTIL_ATOOL]; @@ -4212,9 +4291,16 @@ arg[1] = op; } if (op == 'x') /* extract */ - spawn(util, arg, fpath, NULL, F_NORMAL); + spawn(util, arg, fpath, NULL, F_NORMAL | F_MULTI); else /* list */ get_output(util, arg, fpath, NULL, TRUE, TRUE); + + if (x_to && (chdir(xdirname(fpath)) == -1)) { + printwarn(NULL); + return FALSE; + } + + return TRUE; } static char *visit_parent(char *path, char *newpath, int *presel) @@ -4255,73 +4341,6 @@ break; printwarn(NULL); xdelay(XDELAY_INTERVAL_MS); -} - -/* Create non-existent parents and a file or dir */ -static bool xmktree(char *path, bool dir) -{ - char *p = path; - char *slash = path; - - if (!p || !*p) - return FALSE; - - /* Skip the first '/' */ - ++p; - - while (*p != '\0') { - if (*p == '/') { - slash = p; - *p = '\0'; - } else { - ++p; - continue; - } - - /* Create folder from path to '\0' inserted at p */ - if (mkdir(path, 0777) == -1 && errno != EEXIST) { -#ifdef __HAIKU__ - // XDG_CONFIG_HOME contains a directory - // that is read-only, but the full path - // is writeable. - // Try to continue and see what happens. - // TODO: Find a more robust solution. - if (errno == B_READ_ONLY_DEVICE) - goto next; -#endif - DPRINTF_S("mkdir1!"); - DPRINTF_S(strerror(errno)); - *slash = '/'; - return FALSE; - } - -#ifdef __HAIKU__ -next: -#endif - /* Restore path */ - *slash = '/'; - ++p; - } - - if (dir) { - if (mkdir(path, 0777) == -1 && errno != EEXIST) { - DPRINTF_S("mkdir2!"); - DPRINTF_S(strerror(errno)); - return FALSE; - } - } else { - int fd = open(path, O_CREAT, 0666); - - if (fd == -1 && errno != EEXIST) { - DPRINTF_S("open!"); - DPRINTF_S(strerror(errno)); - return FALSE; - } - - close(fd); - } - - return TRUE; } static bool archive_mount(char *newpath) @@ -6491,7 +6510,10 @@ #endif r = get_input(messages[MSG_ARCHIVE_OPTS]); if (r == 'l' || r == 'x') { mkpath(path, pent->name, newpath); - handle_archive(newpath, r); + if (!handle_archive(newpath, r)) { + presel = MSGWAIT; + goto nochange; + } if (r == 'l') { statusbar(path); goto nochange;