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
);
40 void process_dirent_regular(Ustr
*path
, Ustr
**gophermap
)
46 fd
= open_read(ustr_cstr(path
));
48 write2("fatal: open() failed\n");
51 err
= mem_map_read(&mem
, fd
);
53 write2("fatal: failed to mmap file\n");
56 cdb_make_add(&cdb
, ustr_cstr(path
) + 1, ustr_len(path
) - 1, mem
.data
, mem
.length
);
59 gophermap_add_entry(gophermap
, path
, '0');
62 void process_dirent_directory(const Ustr
*path
, Ustr
**gophermap
)
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
);
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
);
100 void process_directory(const Ustr
*here
)
102 struct dirent
**entries
;
104 Ustr
*gophermap
= USTR("");
106 n
= scandir(ustr_cstr(here
), &entries
, &scandir_filter
, &alphasort
);
108 write2("fatal: failed to scan directory\n");
109 printf("%s\n", ustr_cstr(here
));
114 process_dirent(here
, entries
[n
], &gophermap
);
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
)
128 Ustr
*temp
= USTR("");
131 write2("usage: erinaco-data hostname [output]\n");
136 output
= argc
> 2 ? argv
[2] : "../data.cdb";
138 ustr_set_fmt(&temp
, "%s.%d", output
, getpid());
140 fd
= open_readwrite(ustr_cstr(temp
));
142 write2("fatal: failed to open temporary database for writing\n");
145 if (cdb_make_start(&cdb
, fd
) < 0) {
146 write2("fatal: failed to initialize database\n");
150 process_directory(USTR1(\
2, "./")); /* "./" instead of "." is essential */
152 if (cdb_make_finish(&cdb
) < 0) {
153 write2("fatal: failed to finalize database\n");
158 write2("fatal: failed to close temporary database\n");
161 if (rename(ustr_cstr(temp
), output
) < 0) {
162 write2("fatal: failed to rename temporary database\n");