OSDN Git Service

* src/lhadd.c (build_temporary_file): no use SIGHUP for mingw32.
[lha/lha.git] / src / lhadd.c
1 /* ------------------------------------------------------------------------ */
2 /* LHa for UNIX                                                                                                                         */
3 /*                              lhadd.c -- LHarc Add Command                                                            */
4 /*                                                                                                                                                      */
5 /*              Copyright (C) MCMLXXXIX Yooichi.Tagawa                                                          */
6 /*              Modified                        Nobutaka Watazaki                                                       */
7 /*                                                                                                                                                      */
8 /*      Ver. 1.14       Source All chagned                              1995.01.14      N.Watazaki              */
9 /* ------------------------------------------------------------------------ */
10 #include "lha.h"
11 /* ------------------------------------------------------------------------ */
12 static void     remove_files();
13
14 static char     new_archive_name_buffer[FILENAME_LENGTH];
15 static char    *new_archive_name;
16 /* ------------------------------------------------------------------------ */
17 static void
18 add_one(fp, nafp, hdr)
19         FILE           *fp, *nafp;
20         LzHeader       *hdr;
21 {
22         long            header_pos, next_pos, org_pos, data_pos;
23         long            v_original_size, v_packed_size;
24         int             mode;
25
26         reading_filename = hdr->name;
27         writting_filename = temporary_name;
28
29         if (!fp && generic_format)      /* [generic] doesn't need directory
30                                          * info. */
31                 return;
32         header_pos = ftell(nafp);
33         write_header(nafp, hdr);/* DUMMY */
34
35         if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
36                 char            buf[256], *b1, *b2;
37                 if (!quiet) {
38                         strcpy(buf, hdr->name);
39                         b1 = strtok(buf, "|");
40                         b2 = strtok(NULL, "|");
41                         printf("%s -> %s\t- Symbolic Link\n", b1, b2);
42                 }               /* if quiet .. */
43         }
44
45         if (hdr->original_size == 0)    /* empty file or directory */
46                 return;         /* previous write_header is not DUMMY. (^_^) */
47
48         org_pos = ftell(fp);
49         data_pos = ftell(nafp);
50
51         hdr->crc = encode_lzhuf(fp, nafp, hdr->original_size,
52                   &v_original_size, &v_packed_size, hdr->name, hdr->method);
53
54         if (v_packed_size < v_original_size) {
55                 next_pos = ftell(nafp);
56         }
57         else {                  /* retry by stored method */
58                 fseek(fp, org_pos, SEEK_SET);
59                 fseek(nafp, data_pos, SEEK_SET);
60                 hdr->crc = encode_stored_crc(fp, nafp, hdr->original_size,
61                                           &v_original_size, &v_packed_size);
62                 fflush(nafp);
63                 next_pos = ftell(nafp);
64 #if HAVE_FTRUNCATE
65                 ftruncate(fileno(nafp), next_pos);
66 #endif
67                 bcopy(LZHUFF0_METHOD, hdr->method, METHOD_TYPE_STRAGE);
68         }
69         hdr->original_size = v_original_size;
70         hdr->packed_size = v_packed_size;
71         fseek(nafp, header_pos, SEEK_SET);
72         write_header(nafp, hdr);
73         fseek(nafp, next_pos, SEEK_SET);
74 }
75
76
77 /* ------------------------------------------------------------------------ */
78 FILE           *
79 append_it(name, oafp, nafp)
80         char           *name;
81         FILE           *oafp, *nafp;
82 {
83         LzHeader        ahdr, hdr;
84         FILE           *fp;
85         long            old_header;
86         int             cmp;
87         int             filec;
88         char          **filev;
89         int             i;
90         struct stat     stbuf /*, lstbuf*/;
91
92         boolean         directory, symlink;
93
94         if (GETSTAT(name, &stbuf) < 0) {
95                 error("Cannot access", name);   /* See cleaning_files, Why? */
96                 return oafp;
97         }
98         
99         directory = is_directory(&stbuf);
100 #ifdef S_IFLNK
101         symlink = is_symlink(&stbuf);
102 #else
103         symlink = 0;
104 #endif
105         init_header(name, &stbuf, &hdr);
106
107         if (!directory && !noexec)
108                 if (symlink)
109                         fp = NULL;
110                 else
111                         fp = xfopen(name, READ_BINARY);
112         else {
113                 fp = NULL;
114         }
115
116         while (oafp) {
117                 old_header = ftell(oafp);
118                 if (!get_header(oafp, &ahdr)) {
119                         fclose(oafp);
120                         oafp = NULL;
121                         break;
122                 } else {
123 #if 0                   
124                         cmp = STRING_COMPARE(ahdr.name, hdr.name);
125 #endif
126                         /* for symbolic link. t.okamoto */
127                         cmp = strcmp_filename(ahdr.name, hdr.name);
128                         if (cmp < 0) {  /* SKIP */
129                                 /* copy old to new */
130                                 if (!noexec) {
131                                         fseek(oafp, old_header, SEEK_SET);
132                                         copy_old_one(oafp, nafp, &ahdr);
133                                 }
134                                 else
135                                         fseek(oafp, ahdr.packed_size, SEEK_CUR);
136                         } else if (cmp == 0) {  /* REPLACE */
137                                 /* drop old archive's */
138                                 fseek(oafp, ahdr.packed_size, SEEK_CUR);
139                                 break;
140                         } else {        /* cmp > 0, INSERT */
141                                 fseek(oafp, old_header, SEEK_SET);
142                                 break;
143                         }
144                 }
145         }
146
147         if (update_if_newer) {
148                 if (!oafp ||    /* not in archive */
149                     cmp > 0 ||  /* // */
150                     ahdr.unix_last_modified_stamp <     /* newer than archive's */
151                     hdr.unix_last_modified_stamp) {
152                         if (noexec)
153                                 printf("ADD %s\n", name);
154                         else
155                                 add_one(fp, nafp, &hdr);
156                 } else {                /* cmp == 0 *//* copy old to new */
157                         if (!noexec) {
158                                 fseek(oafp, old_header, SEEK_SET);
159                                 copy_old_one(oafp, nafp, &ahdr);
160                         }
161                 }
162         } else {
163                 if (!oafp || cmp > 0) { /* not in archive or dropped */
164                         if (noexec)
165                                 printf("ADD %s\n", name);
166                         else
167                                 add_one(fp, nafp, &hdr);
168                 }
169                 else {          /* cmp == 0 */
170                         /* replace */
171                         if (noexec)
172                                 printf("REPLACE\n");
173                         else
174                                 add_one(fp, nafp, &hdr);
175                 }
176         }
177
178         if (!directory) {
179                 if (!noexec)
180                         if (!symlink)
181                                 fclose(fp);
182         }
183         else {                  /* recurcive call */
184                 if (find_files(name, &filec, &filev)) {
185                         for (i = 0; i < filec; i++)
186                                 oafp = append_it(filev[i], oafp, nafp);
187                         free_files(filec, filev);
188                 }
189         }
190         return oafp;
191 }
192
193 /* ------------------------------------------------------------------------ */
194 static void
195 find_update_files(oafp)
196         FILE           *oafp;   /* old archive */
197 {
198         char            name[FILENAME_LENGTH];
199         struct string_pool sp;
200         LzHeader        hdr;
201         long            pos;
202         struct stat     stbuf;
203         int             len;
204
205         pos = ftell(oafp);
206
207         init_sp(&sp);
208         while (get_header(oafp, &hdr)) {
209                 if ((hdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR) {
210                         if (stat(hdr.name, &stbuf) >= 0)        /* exist ? */
211                                 add_sp(&sp, hdr.name, strlen(hdr.name) + 1);
212                 }
213                 else if ((hdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY) {
214                         strcpy(name, hdr.name);
215                         len = strlen(name);
216                         if (len > 0 && name[len - 1] == '/')
217                                 name[--len] = '\0';     /* strip tail '/' */
218                         if (stat(name, &stbuf) >= 0)    /* exist ? */
219                                 add_sp(&sp, name, len + 1);
220                 }
221                 fseek(oafp, hdr.packed_size, SEEK_CUR);
222         }
223
224         fseek(oafp, pos, SEEK_SET);
225
226         finish_sp(&sp, &cmd_filec, &cmd_filev);
227 }
228
229 /* ------------------------------------------------------------------------ */
230 static void
231 delete(oafp, nafp)
232         FILE           *oafp, *nafp;
233 {
234         LzHeader        ahdr;
235         long            old_header_pos;
236         char            lpath[256], *b1, *b2;
237
238         old_header_pos = ftell(oafp);
239         while (get_header(oafp, &ahdr)) {
240                 strcpy(lpath, ahdr.name);
241                 b1 = strtok(lpath, "|");
242                 b2 = strtok(NULL, "|");
243                 if (need_file(b1)) {    /* skip */
244                         fseek(oafp, ahdr.packed_size, SEEK_CUR);
245                         if (noexec || !quiet)
246                                 if (b2 != NULL)
247                                         printf("delete %s -> %s\n", b1, b2);
248                                 else
249                                         printf("delete %s\n", b1);
250                 }
251                 else {          /* copy */
252                         if (noexec) {
253                                 fseek(oafp, ahdr.packed_size, SEEK_CUR);
254                         }
255                         else {
256                                 fseek(oafp, old_header_pos, SEEK_SET);
257                                 copy_old_one(oafp, nafp, &ahdr);
258                         }
259                 }
260                 old_header_pos = ftell(oafp);
261         }
262         return;
263 }
264
265 /* ------------------------------------------------------------------------ */
266 /*                                                                                                                                                      */
267 /* ------------------------------------------------------------------------ */
268 static FILE    *
269 build_temporary_file()
270 {
271         int             old_umask;
272         FILE           *afp;
273
274         build_temporary_name();
275         signal(SIGINT, interrupt);
276 #ifdef SIGHUP
277         signal(SIGHUP, interrupt);
278 #endif
279
280         old_umask = umask(077);
281         afp = xfopen(temporary_name, WRITE_BINARY);
282         remove_temporary_at_error = TRUE;
283         temporary_fp = afp;
284         umask(old_umask);
285
286         return afp;
287 }
288
289 /* ------------------------------------------------------------------------ */
290 static void
291 build_backup_file()
292 {
293
294         build_backup_name(backup_archive_name, archive_name);
295         if (!noexec) {
296                 signal(SIGINT, SIG_IGN);
297 #ifdef SIGHUP
298                 signal(SIGHUP, SIG_IGN);
299 #endif
300                 if (rename(archive_name, backup_archive_name) < 0)
301                         fatal_error(archive_name);
302                 recover_archive_when_interrupt = TRUE;
303                 signal(SIGINT, interrupt);
304 #ifdef SIGHUP
305                 signal(SIGHUP, interrupt);
306 #endif
307         }
308 }
309
310 /* ------------------------------------------------------------------------ */
311 static void
312 report_archive_name_if_different()
313 {
314         if (!quiet && new_archive_name == new_archive_name_buffer) {
315                 /* warning at old archive is SFX */
316                 printf("New archive file is \"%s\"\n", new_archive_name);
317         }
318 }
319
320 /* ------------------------------------------------------------------------ */
321 #ifdef TMP_FILENAME_TEMPLATE
322 void
323 temporary_to_new_archive_file(new_archive_size)
324         long            new_archive_size;
325 {
326         FILE           *oafp, *nafp;
327
328         oafp = xfopen(temporary_name, READ_BINARY);
329         if (!strcmp(new_archive_name, "-")) {
330                 nafp = stdout;
331                 writting_filename = "starndard output";
332         }
333         else {
334                 nafp = xfopen(new_archive_name, WRITE_BINARY);
335                 writting_filename = archive_name;
336         }
337         reading_filename = temporary_name;
338         copyfile(oafp, nafp, new_archive_size, 0);
339         if (nafp != stdout)
340                 fclose(nafp);
341         fclose(oafp);
342
343         recover_archive_when_interrupt = FALSE;
344         unlink(temporary_name);
345
346         remove_temporary_at_error = FALSE;
347 }
348 #else
349 temporary_to_new_archive_file(new_archive_size)
350         long            new_archive_size;
351 {
352         char           *p;
353         p = (char *) strrchr(new_archive_name, '/');
354         p = p ? p + 1 : new_archive_name;
355         unlink(new_archive_name);
356         if (rename(temporary_name, p) < 0) {
357                 fprintf(stderr, "Can't rename temporary_name '%s'\n", new_archive_name);
358                 exit(1);
359         }
360 }
361 #endif
362
363 /* ------------------------------------------------------------------------ */
364 static void
365 set_archive_file_mode()
366 {
367         int             umask_value;
368         struct stat     stbuf;
369
370         if (archive_file_gid < 0) {
371                 umask(umask_value = umask(0));
372                 archive_file_mode = (~umask_value) & 0666;      /* rw-rw-rw- */
373                 if (stat(".", &stbuf) >= 0)
374                         archive_file_gid = stbuf.st_gid;
375         }
376         if (archive_file_gid >= 0)
377                 chown(new_archive_name, getuid(), archive_file_gid);
378
379         chmod(new_archive_name, archive_file_mode);
380 }
381
382 /* ------------------------------------------------------------------------ */
383 /*                                                      REMOVE FILE/DIRECTORY                                                   */
384 /* ------------------------------------------------------------------------ */
385 static void
386 remove_one(name)
387         char           *name;
388 {
389         struct stat     stbuf;
390         int             filec;
391         char          **filev;
392
393         if (GETSTAT(name, &stbuf) < 0) {
394                 warning("Cannot access", name);
395         }
396         else if (is_directory(&stbuf)) {
397                 if (find_files(name, &filec, &filev)) {
398                         remove_files(filec, filev);
399                         free_files(filec, filev);
400                 }
401                 else
402                         warning("Cannot open directory", name);
403
404                 if (noexec)
405                         printf("REMOVE DIRECTORY %s\n", name);
406                 else if (rmdir(name) < 0)
407                         warning("Cannot remove directory", name);
408                 else if (verbose)
409                         printf("Removed %s.\n", name);
410         }
411         else if (is_regularfile(&stbuf)) {
412                 if (noexec)
413                         printf("REMOVE FILE %s.\n", name);
414                 else if (unlink(name) < 0)
415                         warning("Cannot remove", name);
416                 else if (verbose)
417                         printf("Removed %s.\n", name);
418         }
419 #ifdef S_IFLNK
420         else if (is_symlink(&stbuf)) {
421                 if (noexec)
422                         printf("REMOVE SYMBOLIC LINK %s.\n", name);
423                 else if (unlink(name) < 0)
424                         warning("Cannot remove", name);
425                 else if (verbose)
426                         printf("Removed %s.\n", name);
427         }
428 #endif
429         else {
430                 error("Cannot remove (not a file or directory)", name);
431         }
432 }
433
434 static void
435 remove_files(filec, filev)
436         int             filec;
437         char          **filev;
438 {
439         int             i;
440
441         for (i = 0; i < filec; i++)
442                 remove_one(filev[i]);
443 }
444
445 /* ------------------------------------------------------------------------ */
446 /*                                                                                                                                                      */
447 /* ------------------------------------------------------------------------ */
448 void
449 cmd_add()
450 {
451         LzHeader        ahdr;
452         FILE           *oafp, *nafp;
453         int             i;
454         long            old_header;
455         boolean         old_archive_exist;
456         long            new_archive_size;
457
458         /* exit if no operation */
459         if (!update_if_newer && cmd_filec == 0) {
460                 error("No files given in argument, do nothing.", "");
461                 return;
462         }
463
464         /* open old archive if exist */
465         if ((oafp = open_old_archive()) == NULL)
466                 old_archive_exist = FALSE;
467         else
468                 old_archive_exist = TRUE;
469
470         if (update_if_newer && cmd_filec == 0 && !oafp)
471                 fatal_error(archive_name);      /* exit if cannot execute
472                                                  * automatic update */
473         errno = 0;
474
475         if (new_archive && old_archive_exist) {
476                 fclose(oafp);
477                 oafp = NULL;
478         }
479
480         if (oafp && archive_is_msdos_sfx1(archive_name)) {
481                 skip_msdos_sfx1_code(oafp);
482                 build_standard_archive_name(new_archive_name_buffer, archive_name);
483                 new_archive_name = new_archive_name_buffer;
484         }
485         else {
486                 new_archive_name = archive_name;
487         }
488
489         /* build temporary file */
490         if (!noexec)
491                 nafp = build_temporary_file();
492
493         /* find needed files when automatic update */
494         if (update_if_newer && cmd_filec == 0)
495                 find_update_files(oafp);
496
497         /* build new archive file */
498         /* cleaning arguments */
499         cleaning_files(&cmd_filec, &cmd_filev);
500         if (cmd_filec == 0) {
501                 if (oafp)
502                         fclose(oafp);
503                 if (!noexec)
504                         fclose(nafp);
505                 return;
506         }
507
508         for (i = 0; i < cmd_filec; i++)
509                 oafp = append_it(cmd_filev[i], oafp, nafp);
510         if (oafp) {
511                 old_header = ftell(oafp);
512                 while (get_header(oafp, &ahdr)) {
513                         if (noexec)
514                                 fseek(oafp, ahdr.packed_size, SEEK_CUR);
515                         else {
516                                 fseek(oafp, old_header, SEEK_SET);
517                                 copy_old_one(oafp, nafp, &ahdr);
518                         }
519                         old_header = ftell(oafp);
520                 }
521                 fclose(oafp);
522         }
523         if (!noexec) {
524                 write_archive_tail(nafp);
525                 new_archive_size = ftell(nafp);
526                 fclose(nafp);
527         }
528
529         /* build backup archive file */
530         if (old_archive_exist)
531                 build_backup_file();
532
533         report_archive_name_if_different();
534
535         /* copy temporary file to new archive file */
536         if (!noexec && (!strcmp(new_archive_name, "-") ||
537                         rename(temporary_name, new_archive_name) < 0))
538                 temporary_to_new_archive_file(new_archive_size);
539
540         /* set new archive file mode/group */
541         set_archive_file_mode();
542
543         /* remove archived files */
544         if (delete_after_append)
545                 remove_files(cmd_filec, cmd_filev);
546
547         return;
548 }
549
550 /* ------------------------------------------------------------------------ */
551 void
552 cmd_delete()
553 {
554         FILE           *oafp, *nafp;
555         long            new_archive_size;
556
557         /* open old archive if exist */
558         if ((oafp = open_old_archive()) == NULL)
559                 fatal_error(archive_name);
560         errno = 0;
561
562         /* exit if no operation */
563         if (cmd_filec == 0) {
564                 fclose(oafp);
565                 warning("No files given in argument, do nothing.", "");
566                 return;
567         }
568
569         if (archive_is_msdos_sfx1(archive_name)) {
570                 skip_msdos_sfx1_code(oafp);
571                 build_standard_archive_name(new_archive_name_buffer, archive_name);
572                 new_archive_name = new_archive_name_buffer;
573         }
574         else {
575                 new_archive_name = archive_name;
576         }
577
578         /* build temporary file */
579         if (!noexec)
580                 nafp = build_temporary_file();
581
582         /* build new archive file */
583         delete(oafp, nafp);
584         fclose(oafp);
585
586         if (!noexec) {
587                 write_archive_tail(nafp);
588                 new_archive_size = ftell(nafp);
589                 fclose(nafp);
590         }
591
592         /* build backup archive file */
593         build_backup_file();
594
595         /* 1999.5.24 t.oka */
596         if(!noexec && new_archive_size <= 1){
597                 unlink(temporary_name);
598                 printf("New archive file \"%s\" is not created because it would be empty.\n", new_archive_name);
599                 return;
600         }
601
602         report_archive_name_if_different();
603
604         /* copy temporary file to new archive file */
605         if (!noexec && rename(temporary_name, new_archive_name) < 0)
606                 temporary_to_new_archive_file(new_archive_size);
607
608         /* set new archive file mode/group */
609         set_archive_file_mode();
610
611         return;
612 }
613
614 /* for symbolic link name. t.okamoto 96/2/20 */
615 int strcmp_filename( str1, str2 )
616 char *str1;
617 char *str2;
618 {
619         char *p, *q;
620
621         p = str1; q = str2;
622         while (*p != 0 && *q != 0) {
623                 if (*p == '|') {
624                         if (*q == 0) return 0;
625                         else if (*q != '|') return -1;
626                 } else if (*q == '|') {
627                         if (*p == 0) return 0;
628                         else if (*q != '|') return 1;
629                 } else if (*p != *q) break;
630                 p++; q++;
631         }
632         return (int)*p-(int)*q;
633 }
634
635                 
636 /* Local Variables: */
637 /* mode:c */
638 /* tab-width:4 */
639 /* compile-command:"gcc -c lhadd.c" */
640 /* End: */