From 478e6a9023c51521b47701673c8335f51dbfbdec Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 1 Nov 2019 16:46:39 +0100 Subject: [PATCH] Cleanup/overhaul of how symlinks are handled and how paths are parsed. Now `bb` will fail on `bb nonexistant/..` and will display `/foo/baz/atfoo/` as `/foo/` if `atfoo` is a symlink to `/foo` --- bb.c | 71 +++++++++++++++++++++++++++++------------------------------- bb.h | 2 +- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/bb.c b/bb.c index 8369959..329b31c 100644 --- a/bb.c +++ b/bb.c @@ -300,7 +300,15 @@ entry_t* load_entry(bb_t *bb, const char *path, int clear_dots) if (!path || !path[0]) return NULL; if (lstat(path, &filestat) == -1) return NULL; char pbuf[PATH_MAX]; - normalize_path(bb->path, path, pbuf, clear_dots); + char *slash = strrchr(path, '/'); + if (slash) { + strncpy(pbuf, path, (slash - path)); + normalize_path(bb->path, pbuf, pbuf); + strcat(pbuf, slash); + } else { + strcpy(pbuf, bb->path); + strcat(pbuf, path); + } if (pbuf[strlen(pbuf)-1] == '/' && pbuf[1]) pbuf[strlen(pbuf)-1] = '\0'; @@ -367,43 +375,23 @@ void* memcheck(void *p) /* * Prepend `root` to relative paths, replace "~" with $HOME. - * If clear_dots is 1, then also replace "/foo/." with "/foo" and replace "/foo/baz/.." with "/foo". * The normalized path is stored in `normalized`. */ -void normalize_path(const char *root, const char *path, char *normalized, int clear_dots) +void normalize_path(const char *root, const char *path, char *normalized) { + char pbuf[PATH_MAX] = {0}; if (path[0] == '~' && (path[1] == '\0' || path[1] == '/')) { char *home; if (!(home = getenv("HOME"))) return; - strcpy(normalized, home); + strcpy(pbuf, home); ++path; - } else if (path[0] == '/') { - normalized[0] = '\0'; - } else { - strcpy(normalized, root); - if (root[strlen(root)-1] != '/') strcat(normalized, "/"); - } - strcat(normalized, path); - - if (clear_dots) { - char *src = normalized, *dest = normalized; - while (*src) { - while (src[0] == '/' && src[1] == '.') { - // Replace "foo/./?" with "foo/?" - if (src[2] == '/' || src[2] == '\0') { - src += 2; - } else if (src[2] == '.' && (src[3] == '/' || src[3] == '\0')) { - // Replace "foo/baz/../asdf" with "foo/asdf" - src += 3; - *dest = '\0'; - if (dest[-1] == '/') dest[-1] = '\0'; - while (dest > normalized && *dest != '/') dest--; - } else break; - } - *(dest++) = *(src++); - } - *dest = '\0'; + } else if (path[0] != '/') { + strcpy(pbuf, root); + if (root[strlen(root)-1] != '/') strcat(pbuf, "/"); } + strcat(pbuf, path); + if (realpath(pbuf, normalized) == NULL) + err("Could not find: \"%s\"", pbuf); } /* @@ -428,7 +416,7 @@ int populate_files(bb_t *bb, const char *path) strcpy(pbuf, bb->prev_path); if (chdir(pbuf)) return -1; } else { - normalize_path(bb->path, path, pbuf, 1); + normalize_path(bb->path, path, pbuf); if (pbuf[strlen(pbuf)-1] != '/') strcat(pbuf, "/"); if (chdir(pbuf)) return -1; @@ -610,7 +598,7 @@ void run_bbcmd(bb_t *bb, const char *cmd) dirty = 1; } else if (matches_cmd(cmd, "deselect:")) { // +deselect char pbuf[PATH_MAX]; - normalize_path(bb->path, value, pbuf, 1); + normalize_path(bb->path, value, pbuf); entry_t *e = load_entry(bb, pbuf, 0); if (e) { set_selected(bb, e, 0); @@ -633,7 +621,7 @@ void run_bbcmd(bb_t *bb, const char *cmd) populate_files(bb, bb->path); } else if (matches_cmd(cmd, "execute:")) { // +execute: move_cursor(tty_out, 0, termheight-1); - fputs("\033[K" T_ON(T_SHOW_CURSOR), tty_out); + fputs("\033[K", tty_out); restore_term(&default_termios); run_script(bb, value); init_term(); @@ -1251,11 +1239,20 @@ int main(int argc, char *argv[]) setenv("BBSHELLFUNC", bbcmdfn, 1); char full_initial_path[PATH_MAX]; getcwd(full_initial_path, PATH_MAX); - normalize_path(full_initial_path, initial_path, full_initial_path, 1); - if (strcmp(full_initial_path, "/") != 0) strcat(full_initial_path, "/"); + normalize_path(full_initial_path, initial_path, full_initial_path); + struct stat path_stat; + if (stat(full_initial_path, &path_stat) != 0) + err("Could not find: \"%s\"", initial_path); + if (S_ISDIR(path_stat.st_mode)) { + if (strcmp(full_initial_path, "/") != 0) strcat(full_initial_path, "/"); + } else { + write(cmdfd, "goto:", 5); + write(cmdfd, full_initial_path, strlen(full_initial_path) + 1); // Include null byte + char *slash = strrchr(full_initial_path, '/'); + *slash = '\0'; + } setenv("BBINITIALPATH", full_initial_path, 1); - tty_in = fopen("/dev/tty", "r"); tty_out = fopen("/dev/tty", "w"); tcgetattr(fileno(tty_out), &orig_termios); @@ -1275,7 +1272,7 @@ int main(int argc, char *argv[]) strcpy(bb->columns, "*smpn"); strcpy(bb->sort, "+n"); if (populate_files(bb, full_initial_path)) - err("Not a valid path: %s", initial_path); + err("Could not find: \"%s\"", initial_path); run_script(bb, runstartup); write(cmdfd, "\0", 1); diff --git a/bb.h b/bb.h index c5378a9..1a3bd70 100644 --- a/bb.h +++ b/bb.h @@ -206,7 +206,7 @@ static int is_simple_bbcmd(const char *s); static entry_t* load_entry(bb_t *bb, const char *path, int clear_dots); static inline int matches_cmd(const char *str, const char *cmd); static void* memcheck(void *p); -static void normalize_path(const char *root, const char *path, char *pbuf, int clear_dots); +static void normalize_path(const char *root, const char *path, char *pbuf); static int populate_files(bb_t *bb, const char *path); static void print_bindings(int fd); static void run_bbcmd(bb_t *bb, const char *cmd);