Thumbnail

rani/cscroll.git

Clone URL: https://git.buni.party/rani/cscroll.git

commit 87433b83d3598d3fcf95e17c214f6fc2a475773d Author: rani <clagv.randomgames@gmail.com> Date: Fri Jan 02 23:20:02 2026 +0000 Add secondary deletion prompt for nonempty directories; Add: file, directory, and recursive directory deletion diff --git a/include/dir.h b/include/dir.h index 052b1ea..0704293 100644 --- a/include/dir.h +++ b/include/dir.h @@ -925 +926 @@ bool dirent_isexec(const dirent_t * de);  const char * dirent_prettymode(const dirent_t * de);  const char * dirent_size_unit(const dirent_t * de);  size_t dirent_subfiles(const dirent_t * de); // number of sub entries in a dir +int dirent_delete(const dirent_t * de);    #endif /* DIR_H */ diff --git a/src/dir.c b/src/dir.c index ba04bf8..8fe8866 100644 --- a/src/dir.c +++ b/src/dir.c @@ -4387 +43810 @@ static int dir_internal_ftw_(   const struct stat * sb,   void * arg   ), - void * arg + void * arg, + bool postorder, + + dev_t rootdev  ) {   int retval = 0;   @@ -45818 +46132 @@ static int dir_internal_ftw_(   if (ret < 0) statbufp = NULL;   else statbufp = &statbuf;   - ret = cb(dirfd(dp), name, statbufp, arg); - // if cb returns a negative value, stop the walk immediately - if (ret < 0) { - retval = -1; - goto done; + if (statbuf.st_dev != rootdev) continue; + + // do an inorder traversal + if (!postorder) { + ret = cb(dirfd(dp), name, statbufp, arg); + // if cb returns a negative value, stop the walk immediately + if (ret < 0) { + retval = ret; + goto done; + }   }     if (S_ISDIR(statbuf.st_mode)) {   int nextfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); - ret = dir_internal_ftw_(nextfd, cb, arg); + ret = dir_internal_ftw_(nextfd, cb, arg, postorder, rootdev);   if (ret < 0) { - retval = -1; + retval = ret; + goto done; + } + } + + // do a postorder traversal + if (postorder) { + ret = cb(dirfd(dp), name, statbufp, arg); + if (ret < 0) { + retval = ret;   goto done;   }   } @@ -48811 +50522 @@ static int dir_internal_ftw(   const struct stat * sb,   void * arg   ), - void * arg + void * arg, + bool postorder  ) {   DIR * d = opendir(path);   if (!d) return -1; - int ret = dir_internal_ftw_(dup(dirfd(d)), cb, arg); + + struct stat statbuf; + // I don't think it can error here + if (lstat(path, &statbuf) < 0) { + closedir(d); + return -1; + } + + dev_t rootdev = statbuf.st_dev; + + int ret = dir_internal_ftw_(dup(dirfd(d)), cb, arg, postorder, rootdev);   closedir(d);   return ret;  } @@ -50510 +53335 @@ static int dirent_subfiles_ftw_cb(   return 0;  }   +static int dirent_delete_ftw_cb( + int dirfd, const char * path, const struct stat * sb, + UNUSED void * arg +) { + int flags = 0; + if (S_ISDIR(sb->st_mode)) flags = AT_REMOVEDIR; + + unlinkat(dirfd, path, flags); + return 0; +} +  size_t dirent_subfiles(const dirent_t * de) {   if (de->type != DE_DIR) return 0;     size_t count = 0; - dir_internal_ftw(de->name, dirent_subfiles_ftw_cb, &count); + dir_internal_ftw(de->name, dirent_subfiles_ftw_cb, &count, false);   return count;  } + +int dirent_delete(const dirent_t * de) { + if (de->type == DE_DIR) { + int ret = dir_internal_ftw(de->name, dirent_delete_ftw_cb, NULL, true); + if (ret >= 0) { + if (rmdir(de->name) < 0) return -errno; + return 0; + } + return ret; + } else { + if (unlink(de->name) < 0) return -errno; + return 0; + } +} diff --git a/src/main.c b/src/main.c index 41e0551..8463892 100644 --- a/src/main.c +++ b/src/main.c @@ -997 +998 @@ int main(int argc, char ** argv) {   break;   case KEY_END:   case 'G': - cursor = dirlen - 1; + if (dirlen == 0) cursor = 0; + else cursor = dirlen - 1;   ui_status_info("");   break;   case '.': { @@ -1478 +14828 @@ int main(int argc, char ** argv) {   ui_status_info("");   ui_refresh();   bool del = ui_prompt_deletion(cur_de); - if (del) ui_status_info("Deleting!"); - else ui_status_info("Not Deleting."); + if (!del) { + ui_status_info("Not Deleting"); + ui_refresh(); + break; + } + + ui_status_info("Deleting"); + ui_refresh(); + + int ret = dirent_delete(cur_de); + if (ret < 0) { + ui_status_error("Deletion Failed"); + } else { + ui_status_info("Deleted"); + } + + dir_free(&dir); + dir_list(cwd, &dir); + dir_sort(&dir); + dirlen = dir_len(&dir); + if (dirlen == 0) cursor = 0; + else if (cursor > dirlen - 1) cursor = dirlen - 1;   break;   }   case 'q': diff --git a/src/ui.c b/src/ui.c index b68a668..4077db4 100644 --- a/src/ui.c +++ b/src/ui.c @@ -4447 +4446 @@ const char * ui_prompt(const char * prompt, prompt_opts_t opts) {   break;   case KEY_RESIZE:   ui_resize(); - ui_refresh();     lines = MIN(oglines, (unsigned)PROMPTWINMAXLINES);   cols = MIN(ogcols, (unsigned)PROMPTWINMAXCOLS); @@ -4698 +4688 @@ const char * ui_prompt(const char * prompt, prompt_opts_t opts) {  }    bool ui_prompt_deletion(const dirent_t * de) { - const char * no = "No"; - const char * yes = "Yes"; + static const char * no = "No"; + static const char * yes = "Yes";     size_t nfiles = 0;   if (de->type == DE_DIR) { @@ -4966 +49512 @@ bool ui_prompt_deletion(const dirent_t * de) {     const char * ret = ui_prompt(prompt, (prompt_opts_t){no, yes, NULL});   free(prompt); - if (ret == yes) return true; - return false; + if (ret != yes) return false; + + if (nfiles != 0) { + ret = ui_prompt("This action cannot be undone. Proceed?", (prompt_opts_t){no, yes, NULL}); + if (ret != yes) return false; + } + + return true;  }