1 /* pfs.c:
2 *
3 ****************************************************************
4 * Copyright (C) 2003 Tom Lord
5 *
6 * See the file "COPYING" for further information about
7 * the copyright and warranty status of this work.
8 */
9
10
11 #include "hackerlab/char/str.h"
12 #include "hackerlab/fs/file-names.h"
13 #include "hackerlab/vu/safe.h"
14 #include "tla/libfsutils/tmp-files.h"
15 #include "tla/libarch/archive.h"
16 #include "tla/libarch/archives.h"
17 #include "tla/libarch/pfs-dav.h"
18 #include "tla/libarch/pfs-sftp.h"
19 #include "tla/libarch/pfs-ftp.h"
20 #include "tla/libarch/pfs-fs.h"
21 #include "tla/libarch/pfs.h"
22
23
24 /* __STDC__ prototypes for static functions */
25 static int dot_listings_equal (rel_table a, rel_table b);
26
27
28
29 void
arch_pfs_rmrf_file(struct arch_pfs_session * pfs,const t_uchar * path)30 arch_pfs_rmrf_file (struct arch_pfs_session * pfs,
31 const t_uchar * path)
32 {
33 int dir_check;
34
35 dir_check = arch_pfs_is_dir (pfs, path);
36
37 if (!dir_check)
38 {
39 arch_pfs_rm (pfs, path, 1);
40 }
41 else if (dir_check > 0)
42 {
43 rel_table contents = rel_table_nil;
44 int x;
45
46 contents = arch_pfs_directory_files (pfs, path, 1);
47
48 for (x = 0; x < rel_n_records (contents); ++x)
49 {
50 t_uchar * subpath = 0;
51
52 subpath = file_name_in_vicinity (0, path, rel_peek_str (contents, x, 0));
53 arch_pfs_rmrf_file (pfs, subpath);
54
55 lim_free (0, subpath);
56 }
57
58 arch_pfs_rmdir (pfs, path, 1);
59
60 rel_free_table (contents);
61 }
62
63 /* dir_check < 0 indicates an error, presumably ENOENT */
64 }
65
66
67
68
69 void
arch_pfs_pfs_make_archive(const t_uchar * name,const t_uchar * uri,const t_uchar * version,const t_uchar * mirror_of,int dot_listing_lossage,int signed_archive)70 arch_pfs_pfs_make_archive (const t_uchar * name,
71 const t_uchar * uri,
72 const t_uchar * version,
73 const t_uchar *mirror_of,
74 int dot_listing_lossage,
75 int signed_archive)
76 {
77 struct arch_pfs_sftp_session * p;
78 struct arch_pfs_session *pfs;
79 t_uchar * meta_info_path = 0;
80 t_uchar * name_file_path = 0;
81 t_uchar * archive_version_path = 0;
82 t_uchar * tmp_path;
83 t_uchar * archdir;
84 t_uchar * hosturi;
85 int name_fd;
86 int version_fd;
87
88 /* TODO: handle URIs like 'sftp://amit@cvs:~f' semi-reasonably
89 * The following code can mangle URIs, since it doesn't ignore the protocol
90 * part. IMHO, it doesn't belong in a general function like this
91 * one. - aaron.bentley@utoronto.ca
92 */
93 tmp_path = file_name_from_directory (0, uri); /* remove any trailing '/' */
94 archdir = file_name_tail (0, tmp_path);
95 hosturi = file_name_directory (0, tmp_path);
96 lim_free (0, tmp_path);
97
98 pfs = arch_pfs_connect (hosturi);
99 p = (struct arch_pfs_sftp_session *)pfs;
100 pfs->vtable->mkdir (pfs, archdir, 0777, 0);
101
102 meta_info_path = file_name_in_vicinity (0, archdir, "=meta-info");
103 archive_version_path = file_name_in_vicinity (0, archdir, ".archive-version");
104 name_file_path = file_name_in_vicinity (0, meta_info_path, "name");
105
106 pfs->vtable->mkdir (pfs, meta_info_path, 0777, 0);
107
108 if (mirror_of)
109 {
110 tmp_path = tmp_file_name ("/tmp", ",,pfs-sftp-file-contents");
111 name_fd = safe_open (tmp_path, O_RDWR | O_CREAT | O_EXCL, 0000);
112 safe_unlink (tmp_path);
113 safe_printfmt (name_fd, "%s\n", mirror_of);
114
115 safe_lseek (name_fd, (off_t)0, SEEK_SET);
116 pfs->vtable->put_file (pfs, name_file_path, 0666, name_fd, 0);
117
118 name_file_path = file_name_in_vicinity (0, meta_info_path, "mirror");
119 safe_lseek (name_fd, (off_t)0, SEEK_SET);
120 pfs->vtable->put_file (pfs, name_file_path, 0666, name_fd, 0);
121
122 safe_close (name_fd);
123 }
124 else
125 {
126 tmp_path = tmp_file_name ("/tmp", ",,pfs-sftp-file-contents");
127 name_fd = safe_open (tmp_path, O_RDWR | O_CREAT | O_EXCL, 0000);
128 safe_unlink (tmp_path);
129 safe_printfmt (name_fd, "%s\n", name);
130 safe_lseek (name_fd, (off_t)0, SEEK_SET);
131 pfs->vtable->put_file (pfs, name_file_path, 0666, name_fd, 0);
132 safe_close (name_fd);
133 }
134
135 if (dot_listing_lossage)
136 {
137 t_uchar * tmp_blowage_path = 0;
138 int tmp_blowage_fd = 0;
139 t_uchar * http_blows_path = 0;
140
141 tmp_blowage_path = tmp_file_name ("/tmp", ",,pfs-http-blows");
142 tmp_blowage_fd = safe_open (tmp_blowage_path, O_RDWR | O_CREAT | O_EXCL, 0000);
143 safe_unlink (tmp_blowage_path);
144 safe_printfmt (tmp_blowage_fd, "it sure does\n");
145
146 http_blows_path = file_name_in_vicinity (0, meta_info_path, "http-blows");
147 safe_lseek (tmp_blowage_fd, (off_t)0, SEEK_SET);
148 pfs->vtable->put_file (pfs, http_blows_path, 0666, tmp_blowage_fd, 0);
149
150 lim_free (0, tmp_blowage_path);
151 safe_close (tmp_blowage_fd);
152 lim_free (0, http_blows_path);
153 }
154
155 if (signed_archive)
156 {
157 t_uchar * tmp_signage_path = 0;
158 int tmp_signage_fd = 0;
159 t_uchar * http_signed_path = 0;
160
161 tmp_signage_path = tmp_file_name ("/tmp", ",,pfs-signed-archive");
162 tmp_signage_fd = safe_open (tmp_signage_path, O_RDWR | O_CREAT | O_EXCL, 0000);
163 safe_unlink (tmp_signage_path);
164 safe_printfmt (tmp_signage_fd, "system cracking is (nearly always) lame\n");
165
166 http_signed_path = file_name_in_vicinity (0, meta_info_path, "signed-archive");
167 safe_lseek (tmp_signage_fd, (off_t)0, SEEK_SET);
168 pfs->vtable->put_file (pfs, http_signed_path, 0666, tmp_signage_fd, 0);
169
170 lim_free (0, tmp_signage_path);
171 safe_close (tmp_signage_fd);
172 lim_free (0, http_signed_path);
173 }
174
175
176 tmp_path = tmp_file_name ("/tmp", ",,pfs-sftp-file-contents");
177 version_fd = safe_open (tmp_path, O_RDWR | O_CREAT | O_EXCL, 0000);
178 safe_unlink (tmp_path);
179 safe_printfmt (version_fd, "%s\n", version);
180 safe_lseek (version_fd, (off_t)0, SEEK_SET);
181 pfs->vtable->put_file (pfs, archive_version_path, 0666, name_fd, 0);
182 safe_close (version_fd);
183
184 if (dot_listing_lossage)
185 {
186 arch_pfs_update_listing_file (pfs, meta_info_path);
187 arch_pfs_update_listing_file (pfs, archdir);
188 }
189
190 arch_set_archive_location (name, uri, 0, ARCH_REG_FAIL_NORM);
191
192 lim_free (0, meta_info_path);
193 lim_free (0, name_file_path);
194 lim_free (0, archive_version_path);
195 lim_free (0, hosturi);
196 lim_free (0, archdir);
197 }
198
199
200 int
arch_valid_uri(const t_uchar * uri)201 arch_valid_uri (const t_uchar * uri)
202 {
203 int answer = 1;
204 if (arch_pfs_sftp_supported_protocol (uri))
205 {
206 t_uchar * user = 0, * hostname = 0, * port = 0;
207 char * path = 0;
208 answer = (arch_pfs_sftp_parse_uri (&user, &hostname, &port, &path, uri) == 0);
209 lim_free (0, user);
210 lim_free (0, hostname);
211 lim_free (0, port);
212 lim_free (0, path);
213 }
214 return answer;
215 }
216
217
218 struct arch_pfs_session *
arch_pfs_connect(const t_uchar * uri)219 arch_pfs_connect (const t_uchar * uri)
220 {
221 struct arch_pfs_session * answer = 0;
222
223 if (arch_pfs_dav_supported_protocol (uri))
224 {
225 return arch_pfs_dav_connect (uri);
226 }
227 else if (arch_pfs_sftp_supported_protocol (uri))
228 {
229 return arch_pfs_sftp_connect (uri);
230 }
231 else if (arch_pfs_ftp_supported_protocol (uri))
232 {
233 return arch_pfs_ftp_connect (uri);
234 }
235 else
236 {
237 return arch_pfs_fs_connect (uri);
238 }
239
240 return answer;
241 }
242
243
244 t_uchar *
arch_pfs_file_contents(struct arch_pfs_session * pfs,const t_uchar * path,int soft_errors)245 arch_pfs_file_contents (struct arch_pfs_session * pfs,
246 const t_uchar * path,
247 int soft_errors)
248 {
249 return pfs->vtable->file_contents (pfs, path, soft_errors);
250 }
251
252
253 rel_table
arch_pfs_directory_files(struct arch_pfs_session * pfs,const t_uchar * path,int soft_errors)254 arch_pfs_directory_files (struct arch_pfs_session * pfs,
255 const t_uchar * path,
256 int soft_errors)
257 {
258 return pfs->vtable->directory_files (pfs, path, soft_errors);
259 }
260
261
262 int
arch_pfs_file_exists(struct arch_pfs_session * pfs,const t_uchar * path)263 arch_pfs_file_exists (struct arch_pfs_session * pfs,
264 const t_uchar * path)
265 {
266 return pfs->vtable->file_exists (pfs, path);
267 }
268
269
270 int
arch_pfs_get_file(struct arch_pfs_session * pfs,int out_fd,const t_uchar * path,int soft_errors)271 arch_pfs_get_file (struct arch_pfs_session * pfs,
272 int out_fd,
273 const t_uchar * path,
274 int soft_errors)
275 {
276 return pfs->vtable->get_file (pfs, out_fd, path, soft_errors);
277 }
278
279
280 int
arch_pfs_put_file(struct arch_pfs_session * pfs,const t_uchar * path,mode_t perms,int in_fd,int soft_errors)281 arch_pfs_put_file (struct arch_pfs_session * pfs,
282 const t_uchar * path,
283 mode_t perms,
284 int in_fd,
285 int soft_errors)
286 {
287 return pfs->vtable->put_file (pfs, path, perms, in_fd, soft_errors);
288 }
289
290
291 int
arch_pfs_put_atomic(struct arch_pfs_session * pfs,t_uchar ** errstr,const t_uchar * path,mode_t perms,int in_fd,int replace,int soft_errors)292 arch_pfs_put_atomic (struct arch_pfs_session * pfs,
293 t_uchar ** errstr,
294 const t_uchar * path,
295 mode_t perms,
296 int in_fd,
297 int replace,
298 int soft_errors)
299 {
300 int result = 0;
301 t_uchar * tmp_dir = file_name_directory_file (0, path);
302 t_uchar * tmp_file = tmp_file_name (tmp_dir, ",,upload-tmp");
303
304 arch_pfs_rmrf_file (pfs, tmp_file);
305 if (!arch_pfs_put_file (pfs, tmp_file, perms, in_fd, soft_errors))
306 {
307 if (replace)
308 arch_pfs_rmrf_file (pfs, path);
309 if (arch_pfs_rename (pfs, errstr, tmp_file, path, soft_errors))
310 result = -1;
311 }
312 else
313 result = -1;
314 lim_free (0, tmp_dir);
315 lim_free (0, tmp_file);
316 return result;
317 }
318
319
320 int
arch_pfs_mkdir(struct arch_pfs_session * pfs,const t_uchar * path,mode_t perms,int soft_errors)321 arch_pfs_mkdir (struct arch_pfs_session * pfs,
322 const t_uchar * path,
323 mode_t perms,
324 int soft_errors)
325 {
326 return pfs->vtable->mkdir (pfs, path, perms, soft_errors);
327 }
328
329
330 int
arch_pfs_rename(struct arch_pfs_session * pfs,t_uchar ** errstr,const t_uchar * from,const t_uchar * to,int soft_errors)331 arch_pfs_rename (struct arch_pfs_session * pfs,
332 t_uchar ** errstr,
333 const t_uchar * from,
334 const t_uchar * to,
335 int soft_errors)
336 {
337 return pfs->vtable->rename (pfs, errstr, from, to, soft_errors);
338 }
339
340
341 int
arch_pfs_is_dir(struct arch_pfs_session * pfs,const t_uchar * path)342 arch_pfs_is_dir (struct arch_pfs_session * pfs,
343 const t_uchar * path)
344 {
345 return pfs->vtable->is_dir (pfs, path);
346 }
347
348
349 int
arch_pfs_rmdir(struct arch_pfs_session * pfs,const t_uchar * path,int soft_errors)350 arch_pfs_rmdir (struct arch_pfs_session * pfs,
351 const t_uchar * path,
352 int soft_errors)
353 {
354 return pfs->vtable->rmdir (pfs, path, soft_errors);
355 }
356
357
358 int
arch_pfs_rm(struct arch_pfs_session * pfs,const t_uchar * path,int soft_errors)359 arch_pfs_rm (struct arch_pfs_session * pfs,
360 const t_uchar * path,
361 int soft_errors)
362 {
363 return pfs->vtable->rm (pfs, path, soft_errors);
364 }
365
366
367 void
arch_pfs_update_listing_file(struct arch_pfs_session * session,const t_uchar * dir)368 arch_pfs_update_listing_file (struct arch_pfs_session * session,
369 const t_uchar * dir)
370 {
371 t_uchar * tmp_path = 0;
372 int tmp_fd = 0;
373 t_uchar * dot_listing_path = 0;
374 t_uchar * dot_listing_tmp = 0;
375 rel_table files_before = rel_table_nil;
376 rel_table files_after = rel_table_nil;
377
378 tmp_path = tmp_file_name ("/tmp", ",,pfs-dot-listing");
379 tmp_fd = safe_open (tmp_path, O_RDWR | O_CREAT | O_EXCL, 0000);
380 safe_unlink (tmp_path);
381
382 dot_listing_path = file_name_in_vicinity (0, dir, ".listing");
383 dot_listing_tmp = archive_tmp_file_name (dir, ",,dot-listing");
384
385 while (1)
386 {
387 int x;
388
389 files_before = arch_pfs_directory_files (session, dir, 0);
390 if (rel_n_records (files_before))
391 rel_sort_table_by_field (0, files_before, 0);
392
393 for (x = 0; x < rel_n_records (files_before); ++x)
394 {
395 const t_uchar * file_name;
396
397 file_name = rel_peek_str (files_before, x, 0);
398
399 if ( (('.' != file_name[0]) && (',' != file_name[0]))
400 || !str_cmp (".archive-version", file_name))
401 {
402 safe_printfmt (tmp_fd, "%s\r\n", rel_peek_str (files_before, x, 0));
403 }
404 }
405
406 safe_lseek (tmp_fd, (off_t)0, SEEK_SET);
407 arch_pfs_put_atomic (session, 0, dot_listing_path, 0444, tmp_fd, 1, 0);
408
409 files_after = arch_pfs_directory_files (session, dir, 0);
410 if (rel_n_records (files_after))
411 rel_sort_table_by_field (0, files_after, 0);
412
413 if (!dot_listings_equal (files_before, files_after))
414 {
415 safe_ftruncate (tmp_fd, (long)0);
416 rel_free_table (files_before);
417 rel_free_table (files_after);
418 files_before = rel_table_nil;
419 files_after = rel_table_nil;
420 }
421 else
422 {
423 break;
424 }
425 }
426
427 lim_free (0, tmp_path);
428 safe_close (tmp_fd);
429 lim_free (0, dot_listing_path);
430 lim_free (0, dot_listing_tmp);
431 rel_free_table (files_before);
432 rel_free_table (files_after);
433 }
434
435
436 static int
dot_listings_equal(rel_table a,rel_table b)437 dot_listings_equal (rel_table a, rel_table b)
438 {
439 int ax;
440 int bx;
441
442 if ((!rel_n_records (a) && rel_n_records (b)) || (rel_n_records (a) && !rel_n_records (b)))
443 return 0;
444
445 ax = 0;
446 bx = 0;
447 while ((ax < rel_n_records (a)) || (bx < rel_n_records (b)))
448 {
449 if ((ax < rel_n_records (a)) && (rel_peek_str (a, ax, 0)[0] == '.'))
450 {
451 ++ax;
452 continue;
453 }
454 if ((ax < rel_n_records (a)) && (rel_peek_str (a, ax, 0)[0] == ','))
455 {
456 ++ax;
457 continue;
458 }
459 if ((bx < rel_n_records (b)) && (rel_peek_str (b, bx, 0)[0] == '.'))
460 {
461 ++bx;
462 continue;
463 }
464 if ((bx < rel_n_records (b)) && (rel_peek_str (b, bx, 0)[0] == ','))
465 {
466 ++bx;
467 continue;
468 }
469
470 if ((ax == rel_n_records (a)) || (bx == rel_n_records (b)))
471 return 0;
472
473 if (str_cmp (rel_peek_str (a, ax, 0), rel_peek_str (b, bx, 0)))
474 return 0;
475
476 ++ax;
477 ++bx;
478 }
479
480 if ((ax != rel_n_records (a)) || (bx != rel_n_records (b)))
481 return 0;
482
483 return 1;
484 }
485
486
487
488 /* tag: Tom Lord Thu Jun 5 15:12:22 2003 (pfs.c)
489 */
490