dir2list.c (3601B)
1 #include <dirent.h> 2 #include <errno.h> 3 #include <stdarg.h> 4 #include <stdio.h> 5 #include <stdint.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sys/stat.h> 9 #include <time.h> 10 11 #include "config.h" 12 13 /* sqrt(SIZE_MAX + 1): for (a < this; b < this) a * b <= SIZE_MAX */ 14 #define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4)) 15 16 struct node { 17 char *path; /* Path containing media files */ 18 int a; /* Applied */ 19 }; 20 21 /* this makes calls to qsort nicer */ 22 struct entry { 23 char *name; 24 }; 25 26 static struct node *nodes; 27 static struct entry *ents; 28 29 static size_t n_nodes; 30 static size_t n_ents; 31 32 static void 33 die(const char *fmt, ...) 34 { 35 va_list ap; 36 37 va_start(ap, fmt); 38 vfprintf(stderr, fmt, ap); 39 va_end(ap); 40 41 exit(1); 42 } 43 44 static void 45 usage(const char *argv0) 46 { 47 die("usage: %s [dir]\n", argv0); 48 } 49 50 static void * 51 xmalloc(size_t s) 52 { 53 void *p; 54 55 if (!(p = malloc(s))) 56 die("malloc()\n"); 57 58 return p; 59 } 60 61 static void * 62 reallocarray(void *p, size_t n, size_t s) 63 { 64 if ((n >= MUL_NO_OVERFLOW || s >= MUL_NO_OVERFLOW) 65 && n > 0 && SIZE_MAX / n < s) 66 die("reallocarray(): Out of Memory\n"); 67 68 return realloc(p, n * s); 69 } 70 71 static int 72 entcmp(const void *va, const void *vb) 73 { 74 const struct entry *a = va, *b = vb; 75 return strcmp(a->name, b->name); 76 } 77 78 static int 79 valid_dir(const char *dir) 80 { 81 if (!strcmp(dir, ".") || !strcmp(dir, "..")) 82 return 0; 83 84 return 1; 85 } 86 87 static int 88 valid_file(const char *file) 89 { 90 const char *s, **types; 91 types = filetypes; 92 for (; *types; types++) { 93 s = *types; 94 if (strstr(file, s)) 95 return 1; 96 } 97 return 0; 98 } 99 100 static void 101 addfiles(const char *path) 102 { 103 DIR *dir; 104 struct dirent *dent; 105 char *s; 106 size_t len, n; 107 108 if (!(dir = opendir(path))) 109 die("opendir(): failed to open: %s\n", path); 110 111 for (n = 0; (dent = readdir(dir));) { 112 if (!valid_file(dent->d_name)) 113 continue; 114 115 ents = reallocarray(ents, n_ents + 1, sizeof(struct entry)); 116 117 len = strlen(path) + strlen(dent->d_name) + 2; 118 s = xmalloc(len); 119 snprintf(s, len, "%s/%s", path, dent->d_name); 120 ents[n_ents++].name = s; 121 n++; 122 } 123 closedir(dir); 124 125 qsort(&ents[n_ents - n], n, sizeof(struct entry), entcmp); 126 } 127 128 /* Fill out the next field for all nodes */ 129 static void 130 subdir(const char *path) 131 { 132 DIR *dir; 133 struct dirent *ent; 134 struct stat sb; 135 char *s; 136 size_t len; 137 138 if (!(dir = opendir(path))) 139 die("opendir(): failed to open: %s\n", path); 140 141 while ((ent = readdir(dir))) { 142 len = strlen(path) + strlen(ent->d_name) + 2; 143 s = xmalloc(len); 144 len = snprintf(s, len, "%s/%s", path, ent->d_name); 145 146 stat(s, &sb); 147 if (!S_ISDIR(sb.st_mode) || !valid_dir(ent->d_name)) { 148 free(s); 149 continue; 150 } 151 152 nodes = reallocarray(nodes, n_nodes + 1, sizeof(struct node)); 153 nodes[n_nodes].path = s; 154 nodes[n_nodes].a = 0; 155 156 /* recurse into subdir */ 157 subdir(nodes[n_nodes++].path); 158 } 159 closedir(dir); 160 } 161 162 static void 163 mklist(void) 164 { 165 int i, j; 166 for (i = 0; i < n_nodes;) { 167 j = rand() % n_nodes; 168 169 if (nodes[j].a) 170 continue; 171 172 addfiles(nodes[j].path); 173 nodes[j].a = 1; 174 i++; 175 } 176 } 177 178 static void 179 printlist(void) 180 { 181 int i; 182 for (i = 0; i < n_ents; i++) 183 fprintf(stdout, "%s\n", ents[i].name); 184 } 185 186 int 187 main(int argc, char *argv[]) 188 { 189 struct stat sb; 190 191 if (argc != 2) 192 usage(argv[0]); 193 194 if (stat(argv[1], &sb) != 0 || !S_ISDIR(sb.st_mode)) { 195 if (errno == ENOENT && argv[1][0] == '/') 196 die("dir: %s: does not exist\n", argv[1]); 197 usage(argv[0]); 198 } 199 200 nodes = reallocarray(nodes, ++n_nodes, sizeof(struct node)); 201 202 nodes[0].path = xmalloc(strlen(argv[1]) + 1); 203 nodes[0].path = strcpy(nodes[0].path, argv[1]); 204 nodes[0].a = 0; 205 206 srand(time(NULL)); 207 208 subdir(nodes[0].path); 209 mklist(); 210 211 printlist(); 212 213 return 0; 214 }