commit: 50f9d24bb94d4595555872641eea33f902cebab7
parent 0f783204c9b25363b3a39b0528de6423c9dd1256
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Thu, 28 Mar 2024 17:53:54 +0100
cmd/rm: Reset errno before every call which might set it
Otherwise checks against errno, particularly the errno == 0 ones end up failing.
Leading to bugs like not removing an empty directory when prior removal failed.
Diffstat:
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/cmd/rm.c b/cmd/rm.c
@@ -35,6 +35,8 @@ consentf(const char *restrict fmt, ...)
va_list ap;
+ errno = 0;
+
va_start(ap, fmt);
int ret = vfprintf(stderr, fmt, ap);
va_end(ap);
@@ -45,7 +47,8 @@ consentf(const char *restrict fmt, ...)
goto end;
}
- errno = 0;
+ errno = 0;
+
ssize_t nread = getline(&line, &len, stdin);
if(nread < 0)
{
@@ -94,6 +97,7 @@ do_unlinkat(int fd, char *name, char *acc_path)
struct stat stats;
int err = 0;
+ errno = 0;
if(fstatat(fd, name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
{
if(force && errno == ENOENT) return 0;
@@ -115,6 +119,7 @@ do_unlinkat(int fd, char *name, char *acc_path)
if(!force && opt_i)
if(!consentf("rm: Recurse into '%s' ? [y/N] ", acc_path)) return 0;
+ errno = 0;
int dir = openat(fd, name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if(dir == -1)
{
@@ -122,6 +127,8 @@ do_unlinkat(int fd, char *name, char *acc_path)
return 1;
}
+ errno = 0;
+
DIR *dirp = fdopendir(dir);
if(dirp == NULL)
{
@@ -132,6 +139,8 @@ do_unlinkat(int fd, char *name, char *acc_path)
while(true)
{
+ errno = 0;
+
struct dirent *dp = readdir(dirp);
if(dp == NULL)
{
@@ -145,6 +154,8 @@ do_unlinkat(int fd, char *name, char *acc_path)
if(strcmp(dp->d_name, ".") == 0) continue;
if(strcmp(dp->d_name, "..") == 0) continue;
+ errno = 0;
+
char new_path[PATH_MAX] = "";
if(snprintf(new_path, PATH_MAX, "%s/%s", acc_path, dp->d_name) < 0)
{
@@ -163,6 +174,7 @@ do_unlinkat(int fd, char *name, char *acc_path)
}
// fdopendir allocates memory for DIR, needs closedir
+ errno = 0;
if(closedir(dirp) != 0)
{
fprintf(stderr,
@@ -180,6 +192,7 @@ do_unlinkat(int fd, char *name, char *acc_path)
if(!consentf("rm: Remove '%s' ? [y/N] ", acc_path)) return 0;
}
+ errno = 0;
if(unlinkat(fd, name, is_dir ? AT_REMOVEDIR : 0) != 0)
{
fprintf(stderr, "rm: Couldn't remove '%s': %s\n", acc_path, strerror(errno));