summaryrefslogtreecommitdiff
path: root/command/rm.c
blob: 9834a40c93c626f4d71ef5a811706f3c81f4d46b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "command.h"
#include "lslib.h"

#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

static struct {
    bool force;
    bool prompt;
    bool verbose;
    bool recurse;
} flags;

static void help(void) {
    printf("Usage: rm [-irfv] FILE...\n\n");
    printf("Remove (unlink) FILESs\n\n");
    printf("\t-i\tAlways prompt before removing\n");
    printf("\t-f\tForce, never prompt\n");
    printf("\t-v\tVerbose\n");
    printf("\t-R,-r\tRecurse\n");
}

static int short_arg(char c, char* next) {
    UNUSED(next);
    switch (c) {
        case 'i':
            flags.prompt = true;
            break;
        case 'f':
            flags.force = true;
            break;
        case 'v':
            flags.verbose = true;
            break;
        case 'R':
        case 'r':
            flags.recurse = true;
            break;
        default:
            return ARG_INVALID;
    }
    return ARG_UNUSED;
}

static void rm_file (char* path);

static bool rm_dir (void) {
    DIR* d;
    struct dirent* file;
    
    d = opendir(get_path_buffer());
    if (d == NULL) {
        error_s("failed to stat '%s'", get_path_buffer());
        return false;
    }

    while ((file = readdir(d)) != NULL) {
        if (is_dot_dir(file->d_name)) continue;
        rm_file(file->d_name);
    }

    closedir(d);
    return true;
}

static void rm_file(char* path) {
    int save = push_path_buffer(path);

    struct stat s;
    if (lstat(get_path_buffer(), &s) < 0) {
        pop_path_buffer(save);
        error_s("failed to stat '%s'", get_path_buffer());
        return;
    }

    if (S_ISDIR(s.st_mode)) {
        if (!flags.force) {
            error_s("cannot delete '%s': Is a directory\n", get_path_buffer());
            pop_path_buffer(save);
            return;
        }
        if (flags.recurse && !rm_dir()) {
            pop_path_buffer(save);
            return;
        }
    }

    if (flags.prompt) {
        char c;

        fprintf(stderr, "delete '%s'? ", get_path_buffer());
        fflush(stderr);
        
        c = getchar();
        if (c != 'y' && c != 'Y') {
            fprintf(stderr, "Skipping...\n");
            pop_path_buffer(save);
            return;
        }
    }

    if (remove(get_path_buffer()) < 0) {
        error_s("failed to delete '%s'", get_path_buffer());
    } else if (flags.verbose) {
        output("deleted '%s'\n", get_path_buffer());
    }

    pop_path_buffer(save);
}

COMMAND(rm) {

    int start, i;

    if (argc < 1) {
        global_help(help);
        return EXIT_SUCCESS;
    }

    flags.prompt = false;
    flags.force = false;
    flags.verbose = false;
    flags.recurse = false;

    start = parse_args(argc, argv, help, short_arg, NULL);

#ifdef FRENCH
    if (streql(argv[0], "-fr")) {
        printf("\x1b[94mremoving \x1b[97mthe \x1b[91mfrench \x1b[93m(baguette noises)\x1b[0m\n");
    }
#endif

    for (i = start; i < argc; i++) {
        rm_file(argv[i]);
    }

    return EXIT_SUCCESS;
}