OSDN Git Service

merged changing from lha-1.14f to lha-1.14i.
[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         signal(SIGHUP, interrupt);
277
278         old_umask = umask(077);
279         afp = xfopen(temporary_name, WRITE_BINARY);
280         remove_temporary_at_error = TRUE;
281         temporary_fp = afp;
282         umask(old_umask);
283
284         return afp;
285 }
286
287 /* ------------------------------------------------------------------------ */
288 static void
289 build_backup_file()
290 {
291
292         build_backup_name(backup_archive_name, archive_name);
293         if (!noexec) {
294                 signal(SIGINT, SIG_IGN);
295                 signal(SIGHUP, SIG_IGN);
296                 if (rename(archive_name, backup_archive_name) < 0)
297                         fatal_error(archive_name);
298                 recover_archive_when_interrupt = TRUE;
299                 signal(SIGINT, interrupt);
300                 signal(SIGHUP, interrupt);
301         }
302 }
303
304 /* ------------------------------------------------------------------------ */
305 static void
306 report_archive_name_if_different()
307 {
308         if (!quiet && new_archive_name == new_archive_name_buffer) {
309                 /* warning at old archive is SFX */
310                 printf("New archive file is \"%s\"\n", new_archive_name);
311         }
312 }
313
314 /* ------------------------------------------------------------------------ */
315 #ifdef TMP_FILENAME_TEMPLATE
316 void
317 temporary_to_new_archive_file(new_archive_size)
318         long            new_archive_size;
319 {
320         FILE           *oafp, *nafp;
321
322         oafp = xfopen(temporary_name, READ_BINARY);
323         if (!strcmp(new_archive_name, "-")) {
324                 nafp = stdout;
325                 writting_filename = "starndard output";
326         }
327         else {
328                 nafp = xfopen(new_archive_name, WRITE_BINARY);
329                 writting_filename = archive_name;
330         }
331         reading_filename = temporary_name;
332         copyfile(oafp, nafp, new_archive_size, 0);
333         if (nafp != stdout)
334                 fclose(nafp);
335         fclose(oafp);
336
337         recover_archive_when_interrupt = FALSE;
338         unlink(temporary_name);
339
340         remove_temporary_at_error = FALSE;
341 }
342 #else
343 temporary_to_new_archive_file(new_archive_size)
344         long            new_archive_size;
345 {
346         char           *p;
347         p = (char *) strrchr(new_archive_name, '/');
348         p = p ? p + 1 : new_archive_name;
349         unlink(new_archive_name);
350         if (rename(temporary_name, p) < 0) {
351                 fprintf(stderr, "Can't rename temporary_name '%s'\n", new_archive_name);
352                 exit(1);
353         }
354 }
355 #endif
356
357 /* ------------------------------------------------------------------------ */
358 static void
359 set_archive_file_mode()
360 {
361         int             umask_value;
362         struct stat     stbuf;
363
364         if (archive_file_gid < 0) {
365                 umask(umask_value = umask(0));
366                 archive_file_mode = (~umask_value) & 0666;      /* rw-rw-rw- */
367                 if (stat(".", &stbuf) >= 0)
368                         archive_file_gid = stbuf.st_gid;
369         }
370         if (archive_file_gid >= 0)
371                 chown(new_archive_name, getuid(), archive_file_gid);
372
373         chmod(new_archive_name, archive_file_mode);
374 }
375
376 /* ------------------------------------------------------------------------ */
377 /*                                                      REMOVE FILE/DIRECTORY                                                   */
378 /* ------------------------------------------------------------------------ */
379 static void
380 remove_one(name)
381         char           *name;
382 {
383         struct stat     stbuf;
384         int             filec;
385         char          **filev;
386
387         if (GETSTAT(name, &stbuf) < 0) {
388                 warning("Cannot access", name);
389         }
390         else if (is_directory(&stbuf)) {
391                 if (find_files(name, &filec, &filev)) {
392                         remove_files(filec, filev);
393                         free_files(filec, filev);
394                 }
395                 else
396                         warning("Cannot open directory", name);
397
398                 if (noexec)
399                         printf("REMOVE DIRECTORY %s\n", name);
400                 else if (rmdir(name) < 0)
401                         warning("Cannot remove directory", name);
402                 else if (verbose)
403                         printf("Removed %s.\n", name);
404         }
405         else if (is_regularfile(&stbuf)) {
406                 if (noexec)
407                         printf("REMOVE FILE %s.\n", name);
408                 else if (unlink(name) < 0)
409                         warning("Cannot remove", name);
410                 else if (verbose)
411                         printf("Removed %s.\n", name);
412         }
413 #ifdef S_IFLNK
414         else if (is_symlink(&stbuf)) {
415                 if (noexec)
416                         printf("REMOVE SYMBOLIC LINK %s.\n", name);
417                 else if (unlink(name) < 0)
418                         warning("Cannot remove", name);
419                 else if (verbose)
420                         printf("Removed %s.\n", name);
421         }
422 #endif
423         else {
424                 error("Cannot remove (not a file or directory)", name);
425         }
426 }
427
428 static void
429 remove_files(filec, filev)
430         int             filec;
431         char          **filev;
432 {
433         int             i;
434
435         for (i = 0; i < filec; i++)
436                 remove_one(filev[i]);
437 }
438
439 /* ------------------------------------------------------------------------ */
440 /*                                                                                                                                                      */
441 /* ------------------------------------------------------------------------ */
442 void
443 cmd_add()
444 {
445         LzHeader        ahdr;
446         FILE           *oafp, *nafp;
447         int             i;
448         long            old_header;
449         boolean         old_archive_exist;
450         long            new_archive_size;
451
452         /* exit if no operation */
453         if (!update_if_newer && cmd_filec == 0) {
454                 error("No files given in argument, do nothing.", "");
455                 return;
456         }
457
458         /* open old archive if exist */
459         if ((oafp = open_old_archive()) == NULL)
460                 old_archive_exist = FALSE;
461         else
462                 old_archive_exist = TRUE;
463
464         if (update_if_newer && cmd_filec == 0 && !oafp)
465                 fatal_error(archive_name);      /* exit if cannot execute
466                                                  * automatic update */
467         errno = 0;
468
469         if (new_archive && old_archive_exist) {
470                 fclose(oafp);
471                 oafp = NULL;
472         }
473
474         if (oafp && archive_is_msdos_sfx1(archive_name)) {
475                 skip_msdos_sfx1_code(oafp);
476                 build_standard_archive_name(new_archive_name_buffer, archive_name);
477                 new_archive_name = new_archive_name_buffer;
478         }
479         else {
480                 new_archive_name = archive_name;
481         }
482
483         /* build temporary file */
484         if (!noexec)
485                 nafp = build_temporary_file();
486
487         /* find needed files when automatic update */
488         if (update_if_newer && cmd_filec == 0)
489                 find_update_files(oafp);
490
491         /* build new archive file */
492         /* cleaning arguments */
493         cleaning_files(&cmd_filec, &cmd_filev);
494         if (cmd_filec == 0) {
495                 if (oafp)
496                         fclose(oafp);
497                 if (!noexec)
498                         fclose(nafp);
499                 return;
500         }
501
502         for (i = 0; i < cmd_filec; i++)
503                 oafp = append_it(cmd_filev[i], oafp, nafp);
504         if (oafp) {
505                 old_header = ftell(oafp);
506                 while (get_header(oafp, &ahdr)) {
507                         if (noexec)
508                                 fseek(oafp, ahdr.packed_size, SEEK_CUR);
509                         else {
510                                 fseek(oafp, old_header, SEEK_SET);
511                                 copy_old_one(oafp, nafp, &ahdr);
512                         }
513                         old_header = ftell(oafp);
514                 }
515                 fclose(oafp);
516         }
517         if (!noexec) {
518                 write_archive_tail(nafp);
519                 new_archive_size = ftell(nafp);
520                 fclose(nafp);
521         }
522
523         /* build backup archive file */
524         if (old_archive_exist)
525                 build_backup_file();
526
527         report_archive_name_if_different();
528
529         /* copy temporary file to new archive file */
530         if (!noexec && (!strcmp(new_archive_name, "-") ||
531                         rename(temporary_name, new_archive_name) < 0))
532                 temporary_to_new_archive_file(new_archive_size);
533
534         /* set new archive file mode/group */
535         set_archive_file_mode();
536
537         /* remove archived files */
538         if (delete_after_append)
539                 remove_files(cmd_filec, cmd_filev);
540
541         return;
542 }
543
544 /* ------------------------------------------------------------------------ */
545 void
546 cmd_delete()
547 {
548         FILE           *oafp, *nafp;
549         long            new_archive_size;
550
551         /* open old archive if exist */
552         if ((oafp = open_old_archive()) == NULL)
553                 fatal_error(archive_name);
554         errno = 0;
555
556         /* exit if no operation */
557         if (cmd_filec == 0) {
558                 fclose(oafp);
559                 warning("No files given in argument, do nothing.", "");
560                 return;
561         }
562
563         if (archive_is_msdos_sfx1(archive_name)) {
564                 skip_msdos_sfx1_code(oafp);
565                 build_standard_archive_name(new_archive_name_buffer, archive_name);
566                 new_archive_name = new_archive_name_buffer;
567         }
568         else {
569                 new_archive_name = archive_name;
570         }
571
572         /* build temporary file */
573         if (!noexec)
574                 nafp = build_temporary_file();
575
576         /* build new archive file */
577         delete(oafp, nafp);
578         fclose(oafp);
579
580         if (!noexec) {
581                 write_archive_tail(nafp);
582                 new_archive_size = ftell(nafp);
583                 fclose(nafp);
584         }
585
586         /* build backup archive file */
587         build_backup_file();
588
589         /* 1999.5.24 t.oka */
590         if(!noexec && new_archive_size <= 1){
591                 unlink(temporary_name);
592                 printf("New archive file \"%s\" is not created because it would be empty.\n", new_archive_name);
593                 return;
594         }
595
596         report_archive_name_if_different();
597
598         /* copy temporary file to new archive file */
599         if (!noexec && rename(temporary_name, new_archive_name) < 0)
600                 temporary_to_new_archive_file(new_archive_size);
601
602         /* set new archive file mode/group */
603         set_archive_file_mode();
604
605         return;
606 }
607
608 /* for symbolic link name. t.okamoto 96/2/20 */
609 int strcmp_filename( str1, str2 )
610 char *str1;
611 char *str2;
612 {
613         char *p, *q;
614
615         p = str1; q = str2;
616         while (*p != 0 && *q != 0) {
617                 if (*p == '|') {
618                         if (*q == 0) return 0;
619                         else if (*q != '|') return -1;
620                 } else if (*q == '|') {
621                         if (*p == 0) return 0;
622                         else if (*q != '|') return 1;
623                 } else if (*p != *q) break;
624                 p++; q++;
625         }
626         return (int)*p-(int)*q;
627 }
628
629                 
630 /* Local Variables: */
631 /* mode:c */
632 /* tab-width:4 */
633 /* compile-command:"gcc -c lhadd.c" */
634 /* End: */