Initial support for recursive deletion.
[zero.git] / main.c
blob851bf169aef848052e9237344177726eb89814aa
1 #include <sys/stat.h>
3 #include <err.h>
4 #define __USE_XOPEN_EXTENDED
5 #include <ftw.h>
6 #include <fcntl.h>
7 #include <libgen.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <time.h>
12 #include <unistd.h>
14 #include "util.h"
16 int verbose = 0;
18 static char *randstr(size_t len) {
19 const char *chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
21 char *name;
22 size_t i;
24 name = emalloc(len+1);
26 for (i = 0; i < len; i++) {
27 name[i] = chars[rand() % strlen(chars)];
29 name[len+1] = '\0';
31 return name;
34 static char *randren(const char *path) {
35 unsigned long newpathlen = 0;
36 unsigned int error = 0;
38 char *dname, *rname, *pathcopy, *newpath;
40 /* glibc dirname modifies its argument */
41 pathcopy = strdup(path);
43 dname = dirname(pathcopy);
45 /* Calling pathconf directly on a symlink will return the value for
46 * the file that it links to or, if it's a dangling symlink, -1
47 * (failure) so we use the directory it's stored in instead. */
48 rname = randstr(pathconf(dname, _PC_NAME_MAX));
50 newpathlen += strlen(dname);
51 newpathlen += strlen(rname);
52 newpathlen += 2; /* '/' & '\0' */
54 newpath = emalloc(newpathlen);
56 strcpy(newpath, dname);
57 strcpy(newpath + strlen(newpath), "/");
58 strcpy(newpath + strlen(newpath), rname);
59 strcpy(newpath + strlen(newpath), "\0");
61 /* check whether the file exists */
62 if (access(newpath, F_OK) == 0) {
63 warnx("randren: File exists");
64 error = 1;
65 } else {
66 if (rename(path, newpath) == -1) {
67 warn("randren");
68 error = 1;
72 free(pathcopy);
73 free(rname);
75 if (error == 1) {
76 free(newpath);
77 return NULL;
78 } else {
79 return newpath;
83 static int fzero(const char *path) {
84 ssize_t written = 0;
86 int fd;
87 void *buf;
88 struct stat stbuf;
90 if (stat(path, &stbuf) == -1) {
91 warn("fzero");
92 return -1;
95 buf = emalloc(stbuf.st_blksize);
97 if ((fd = open(path, O_WRONLY)) == -1) {
98 warn("fzero");
99 return -1;
102 while (written < stbuf.st_size) {
103 written += write(fd, buf, stbuf.st_blksize);
106 fdatasync(fd);
108 close(fd);
109 free(buf);
111 return 0;
114 int can_write(const struct stat *sb) {
115 uid_t id;
117 id = geteuid();
118 if (sb->st_uid == id) {
119 return 1;
120 } else {
121 return 0;
125 int fn(const char *fpath, const struct stat *sb, int typeflag,
126 struct FTW *ftwbuf) {
127 char *path;
129 if (!can_write(sb)) {
130 return 0;
133 path = randren(fpath);
134 if (path == NULL) {
135 return 1;
138 switch (typeflag) {
139 case FTW_SL:
140 unlink(path);
141 break;
142 case FTW_F:
143 if (fzero(path) != -1) {
144 unlink(path);
146 break;
147 case FTW_DP:
148 rmdir(path);
149 break;
151 free(path);
153 return 0;
156 int main(int argc, char *argv[]) {
157 int i, c;
159 while ((c = getopt(argc, argv, "+v")) != -1) {
160 switch (c) {
161 case 'v':
162 verbose = 1;
163 break;
167 if (optind == argc) {
168 fprintf(stderr, "usage: %s [-rv] [file ...]\n", argv[0]);
169 return 1;
172 srand(time(NULL));
174 for (i = optind; i < argc; i++) {
175 nftw(argv[i], fn, 10, FTW_DEPTH | FTW_PHYS);
178 return 0;