1 /* ------------------------------------------------------------------------ */
3 /* lhadd.c -- LHarc Add Command */
5 /* Copyright (C) MCMLXXXIX Yooichi.Tagawa */
6 /* Modified Nobutaka Watazaki */
8 /* Ver. 1.14 Source All chagned 1995.01.14 N.Watazaki */
9 /* ------------------------------------------------------------------------ */
11 /* ------------------------------------------------------------------------ */
12 static void remove_files();
14 static char new_archive_name_buffer[FILENAME_LENGTH];
15 static char *new_archive_name;
16 static time_t most_recent; /* for time-stamp archiving */
19 copy_old_one(oafp, nafp, hdr)
24 fseeko(oafp, hdr->header_size + hdr->packed_size, SEEK_CUR);
27 reading_filename = archive_name;
28 writing_filename = temporary_name;
29 copyfile(oafp, nafp, hdr->header_size + hdr->packed_size, 0, 0);
31 /* directory and symlink are ignored for time-stamp archiving */
32 if (memcmp(hdr->method, "-lhd-", 5) != 0) {
33 if (most_recent < hdr->unix_last_modified_stamp)
34 most_recent = hdr->unix_last_modified_stamp;
40 add_one(fp, nafp, hdr)
44 off_t header_pos, next_pos, org_pos, data_pos;
45 off_t v_original_size, v_packed_size;
47 reading_filename = hdr->name;
48 writing_filename = temporary_name;
50 /* directory and symlink are ignored for time-stamp archiving */
51 if (memcmp(hdr->method, "-lhd-", 5) != 0) {
52 if (most_recent < hdr->unix_last_modified_stamp)
53 most_recent = hdr->unix_last_modified_stamp;
56 if (!fp && generic_format) /* [generic] doesn't need directory info. */
58 header_pos = ftello(nafp);
59 write_header(nafp, hdr);/* DUMMY */
61 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
63 printf("%s -> %s\t- Symbolic Link\n", hdr->name, hdr->realname);
66 if (hdr->original_size == 0) { /* empty file, symlink or directory */
67 finish_indicator2(hdr->name, "Frozen", 0);
68 return; /* previous write_header is not DUMMY. (^_^) */
71 data_pos = ftello(nafp);
73 hdr->crc = encode_lzhuf(fp, nafp, hdr->original_size,
74 &v_original_size, &v_packed_size, hdr->name, hdr->method);
76 if (v_packed_size < v_original_size) {
77 next_pos = ftello(nafp);
79 else { /* retry by stored method */
80 fseeko(fp, org_pos, SEEK_SET);
81 fseeko(nafp, data_pos, SEEK_SET);
82 hdr->crc = encode_stored_crc(fp, nafp, hdr->original_size,
83 &v_original_size, &v_packed_size);
85 next_pos = ftello(nafp);
87 if (ftruncate(fileno(nafp), next_pos) == -1)
88 error("cannot truncate archive");
90 if (chsize(fileno(nafp), next_pos) == -1)
91 error("cannot truncate archive");
95 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STORAGE);
97 hdr->original_size = v_original_size;
98 hdr->packed_size = v_packed_size;
99 fseeko(nafp, header_pos, SEEK_SET);
100 write_header(nafp, hdr);
101 fseeko(nafp, next_pos, SEEK_SET);
105 append_it(name, oafp, nafp)
118 boolean directory, symlink;
120 if (GETSTAT(name, &stbuf) < 0) {
121 error("Cannot access file \"%s\"", name); /* See cleaning_files, Why? */
125 directory = is_directory(&stbuf);
127 symlink = is_symlink(&stbuf);
133 if (!directory && !symlink && !noexec) {
134 fp = fopen(name, READ_BINARY);
136 error("Cannot open file \"%s\": %s", name, strerror(errno));
141 init_header(name, &stbuf, &hdr);
143 cmp = 0; /* avoid compiler warnings `uninitialized' */
145 old_header = ftello(oafp);
146 if (!get_header(oafp, &ahdr)) {
147 /* end of archive or error occurred */
153 if (!sort_contents) {
155 fseeko(oafp, old_header, SEEK_SET);
156 copy_old_one(oafp, nafp, &ahdr);
159 fseeko(oafp, ahdr.packed_size, SEEK_CUR);
160 cmp = -1; /* to be -1 always */
164 cmp = strcmp(ahdr.name, hdr.name);
165 if (cmp < 0) { /* SKIP */
166 /* copy old to new */
168 fseeko(oafp, old_header, SEEK_SET);
169 copy_old_one(oafp, nafp, &ahdr);
172 fseeko(oafp, ahdr.packed_size, SEEK_CUR);
173 } else if (cmp == 0) { /* REPLACE */
174 /* drop old archive's */
175 fseeko(oafp, ahdr.packed_size, SEEK_CUR);
177 } else { /* cmp > 0, INSERT */
178 fseeko(oafp, old_header, SEEK_SET);
183 if (!oafp || cmp > 0) { /* not in archive */
185 printf("ADD %s\n", name);
187 add_one(fp, nafp, &hdr);
189 else { /* cmp == 0 */
190 if (!update_if_newer ||
191 ahdr.unix_last_modified_stamp < hdr.unix_last_modified_stamp) {
192 /* newer than archive's */
194 printf("REPLACE %s\n", name);
196 add_one(fp, nafp, &hdr);
198 else { /* copy old to new */
200 fseeko(oafp, old_header, SEEK_SET);
201 copy_old_one(oafp, nafp, &ahdr);
208 if (directory && recursive_archiving) { /* recursive call */
209 if (find_files(name, &filec, &filev)) {
210 for (i = 0; i < filec; i++)
211 oafp = append_it(filev[i], oafp, nafp);
212 free_files(filec, filev);
218 /* ------------------------------------------------------------------------ */
220 find_update_files(oafp)
221 FILE *oafp; /* old archive */
223 char name[FILENAME_LENGTH];
224 struct string_pool sp;
233 while (get_header(oafp, &hdr)) {
234 if ((hdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR) {
235 if (stat(hdr.name, &stbuf) >= 0) /* exist ? */
236 add_sp(&sp, hdr.name, strlen(hdr.name) + 1);
238 else if ((hdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY) {
239 strcpy(name, hdr.name); /* ok */
241 if (len > 0 && name[len - 1] == '/')
242 name[--len] = '\0'; /* strip tail '/' */
243 if (stat(name, &stbuf) >= 0) /* exist ? */
244 add_sp(&sp, name, len + 1);
246 fseeko(oafp, hdr.packed_size, SEEK_CUR);
249 fseeko(oafp, pos, SEEK_SET);
251 finish_sp(&sp, &cmd_filec, &cmd_filev);
254 /* ------------------------------------------------------------------------ */
260 off_t old_header_pos;
262 old_header_pos = ftello(oafp);
263 while (get_header(oafp, &ahdr)) {
264 if (need_file(ahdr.name)) { /* skip */
265 fseeko(oafp, ahdr.packed_size, SEEK_CUR);
266 if (noexec || !quiet) {
267 if ((ahdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK)
268 message("delete %s -> %s", ahdr.name, ahdr.realname);
270 message("delete %s", ahdr.name);
275 fseeko(oafp, ahdr.packed_size, SEEK_CUR);
278 fseeko(oafp, old_header_pos, SEEK_SET);
279 copy_old_one(oafp, nafp, &ahdr);
282 old_header_pos = ftello(oafp);
287 /* ------------------------------------------------------------------------ */
289 /* ------------------------------------------------------------------------ */
291 build_temporary_file()
295 signal(SIGINT, interrupt);
297 signal(SIGHUP, interrupt);
300 temporary_fd = build_temporary_name();
301 if (temporary_fd == -1)
302 fatal_error("Cannot open temporary file \"%s\"", temporary_name);
304 afp = fdopen(temporary_fd, WRITE_BINARY);
306 fatal_error("Cannot open temporary file \"%s\"", temporary_name);
311 /* ------------------------------------------------------------------------ */
316 build_backup_name(backup_archive_name, archive_name,
317 sizeof(backup_archive_name));
319 signal(SIGINT, SIG_IGN);
321 signal(SIGHUP, SIG_IGN);
323 if (rename(archive_name, backup_archive_name) < 0) {
325 /* On MinGW, cannot rename when
326 newfile (backup_archive_name) already exists */
327 if (unlink(backup_archive_name) < 0 ||
328 rename(archive_name, backup_archive_name) < 0)
330 fatal_error("Cannot make backup file \"%s\"", archive_name);
332 recover_archive_when_interrupt = TRUE;
333 signal(SIGINT, interrupt);
335 signal(SIGHUP, interrupt);
340 /* ------------------------------------------------------------------------ */
342 report_archive_name_if_different()
344 if (!quiet && new_archive_name == new_archive_name_buffer) {
345 /* warning at old archive is SFX */
346 message("New archive file is \"%s\"", new_archive_name);
350 /* ------------------------------------------------------------------------ */
352 temporary_to_new_archive_file(new_archive_size)
353 off_t new_archive_size;
357 if (!strcmp(new_archive_name, "-")) {
359 writing_filename = "standard output";
360 #if defined(__MINGW32__) || defined(__DJGPP__)
361 setmode(fileno(stdout), O_BINARY);
365 unlink(new_archive_name);
366 if (rename(temporary_name, new_archive_name) == 0)
368 nafp = xfopen(new_archive_name, WRITE_BINARY);
369 writing_filename = archive_name;
372 oafp = xfopen(temporary_name, READ_BINARY);
373 reading_filename = temporary_name;
374 copyfile(oafp, nafp, new_archive_size, 0, 0);
379 recover_archive_when_interrupt = FALSE;
380 unlink(temporary_name);
383 /* ------------------------------------------------------------------------ */
385 set_archive_file_mode()
390 if (archive_file_gid < 0) {
391 umask(umask_value = umask(0));
392 archive_file_mode = (~umask_value) & 0666; /* rw-rw-rw- */
393 if (stat(".", &stbuf) >= 0)
394 archive_file_gid = stbuf.st_gid;
396 if (archive_file_gid >= 0)
397 chown(new_archive_name, getuid(), archive_file_gid);
399 chmod(new_archive_name, archive_file_mode);
401 if (timestamp_archive && most_recent) {
402 struct utimbuf utimebuf;
403 utimebuf.actime = utimebuf.modtime = most_recent;
404 utime(new_archive_name, &utimebuf);
408 /* ------------------------------------------------------------------------ */
409 /* REMOVE FILE/DIRECTORY */
410 /* ------------------------------------------------------------------------ */
419 if (GETSTAT(name, &stbuf) < 0) {
420 warning("Cannot access \"%s\": %s", name, strerror(errno));
422 else if (is_directory(&stbuf)) {
423 if (find_files(name, &filec, &filev)) {
424 remove_files(filec, filev);
425 free_files(filec, filev);
428 warning("Cannot open directory \"%s\"", name);
431 message("REMOVE DIRECTORY %s", name);
432 else if (rmdir(name) < 0)
433 warning("Cannot remove directory \"%s\"", name);
435 message("Removed %s.", name);
437 else if (is_regularfile(&stbuf)) {
439 message("REMOVE FILE %s.", name);
440 else if (unlink(name) < 0)
441 warning("Cannot remove \"%s\"", name);
443 message("Removed %s.", name);
446 else if (is_symlink(&stbuf)) {
448 message("REMOVE SYMBOLIC LINK %s.", name);
449 else if (unlink(name) < 0)
450 warning("Cannot remove", name);
452 message("Removed %s.", name);
456 error("Cannot remove file \"%s\" (not a file or directory)", name);
461 remove_files(filec, filev)
467 for (i = 0; i < filec; i++)
468 remove_one(filev[i]);
471 /* ------------------------------------------------------------------------ */
473 /* ------------------------------------------------------------------------ */
481 boolean old_archive_exist;
482 off_t new_archive_size;
486 /* exit if no operation */
487 if (!update_if_newer && cmd_filec == 0) {
488 error("No files given in argument, do nothing.");
492 /* open old archive if exist */
493 if ((oafp = open_old_archive()) == NULL)
494 old_archive_exist = FALSE;
496 old_archive_exist = TRUE;
498 if (update_if_newer && cmd_filec == 0) {
499 warning("No files given in argument");
501 error("archive file \"%s\" does not exists.",
507 if (new_archive && old_archive_exist) {
512 if (oafp && archive_is_msdos_sfx1(archive_name)) {
513 seek_lha_header(oafp);
514 build_standard_archive_name(new_archive_name_buffer,
516 sizeof(new_archive_name_buffer));
517 new_archive_name = new_archive_name_buffer;
520 new_archive_name = archive_name;
523 /* build temporary file */
524 nafp = NULL; /* avoid compiler warnings `uninitialized' */
526 nafp = build_temporary_file();
528 /* find needed files when automatic update */
529 if (update_if_newer && cmd_filec == 0)
530 find_update_files(oafp);
532 /* build new archive file */
533 /* cleaning arguments */
534 cleaning_files(&cmd_filec, &cmd_filev);
535 if (cmd_filec == 0) {
543 for (i = 0; i < cmd_filec; i++) {
546 if (strcmp(cmd_filev[i], archive_name) == 0) {
547 /* exclude target archive */
548 warning("specified file \"%s\" is the generating archive. skip",
550 for (j = i; j < cmd_filec-1; j++)
551 cmd_filev[j] = cmd_filev[j+1];
557 /* exclude files specified by -x option */
558 for (j = 0; exclude_files && exclude_files[j]; j++) {
559 if (fnmatch(exclude_files[j], basename(cmd_filev[i]),
560 FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD) == 0)
564 oafp = append_it(cmd_filev[i], oafp, nafp);
570 old_header = ftello(oafp);
571 while (get_header(oafp, &ahdr)) {
573 fseeko(oafp, ahdr.packed_size, SEEK_CUR);
575 fseeko(oafp, old_header, SEEK_SET);
576 copy_old_one(oafp, nafp, &ahdr);
578 old_header = ftello(oafp);
583 new_archive_size = 0; /* avoid compiler warnings `uninitialized' */
587 write_archive_tail(nafp);
590 warning("ftello(): %s", strerror(errno));
591 new_archive_size = 0;
594 new_archive_size = tmp;
599 /* build backup archive file */
600 if (old_archive_exist && backup_old_archive)
603 report_archive_name_if_different();
605 /* copy temporary file to new archive file */
607 if (strcmp(new_archive_name, "-") == 0 ||
608 rename(temporary_name, new_archive_name) < 0) {
610 temporary_to_new_archive_file(new_archive_size);
613 /* set new archive file mode/group */
614 set_archive_file_mode();
617 /* remove archived files */
618 if (delete_after_append)
619 remove_files(cmd_filec, cmd_filev);
624 /* ------------------------------------------------------------------------ */
629 off_t new_archive_size;
633 /* open old archive if exist */
634 if ((oafp = open_old_archive()) == NULL)
635 fatal_error("Cannot open archive file \"%s\"", archive_name);
637 /* exit if no operation */
638 if (cmd_filec == 0) {
640 warning("No files given in argument, do nothing.");
644 if (archive_is_msdos_sfx1(archive_name)) {
645 seek_lha_header(oafp);
646 build_standard_archive_name(new_archive_name_buffer,
648 sizeof(new_archive_name_buffer));
649 new_archive_name = new_archive_name_buffer;
652 new_archive_name = archive_name;
655 /* build temporary file */
656 nafp = NULL; /* avoid compiler warnings `uninitialized' */
658 nafp = build_temporary_file();
660 /* build new archive file */
664 new_archive_size = 0; /* avoid compiler warnings `uninitialized' */
668 write_archive_tail(nafp);
671 warning("ftello(): %s", strerror(errno));
672 new_archive_size = 0;
675 new_archive_size = tmp;
680 /* build backup archive file */
681 if (backup_old_archive)
684 /* 1999.5.24 t.oka */
685 if(!noexec && new_archive_size <= 1){
686 unlink(temporary_name);
687 if (!backup_old_archive)
688 unlink(archive_name);
689 warning("The archive file \"%s\" was removed because it would be empty.", new_archive_name);
693 report_archive_name_if_different();
695 /* copy temporary file to new archive file */
697 if (rename(temporary_name, new_archive_name) < 0)
698 temporary_to_new_archive_file(new_archive_size);
700 /* set new archive file mode/group */
701 set_archive_file_mode();