Browse Source

noice: No need to perform so many memory allocations

The code was quite fragile.  As a first pass, use buffers of size
PATH_MAX and LINE_MAX accordingly until we simplify the overall logic.
master
sin 8 years ago
parent
commit
65fae61bea
1 changed files with 55 additions and 85 deletions
  1. +55
    -85
      noice.c

+ 55
- 85
noice.c View File

@@ -74,7 +74,7 @@ struct key {
#include "config.h" #include "config.h"


struct entry { struct entry {
char *name;
char name[PATH_MAX];
mode_t mode; mode_t mode;
time_t t; time_t t;
}; };
@@ -82,8 +82,8 @@ struct entry {
/* Global context */ /* Global context */
struct entry *dents; struct entry *dents;
int n, cur; int n, cur;
char *path, *oldpath;
char *fltr;
char path[PATH_MAX], oldpath[PATH_MAX];
char fltr[LINE_MAX];
int idle; int idle;


/* /*
@@ -106,7 +106,7 @@ int idle;
void printmsg(char *); void printmsg(char *);
void printwarn(void); void printwarn(void);
void printerr(int, char *); void printerr(int, char *);
char *mkpath(char *, char *);
char *mkpath(char *, char *, char *, size_t);


#undef dprintf #undef dprintf
int int
@@ -155,20 +155,20 @@ xstrdup(const char *s)
return p; return p;
} }


/* Some implementations of dirname(3) may modify `path' and some
* return a pointer inside `path'. */
char * char *
xdirname(const char *path) xdirname(const char *path)
{ {
static char out[PATH_MAX];
char tmp[PATH_MAX], *p; char tmp[PATH_MAX], *p;


/* Some implementations of dirname(3) may modify `path' and some
* return a pointer inside `path' and we cannot free(3) the
* original string if we lose track of it. */
strlcpy(tmp, path, sizeof(tmp)); strlcpy(tmp, path, sizeof(tmp));
p = dirname(tmp); p = dirname(tmp);
if (p == NULL) if (p == NULL)
printerr(1, "dirname"); printerr(1, "dirname");
/* Make sure this is a malloc(3)-ed string */
return xstrdup(p);
strlcpy(out, p, sizeof(out));
return out;
} }


void void
@@ -226,15 +226,17 @@ openwith(char *file)
int int
setfilter(regex_t *regex, char *filter) setfilter(regex_t *regex, char *filter)
{ {
char *errbuf;
char errbuf[LINE_MAX];
size_t len;
int r; int r;


r = regcomp(regex, filter, REG_NOSUB | REG_EXTENDED | REG_ICASE); r = regcomp(regex, filter, REG_NOSUB | REG_EXTENDED | REG_ICASE);
if (r != 0) { if (r != 0) {
errbuf = xmalloc(COLS);
regerror(r, regex, errbuf, COLS);
len = COLS;
if (len > sizeof(errbuf))
len = sizeof(errbuf);
regerror(r, regex, errbuf, len);
printmsg(errbuf); printmsg(errbuf);
free(errbuf);
} }


return r; return r;
@@ -461,10 +463,10 @@ int
dentfill(char *path, struct entry **dents, dentfill(char *path, struct entry **dents,
int (*filter)(regex_t *, char *), regex_t *re) int (*filter)(regex_t *, char *), regex_t *re)
{ {
char newpath[PATH_MAX];
DIR *dirp; DIR *dirp;
struct dirent *dp; struct dirent *dp;
struct stat sb; struct stat sb;
char *newpath;
int r, n = 0; int r, n = 0;


dirp = opendir(path); dirp = opendir(path);
@@ -479,13 +481,12 @@ dentfill(char *path, struct entry **dents,
if (filter(re, dp->d_name) == 0) if (filter(re, dp->d_name) == 0)
continue; continue;
*dents = xrealloc(*dents, (n + 1) * sizeof(**dents)); *dents = xrealloc(*dents, (n + 1) * sizeof(**dents));
(*dents)[n].name = xstrdup(dp->d_name);
strlcpy((*dents)[n].name, dp->d_name, sizeof((*dents)[n].name));
/* Get mode flags */ /* Get mode flags */
newpath = mkpath(path, dp->d_name);
mkpath(path, dp->d_name, newpath, sizeof(newpath));
r = lstat(newpath, &sb); r = lstat(newpath, &sb);
if (r == -1) if (r == -1)
printerr(1, "lstat"); printerr(1, "lstat");
free(newpath);
(*dents)[n].mode = sb.st_mode; (*dents)[n].mode = sb.st_mode;
(*dents)[n].t = sb.st_mtime; (*dents)[n].t = sb.st_mtime;
n++; n++;
@@ -500,58 +501,47 @@ dentfill(char *path, struct entry **dents,
} }


void void
dentfree(struct entry *dents, int n)
dentfree(struct entry *dents)
{ {
int i;

for (i = 0; i < n; i++)
free(dents[i].name);
free(dents); free(dents);
} }


char * char *
mkpath(char *dir, char *name)
mkpath(char *dir, char *name, char *out, size_t n)
{ {
char path[PATH_MAX];

/* Handle absolute path */ /* Handle absolute path */
if (name[0] == '/') { if (name[0] == '/') {
strlcpy(path, name, sizeof(path));
strlcpy(out, name, n);
} else { } else {
/* Handle root case */ /* Handle root case */
if (strcmp(dir, "/") == 0) { if (strcmp(dir, "/") == 0) {
strlcpy(path, "/", sizeof(path));
strlcat(path, name, sizeof(path));
strlcpy(out, "/", n);
strlcat(out, name, n);
} else { } else {
strlcpy(path, dir, sizeof(path));
strlcat(path, "/", sizeof(path));
strlcat(path, name, sizeof(path));
strlcpy(out, dir, n);
strlcat(out, "/", n);
strlcat(out, name, n);
} }
} }
return xstrdup(path);
return out;
} }


/* Return the position of the matching entry or 0 otherwise */ /* Return the position of the matching entry or 0 otherwise */
int int
dentfind(struct entry *dents, int n, char *cwd, char *path) dentfind(struct entry *dents, int n, char *cwd, char *path)
{ {
char tmp[PATH_MAX];
int i; int i;
char *tmp;


if (path == NULL) if (path == NULL)
return 0; return 0;

for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
tmp = mkpath(cwd, dents[i].name);
mkpath(cwd, dents[i].name, tmp, sizeof(tmp));
DPRINTF_S(path); DPRINTF_S(path);
DPRINTF_S(tmp); DPRINTF_S(tmp);
if (strcmp(tmp, path) == 0) {
free(tmp);
if (strcmp(tmp, path) == 0)
return i; return i;
}
free(tmp);
} }

return 0; return 0;
} }


@@ -570,7 +560,7 @@ populate(void)
if (r != 0) if (r != 0)
return -1; return -1;


dentfree(dents, n);
dentfree(dents);


n = 0; n = 0;
dents = NULL; dents = NULL;
@@ -581,9 +571,6 @@ populate(void)


/* Find cur from history */ /* Find cur from history */
cur = dentfind(dents, n, path, oldpath); cur = dentfind(dents, n, path, oldpath);
free(oldpath);
oldpath = NULL;

return 0; return 0;
} }


@@ -638,18 +625,16 @@ redraw(void)
void void
browse(const char *ipath, const char *ifilter) browse(const char *ipath, const char *ifilter)
{ {
int r, fd;
regex_t re;
char *newpath;
struct stat sb;
char newpath[PATH_MAX];
char *name, *bin, *dir, *tmp, *run, *env; char *name, *bin, *dir, *tmp, *run, *env;
struct stat sb;
regex_t re;
int r, fd;
int nowtyping = 0; int nowtyping = 0;


oldpath = NULL;
path = xstrdup(ipath);
fltr = xstrdup(ifilter);
strlcpy(path, ipath, sizeof(path));
strlcpy(fltr, ifilter, sizeof(fltr));
begin: begin:
/* Path and filter should be malloc(3)-ed strings at all times */
r = populate(); r = populate();
if (r == -1) { if (r == -1) {
if (!nowtyping) { if (!nowtyping) {
@@ -667,9 +652,7 @@ begin:
nochange: nochange:
switch (nextsel(&run, &env)) { switch (nextsel(&run, &env)) {
case SEL_QUIT: case SEL_QUIT:
free(path);
free(fltr);
dentfree(dents, n);
dentfree(dents);
return; return;
case SEL_BACK: case SEL_BACK:
/* There is no going back */ /* There is no going back */
@@ -679,16 +662,14 @@ nochange:
goto nochange; goto nochange;
dir = xdirname(path); dir = xdirname(path);
if (canopendir(dir) == 0) { if (canopendir(dir) == 0) {
free(dir);
printwarn(); printwarn();
goto nochange; goto nochange;
} }
/* Save history */ /* Save history */
oldpath = path;
path = dir;
strlcpy(oldpath, path, sizeof(path));
strlcpy(path, dir, sizeof(path));
/* Reset filter */ /* Reset filter */
free(fltr);
fltr = xstrdup(ifilter);
strlcpy(fltr, ifilter, sizeof(fltr));
goto begin; goto begin;
case SEL_GOIN: case SEL_GOIN:
/* Cannot descend in empty directories */ /* Cannot descend in empty directories */
@@ -696,21 +677,19 @@ nochange:
goto nochange; goto nochange;


name = dents[cur].name; name = dents[cur].name;
newpath = mkpath(path, name);
mkpath(path, name, newpath, sizeof(newpath));
DPRINTF_S(newpath); DPRINTF_S(newpath);


/* Get path info */ /* Get path info */
fd = open(newpath, O_RDONLY | O_NONBLOCK); fd = open(newpath, O_RDONLY | O_NONBLOCK);
if (fd == -1) { if (fd == -1) {
printwarn(); printwarn();
free(newpath);
goto nochange; goto nochange;
} }
r = fstat(fd, &sb); r = fstat(fd, &sb);
if (r == -1) { if (r == -1) {
printwarn(); printwarn();
close(fd); close(fd);
free(newpath);
goto nochange; goto nochange;
} }
close(fd); close(fd);
@@ -720,26 +699,21 @@ nochange:
case S_IFDIR: case S_IFDIR:
if (canopendir(newpath) == 0) { if (canopendir(newpath) == 0) {
printwarn(); printwarn();
free(newpath);
goto nochange; goto nochange;
} }
free(path);
path = newpath;
strlcpy(path, newpath, sizeof(path));
/* Reset filter */ /* Reset filter */
free(fltr);
fltr = xstrdup(ifilter);
strlcpy(fltr, ifilter, sizeof(fltr));
goto begin; goto begin;
case S_IFREG: case S_IFREG:
bin = openwith(newpath); bin = openwith(newpath);
if (bin == NULL) { if (bin == NULL) {
printmsg("No association"); printmsg("No association");
free(newpath);
goto nochange; goto nochange;
} }
exitcurses(); exitcurses();
spawn(bin, newpath, NULL); spawn(bin, newpath, NULL);
initcurses(); initcurses();
free(newpath);
continue; continue;
default: default:
printmsg("Unsupported file"); printmsg("Unsupported file");
@@ -757,12 +731,11 @@ nochange:
free(tmp); free(tmp);
goto nochange; goto nochange;
} }
free(fltr);
fltr = tmp;
strlcpy(fltr, tmp, sizeof(fltr));
DPRINTF_S(fltr); DPRINTF_S(fltr);
/* Save current */ /* Save current */
if (n > 0) if (n > 0)
oldpath = mkpath(path, dents[cur].name);
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
goto begin; goto begin;
case SEL_TYPE: case SEL_TYPE:
nowtyping = 1; nowtyping = 1;
@@ -788,14 +761,13 @@ moretyping:
} }
} }
/* Copy or reset filter */ /* Copy or reset filter */
free(fltr);
if (tmp != NULL) if (tmp != NULL)
fltr = xstrdup(tmp);
strlcpy(fltr, tmp, sizeof(fltr));
else else
fltr = xstrdup(ifilter);
strlcpy(fltr, ifilter, sizeof(fltr));
/* Save current */ /* Save current */
if (n > 0) if (n > 0)
oldpath = mkpath(path, dents[cur].name);
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
if (!nowtyping) if (!nowtyping)
free(tmp); free(tmp);
goto begin; goto begin;
@@ -829,29 +801,27 @@ moretyping:
clearprompt(); clearprompt();
goto nochange; goto nochange;
} }
newpath = mkpath(path, tmp);
mkpath(path, tmp, newpath, sizeof(newpath));
free(tmp); free(tmp);
if (canopendir(newpath) == 0) { if (canopendir(newpath) == 0) {
free(newpath);
printwarn(); printwarn();
goto nochange; goto nochange;
} }
free(path);
path = newpath;
free(fltr);
fltr = xstrdup(ifilter); /* Reset filter */
strlcpy(path, newpath, sizeof(path));
/* Reset filter */
strlcpy(fltr, ifilter, sizeof(fltr))
DPRINTF_S(path); DPRINTF_S(path);
goto begin; goto begin;
case SEL_MTIME: case SEL_MTIME:
mtimeorder = !mtimeorder; mtimeorder = !mtimeorder;
/* Save current */ /* Save current */
if (n > 0) if (n > 0)
oldpath = mkpath(path, dents[cur].name);
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
goto begin; goto begin;
case SEL_REDRAW: case SEL_REDRAW:
/* Save current */ /* Save current */
if (n > 0) if (n > 0)
oldpath = mkpath(path, dents[cur].name);
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
goto begin; goto begin;
case SEL_RUN: case SEL_RUN:
run = xgetenv(env, run); run = xgetenv(env, run);


Loading…
Cancel
Save