From: Richard Russon Date: Wed, 15 Aug 2018 11:27:46 +0000 (+0100) Subject: group path functions X-Git-Tag: 2019-10-25~699 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4bec8d3c3bfed929bcf143ff878d669fb4b0cb30;p=neomutt group path functions --- diff --git a/browser.c b/browser.c index bf3e0c26b..afb4bdc3a 100644 --- a/browser.c +++ b/browser.c @@ -330,7 +330,7 @@ static bool link_is_dir(const char *folder, const char *path) struct stat st; char fullpath[PATH_MAX]; - mutt_file_concat_path(fullpath, folder, path, sizeof(fullpath)); + mutt_path_concat(fullpath, folder, path, sizeof(fullpath)); if (stat(fullpath, &st) == 0) return S_ISDIR(st.st_mode); @@ -855,7 +855,7 @@ static int examine_directory(struct Menu *menu, struct BrowserState *state, continue; } - mutt_file_concat_path(buffer, d, de->d_name, sizeof(buffer)); + mutt_path_concat(buffer, d, de->d_name, sizeof(buffer)); if (lstat(buffer, &s) == -1) continue; @@ -1552,7 +1552,7 @@ void mutt_select_file(char *file, size_t filelen, int flags, char ***files, int #endif else { - mutt_file_concat_path(buf, LastDir, state.entry[menu->current].name, + mutt_path_concat(buf, LastDir, state.entry[menu->current].name, sizeof(buf)); } @@ -1614,7 +1614,7 @@ void mutt_select_file(char *file, size_t filelen, int flags, char ***files, int else { char tmp[PATH_MAX]; - mutt_file_concat_path(tmp, LastDir, + mutt_path_concat(tmp, LastDir, state.entry[menu->current].name, sizeof(tmp)); mutt_str_strfcpy(LastDir, tmp, sizeof(LastDir)); } @@ -1675,7 +1675,7 @@ void mutt_select_file(char *file, size_t filelen, int flags, char ***files, int mutt_str_strfcpy(file, state.entry[menu->current].name, filelen); #endif else - mutt_file_concat_path(file, LastDir, state.entry[menu->current].name, filelen); + mutt_path_concat(file, LastDir, state.entry[menu->current].name, filelen); /* fallthrough */ case OP_EXIT: @@ -1694,7 +1694,7 @@ void mutt_select_file(char *file, size_t filelen, int flags, char ***files, int if (ff.tagged) { char full[PATH_MAX]; - mutt_file_concat_path(full, LastDir, ff.name, sizeof(full)); + mutt_path_concat(full, LastDir, ff.name, sizeof(full)); mutt_expand_path(full, sizeof(full)); tfiles[k++] = mutt_str_strdup(full); } @@ -1875,7 +1875,7 @@ void mutt_select_file(char *file, size_t filelen, int flags, char ***files, int /* in case dir is relative, make it relative to LastDir, * not current working dir */ char tmp[PATH_MAX]; - mutt_file_concat_path(tmp, LastDir, buf, sizeof(tmp)); + mutt_path_concat(tmp, LastDir, buf, sizeof(tmp)); mutt_str_strfcpy(buf, tmp, sizeof(buf)); } /* Resolve path from @@ -2121,7 +2121,7 @@ void mutt_select_file(char *file, size_t filelen, int flags, char ***files, int { char buf2[PATH_MAX]; - mutt_file_concat_path(buf2, LastDir, state.entry[menu->current].name, + mutt_path_concat(buf2, LastDir, state.entry[menu->current].name, sizeof(buf2)); struct Body *b = mutt_make_file_attach(buf2); if (b) diff --git a/complete.c b/complete.c index 19b8b45ee..e83deb4a4 100644 --- a/complete.c +++ b/complete.c @@ -137,7 +137,7 @@ int mutt_complete(char *buf, size_t buflen) else p = NONULL(Folder); - mutt_file_concat_path(imap_path, p, buf + 1, sizeof(imap_path)); + mutt_path_concat(imap_path, p, buf + 1, sizeof(imap_path)); } else mutt_str_strfcpy(imap_path, buf, sizeof(imap_path)); @@ -158,7 +158,7 @@ int mutt_complete(char *buf, size_t buflen) if (p) { char tmp[PATH_MAX]; - if (mutt_file_concatn_path(tmp, sizeof(tmp), exp_dirpart, strlen(exp_dirpart), + if (mutt_path_concatn(tmp, sizeof(tmp), exp_dirpart, strlen(exp_dirpart), buf + 1, (size_t)(p - buf - 1)) == NULL) { return -1; diff --git a/compose.c b/compose.c index 59d21f373..f1b4df5bc 100644 --- a/compose.c +++ b/compose.c @@ -1704,7 +1704,7 @@ int mutt_compose_menu(struct Header *msg, char *fcc, size_t fcclen, src = CURATTACH->content->d_filename; else src = CURATTACH->content->filename; - mutt_str_strfcpy(fname, mutt_file_basename(NONULL(src)), sizeof(fname)); + mutt_str_strfcpy(fname, mutt_path_basename(NONULL(src)), sizeof(fname)); ret = mutt_get_field(_("Send attachment with name: "), fname, sizeof(fname), MUTT_FILE); if (ret == 0) { diff --git a/hook.c b/hook.c index b0c0c169e..903f7cfb0 100644 --- a/hook.c +++ b/hook.c @@ -573,7 +573,7 @@ void mutt_select_fcc(char *path, size_t pathlen, struct Header *hdr) struct Address *addr = env->to ? env->to : (env->cc ? env->cc : env->bcc); char buf[PATH_MAX]; mutt_safe_path(buf, sizeof(buf), addr); - mutt_file_concat_path(path, NONULL(Folder), buf, pathlen); + mutt_path_concat(path, NONULL(Folder), buf, pathlen); if (!ForceName && mx_access(path, W_OK) != 0) mutt_str_strfcpy(path, Record, pathlen); } diff --git a/init.c b/init.c index 9c8267885..cfb726010 100644 --- a/init.c +++ b/init.c @@ -814,7 +814,7 @@ static int source_rc(const char *rcfile_path, struct Buffer *err) if (!ispipe) { struct ListNode *np = STAILQ_FIRST(&MuttrcStack); - if (!mutt_file_to_absolute_path(rcfile, np ? NONULL(np->data) : "")) + if (!mutt_path_to_absolute(rcfile, np ? NONULL(np->data) : "")) { mutt_error(_("Error: impossible to build path of '%s'"), rcfile_path); return -1; @@ -1745,7 +1745,7 @@ static int parse_set(struct Buffer *buf, struct Buffer *s, unsigned long data, (url_check_scheme(scratch) == U_UNKNOWN)) /* probably a local file */ { struct ListNode *np = STAILQ_FIRST(&MuttrcStack); - if (mutt_file_to_absolute_path(scratch, np ? NONULL(np->data) : "./")) + if (mutt_path_to_absolute(scratch, np ? NONULL(np->data) : "./")) { mutt_buffer_reset(buf); mutt_buffer_addstr(buf, scratch); @@ -3109,9 +3109,9 @@ int mutt_init(bool skip_sys_rc, struct ListHead *commands) if (!p) { #ifdef HOMESPOOL - mutt_file_concat_path(buffer, NONULL(HomeDir), MAILPATH, sizeof(buffer)); + mutt_path_concat(buffer, NONULL(HomeDir), MAILPATH, sizeof(buffer)); #else - mutt_file_concat_path(buffer, MAILPATH, NONULL(Username), sizeof(buffer)); + mutt_path_concat(buffer, MAILPATH, NONULL(Username), sizeof(buffer)); #endif p = buffer; } diff --git a/mutt/file.c b/mutt/file.c index 93c874183..118ed06d7 100644 --- a/mutt/file.c +++ b/mutt/file.c @@ -701,97 +701,6 @@ size_t mutt_file_quote_filename(char *d, size_t l, const char *f) return j; } -/** - * mutt_file_concatn_path - Concatenate directory and filename - * @param dst Buffer for result - * @param dstlen Buffer length - * @param dir Directory - * @param dirlen Directory length - * @param fname Filename - * @param fnamelen Filename length - * @retval NULL Error - * @retval ptr Success, pointer to \a dst - * - * Write the concatenated pathname (dir + "/" + fname) into dst. - * The slash is omitted when dir or fname is of 0 length. - */ -char *mutt_file_concatn_path(char *dst, size_t dstlen, const char *dir, - size_t dirlen, const char *fname, size_t fnamelen) -{ - size_t req; - size_t offset = 0; - - if (dstlen == 0) - return NULL; /* probably should not mask errors like this */ - - /* size check */ - req = dirlen + fnamelen + 1; /* +1 for the trailing nul */ - if (dirlen && fnamelen) - req++; /* when both components are non-nul, we add a "/" in between */ - if (req > dstlen) - { /* check for condition where the dst length is too short */ - /* Two options here: - * 1) assert(0) or return NULL to signal error - * 2) copy as much of the path as will fit - * It doesn't appear that the return value is actually checked anywhere mutt_file_concat_path() - * is called, so we should just copy set dst to nul and let the calling function fail later. - */ - dst[0] = '\0'; /* safe since we bail out early if dstlen == 0 */ - return NULL; - } - - if (dirlen) - { /* when dir is not empty */ - memcpy(dst, dir, dirlen); - offset = dirlen; - if (fnamelen) - dst[offset++] = '/'; - } - if (fnamelen) - { /* when fname is not empty */ - memcpy(dst + offset, fname, fnamelen); - offset += fnamelen; - } - dst[offset] = '\0'; - return dst; -} - -/** - * mutt_file_concat_path - Join a directory name and a filename - * @param d Buffer for the result - * @param dir Directory name - * @param fname File name - * @param l Length of buffer - * @retval ptr Destination buffer - * - * If both dir and fname are supplied, they are separated with '/'. - * If either is missing, then the other will be copied exactly. - */ -char *mutt_file_concat_path(char *d, const char *dir, const char *fname, size_t l) -{ - const char *fmt = "%s/%s"; - - if (!*fname || (*dir && dir[strlen(dir) - 1] == '/')) - fmt = "%s%s"; - - snprintf(d, l, fmt, dir, fname); - return d; -} - -/** - * mutt_file_basename - Find the last component for a pathname - * @param f String to be examined - * @retval ptr Part of pathname after last '/' character - */ -const char *mutt_file_basename(const char *f) -{ - const char *p = strrchr(f, '/'); - if (p) - return p + 1; - else - return f; -} - /** * mutt_file_mkdir - Recursively create directories * @param path Directories to create @@ -918,22 +827,6 @@ time_t mutt_file_decrease_mtime(const char *f, struct stat *st) return mtime; } -/** - * mutt_file_dirname - Return a path up to, but not including, the final '/' - * @param path Path - * @retval ptr The directory containing p - * - * Unlike the IEEE Std 1003.1-2001 specification of dirname(3), this - * implementation does not modify its parameter, so callers need not manually - * copy their paths into a modifiable buffer prior to calling this function. - */ -char *mutt_file_dirname(const char *path) -{ - char buf[PATH_MAX] = { 0 }; - mutt_str_strfcpy(buf, path, sizeof(buf)); - return mutt_str_strdup(dirname(buf)); -} - /** * mutt_file_set_mtime - Set the modification time of one file from another * @param from Filename whose mtime should be copied @@ -1296,47 +1189,6 @@ int mutt_file_rename(char *oldfile, char *newfile) return 0; } -/** - * mutt_file_to_absolute_path - Convert relative filepath to an absolute path - * @param path Relative path - * @param reference Absolute path that \a path is relative to - * @retval true Success - * @retval false Failure - * - * Use POSIX functions to convert a path to absolute, relatively to another path - * - * @note \a path should be at least of PATH_MAX length - */ -int mutt_file_to_absolute_path(char *path, const char *reference) -{ - char abs_path[PATH_MAX]; - int path_len; - - /* if path is already absolute, don't do anything */ - if ((strlen(path) > 1) && (path[0] == '/')) - { - return true; - } - - char *dirpath = mutt_file_dirname(reference); - mutt_str_strfcpy(abs_path, dirpath, sizeof(abs_path)); - FREE(&dirpath); - mutt_str_strncat(abs_path, sizeof(abs_path), "/", 1); /* append a / at the end of the path */ - - path_len = sizeof(abs_path) - strlen(path); - - mutt_str_strncat(abs_path, sizeof(abs_path), path, path_len > 0 ? path_len : 0); - - path = realpath(abs_path, path); - if (!path && (errno != ENOENT)) - { - mutt_perror(_("Error: converting path to absolute")); - return false; - } - - return true; -} - /** * mutt_file_read_keyword - Read a keyword from a file * @param file File to read diff --git a/mutt/file.h b/mutt/file.h index 12e27d158..f8d827ff2 100644 --- a/mutt/file.h +++ b/mutt/file.h @@ -35,19 +35,15 @@ extern char *Tmpdir; #define MUTT_CONT (1 << 0) /**< \-continuation */ #define MUTT_EOL (1 << 1) /**< don't strip `\n` / `\r\n` */ -const char *mutt_file_basename(const char *f); int mutt_file_check_empty(const char *path); int mutt_file_chmod(const char *path, mode_t mode); int mutt_file_chmod_add(const char *path, mode_t mode); int mutt_file_chmod_add_stat(const char *path, mode_t mode, struct stat *st); int mutt_file_chmod_rm(const char *path, mode_t mode); int mutt_file_chmod_rm_stat(const char *path, mode_t mode, struct stat *st); -char * mutt_file_concat_path(char *d, const char *dir, const char *fname, size_t l); -char * mutt_file_concatn_path(char *dst, size_t dstlen, const char *dir, size_t dirlen, const char *fname, size_t fnamelen); int mutt_file_copy_bytes(FILE *in, FILE *out, size_t size); int mutt_file_copy_stream(FILE *fin, FILE *fout); time_t mutt_file_decrease_mtime(const char *f, struct stat *st); -char * mutt_file_dirname(const char *path); int mutt_file_fclose(FILE **f); FILE * mutt_file_fopen(const char *path, const char *mode); int mutt_file_fsync_close(FILE **f); @@ -66,7 +62,6 @@ void mutt_file_sanitize_filename(char *f, bool slash); int mutt_file_sanitize_regex(char *dest, size_t destlen, const char *src); void mutt_file_set_mtime(const char *from, const char *to); int mutt_file_symlink(const char *oldpath, const char *newpath); -int mutt_file_to_absolute_path(char *path, const char *reference); void mutt_file_touch_atime(int fd); void mutt_file_unlink(const char *s); void mutt_file_unlink_empty(const char *path); diff --git a/mutt/mutt.h b/mutt/mutt.h index b8b771302..16b5c0a2e 100644 --- a/mutt/mutt.h +++ b/mutt/mutt.h @@ -42,6 +42,7 @@ * | mutt/mbyte.c | @subpage mbyte | * | mutt/md5.c | @subpage md5 | * | mutt/memory.c | @subpage memory | + * | mutt/path.c | @subpage path | * | mutt/regex.c | @subpage regex | * | mutt/sha1.c | @subpage sha1 | * | mutt/signal.c | @subpage signal | @@ -71,6 +72,7 @@ #include "memory.h" #include "message.h" #include "queue.h" +#include "path.h" #include "regex3.h" #include "sha1.h" #include "signal2.h" diff --git a/mutt/path.c b/mutt/path.c index 16fb312d0..b0e97e279 100644 --- a/mutt/path.c +++ b/mutt/path.c @@ -20,20 +20,25 @@ * this program. If not, see . */ +/** + * @page path Path manipulation functions + * + * Path manipulation functions + */ + #include "config.h" +#include +#include #include #include #include #include #include #include -#include "mutt/mutt.h" -#include "email/email.h" -#include "alias.h" -#include "globals.h" -#include "hook.h" -#include "imap/imap.h" -#include "mx.h" +#include "mutt/logging.h" +#include "mutt/memory.h" +#include "mutt/message.h" +#include "mutt/string2.h" /** * mutt_path_tidy_slash - Remove unnecessary slashes and dots @@ -258,3 +263,152 @@ bool mutt_path_canon(char *buf, size_t buflen, const char *homedir) return true; } + +/** + * mutt_path_basename - Find the last component for a pathname + * @param f String to be examined + * @retval ptr Part of pathname after last '/' character + */ +const char *mutt_path_basename(const char *f) +{ + const char *p = strrchr(f, '/'); + if (p) + return p + 1; + else + return f; +} + +/** + * mutt_path_concat - Join a directory name and a filename + * @param d Buffer for the result + * @param dir Directory name + * @param fname File name + * @param l Length of buffer + * @retval ptr Destination buffer + * + * If both dir and fname are supplied, they are separated with '/'. + * If either is missing, then the other will be copied exactly. + */ +char *mutt_path_concat(char *d, const char *dir, const char *fname, size_t l) +{ + const char *fmt = "%s/%s"; + + if (!*fname || (*dir && dir[strlen(dir) - 1] == '/')) + fmt = "%s%s"; + + snprintf(d, l, fmt, dir, fname); + return d; +} + +/** + * mutt_path_concatn - Concatenate directory and filename + * @param dst Buffer for result + * @param dstlen Buffer length + * @param dir Directory + * @param dirlen Directory length + * @param fname Filename + * @param fnamelen Filename length + * @retval NULL Error + * @retval ptr Success, pointer to \a dst + * + * Write the concatenated pathname (dir + "/" + fname) into dst. + * The slash is omitted when dir or fname is of 0 length. + */ +char *mutt_path_concatn(char *dst, size_t dstlen, const char *dir, + size_t dirlen, const char *fname, size_t fnamelen) +{ + size_t req; + size_t offset = 0; + + if (dstlen == 0) + return NULL; /* probably should not mask errors like this */ + + /* size check */ + req = dirlen + fnamelen + 1; /* +1 for the trailing nul */ + if (dirlen && fnamelen) + req++; /* when both components are non-nul, we add a "/" in between */ + if (req > dstlen) + { /* check for condition where the dst length is too short */ + /* Two options here: + * 1) assert(0) or return NULL to signal error + * 2) copy as much of the path as will fit + * It doesn't appear that the return value is actually checked anywhere mutt_path_concat() + * is called, so we should just copy set dst to nul and let the calling function fail later. + */ + dst[0] = '\0'; /* safe since we bail out early if dstlen == 0 */ + return NULL; + } + + if (dirlen) + { /* when dir is not empty */ + memcpy(dst, dir, dirlen); + offset = dirlen; + if (fnamelen) + dst[offset++] = '/'; + } + if (fnamelen) + { /* when fname is not empty */ + memcpy(dst + offset, fname, fnamelen); + offset += fnamelen; + } + dst[offset] = '\0'; + return dst; +} + +/** + * mutt_path_dirname - Return a path up to, but not including, the final '/' + * @param path Path + * @retval ptr The directory containing p + * + * Unlike the IEEE Std 1003.1-2001 specification of dirname(3), this + * implementation does not modify its parameter, so callers need not manually + * copy their paths into a modifiable buffer prior to calling this function. + */ +char *mutt_path_dirname(const char *path) +{ + char buf[PATH_MAX] = { 0 }; + mutt_str_strfcpy(buf, path, sizeof(buf)); + return mutt_str_strdup(dirname(buf)); +} + +/** + * mutt_path_to_absolute - Convert relative filepath to an absolute path + * @param path Relative path + * @param reference Absolute path that \a path is relative to + * @retval true Success + * @retval false Failure + * + * Use POSIX functions to convert a path to absolute, relatively to another path + * + * @note \a path should be at least of PATH_MAX length + */ +int mutt_path_to_absolute(char *path, const char *reference) +{ + char abs_path[PATH_MAX]; + int path_len; + + /* if path is already absolute, don't do anything */ + if ((strlen(path) > 1) && (path[0] == '/')) + { + return true; + } + + char *dirpath = mutt_path_dirname(reference); + mutt_str_strfcpy(abs_path, dirpath, sizeof(abs_path)); + FREE(&dirpath); + mutt_str_strncat(abs_path, sizeof(abs_path), "/", 1); /* append a / at the end of the path */ + + path_len = sizeof(abs_path) - strlen(path); + + mutt_str_strncat(abs_path, sizeof(abs_path), path, path_len > 0 ? path_len : 0); + + path = realpath(abs_path, path); + if (!path && (errno != ENOENT)) + { + mutt_perror(_("Error: converting path to absolute")); + return false; + } + + return true; +} + diff --git a/mutt/path.h b/mutt/path.h index 42b3404c3..385de6fcc 100644 --- a/mutt/path.h +++ b/mutt/path.h @@ -26,11 +26,15 @@ #include #include -bool mutt_path_tidy (char *buf); -bool mutt_path_tidy_dotdot(char *buf); -bool mutt_path_tidy_slash (char *buf); - -bool mutt_path_canon (char *buf, size_t buflen, const char *homedir); -bool mutt_path_pretty(char *buf, size_t buflen, const char *homedir); +const char *mutt_path_basename(const char *f); +bool mutt_path_canon(char *buf, size_t buflen, const char *homedir); +char * mutt_path_concat(char *d, const char *dir, const char *fname, size_t l); +char * mutt_path_concatn(char *dst, size_t dstlen, const char *dir, size_t dirlen, const char *fname, size_t fnamelen); +char * mutt_path_dirname(const char *path); +bool mutt_path_pretty(char *buf, size_t buflen, const char *homedir); +bool mutt_path_tidy(char *buf); +bool mutt_path_tidy_dotdot(char *buf); +bool mutt_path_tidy_slash(char *buf); +int mutt_path_to_absolute(char *path, const char *reference); #endif /* _MUTT_PATH_H */ diff --git a/muttlib.c b/muttlib.c index e9d919bf1..bfef8655e 100644 --- a/muttlib.c +++ b/muttlib.c @@ -746,14 +746,14 @@ int mutt_check_overwrite(const char *attname, const char *path, char *fname, return (rc == MUTT_NO) ? 1 : -1; char tmp[PATH_MAX]; - mutt_str_strfcpy(tmp, mutt_file_basename(NONULL(attname)), sizeof(tmp)); + mutt_str_strfcpy(tmp, mutt_path_basename(NONULL(attname)), sizeof(tmp)); if (mutt_get_field(_("File under directory: "), tmp, sizeof(tmp), MUTT_FILE | MUTT_CLEAR) != 0 || !tmp[0]) { return -1; } - mutt_file_concat_path(fname, path, tmp, flen); + mutt_path_concat(fname, path, tmp, flen); } if (*append == 0 && access(fname, F_OK) == 0) @@ -1460,7 +1460,7 @@ int mutt_save_confirm(const char *s, struct stat *st) if (ret == 0) { /* create dir recursively */ - char *tmp_path = mutt_file_dirname(s); + char *tmp_path = mutt_path_dirname(s); if (mutt_file_mkdir(tmp_path, S_IRWXU) == -1) { /* report failure & abort */ diff --git a/recvattach.c b/recvattach.c index a00d2ee46..15f19297d 100644 --- a/recvattach.c +++ b/recvattach.c @@ -490,7 +490,7 @@ static int query_save_attachment(FILE *fp, struct Body *body, { if (directory && *directory) { - mutt_file_concat_path(buf, *directory, mutt_file_basename(body->filename), + mutt_path_concat(buf, *directory, mutt_path_basename(body->filename), sizeof(buf)); } else @@ -600,7 +600,7 @@ void mutt_save_attachment_list(struct AttachCtx *actx, FILE *fp, bool tag, { int append = 0; - mutt_str_strfcpy(buf, mutt_file_basename(NONULL(top->filename)), sizeof(buf)); + mutt_str_strfcpy(buf, mutt_path_basename(NONULL(top->filename)), sizeof(buf)); prepend_curdir(buf, sizeof(buf)); if (mutt_get_field(_("Save to file: "), buf, sizeof(buf), MUTT_FILE | MUTT_CLEAR) != 0 ||