Opinionated xstrlcpy changes (#513)

* Unvectorize xstrlcpy

On all libcs I could find, memcpy does a better job than we can.

* Rename xstrlcpy to xstrsncpy to avoid confusion

The semantics of our xstrlcpy differed slightly from strlcpy; we return
the number of copied characters; strlcpy returns the strlen(src).
strscpy from Linux is similar except it returns the number of copied
characters sans the NUL byte, so this is named strsncpy to be different.
This commit is contained in:
Saagar Jha 2020-04-11 17:35:14 -07:00 committed by GitHub
parent 2115d75ac6
commit 3bab34e962
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

216
src/nnn.c
View file

@ -359,7 +359,6 @@ static kv *bookmark;
static kv *plug; static kv *plug;
static uchar tmpfplen; static uchar tmpfplen;
static uchar blk_shift = BLK_SHIFT_512; static uchar blk_shift = BLK_SHIFT_512;
static const uint _WSHIFT = (LONG_SIZE == 8) ? 3 : 2;
#ifndef NOMOUSE #ifndef NOMOUSE
static int middle_click_key; static int middle_click_key;
#endif #endif
@ -670,7 +669,7 @@ static haiku_nm_h haiku_hnd;
#define exitcurses() endwin() #define exitcurses() endwin()
#define printwarn(presel) printwait(strerror(errno), presel) #define printwarn(presel) printwait(strerror(errno), presel)
#define istopdir(path) ((path)[1] == '\0' && (path)[0] == '/') #define istopdir(path) ((path)[1] == '\0' && (path)[0] == '/')
#define copycurname() xstrlcpy(lastname, dents[cur].name, NAME_MAX + 1) #define copycurname() xstrsncpy(lastname, dents[cur].name, NAME_MAX + 1)
#define settimeout() timeout(1000) #define settimeout() timeout(1000)
#define cleartimeout() timeout(-1) #define cleartimeout() timeout(-1)
#define errexit() printerr(__LINE__) #define errexit() printerr(__LINE__)
@ -689,7 +688,7 @@ static haiku_nm_h haiku_hnd;
#endif /* __GNUC__ */ #endif /* __GNUC__ */
/* Forward declarations */ /* Forward declarations */
static size_t xstrlcpy(char *dest, const char *src, size_t n); static size_t xstrsncpy(char *dest, const char *src, size_t n);
static void redraw(char *path); static void redraw(char *path);
static int spawn(char *file, char *arg1, char *arg2, const char *dir, uchar flag); static int spawn(char *file, char *arg1, char *arg2, const char *dir, uchar flag);
static int (*nftw_fn)(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf); static int (*nftw_fn)(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf);
@ -805,7 +804,7 @@ static void printwait(const char *msg, int *presel)
if (presel) { if (presel) {
*presel = MSGWAIT; *presel = MSGWAIT;
if (ndents) if (ndents)
xstrlcpy(g_ctx[cfg.curctx].c_name, dents[cur].name, NAME_MAX + 1); xstrsncpy(g_ctx[cfg.curctx].c_name, dents[cur].name, NAME_MAX + 1);
} }
} }
@ -937,54 +936,21 @@ static void *xrealloc(void *pcur, size_t len)
* Always null ('\0') terminates if both src and dest are valid pointers. * Always null ('\0') terminates if both src and dest are valid pointers.
* Returns the number of bytes copied including terminating null byte. * Returns the number of bytes copied including terminating null byte.
*/ */
static size_t xstrlcpy(char *dest, const char *src, size_t n) static size_t xstrsncpy(char *restrict dest, const char *restrict src, size_t n)
{ {
if (!src || !dest || !n) if (!src || !dest || !n)
return 0; return 0;
ulong *s, *d; size_t len = strlen(src) + 1;
size_t len = strlen(src) + 1, blocks; if (len <= n) {
memcpy(dest, src, len);
if (n > len)
n = len; n = len;
else if (len > n) } else {
/* Save total number of bytes to copy in len */ memcpy(dest, src, n - 1);
len = n; dest[n - 1] = '\0';
/*
* To enable -O3 ensure src and dest are 16-byte aligned
* More info: https://www.felixcloutier.com/x86/MOVDQA:VMOVDQA32:VMOVDQA64
*/
if ((n >= LONG_SIZE) && (((ulong)src & _ALIGNMENT_MASK) == 0 &&
((ulong)dest & _ALIGNMENT_MASK) == 0)) {
s = (ulong *)src;
d = (ulong *)dest;
blocks = n >> _WSHIFT;
n &= LONG_SIZE - 1;
while (blocks) {
*d = *s; // NOLINT
++d, ++s;
--blocks;
} }
if (!n) { return n;
dest = (char *)d;
*--dest = '\0';
return len;
}
src = (char *)s;
dest = (char *)d;
}
while (--n && (*dest = *src)) // NOLINT
++dest, ++src;
if (!n)
*dest = '\0';
return len;
} }
static bool is_suffix(const char *str, const char *suffix) static bool is_suffix(const char *str, const char *suffix)
@ -1032,7 +998,7 @@ static char *common_prefix(const char *path, char *prefix)
return NULL; return NULL;
if (!*prefix) { if (!*prefix) {
xstrlcpy(prefix, path, PATH_MAX); xstrsncpy(prefix, path, PATH_MAX);
return prefix; return prefix;
} }
@ -1045,7 +1011,7 @@ static char *common_prefix(const char *path, char *prefix)
/* Path is shorter */ /* Path is shorter */
if (!*x && *y == '/') { if (!*x && *y == '/') {
xstrlcpy(prefix, path, y - path); xstrsncpy(prefix, path, y - path);
return prefix; return prefix;
} }
@ -1083,7 +1049,7 @@ static char *abspath(const char *path, const char *cwd)
/* Turn relative paths into absolute */ /* Turn relative paths into absolute */
if (path[0] != '/') if (path[0] != '/')
dst_size = xstrlcpy(resolved_path, cwd, cwd_size + 1) - 1; dst_size = xstrsncpy(resolved_path, cwd, cwd_size + 1) - 1;
else else
resolved_path[0] = '\0'; resolved_path[0] = '\0';
@ -1103,7 +1069,7 @@ static char *abspath(const char *path, const char *cwd)
/* NOP */ /* NOP */
} else if (next - src) { } else if (next - src) {
*(dst++) = '/'; *(dst++) = '/';
xstrlcpy(dst, src, next - src + 1); xstrsncpy(dst, src, next - src + 1);
dst += next - src; dst += next - src;
} }
@ -1127,7 +1093,7 @@ static char *xbasename(char *path)
static int create_tmp_file(void) static int create_tmp_file(void)
{ {
xstrlcpy(g_tmpfpath + tmpfplen - 1, messages[STR_TMPFILE], TMP_LEN_MAX - tmpfplen); xstrsncpy(g_tmpfpath + tmpfplen - 1, messages[STR_TMPFILE], TMP_LEN_MAX - tmpfplen);
int fd = mkstemp(g_tmpfpath); int fd = mkstemp(g_tmpfpath);
@ -1163,7 +1129,7 @@ static void appendfpath(const char *path, const size_t len)
errexit(); errexit();
} }
selbufpos += xstrlcpy(pselbuf + selbufpos, path, len); selbufpos += xstrsncpy(pselbuf + selbufpos, path, len);
} }
/* Write selected file paths to fd, linefeed separated */ /* Write selected file paths to fd, linefeed separated */
@ -1671,7 +1637,7 @@ static int spawn(char *file, char *arg1, char *arg2, const char *dir, uchar flag
return retstatus; return retstatus;
} }
xstrlcpy(cmd, file, len); xstrsncpy(cmd, file, len);
status = parseargs(cmd, argv); status = parseargs(cmd, argv);
if (status == -1 || status > (EXEC_ARGS_MAX - 3)) { /* arg1, arg2 and last NULL */ if (status == -1 || status > (EXEC_ARGS_MAX - 3)) { /* arg1, arg2 and last NULL */
free(cmd); free(cmd);
@ -1921,7 +1887,7 @@ static bool batch_rename(const char *path)
if (fd1 == -1) if (fd1 == -1)
return ret; return ret;
xstrlcpy(foriginal, g_tmpfpath, strlen(g_tmpfpath)+1); xstrsncpy(foriginal, g_tmpfpath, strlen(g_tmpfpath)+1);
fd2 = create_tmp_file(); fd2 = create_tmp_file();
if (fd2 == -1) { if (fd2 == -1) {
@ -1986,7 +1952,7 @@ static void get_archive_cmd(char *cmd, const char *archive)
i = 2; i = 2;
// else tar // else tar
xstrlcpy(cmd, arcmd[i], ARCHIVE_CMD_LEN); xstrsncpy(cmd, arcmd[i], ARCHIVE_CMD_LEN);
} }
static void archive_selection(const char *cmd, const char *archive, const char *curpath) static void archive_selection(const char *cmd, const char *archive, const char *curpath)
@ -2016,7 +1982,7 @@ static bool write_lastdir(const char *curpath)
bool ret = TRUE; bool ret = TRUE;
size_t len = strlen(cfgdir); size_t len = strlen(cfgdir);
xstrlcpy(cfgdir + len, "/.lastd", 8); xstrsncpy(cfgdir + len, "/.lastd", 8);
DPRINTF_S(cfgdir); DPRINTF_S(cfgdir);
FILE *fp = fopen(cfgdir, "w"); FILE *fp = fopen(cfgdir, "w");
@ -2873,7 +2839,7 @@ static char *getreadline(const char *prompt, char *path, char *curpath, int *pre
printwarn(presel); printwarn(presel);
else if (input && input[0]) { else if (input && input[0]) {
add_history(input); add_history(input);
xstrlcpy(g_buf, input, CMD_LEN_MAX); xstrsncpy(g_buf, input, CMD_LEN_MAX);
free(input); free(input);
return g_buf; return g_buf;
} }
@ -2893,16 +2859,16 @@ static size_t mkpath(const char *dir, const char *name, char *out)
/* Handle absolute path */ /* Handle absolute path */
if (name[0] == '/') if (name[0] == '/')
return xstrlcpy(out, name, PATH_MAX); return xstrsncpy(out, name, PATH_MAX);
/* Handle root case */ /* Handle root case */
if (istopdir(dir)) if (istopdir(dir))
len = 1; len = 1;
else else
len = xstrlcpy(out, dir, PATH_MAX); len = xstrsncpy(out, dir, PATH_MAX);
out[len - 1] = '/'; // NOLINT out[len - 1] = '/'; // NOLINT
return (xstrlcpy(out + len, name, PATH_MAX - len) + len); return (xstrsncpy(out + len, name, PATH_MAX - len) + len);
} }
/* /*
@ -2927,8 +2893,8 @@ static int xlink(char *prefix, char *path, char *curfname, char *buf, int *prese
link_fn = &link; link_fn = &link;
if (choice == 'c') { if (choice == 'c') {
r = xstrlcpy(buf, prefix, NAME_MAX + 1); /* Copy prefix */ r = xstrsncpy(buf, prefix, NAME_MAX + 1); /* Copy prefix */
xstrlcpy(buf + r - 1, curfname, NAME_MAX - r); /* Suffix target file name */ xstrsncpy(buf + r - 1, curfname, NAME_MAX - r); /* Suffix target file name */
mkpath(path, buf, lnpath); /* Generate link path */ mkpath(path, buf, lnpath); /* Generate link path */
mkpath(path, curfname, buf); /* Generate target file path */ mkpath(path, curfname, buf); /* Generate target file path */
@ -2943,8 +2909,8 @@ static int xlink(char *prefix, char *path, char *curfname, char *buf, int *prese
len = strlen(psel); len = strlen(psel);
fname = xbasename(psel); fname = xbasename(psel);
r = xstrlcpy(buf, prefix, NAME_MAX + 1); /* Copy prefix */ r = xstrsncpy(buf, prefix, NAME_MAX + 1); /* Copy prefix */
xstrlcpy(buf + r - 1, fname, NAME_MAX - r); /* Suffix target file name */ xstrsncpy(buf + r - 1, fname, NAME_MAX - r); /* Suffix target file name */
mkpath(path, buf, lnpath); /* Generate link path */ mkpath(path, buf, lnpath); /* Generate link path */
if (!link_fn(psel, lnpath)) if (!link_fn(psel, lnpath))
@ -3057,8 +3023,8 @@ static char *get_kv_val(kv *kvarr, char *buf, int key, uchar max, bool bookmark)
ssize_t len = strlen(home); ssize_t len = strlen(home);
ssize_t loclen = strlen(kvarr[r].val); ssize_t loclen = strlen(kvarr[r].val);
xstrlcpy(g_buf, home, len + 1); xstrsncpy(g_buf, home, len + 1);
xstrlcpy(g_buf + len, kvarr[r].val + 1, loclen); xstrsncpy(g_buf + len, kvarr[r].val + 1, loclen);
} }
return realpath(((kvarr[r].val[0] == '~') ? g_buf : kvarr[r].val), buf); return realpath(((kvarr[r].val[0] == '~') ? g_buf : kvarr[r].val), buf);
@ -3176,7 +3142,7 @@ static char *coolsize(off_t size)
} }
if (i > 0 && i < 6 && rem) { if (i > 0 && i < 6 && rem) {
ret = xstrlcpy(size_buf, xitoa(size), 12); ret = xstrsncpy(size_buf, xitoa(size), 12);
size_buf[ret - 1] = '.'; size_buf[ret - 1] = '.';
char *frac = xitoa(rem); char *frac = xitoa(rem);
@ -3185,13 +3151,13 @@ static char *coolsize(off_t size)
if (len < toprint) { if (len < toprint) {
size_buf[ret] = size_buf[ret + 1] = size_buf[ret + 2] = '0'; size_buf[ret] = size_buf[ret + 1] = size_buf[ret + 2] = '0';
xstrlcpy(size_buf + ret + (toprint - len), frac, len + 1); xstrsncpy(size_buf + ret + (toprint - len), frac, len + 1);
} else } else
xstrlcpy(size_buf + ret, frac, toprint + 1); xstrsncpy(size_buf + ret, frac, toprint + 1);
ret += toprint; ret += toprint;
} else { } else {
ret = xstrlcpy(size_buf, size ? xitoa(size) : "0", 12); ret = xstrsncpy(size_buf, size ? xitoa(size) : "0", 12);
--ret; --ret;
} }
@ -3235,9 +3201,9 @@ static char *get_lsperms(mode_t mode)
bits[0] = get_ind(mode, TRUE); bits[0] = get_ind(mode, TRUE);
xstrlcpy(&bits[1], rwx[(mode >> 6) & 7], 4); xstrsncpy(&bits[1], rwx[(mode >> 6) & 7], 4);
xstrlcpy(&bits[4], rwx[(mode >> 3) & 7], 4); xstrsncpy(&bits[4], rwx[(mode >> 3) & 7], 4);
xstrlcpy(&bits[7], rwx[(mode & 7)], 4); xstrsncpy(&bits[7], rwx[(mode & 7)], 4);
if (mode & S_ISUID) if (mode & S_ISUID)
bits[3] = (mode & 0100) ? 's' : 'S'; /* user executable */ bits[3] = (mode & 0100) ? 's' : 'S'; /* user executable */
@ -3374,7 +3340,7 @@ static void savecurctx(settings *curcfg, char *path, char *curname, int r /* nex
bool selmode = cfg.selmode ? TRUE : FALSE; bool selmode = cfg.selmode ? TRUE : FALSE;
/* Save current context */ /* Save current context */
xstrlcpy(g_ctx[cfg.curctx].c_name, curname, NAME_MAX + 1); xstrsncpy(g_ctx[cfg.curctx].c_name, curname, NAME_MAX + 1);
g_ctx[cfg.curctx].c_cfg = cfg; g_ctx[cfg.curctx].c_cfg = cfg;
if (g_ctx[r].c_cfg.ctxactive) { /* Switch to saved context */ if (g_ctx[r].c_cfg.ctxactive) { /* Switch to saved context */
@ -3386,7 +3352,7 @@ static void savecurctx(settings *curcfg, char *path, char *curname, int r /* nex
cfg = g_ctx[r].c_cfg; cfg = g_ctx[r].c_cfg;
} else { /* Setup a new context from current context */ } else { /* Setup a new context from current context */
g_ctx[r].c_cfg.ctxactive = 1; g_ctx[r].c_cfg.ctxactive = 1;
xstrlcpy(g_ctx[r].c_path, path, PATH_MAX); xstrsncpy(g_ctx[r].c_path, path, PATH_MAX);
g_ctx[r].c_last[0] = '\0'; g_ctx[r].c_last[0] = '\0';
g_ctx[r].c_name[0] = '\0'; g_ctx[r].c_name[0] = '\0';
g_ctx[r].c_fltr[0] = g_ctx[r].c_fltr[1] = '\0'; g_ctx[r].c_fltr[0] = g_ctx[r].c_fltr[1] = '\0';
@ -3418,7 +3384,7 @@ static void save_session(bool last_session, int *presel)
if (g_ctx[i].c_cfg.ctxactive) { if (g_ctx[i].c_cfg.ctxactive) {
if (cfg.curctx == i && ndents) if (cfg.curctx == i && ndents)
/* Update current file name, arrows don't update it */ /* Update current file name, arrows don't update it */
xstrlcpy(g_ctx[i].c_name, dents[cur].name, NAME_MAX + 1); xstrsncpy(g_ctx[i].c_name, dents[cur].name, NAME_MAX + 1);
header.pathln[i] = strnlen(g_ctx[i].c_path, PATH_MAX) + 1; header.pathln[i] = strnlen(g_ctx[i].c_path, PATH_MAX) + 1;
header.lastln[i] = strnlen(g_ctx[i].c_last, PATH_MAX) + 1; header.lastln[i] = strnlen(g_ctx[i].c_last, PATH_MAX) + 1;
header.nameln[i] = strnlen(g_ctx[i].c_name, NAME_MAX) + 1; header.nameln[i] = strnlen(g_ctx[i].c_name, NAME_MAX) + 1;
@ -3631,8 +3597,8 @@ static bool show_stats(const char *fpath, const struct stat *sb)
if (fd == -1) if (fd == -1)
return FALSE; return FALSE;
r = xstrlcpy(g_buf, "stat \"", PATH_MAX); r = xstrsncpy(g_buf, "stat \"", PATH_MAX);
r += xstrlcpy(g_buf + r - 1, fpath, PATH_MAX); r += xstrsncpy(g_buf + r - 1, fpath, PATH_MAX);
g_buf[r - 2] = '\"'; g_buf[r - 2] = '\"';
g_buf[r - 1] = '\0'; g_buf[r - 1] = '\0';
DPRINTF_S(g_buf); DPRINTF_S(g_buf);
@ -3740,7 +3706,7 @@ static char *visit_parent(char *path, char *newpath, int *presel)
} }
/* Use a copy as dirname() may change the string passed */ /* Use a copy as dirname() may change the string passed */
xstrlcpy(newpath, path, PATH_MAX); xstrsncpy(newpath, path, PATH_MAX);
dir = dirname(newpath); dir = dirname(newpath);
if (access(dir, R_OK) == -1) { if (access(dir, R_OK) == -1) {
@ -3756,9 +3722,9 @@ static void find_accessible_parent(char *path, char *newpath, char *lastname, in
char *dir; char *dir;
/* Save history */ /* Save history */
xstrlcpy(lastname, xbasename(path), NAME_MAX + 1); xstrsncpy(lastname, xbasename(path), NAME_MAX + 1);
xstrlcpy(newpath, path, PATH_MAX); xstrsncpy(newpath, path, PATH_MAX);
while (true) { while (true) {
dir = visit_parent(path, newpath, presel); dir = visit_parent(path, newpath, presel);
if (istopdir(path) || istopdir(newpath)) { if (istopdir(path) || istopdir(newpath)) {
@ -3767,13 +3733,13 @@ static void find_accessible_parent(char *path, char *newpath, char *lastname, in
break; break;
} }
if (!dir) { if (!dir) {
xstrlcpy(path, newpath, PATH_MAX); xstrsncpy(path, newpath, PATH_MAX);
continue; continue;
} }
break; break;
} }
xstrlcpy(path, dir, PATH_MAX); xstrsncpy(path, dir, PATH_MAX);
printwarn(NULL); printwarn(NULL);
xdelay(XDELAY_INTERVAL_MS); xdelay(XDELAY_INTERVAL_MS);
} }
@ -3930,7 +3896,7 @@ static bool remote_mount(char *newpath, char *currentpath)
if (tmp[0] == '-' && !tmp[1]) { if (tmp[0] == '-' && !tmp[1]) {
if (!strcmp(cfgdir, currentpath) && ndents && (dents[cur].flags & DIR_OR_LINK_TO_DIR)) if (!strcmp(cfgdir, currentpath) && ndents && (dents[cur].flags & DIR_OR_LINK_TO_DIR))
xstrlcpy(tmp, dents[cur].name, NAME_MAX + 1); xstrsncpy(tmp, dents[cur].name, NAME_MAX + 1);
else { else {
printmsg(messages[MSG_FAILED]); printmsg(messages[MSG_FAILED]);
return FALSE; return FALSE;
@ -4069,7 +4035,7 @@ static void printkeys(kv *kvarr, char *buf, uchar max)
static size_t handle_bookmark(const char *mark, char *newpath) static size_t handle_bookmark(const char *mark, char *newpath)
{ {
int fd; int fd;
size_t r = xstrlcpy(g_buf, messages[MSG_BOOKMARK_KEYS], CMD_LEN_MAX); size_t r = xstrsncpy(g_buf, messages[MSG_BOOKMARK_KEYS], CMD_LEN_MAX);
if (mark) { /* There is a pinned directory */ if (mark) { /* There is a pinned directory */
g_buf[--r] = ' '; g_buf[--r] = ' ';
@ -4083,7 +4049,7 @@ static size_t handle_bookmark(const char *mark, char *newpath)
r = FALSE; r = FALSE;
fd = get_input(NULL); fd = get_input(NULL);
if (fd == ',') /* Visit pinned directory */ if (fd == ',') /* Visit pinned directory */
mark ? xstrlcpy(newpath, mark, PATH_MAX) : (r = MSG_NOT_SET); mark ? xstrsncpy(newpath, mark, PATH_MAX) : (r = MSG_NOT_SET);
else if (!get_kv_val(bookmark, newpath, fd, maxbm, TRUE)) else if (!get_kv_val(bookmark, newpath, fd, maxbm, TRUE))
r = MSG_INVALID_KEY; r = MSG_INVALID_KEY;
@ -4217,7 +4183,7 @@ static bool run_cmd_as_plugin(const char *path, const char *file, char *runfile)
return FALSE; return FALSE;
} }
xstrlcpy(g_buf, file, PATH_MAX); xstrsncpy(g_buf, file, PATH_MAX);
len = strlen(g_buf); len = strlen(g_buf);
if (len > 1 && g_buf[len - 1] == '*') { if (len > 1 && g_buf[len - 1] == '*') {
@ -4271,7 +4237,7 @@ static bool run_selected_plugin(char **path, const char *file, char *runfile, ch
mkpath(plugindir, file, g_buf); mkpath(plugindir, file, g_buf);
if (runfile && runfile[0]) { if (runfile && runfile[0]) {
xstrlcpy(*lastname, runfile, NAME_MAX); xstrsncpy(*lastname, runfile, NAME_MAX);
spawn(g_buf, *lastname, *path, *path, F_NORMAL); spawn(g_buf, *lastname, *path, *path, F_NORMAL);
} else } else
spawn(g_buf, NULL, *path, *path, F_NORMAL); spawn(g_buf, NULL, *path, *path, F_NORMAL);
@ -4285,8 +4251,8 @@ static bool run_selected_plugin(char **path, const char *file, char *runfile, ch
int ctx = g_buf[0] - '0'; int ctx = g_buf[0] - '0';
if (ctx == 0 || ctx == cfg.curctx + 1) { if (ctx == 0 || ctx == cfg.curctx + 1) {
xstrlcpy(*lastdir, *path, PATH_MAX); xstrsncpy(*lastdir, *path, PATH_MAX);
xstrlcpy(*path, g_buf + 1, PATH_MAX); xstrsncpy(*path, g_buf + 1, PATH_MAX);
} else if (ctx >= 1 && ctx <= CTX_MAX) { } else if (ctx >= 1 && ctx <= CTX_MAX) {
int r = ctx - 1; int r = ctx - 1;
@ -4524,7 +4490,7 @@ static int dentfill(char *path, struct entry **dents)
/* Selection file name */ /* Selection file name */
dentp->name = (char *)((size_t)pnamebuf + off); dentp->name = (char *)((size_t)pnamebuf + off);
dentp->nlen = xstrlcpy(dentp->name, namep, NAME_MAX + 1); dentp->nlen = xstrsncpy(dentp->name, namep, NAME_MAX + 1);
off += dentp->nlen; off += dentp->nlen;
/* Copy other fields */ /* Copy other fields */
@ -4850,7 +4816,7 @@ static bool set_time_type(int *presel)
for (; r < (int)ELEMENTS(time_type); ++r) for (; r < (int)ELEMENTS(time_type); ++r)
if (r != cfg.timetype) { if (r != cfg.timetype) {
chars += xstrlcpy(buf + chars, time_type[r], sizeof(buf) - chars) - 1; chars += xstrsncpy(buf + chars, time_type[r], sizeof(buf) - chars) - 1;
if (first) { if (first) {
buf[chars++] = ' '; buf[chars++] = ' ';
buf[chars++] = '/'; buf[chars++] = '/';
@ -4910,7 +4876,7 @@ static void statusbar(char *path)
if (cfg.blkorder) { /* du mode */ if (cfg.blkorder) { /* du mode */
char buf[24]; char buf[24];
xstrlcpy(buf, coolsize(dir_blocks << blk_shift), 12); xstrsncpy(buf, coolsize(dir_blocks << blk_shift), 12);
printw("%d/%d [%s:%s] %cu:%s free:%s files:%lu %lldB %s\n", printw("%d/%d [%s:%s] %cu:%s free:%s files:%lu %lldB %s\n",
cur + 1, ndents, (cfg.selmode ? "s" : ""), cur + 1, ndents, (cfg.selmode ? "s" : ""),
@ -5103,10 +5069,10 @@ static bool cdprep(char *lastdir, char *lastname, char *path, char *newpath)
lastname[0] = '\0'; lastname[0] = '\0';
/* Save last working directory */ /* Save last working directory */
xstrlcpy(lastdir, path, PATH_MAX); xstrsncpy(lastdir, path, PATH_MAX);
/* Save the newly opted dir in path */ /* Save the newly opted dir in path */
xstrlcpy(path, newpath, PATH_MAX); xstrsncpy(path, newpath, PATH_MAX);
DPRINTF_S(path); DPRINTF_S(path);
clearfilter(); clearfilter();
@ -5143,7 +5109,7 @@ static bool browse(char *ipath, const char *session)
/* setup first context */ /* setup first context */
if (!session || !load_session(session, &path, &lastdir, &lastname, FALSE)) { if (!session || !load_session(session, &path, &lastdir, &lastname, FALSE)) {
xstrlcpy(g_ctx[0].c_path, ipath, PATH_MAX); /* current directory */ xstrsncpy(g_ctx[0].c_path, ipath, PATH_MAX); /* current directory */
path = g_ctx[0].c_path; path = g_ctx[0].c_path;
g_ctx[0].c_last[0] = g_ctx[0].c_name[0] = '\0'; g_ctx[0].c_last[0] = g_ctx[0].c_name[0] = '\0';
lastdir = g_ctx[0].c_last; /* last visited directory */ lastdir = g_ctx[0].c_last; /* last visited directory */
@ -5295,7 +5261,7 @@ nochange:
goto nochange; goto nochange;
/* Save history */ /* Save history */
xstrlcpy(lastname, xbasename(path), NAME_MAX + 1); xstrsncpy(lastname, xbasename(path), NAME_MAX + 1);
cdprep(lastdir, NULL, path, dir) ? (presel = FILTER) : (watch = TRUE); cdprep(lastdir, NULL, path, dir) ? (presel = FILTER) : (watch = TRUE);
goto begin; goto begin;
@ -5427,7 +5393,7 @@ nochange:
if ((cfg.runctx == cfg.curctx) && !strcmp(path, plugindir)) { if ((cfg.runctx == cfg.curctx) && !strcmp(path, plugindir)) {
endselection(); endselection();
/* Copy path so we can return back to earlier dir */ /* Copy path so we can return back to earlier dir */
xstrlcpy(path, rundir, PATH_MAX); xstrsncpy(path, rundir, PATH_MAX);
rundir[0] = '\0'; rundir[0] = '\0';
if (!run_selected_plugin(&path, dents[cur].name, if (!run_selected_plugin(&path, dents[cur].name,
@ -5557,7 +5523,7 @@ nochange:
} }
/* SEL_CDLAST: dir pointing to lastdir */ /* SEL_CDLAST: dir pointing to lastdir */
xstrlcpy(newpath, dir, PATH_MAX); // fallthrough xstrsncpy(newpath, dir, PATH_MAX); // fallthrough
case SEL_BOOKMARK: case SEL_BOOKMARK:
if (sel == SEL_BOOKMARK) { if (sel == SEL_BOOKMARK) {
r = (int)handle_bookmark(mark, newpath); r = (int)handle_bookmark(mark, newpath);
@ -5928,7 +5894,7 @@ nochange:
plugscript(utils[UTIL_NTFY], NULL, F_NOWAIT | F_NOTRACE); plugscript(utils[UTIL_NTFY], NULL, F_NOWAIT | F_NOTRACE);
if (newpath[0] && !access(newpath, F_OK)) if (newpath[0] && !access(newpath, F_OK))
xstrlcpy(lastname, xbasename(newpath), NAME_MAX+1); xstrsncpy(lastname, xbasename(newpath), NAME_MAX+1);
else if (ndents) else if (ndents)
copycurname(); copycurname();
goto begin; goto begin;
@ -6019,7 +5985,7 @@ nochange:
mkpath(path, tmp, newpath); mkpath(path, tmp, newpath);
if (access(newpath, F_OK) == 0) { /* File created */ if (access(newpath, F_OK) == 0) { /* File created */
xstrlcpy(lastname, tmp, NAME_MAX + 1); xstrsncpy(lastname, tmp, NAME_MAX + 1);
clearfilter(); /* Archive name may not match */ clearfilter(); /* Archive name may not match */
goto begin; goto begin;
} }
@ -6090,7 +6056,7 @@ nochange:
goto nochange; goto nochange;
} }
close(fd); close(fd);
xstrlcpy(lastname, tmp, NAME_MAX + 1); xstrsncpy(lastname, tmp, NAME_MAX + 1);
} else { /* SEL_NEW */ } else { /* SEL_NEW */
close(fd); close(fd);
presel = 0; presel = 0;
@ -6116,7 +6082,7 @@ nochange:
goto nochange; goto nochange;
if (r == 'f' || r == 'd') if (r == 'f' || r == 'd')
xstrlcpy(lastname, tmp, NAME_MAX + 1); xstrsncpy(lastname, tmp, NAME_MAX + 1);
else if (ndents) { else if (ndents) {
if (cfg.filtermode) if (cfg.filtermode)
presel = FILTER; presel = FILTER;
@ -6134,7 +6100,7 @@ nochange:
goto nochange; goto nochange;
} }
r = xstrlcpy(g_buf, messages[MSG_PLUGIN_KEYS], CMD_LEN_MAX); r = xstrsncpy(g_buf, messages[MSG_PLUGIN_KEYS], CMD_LEN_MAX);
printkeys(plug, g_buf + r - 1, maxplug); printkeys(plug, g_buf + r - 1, maxplug);
printmsg(g_buf); printmsg(g_buf);
r = get_input(NULL); r = get_input(NULL);
@ -6173,8 +6139,8 @@ nochange:
* switch to original directory * switch to original directory
*/ */
if (strcmp(path, plugindir) == 0) { if (strcmp(path, plugindir) == 0) {
xstrlcpy(path, rundir, PATH_MAX); xstrsncpy(path, rundir, PATH_MAX);
xstrlcpy(lastname, runfile, NAME_MAX); xstrsncpy(lastname, runfile, NAME_MAX);
rundir[0] = runfile[0] = '\0'; rundir[0] = runfile[0] = '\0';
setdirwatch(); setdirwatch();
goto begin; goto begin;
@ -6184,10 +6150,10 @@ nochange:
cfg.runplugin = 1; cfg.runplugin = 1;
} }
xstrlcpy(rundir, path, PATH_MAX); xstrsncpy(rundir, path, PATH_MAX);
xstrlcpy(path, plugindir, PATH_MAX); xstrsncpy(path, plugindir, PATH_MAX);
if (ndents) if (ndents)
xstrlcpy(runfile, dents[cur].name, NAME_MAX); xstrsncpy(runfile, dents[cur].name, NAME_MAX);
cfg.runctx = cfg.curctx; cfg.runctx = cfg.curctx;
lastname[0] = '\0'; lastname[0] = '\0';
} }
@ -6362,8 +6328,8 @@ static char *make_tmp_tree(char **paths, ssize_t entries, const char *prefix)
} }
tmp = tmpdir + tmpfplen - 1; tmp = tmpdir + tmpfplen - 1;
xstrlcpy(tmpdir, g_tmpfpath, tmpfplen); xstrsncpy(tmpdir, g_tmpfpath, tmpfplen);
xstrlcpy(tmp, "/nnnXXXXXX", 11); xstrsncpy(tmp, "/nnnXXXXXX", 11);
/* Points right after the base tmp dir */ /* Points right after the base tmp dir */
tmp += 10; tmp += 10;
@ -6388,7 +6354,7 @@ static char *make_tmp_tree(char **paths, ssize_t entries, const char *prefix)
} }
/* Don't copy the common prefix */ /* Don't copy the common prefix */
xstrlcpy(tmp, paths[i] + len, strlen(paths[i]) - len + 1); xstrsncpy(tmp, paths[i] + len, strlen(paths[i]) - len + 1);
/* Get the dir containing the path */ /* Get the dir containing the path */
slash = xmemrchr((uchar *)tmp, '/', strlen(paths[i]) - len); slash = xmemrchr((uchar *)tmp, '/', strlen(paths[i]) - len);
@ -6530,7 +6496,7 @@ static char *load_input()
DPRINTF_S(paths[i]); DPRINTF_S(paths[i]);
xstrlcpy(g_buf, paths[i], PATH_MAX); xstrsncpy(g_buf, paths[i], PATH_MAX);
if (!common_prefix(dirname(g_buf), prefixpath)) { if (!common_prefix(dirname(g_buf), prefixpath)) {
entries = i + 1; // free from the current entry entries = i + 1; // free from the current entry
goto malloc_2; goto malloc_2;
@ -6625,8 +6591,8 @@ static bool setup_config(void)
if (xdgcfg && xdgcfg[0]) { if (xdgcfg && xdgcfg[0]) {
DPRINTF_S(xdgcfg); DPRINTF_S(xdgcfg);
if (xdgcfg[0] == '~') { if (xdgcfg[0] == '~') {
r = xstrlcpy(g_buf, home, PATH_MAX); r = xstrsncpy(g_buf, home, PATH_MAX);
xstrlcpy(g_buf + r - 1, xdgcfg + 1, PATH_MAX); xstrsncpy(g_buf + r - 1, xdgcfg + 1, PATH_MAX);
xdgcfg = g_buf; xdgcfg = g_buf;
DPRINTF_S(xdgcfg); DPRINTF_S(xdgcfg);
} }
@ -6652,24 +6618,24 @@ static bool setup_config(void)
} }
if (xdg) { if (xdg) {
xstrlcpy(cfgdir, xdgcfg, len); xstrsncpy(cfgdir, xdgcfg, len);
r = len - 13; /* subtract length of "/nnn/sessions" */ r = len - 13; /* subtract length of "/nnn/sessions" */
} else { } else {
r = xstrlcpy(cfgdir, home, len); r = xstrsncpy(cfgdir, home, len);
/* Create ~/.config */ /* Create ~/.config */
xstrlcpy(cfgdir + r - 1, "/.config", len - r); xstrsncpy(cfgdir + r - 1, "/.config", len - r);
DPRINTF_S(cfgdir); DPRINTF_S(cfgdir);
r += 8; /* length of "/.config" */ r += 8; /* length of "/.config" */
} }
/* Create ~/.config/nnn */ /* Create ~/.config/nnn */
xstrlcpy(cfgdir + r - 1, "/nnn", len - r); xstrsncpy(cfgdir + r - 1, "/nnn", len - r);
DPRINTF_S(cfgdir); DPRINTF_S(cfgdir);
/* Create ~/.config/nnn/plugins */ /* Create ~/.config/nnn/plugins */
xstrlcpy(plugindir, cfgdir, PATH_MAX); xstrsncpy(plugindir, cfgdir, PATH_MAX);
xstrlcpy(plugindir + r + 4 - 1, "/plugins", 9); /* subtract length of "/nnn" (4) */ xstrsncpy(plugindir + r + 4 - 1, "/plugins", 9); /* subtract length of "/nnn" (4) */
DPRINTF_S(plugindir); DPRINTF_S(plugindir);
if (access(plugindir, F_OK) && !xmktree(plugindir, TRUE)) { if (access(plugindir, F_OK) && !xmktree(plugindir, TRUE)) {
@ -6678,8 +6644,8 @@ static bool setup_config(void)
} }
/* Create ~/.config/nnn/sessions */ /* Create ~/.config/nnn/sessions */
xstrlcpy(sessiondir, cfgdir, PATH_MAX); xstrsncpy(sessiondir, cfgdir, PATH_MAX);
xstrlcpy(sessiondir + r + 4 - 1, "/sessions", 10); /* subtract length of "/nnn" (4) */ xstrsncpy(sessiondir + r + 4 - 1, "/sessions", 10); /* subtract length of "/nnn" (4) */
DPRINTF_S(sessiondir); DPRINTF_S(sessiondir);
if (access(sessiondir, F_OK) && !xmktree(sessiondir, TRUE)) { if (access(sessiondir, F_OK) && !xmktree(sessiondir, TRUE)) {
@ -6696,8 +6662,8 @@ static bool setup_config(void)
return FALSE; return FALSE;
} }
r = xstrlcpy(selpath, cfgdir, len + 3); r = xstrsncpy(selpath, cfgdir, len + 3);
xstrlcpy(selpath + r - 1, "/.selection", 12); xstrsncpy(selpath + r - 1, "/.selection", 12);
DPRINTF_S(selpath); DPRINTF_S(selpath);
} }
@ -6714,7 +6680,7 @@ static bool set_tmp_path(void)
return FALSE; return FALSE;
} }
tmpfplen = (uchar)xstrlcpy(g_tmpfpath, path, TMP_LEN_MAX); tmpfplen = (uchar)xstrsncpy(g_tmpfpath, path, TMP_LEN_MAX);
return TRUE; return TRUE;
} }