fe

terminal file explorer and picker

git clone https://9o.is/git/fe.git

commit ca95bad8a50f50dd7e71ff3926df0bc75208a458
parent 7425f960ebff80875ad5f4492c1fef67f42cb4ea
Author: Jul <jul@9o.is>
Date:   Tue, 27 Jan 2026 07:06:25 -0500

support copy/paste directories

Diffstat:
Mentries.c | 65++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 64 insertions(+), 1 deletion(-)

diff --git a/entries.c b/entries.c @@ -430,7 +430,7 @@ int entries_find_file(entries_t *entries, const char *filename) { return -1; } -int entries_copy_file(const char *src, const char *dst) { +static int copy_internal(const char *src, const char *dst) { int src_fd, dst_fd; char buffer[4096]; ssize_t bytes_read; @@ -459,6 +459,69 @@ int entries_copy_file(const char *src, const char *dst) { return 0; } +int entries_copy_file(const char *src, const char *dst) { + if (filetype(src) != S_IFDIR) { + return copy_internal(src, dst); + } + + struct { + char src[PATH_MAX]; + char dst[PATH_MAX]; + } stack[128]; + int stack_top = 0; + + if (mkdir(dst, 0755) == -1 && errno != EEXIST) { + perror("mkdir"); + return -1; + } + + strlcpy(stack[stack_top].src, src, PATH_MAX); + strlcpy(stack[stack_top].dst, dst, PATH_MAX); + stack_top++; + + while (stack_top > 0) { + stack_top--; + char curr_src[PATH_MAX]; + char curr_dst[PATH_MAX]; + strlcpy(curr_src, stack[stack_top].src, PATH_MAX); + strlcpy(curr_dst, stack[stack_top].dst, PATH_MAX); + + DIR *dirp = opendir(curr_src); + if (dirp == NULL) { + perror("opendir"); + continue; + } + + struct dirent *dp; + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) + continue; + + char next_src[PATH_MAX]; + char next_dst[PATH_MAX]; + mkpath(curr_src, dp->d_name, next_src, sizeof(next_src)); + mkpath(curr_dst, dp->d_name, next_dst, sizeof(next_dst)); + + if (filetype(next_src) == S_IFDIR) { + if (mkdir(next_dst, 0755) == -1 && errno != EEXIST) { + perror("mkdir"); + } else if (stack_top < 128) { + strlcpy(stack[stack_top].src, next_src, PATH_MAX); + strlcpy(stack[stack_top].dst, next_dst, PATH_MAX); + stack_top++; + } + } else { + if (copy_internal(next_src, next_dst) == -1) { + perror("copy_internal"); + } + } + } + closedir(dirp); + } + + return 0; +} + void entries_reload(entries_t *entries) { char *name = entries->dents[entries->selection].name; set_directory(entries, entries->path);