OSDN Git Service

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