1
1
mirror of https://github.com/jarun/nnn.git synced 2024-10-26 14:28:31 +03:00

Improve archive, rename, new workflows

1. hover on entry created in cwd
2. check user input doesn't end with /
3. check user input len < PATH_MAX
4. support creation in ~ directory
5. handle filter mode after creation
6. ensure absolute path len < PATH_MAX
This commit is contained in:
Arun Prakash Jana 2022-12-12 09:52:16 +05:30
parent 32a6a63f44
commit e8bc59a816
No known key found for this signature in database
GPG Key ID: A75979F35C080412

105
src/nnn.c
View File

@ -1008,6 +1008,32 @@ static inline bool is_prefix(const char *restrict str, const char *restrict pref
return !strncmp(str, prefix, len); return !strncmp(str, prefix, len);
} }
static inline bool is_bad_len_or_dir(const char *restrict path)
{
size_t len = xstrlen(path);
return ((len >= PATH_MAX) || (path[len - 1] == '/'));
}
static char *get_cwd_entry(const char *restrict cwdpath, char *entrypath, size_t *tokenlen)
{
size_t len = xstrlen(cwdpath);
char *end;
if (!is_prefix(entrypath, cwdpath, len))
return NULL;
entrypath += len + 1; /* Add 1 for trailing / */
end = strchr(entrypath, '/');
if (end)
*tokenlen = end - entrypath;
else
*tokenlen = xstrlen(entrypath);
DPRINTF_U(*tokenlen);
return entrypath;
}
/* /*
* The poor man's implementation of memrchr(3). * The poor man's implementation of memrchr(3).
* We are only looking for '/' and '.' in this program. * We are only looking for '/' and '.' in this program.
@ -1246,6 +1272,12 @@ static char *abspath(const char *filepath, char *cwd, char *buf)
resolved_path[1] = '\0'; resolved_path[1] = '\0';
} }
if (xstrlen(resolved_path) >= PATH_MAX) {
if (!buf)
free(resolved_path);
return NULL;
}
return resolved_path; return resolved_path;
} }
@ -7511,7 +7543,8 @@ nochange:
case SEL_NEW: // fallthrough case SEL_NEW: // fallthrough
case SEL_RENAME: case SEL_RENAME:
{ {
int fd, ret = 'n'; int ret = 'n';
size_t len;
if (!ndents && (sel == SEL_OPENWITH || sel == SEL_RENAME)) if (!ndents && (sel == SEL_OPENWITH || sel == SEL_RENAME))
break; break;
@ -7572,7 +7605,7 @@ nochange:
break; break;
} }
if (!tmp || !*tmp) if (!tmp || !*tmp || is_bad_len_or_dir(tmp))
break; break;
switch (sel) { switch (sel) {
@ -7592,15 +7625,16 @@ nochange:
NULL, F_CLI | F_CONFIRM); NULL, F_CLI | F_CONFIRM);
if (tmp && (access(tmp, F_OK) == 0)) { /* File created */ if (tmp && (access(tmp, F_OK) == 0)) { /* File created */
char *base = xbasename(tmp); if (r == 's')
char *parent = xdirname(tmp); clearselection(); /* Archive operation complete */
/* Check if file is created in the current directory */ /* Check if any entry is created in the current directory */
if (strcmp(path, parent) == 0) { tmp = get_cwd_entry(path, tmp, &len);
xstrsncpy(lastname, base, NAME_MAX + 1); if (tmp) {
xstrsncpy(lastname, tmp, len + 1);
clearfilter(); /* Archive name may not match */ clearfilter(); /* Archive name may not match */
} } if (cfg.filtermode)
clearselection(); /* Archive operation complete */ presel = FILTER;
cd = FALSE; cd = FALSE;
goto begin; goto begin;
} }
@ -7612,10 +7646,12 @@ nochange:
copycurname(); copycurname();
goto nochange; goto nochange;
case SEL_RENAME: case SEL_RENAME:
r = 0;
/* Skip renaming to same name */ /* Skip renaming to same name */
if (strcmp(tmp, pdents[cur].name) == 0) { if (strcmp(tmp, pdents[cur].name) == 0) {
tmp = xreadline(pdents[cur].name, messages[MSG_COPY_NAME]); tmp = xreadline(pdents[cur].name, messages[MSG_COPY_NAME]);
if (!tmp || !tmp[0] || !strcmp(tmp, pdents[cur].name)) { if (!tmp || !tmp[0] || is_bad_len_or_dir(tmp)
|| !strcmp(tmp, pdents[cur].name)) {
cfg.filtermode ? presel = FILTER : statusbar(path); cfg.filtermode ? presel = FILTER : statusbar(path);
copycurname(); copycurname();
goto nochange; goto nochange;
@ -7627,28 +7663,22 @@ nochange:
break; break;
} }
/* Open the descriptor to currently open directory */ if (!(r == 's' || r == 'h')) {
#ifdef O_DIRECTORY tmp = abspath(tmp, NULL, newpath);
fd = open(path, O_RDONLY | O_DIRECTORY); if (!tmp) {
#else printwarn(&presel);
fd = open(path, O_RDONLY); goto nochange;
#endif }
if (fd == -1) {
printwarn(&presel);
goto nochange;
} }
/* Check if another file with same name exists */ /* Check if another file with same name exists */
if (fstatat(fd, tmp, &sb, AT_SYMLINK_NOFOLLOW) == 0) { if (lstat(tmp, &sb) == 0) {
if ((sel == SEL_RENAME) || ((r == 'f') && (S_ISREG(sb.st_mode)))) { if ((sel == SEL_RENAME) || ((r == 'f') && (S_ISREG(sb.st_mode)))) {
/* Overwrite file with same name? */ /* Overwrite file with same name? */
if (!xconfirm(get_input(messages[MSG_OVERWRITE]))) { if (!xconfirm(get_input(messages[MSG_OVERWRITE])))
close(fd);
break; break;
}
} else { } else {
/* Do nothing for SEL_NEW if a non-regular entry exists */ /* Do nothing for SEL_NEW if a non-regular entry exists */
close(fd);
printwait(messages[MSG_EXISTS], &presel); printwait(messages[MSG_EXISTS], &presel);
goto nochange; goto nochange;
} }
@ -7658,21 +7688,22 @@ nochange:
/* Rename the file */ /* Rename the file */
if (ret == 'd') if (ret == 'd')
spawn("cp -rp", pdents[cur].name, tmp, NULL, F_SILENT); spawn("cp -rp", pdents[cur].name, tmp, NULL, F_SILENT);
else if (renameat(fd, pdents[cur].name, fd, tmp) != 0) { else if (rename(pdents[cur].name, tmp) != 0) {
close(fd);
printwarn(&presel); printwarn(&presel);
goto nochange; goto nochange;
} }
close(fd);
xstrsncpy(lastname, tmp, NAME_MAX + 1); /* Check if any entry is created in the current directory */
tmp = get_cwd_entry(path, tmp, &len);
if (tmp)
xstrsncpy(lastname, tmp, len + 1);
/* Directory must be reloeaded for rename case */
} else { /* SEL_NEW */ } else { /* SEL_NEW */
close(fd);
presel = 0; presel = 0;
/* Check if it's a dir or file */ /* Check if it's a dir or file */
if (r == 'f' || r == 'd') { if (r == 'f' || r == 'd') {
mkpath(path, tmp, newpath); ret = xmktree(tmp, r == 'f' ? FALSE : TRUE);
ret = xmktree(newpath, r == 'f' ? FALSE : TRUE);
} else if (r == 's' || r == 'h') { } else if (r == 's' || r == 'h') {
if (nselected > 1 && tmp[0] == '@' && tmp[1] == '\0') if (nselected > 1 && tmp[0] == '@' && tmp[1] == '\0')
tmp[0] = '\0'; tmp[0] = '\0';
@ -7686,15 +7717,19 @@ nochange:
if (ret <= 0) if (ret <= 0)
goto nochange; goto nochange;
if (r == 'f' || r == 'd') if (r == 'f' || r == 'd') {
xstrsncpy(lastname, tmp, NAME_MAX + 1); tmp = get_cwd_entry(path, tmp, &len);
else if (ndents) { if (tmp)
xstrsncpy(lastname, tmp, len + 1);
else
continue; /* No change in directory */
} else if (ndents) {
if (cfg.filtermode) if (cfg.filtermode)
presel = FILTER; presel = FILTER;
copycurname(); copycurname();
} }
clearfilter();
} }
clearfilter();
cd = FALSE; cd = FALSE;
goto begin; goto begin;