cex

C/Curses file EXplorer
git clone git://git.wimdupont.com/cex.git
Log | Files | Refs | README | LICENSE

commit 47367e6f8624effc2735a592094acf41b814f42f
parent fa9721fc35ae7afa230f86ed6fbb10ba6c12a4f1
Author: Wim Dupont <wim@wimdupont.com>
Date:   Mon,  6 Apr 2026 18:12:08 +0200

added safety checks

Diffstat:
MMakefile | 9++++++---
Mcex.c | 59++++++++++++++++++++++++++++++++++++++++++-----------------
Mconfig.mk | 1+
3 files changed, 49 insertions(+), 20 deletions(-)

diff --git a/Makefile b/Makefile @@ -5,10 +5,10 @@ SRC = cex.c OBJ = ${SRC:.c=.o} MAN1 = ${BIN:=.1} -${OBJ}: config.h - all: ${BIN} +${OBJ}: config.h + LDFLAGS=-lncurses $(LIBGIT2_LDFLAGS) .c.o: @@ -23,6 +23,9 @@ config.h: clean: rm -f ${BIN} ${OBJ} +strict: config.h + ${CC} -g -c ${STRICTCFLAGS} ${SRC} -o /tmp/${OBJ} + install: all mkdir -p ${DESTDIR}${PREFIX}/bin cp -f ${BIN} "${DESTDIR}${PREFIX}/bin" @@ -36,4 +39,4 @@ uninstall: "${DESTDIR}${PREFIX}/bin/${BIN}"\ "${DESTDIR}${MANPREFIX}/man1/${MAN1}" -.PHONY: all clean install uninstall +.PHONY: all clean install strict uninstall diff --git a/cex.c b/cex.c @@ -115,7 +115,7 @@ static char *human_readable_bytes(char *buf, intmax_t bytes); static char *prompt_answer(char *buf, size_t size, const char *question); static char *cpstr(char *dest, const char *src); static char *substr(char *buf, const char *haystack, const char *needle, const bool casesens); -static char *get_file_info(char *buf, const char *filepath); +static char *get_file_info(char *buf, size_t bufsize, const char *filepath); static char *get_fullpath(char *buf, DirWin *dirwin, size_t index); static char *get_dirname(char *buf, const char *path); static char *replace_home(char *buf, const char *path); @@ -564,6 +564,8 @@ set_win_message(DirWin *dirwin, char *message) void print_win(DirWin *dirwin) { + const char *curbase; + if (dirwin->holdupdate) return; @@ -586,11 +588,16 @@ print_win(DirWin *dirwin) wattroff(dirwin->window, COLOR_PAIR(CHILDWIN_MESSAGE_COLOR)); } } else if (dirwin->winfiles != NULL) { + curbase = strrchr(curwin.path, '/'); + if (curbase != NULL && curbase != curwin.path) + curbase++; + else if (curbase == NULL) + curbase = curwin.path; while (!dirwin->usehighlight) { for (int i = 0; i < dirwin->filecount; ++i) { memcpy(name, dirwin->winfiles[i].d_name, size); name[size] = '\0'; - if (strcmp(basename(curwin.path), dirwin->winfiles[i].d_name) == 0) { + if (strcmp(curbase, dirwin->winfiles[i].d_name) == 0) { dirwin->usehighlight = TRUE; dirwin->highlight = i; set_startpr(dirwin); @@ -694,18 +701,23 @@ update_child_win(void) void print_top_title(void) { - char path[PATH_MAX + sizeof(curwin.path)]; + char path[PATH_MAX]; move(0, 0); clrtoeol(); - snprintf(path, sizeof(path), "%s/%s", curwin.path, curwin.winfiles[curwin.highlight].d_name); + if (curwin.filecount == 0) { + cpstr(path, curwin.path); + if (strcmp(path, "/") != 0) + strcat(path, "/"); + } else + get_fullpath(path, &curwin, curwin.highlight); attron(COLOR_PAIR(TOP_TITLE_COLOR)); #if GIT_INFO truncate_buf_prefix(path, sizeof(path), maxx - strlen(username) - 2 - strlen(gitbranch)); printw("%s:%s", username, path); attron(COLOR_PAIR(GIT_BRANCH_COLOR)); - printw(gitbranch); + printw("%s", gitbranch); attroff(COLOR_PAIR(GIT_BRANCH_COLOR)); #else truncate_buf_prefix(path, sizeof(path), maxx - strlen(username) - 2); @@ -717,11 +729,13 @@ print_top_title(void) void print_bot_title(void) { - char pathbuf[PATH_MAX], fileinf[maxx]; + char pathbuf[PATH_MAX], fileinf[maxx + 1]; - get_fullpath(pathbuf, &curwin, curwin.highlight); - memcpy(fileinf, get_file_info(fileinf, pathbuf), maxx); - fileinf[maxx] = '\0'; + if (curwin.filecount == 0) + fileinf[0] = '\0'; + else + get_file_info(fileinf, sizeof(fileinf), + get_fullpath(pathbuf, &curwin, curwin.highlight)); move(maxy-1, 0); clrtoeol(); @@ -736,7 +750,7 @@ print_bot_title(void) } char * -get_file_info(char *buf, const char *filepath) +get_file_info(char *buf, size_t bufsize, const char *filepath) { struct stat statbuf; struct passwd *usr; @@ -781,7 +795,7 @@ get_file_info(char *buf, const char *filepath) tm = localtime(&statbuf.st_mtime); strftime(datestr, sizeof(datestr), nl_langinfo(D_T_FMT), tm); - sprintf(buf, "%10.10s %s %s %s %s", + snprintf(buf, bufsize, "%10.10s %s %s %s %s", mods, usr->pw_name, grp->gr_name, @@ -1300,9 +1314,11 @@ get_st_mode(DirWin *dirwin, size_t index) { struct stat statbuf; char linkpath[PATH_MAX], abspath[PATH_MAX]; + char *resolved; get_fullpath(linkpath, dirwin, index); - if (lstat(realpath(linkpath, abspath), &statbuf) >= 0) + resolved = realpath(linkpath, abspath); + if (resolved != NULL && lstat(resolved, &statbuf) >= 0) return statbuf.st_mode; return -1; @@ -1375,9 +1391,12 @@ prompt_answer(char *buf, size_t size, const char *question) addstr(question); attroff(COLOR_PAIR(PROMPT_COLOR)); + if (size == 0) + return buf; + echo(); curs_set(1); - getnstr(buf, size); + getnstr(buf, (int) size - 1); noecho(); curs_set(0); @@ -1387,14 +1406,14 @@ prompt_answer(char *buf, size_t size, const char *question) bool prompt_confirm(size_t size, const char *fmt, ...) { - char response[1], question[size]; + char response[2], question[size]; va_list ap; va_start(ap, fmt); vsnprintf(question, size, fmt, ap); va_end(ap); - prompt_answer(response, 1, question); + prompt_answer(response, sizeof(response), question); return strcasecmp(response, "y") == 0; } @@ -1610,7 +1629,8 @@ make_chown(void) { struct passwd *usr; struct group *grp; - long len = sysconf(_SC_LOGIN_NAME_MAX); + long maxlogin = sysconf(_SC_LOGIN_NAME_MAX); + size_t len = maxlogin > 0 ? (size_t) maxlogin + 1 : 256; char owner[len], group[len], *err; prompt_answer(owner, len, "Owner name? "); @@ -1633,7 +1653,7 @@ make_chown(void) switch (errno) { case EACCES: case EPERM: - sudo_chown(owner, group, len); + sudo_chown(owner, group, (long) len); break; default: err = "Error during chown: %d."; @@ -1783,6 +1803,11 @@ substr(char *buf, const char *haystack, const char *needle, const bool casesens) char * get_fullpath(char *buf, DirWin *dirwin, size_t index) { + if (dirwin->filecount == 0 || dirwin->winfiles == NULL) { + buf[0] = '\0'; + return buf; + } + index = MIN(index, dirwin->filecount-1); index = MAX(index, 0); diff --git a/config.mk b/config.mk @@ -4,6 +4,7 @@ VERSION = 0.1 CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" CFLAGS = -std=c99 -pedantic -Wall -Wextra -I/usr/local/include ${CPPFLAGS} +STRICTCFLAGS = ${CFLAGS} -Wshadow -Wconversion -Wformat=2 PREFIX = /usr/local MANPREFIX = ${PREFIX}/share/man