Use WTFPL.
[zero.git] / main.c
blob0f7e3832f77ae39a20b1cfd85a867fdba658d1d3
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);
112 fdatasync(fd);
114 close(fd);
115 free(buf);
117 return 0;
120 int can_write(const struct stat *sb) {
121 uid_t id;
123 id = geteuid();
124 if (sb->st_uid == id) {
125 return 1;
126 } else {
127 return 0;
131 int fn(const char *fpath, const struct stat *sb, int typeflag,
132 struct FTW *ftwbuf) {
133 char *path;
135 if (!can_write(sb)) {
136 return 0;
139 path = randren(fpath);
140 if (path == NULL) {
141 return 1;
144 switch (typeflag) {
145 case FTW_SL:
146 unlink(path);
147 break;
148 case FTW_F:
149 if (fzero(path) != -1) {
150 unlink(path);
152 break;
153 case FTW_DP:
154 rmdir(path);
155 break;
157 free(path);
159 return 0;
162 int main(int argc, char *argv[]) {
163 int i, c;
165 while ((c = getopt(argc, argv, "+v")) != -1) {
166 switch (c) {
167 case 'v':
168 verbose = 1;
169 break;
173 if (optind == argc) {
174 fprintf(stderr, "usage: %s [-rv] [file ...]\n", argv[0]);
175 return 1;
178 srand(time(NULL));
180 for (i = optind; i < argc; i++) {
181 nftw(argv[i], fn, 10, FTW_DEPTH | FTW_PHYS);
184 return 0;