Add recursive scanning
[erinaco.git] / erinaco-data.c
blob0ccbcefc17503afd7f50347c791b5508d72aef7b
1 #include <dirent.h>
2 #include <stdbool.h>
3 #include <sys/stat.h>
4 #include <sys/types.h>
5 #include <unistd.h>
7 #include <cdb.h>
8 #include <ustr.h>
10 #include "open.h"
11 #include "file.h"
12 #include "dirent.h"
13 #include "memmap.h"
14 #include "ustr-extra.h"
16 #define write2(x) write(2, x"", sizeof(x))
18 static struct cdb_make cdb;
19 static const char *hostname;
21 extern void process_directory(const Ustr *);
24 int scandir_filter (const struct dirent *entry)
26 return entry->d_name[0] != '.';
29 void gophermap_add_entry(Ustr **gophermap, const Ustr *path, char c)
31 Ustr *name = ustr_filename(path);
33 ustr_add_fmt(gophermap, "%c%s\t%s\t%s\t70\r\n",
34 c, ustr_cstr(name), ustr_cstr(path) + 1, hostname);
35 ustr_free(name);
40 void process_dirent_regular(Ustr *path, Ustr **gophermap)
42 struct memory mem;
43 int err;
44 int fd;
46 fd = open_read(ustr_cstr(path));
47 if (fd < 0) {
48 write2("fatal: open() failed\n");
49 exit(1);
51 err = mem_map_read(&mem, fd);
52 if (err != 0) {
53 write2("fatal: failed to mmap file\n");
54 exit(1);
56 cdb_make_add(&cdb, ustr_cstr(path) + 1, ustr_len(path) - 1, mem.data, mem.length);
57 mem_unmap(&mem);
59 gophermap_add_entry(gophermap, path, '0');
62 void process_dirent_directory(const Ustr *path, Ustr **gophermap)
64 Ustr *name;
65 Ustr *dirname;
67 name = ustr_filename(path);
68 dirname = ustr_dup(path);
69 ustr_add_cstr(&dirname, "/");
71 ustr_add_cstr(gophermap, "1");
72 ustr_add(gophermap, name);
73 ustr_add_cstr(gophermap, "\t");
74 ustr_add_cstr(gophermap, ustr_cstr(path) + 1);
75 ustr_add_cstr(gophermap, "/\t");
76 ustr_add_cstr(gophermap, hostname);
77 ustr_add_cstr(gophermap, "\t70\r\n");
79 process_directory(dirname);
81 ustr_free(name);
82 ustr_free(dirname);
86 void process_dirent(const Ustr *here, const struct dirent *d, Ustr **gophermap)
88 Ustr *path = USTR("");
90 ustr_set_fmt(&path, "%s%s", ustr_cstr(here), d->d_name); /* {here} ends with slash */
92 if (dirent_regular_p(d))
93 process_dirent_regular(path, gophermap);
94 else if (dirent_directory_p(d))
95 process_dirent_directory(path, gophermap);
97 ustr_free(path);
100 void process_directory(const Ustr *here)
102 struct dirent **entries;
103 int n;
104 Ustr *gophermap = USTR("");
106 n = scandir(ustr_cstr(here), &entries, &scandir_filter, &alphasort);
107 if (n < 0) {
108 write2("fatal: failed to scan directory\n");
109 printf("%s\n", ustr_cstr(here));
110 exit(1);
113 while (n--) {
114 process_dirent(here, entries[n], &gophermap);
115 free(entries[n]);
117 free(entries);
119 ustr_add_cstr(&gophermap, ".\r\n"); /* Be nice, finalize gophermap */
120 cdb_make_add(&cdb, ustr_cstr(here) + 1, ustr_len(here) - 1, ustr_cstr(gophermap), ustr_len(gophermap));
121 ustr_free(gophermap);
124 int main (int argc, char **argv)
126 int fd;
127 const char *output;
128 Ustr *temp = USTR("");
130 if (argc < 2) {
131 write2("usage: erinaco-data hostname [output]\n");
132 return 1;
135 hostname = argv[1];
136 output = argc > 2 ? argv[2] : "../data.cdb";
138 ustr_set_fmt(&temp, "%s.%d", output, getpid());
140 fd = open_readwrite(ustr_cstr(temp));
141 if (fd < 0) {
142 write2("fatal: failed to open temporary database for writing\n");
143 return 1;
145 if (cdb_make_start(&cdb, fd) < 0) {
146 write2("fatal: failed to initialize database\n");
147 return 1;
150 process_directory(USTR1(\2, "./")); /* "./" instead of "." is essential */
152 if (cdb_make_finish(&cdb) < 0) {
153 write2("fatal: failed to finalize database\n");
154 return 1;
157 if (close(fd) < 0) {
158 write2("fatal: failed to close temporary database\n");
159 return 1;
161 if (rename(ustr_cstr(temp), output) < 0) {
162 write2("fatal: failed to rename temporary database\n");
163 return 1;
165 ustr_free(temp);
166 return 0;