3 // Copyright (C) 2005 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 #include "pathconfig.h"
19 #include "lib_internal/util-dotfile.h"
21 #include <sys/param.h>
24 freeHashList(HashDirCollection *hash_vec)
26 for (struct HashDirInfo *itm = Vector_begin(hash_vec);
27 itm!=Vector_end(hash_vec);
29 free(const_cast(char *)(itm->path.d));
32 Vector_free(hash_vec);
36 initHashList(HashDirCollection *hash_vec, char const *hashdir)
38 int cur_dir = Eopen(".", O_RDONLY|O_DIRECTORY, 0);
41 DIR *d = Eopendir(".");
43 size_t l = strlen(hashdir);
46 while ((ep=readdir(d)) != 0) {
49 if (isDotfile(ep->d_name) ||
50 stat(ep->d_name, &st)==-1 || !S_ISDIR(st.st_mode))
53 if (HashDirInfo_findDevice(hash_vec, st.st_dev)!=0) {
54 WRITE_MSG(2, "Duplicate hash-dir entry '");
55 WRITE_STR(2, ep->d_name);
56 WRITE_MSG(2, "' found\n");
60 char *full_path = Emalloc(l + strlen(ep->d_name) + 3);
61 char *ptr = full_path + l;
63 memcpy(full_path, hashdir, l);
64 while (ptr>full_path && ptr[-1]=='/') --ptr;
66 strcpy(ptr, ep->d_name);
67 strcat(ptr, "/"); // append a trailing '/'
70 struct HashDirInfo tmp = {
72 .path = { full_path, strlen(full_path) },
75 res = MAX(res, tmp.path.l);
77 memcpy(Vector_pushback(hash_vec), &tmp, sizeof tmp);
80 if (Vector_count(hash_vec)==0) {
81 WRITE_MSG(2, "Could not find a place for the hashified files at '");
82 WRITE_STR(2, hashdir);
84 exit(wrapper_exit_code);
95 initHashMethod(struct HashDirConfiguration *conf, char const *filename)
97 int fd = open(filename, O_RDONLY);
98 if (fd==-1 && conf->method==0)
99 conf->method = ensc_crypto_hash_get_default();
102 char const *hash_name;
103 assert(conf->method!=0);
104 if (conf->method==0) return false;
105 if (global_args->dry_run) return true; // do not create the file
107 fd = Eopen(filename, O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, 0644);
109 hash_name = ensc_crypto_hash_get_name(conf->method);
110 TEMP_FAILURE_RETRY(write(fd, hash_name, strlen(hash_name)));
111 TEMP_FAILURE_RETRY(write(fd, "\n", 1));
114 off_t s = Elseek(fd, 0, SEEK_END);
116 Elseek(fd, 0, SEEK_SET);
120 if (s>0 && read(fd, buf, s+1)==s) {
121 while (s>0 && (buf[s-1]=='\0' || buf[s-1]=='\n'))
125 conf->method = ensc_crypto_hash_find(buf);
126 if (conf->method==0) {
127 WRITE_MSG(2, "Can not find hash-function '");
133 WRITE_MSG(2, "Can not read configuration file for hash-method\n");
136 if (conf->method!=0 && ensc_crypto_hash_get_digestsize(conf->method)*8>HASH_MAXBITS) {
137 WRITE_MSG(2, "Wow... what an huge hash-function. I can not handle so much bits; giving up...\n");
142 return conf->method!=0;
146 initHashBlocks(struct HashDirConfiguration *conf, char const *filename)
148 int fd = open(filename, O_RDONLY);
151 char str[sizeof("all,start,middle,end,")] = { [0] = '\0' };
153 if (global_args->dry_run) return true; // do not create the file
155 fd = Eopen(filename, O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, 0644);
157 if (conf->blocks== hshALL) strcat(str, "all\n");
158 if (conf->blocks & hshSTART) strcat(str, "start\n");
159 if (conf->blocks & hshMIDDLE) strcat(str, "middle\n");
160 if (conf->blocks & hshEND) strcat(str, "end\n");
162 EwriteAll(fd, str, strlen(str));
165 off_t s = Elseek(fd, 0, SEEK_END);
167 Elseek(fd, 0, SEEK_SET);
169 conf->blocks = hshINVALID;
171 if (s>0 && read(fd, buf, s+1)==s) {
173 char *sep = "\n,\t ";
176 conf->blocks = hshALL;
179 char *ptr = strsep(&tok, sep);
181 if (*ptr=='#') { sep = "\n"; continue; }
183 if (*ptr=='\0') continue;
185 if (strcasecmp(ptr, "all") ==0) conf->blocks = hshALL;
187 if (conf->blocks==hshINVALID) conf->blocks = 0;
189 else if (strcasecmp(ptr, "start") ==0) conf->blocks |= hshSTART;
190 else if (strcasecmp(ptr, "middle")==0) conf->blocks |= hshMIDDLE;
191 else if (strcasecmp(ptr, "end") ==0) conf->blocks |= hshEND;
193 WRITE_MSG(2, "Invalid block descriptor '");
196 conf->blocks = hshINVALID;
203 WRITE_MSG(2, "Can not read configuration file for hash-blocks\n");
207 return conf->blocks!=hshINVALID;
211 initHashBlockSize(struct HashDirConfiguration *conf, char const *filename)
213 if (conf->blocks==hshALL) return true;
215 int fd = open(filename, O_RDONLY);
217 char str[sizeof("0x") + sizeof(size_t)*3+2] = {
220 size_t len = utilvserver_fmt_xuint(str+2, conf->blocksize);
222 if (global_args->dry_run) return true; // do not create the file
224 fd = Eopen(filename, O_WRONLY|O_CREAT|O_EXCL|O_NOFOLLOW, 0644);
225 EwriteAll(fd, str, len+2);
228 off_t s = Elseek(fd, 0, SEEK_END);
230 Elseek(fd, 0, SEEK_SET);
232 conf->blocksize = (size_t)(-1);
234 if (s>0 && read(fd, buf, s+1)==s) {
237 while (s>0 && (buf[s-1]=='\0' || buf[s-1]=='\n'))
241 conf->blocksize = strtol(buf, &errptr, 0);
242 if (errptr==buf || (*errptr!='\0' && *errptr!='\n')) {
243 WRITE_MSG(2, "Failed to parse blocksize '");
246 conf->blocksize = (size_t)(-1);
250 WRITE_MSG(2, "Can not read configuration file for hash-blocksize\n");
254 return conf->blocksize!=(size_t)(-1);
258 initHashConf(struct HashDirConfiguration *conf, char const *hashdir)
260 size_t l = strlen(hashdir);
261 char tmp[l + MAX(MAX(sizeof("/method"), sizeof("/blocks")),
262 sizeof("/blocksize"))];
264 memcpy(tmp, hashdir, l);
266 return ((strcpy(tmp+l, "/method"), initHashMethod (conf, tmp)) &&
267 (strcpy(tmp+l, "/blocks"), initHashBlocks (conf, tmp)) &&
268 (strcpy(tmp+l, "/blocksize"), initHashBlockSize(conf, tmp)));
272 searchHashdir(char const *lhs, char const *rhs)
274 size_t l1 = strlen(lhs);
275 size_t l2 = rhs ? strlen(rhs) : 0;
276 char * res = Emalloc(l1 + l2 + 1);
280 if (rhs) strcat(res, rhs);
282 if (stat(res, &st)==-1 || !S_ISDIR(st.st_mode)) {
291 initModeManually(struct Arguments const UNUSED *args, int argc, char *argv[])
293 assert(args->hash_dir!=0);
296 WRITE_MSG(2, "No exclude list specified\n");
300 if (!initHashConf(&global_info.hash_conf, args->hash_dir)) {
301 WRITE_MSG(2, "failed to initialize hash-configuration\n");
305 global_info.hash_dirs_max_size = initHashList(&global_info.hash_dirs,
307 MatchList_initManually(&global_info.dst_list, 0, strdup(argv[0]), argv[1]);
311 initModeVserver(struct Arguments const UNUSED *args, int argc, char *argv[])
313 char const *hashdir = args->hash_dir;
314 struct MatchVserverInfo vserver = {
319 if (!MatchVserverInfo_init(&vserver)) {
320 WRITE_MSG(2, "Failed to initialize unification for vserver\n");
325 WRITE_MSG(2, "More than one vserver is not supported\n");
329 if (!MatchList_initByVserver(&global_info.dst_list, &vserver)) {
330 WRITE_MSG(2, "unification not configured for this vserver\n");
334 if (hashdir==0) hashdir = searchHashdir(vserver.appdir.d, "/hash");
335 if (hashdir==0) hashdir = searchHashdir(CONFDIR "/.defaults/apps/vunify/hash", 0);
338 WRITE_MSG(2, "no hash-directory configured for this vserver.\n");
342 if (!initHashConf(&global_info.hash_conf, hashdir)) {
343 WRITE_MSG(2, "failed to initialize hash-configuration\n");
347 global_info.hash_dirs_max_size = initHashList(&global_info.hash_dirs, hashdir);
349 free(const_cast(char *)(hashdir));
350 MatchVserverInfo_free(&vserver);