Split implementation into two files.

- also fix threadings bugs: threads could leak (if the join loop exited
  due to some error) or non existent threads could be joined (we add the
  created struct member to avoid this)
This commit is contained in:
Érico Nogueira 2021-05-18 00:33:51 -03:00
parent 75c36e6432
commit e24aef5395
4 changed files with 78 additions and 47 deletions

View File

@ -1,3 +1,5 @@
.PHONY: all
all: erm
erm: erm.c remove.c | erm.h

55
erm.c
View File

@ -1,7 +1,4 @@
#define _XOPEN_SOURCE 500 /* nftw */
#include <errno.h>
#include <ftw.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdnoreturn.h>
#include <stdio.h>
@ -9,41 +6,7 @@
#include <string.h>
#include <unistd.h>
static int ftw_cb(const char *fpath, const struct stat *sb,
int typeflag, struct FTW *ftwbuf)
{
if (typeflag == FTW_D || typeflag == FTW_DP) return rmdir(fpath);
else return unlink(fpath);
}
struct task {
pthread_t thread;
const char *path;
int rv;
} *task_list = NULL;
void *run_ftw(void *arg)
{
struct task *t = arg;
t->rv = nftw(t->path, ftw_cb, 20, FTW_DEPTH|FTW_PHYS);
return NULL;
}
static int recurse_into(const char *path, int c)
{
task_list[c].path = path;
return pthread_create(&task_list[c].thread, NULL, run_ftw, &task_list[c]);
}
static int join_thread(const char *path, int c)
{
pthread_join(task_list[c].thread, NULL);
return task_list[c].rv;
}
static int single_file(const char *path, int c)
{
(void)c;
return remove(path);
}
#include "erm.h"
noreturn static void usage(int s)
{
@ -73,16 +36,18 @@ int main(int argc, char **argv)
}
argc -= optind;
argv += optind;
if (argc == 0) {
usage(1);
}
if (recursive) {
task_list = calloc(sizeof(*task_list), argc);
if (!task_list) {
if (!malloc_task_list(argc)) {
perror("malloc");
return 5;
}
}
int (*action)(const char *, int) = recursive ? recurse_into : single_file;
int (*callback)(const char *, int) = recursive ? join_thread : NULL;
file_action action = recursive ? recurse_into : single_file;
file_action callback = recursive ? join_thread : NULL;
const char *err_fmt = recursive ?
"failed to delve into '%s': %s\n" : "failed to remove '%s': %s\n";
@ -103,11 +68,7 @@ int main(int argc, char **argv)
const char *path = argv[i];
if (callback(path, i)) {
fprintf(stderr, err_fmt, path, strerror(errno));
if (stop_at_error) {
return 1;
} else {
rv = 1;
}
rv = 1;
}
}
}

8
erm.h Normal file
View File

@ -0,0 +1,8 @@
typedef int (*file_action)(const char *path, int position);
struct task;
/* remove.c */
struct task *malloc_task_list(size_t);
int recurse_into(const char *, int);
int join_thread(const char *, int);
int single_file(const char *, int);

60
remove.c Normal file
View File

@ -0,0 +1,60 @@
#define _XOPEN_SOURCE 500 /* nftw */
#include <errno.h>
#include <ftw.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "erm.h"
struct task {
pthread_t thread;
const char *path;
int rv;
int created;
} *task_list = NULL;
struct task *malloc_task_list(size_t n)
{
return task_list = calloc(sizeof(struct task), n);
}
static int ftw_cb(const char *fpath, const struct stat *sb,
int typeflag, struct FTW *ftwbuf)
{
if (typeflag == FTW_D || typeflag == FTW_DP) return rmdir(fpath);
else return unlink(fpath);
}
static void *run_ftw(void *arg)
{
struct task *t = arg;
t->rv = nftw(t->path, ftw_cb, 20, FTW_DEPTH|FTW_PHYS) ? errno : 0;
return NULL;
}
int recurse_into(const char *path, int c)
{
task_list[c].path = path;
int rv = pthread_create(&task_list[c].thread, NULL, run_ftw, &task_list[c]);
if (!rv) task_list[c].created = 1;
return rv;
}
int join_thread(const char *path, int c)
{
if (!task_list[c].created) {
errno = EINVAL;
return -1;
}
pthread_join(task_list[c].thread, NULL);
errno = task_list[c].rv;
return errno ? -1 : 0;
}
int single_file(const char *path, int c)
{
(void)c;
return remove(path);
}