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