OSDN Git Service

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