If verbose output is specified, print a '.' at every block write.
[zero.git] / main.c
blob4605911fbb17f444416924e68ffe46c5dea43187
1 /* This program is free software. It comes without any warranty, to
2 * the extent permitted by applicable law. You can redistribute it
3 * and/or modify it under the terms of the Do What The Fuck You Want
4 * To Public License, Version 2, as published by Sam Hocevar. See
5 * http://sam.zoy.org/wtfpl/COPYING for more details. */
7 #include <sys/stat.h>
9 #include <err.h>
10 #define __USE_XOPEN_EXTENDED
11 #include <ftw.h>
12 #include <fcntl.h>
13 #include <libgen.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <time.h>
18 #include <unistd.h>
20 #include "util.h"
22 int verbose = 0;
24 static char *randstr(size_t len) {
25 const char *chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
27 char *name;
28 size_t i;
30 name = emalloc(len+1);
32 for (i = 0; i < len; i++) {
33 name[i] = chars[rand() % strlen(chars)];
35 name[len+1] = '\0';
37 return name;
40 static char *randren(const char *path) {
41 unsigned long newpathlen = 0;
42 unsigned int error = 0;
44 char *dname, *rname, *pathcopy, *newpath;
46 /* glibc dirname modifies its argument */
47 pathcopy = strdup(path);
49 dname = dirname(pathcopy);
51 /* Calling pathconf directly on a symlink will return the value for
52 * the file that it links to or, if it's a dangling symlink, -1
53 * (failure) so we use the directory it's stored in instead. */
54 rname = randstr(pathconf(dname, _PC_NAME_MAX));
56 newpathlen += strlen(dname);
57 newpathlen += strlen(rname);
58 newpathlen += 2; /* '/' & '\0' */
60 newpath = emalloc(newpathlen);
62 strcpy(newpath, dname);
63 strcpy(newpath + strlen(newpath), "/");
64 strcpy(newpath + strlen(newpath), rname);
65 strcpy(newpath + strlen(newpath), "\0");
67 /* check whether the file exists */
68 if (access(newpath, F_OK) == 0) {
69 warnx("randren: File exists");
70 error = 1;
71 } else {
72 if (rename(path, newpath) == -1) {
73 warn("randren");
74 error = 1;
78 free(pathcopy);
79 free(rname);
81 if (error == 1) {
82 free(newpath);
83 return NULL;
84 } else {
85 return newpath;
89 static int fzero(const char *path) {
90 ssize_t written = 0;
92 int fd;
93 void *buf;
94 struct stat stbuf;
96 if (stat(path, &stbuf) == -1) {
97 warn("fzero");
98 return -1;
101 buf = emalloc(stbuf.st_blksize);
103 if ((fd = open(path, O_WRONLY)) == -1) {
104 warn("fzero");
105 return -1;
108 while (written < stbuf.st_size) {
109 written += write(fd, buf, stbuf.st_blksize);
110 if (verbose) {
111 putchar('.');
114 if (verbose) {
115 putchar('\n');
118 fdatasync(fd);
120 close(fd);
121 free(buf);
123 return 0;
126 int can_write(const struct stat *sb) {
127 uid_t id;
129 id = geteuid();
130 if (sb->st_uid == id) {
131 return 1;
132 } else {
133 return 0;
137 int fn(const char *fpath, const struct stat *sb, int typeflag,
138 struct FTW *ftwbuf) {
139 char *path;
141 if (!can_write(sb)) {
142 return 0;
145 path = randren(fpath);
146 if (path == NULL) {
147 return 1;
150 switch (typeflag) {
151 case FTW_SL:
152 unlink(path);
153 break;
154 case FTW_F:
155 if (fzero(path) != -1) {
156 unlink(path);
158 break;
159 case FTW_DP:
160 rmdir(path);
161 break;
163 free(path);
165 return 0;
168 int main(int argc, char *argv[]) {
169 int i, c;
171 while ((c = getopt(argc, argv, "+v")) != -1) {
172 switch (c) {
173 case 'v':
174 verbose = 1;
175 break;
179 if (optind == argc) {
180 fprintf(stderr, "usage: %s [-rv] [file ...]\n", argv[0]);
181 return 1;
184 srand(time(NULL));
186 for (i = optind; i < argc; i++) {
187 nftw(argv[i], fn, 10, FTW_DEPTH | FTW_PHYS);
190 return 0;