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 /* ------------------------------------------------------------------------ */
18 add_one(fp, nafp, hdr)
22 long header_pos, next_pos, org_pos, data_pos;
23 long v_original_size, v_packed_size;
25 reading_filename = hdr->name;
26 writing_filename = temporary_name;
28 if (!fp && generic_format) /* [generic] doesn't need directory info. */
30 header_pos = ftell(nafp);
31 write_header(nafp, hdr);/* DUMMY */
33 if ((hdr->unix_mode & UNIX_FILE_SYMLINK) == UNIX_FILE_SYMLINK) {
35 printf("%s -> %s\t- Symbolic Link\n", hdr->realname, hdr->name);
38 if (hdr->original_size == 0) { /* empty file or directory */
39 finish_indicator2(hdr->name, "Frozen", 0);
40 return; /* previous write_header is not DUMMY. (^_^) */
43 data_pos = ftell(nafp);
45 hdr->crc = encode_lzhuf(fp, nafp, hdr->original_size,
46 &v_original_size, &v_packed_size, hdr->name, hdr->method);
48 if (v_packed_size < v_original_size) {
49 next_pos = ftell(nafp);
51 else { /* retry by stored method */
52 fseek(fp, org_pos, SEEK_SET);
53 fseek(nafp, data_pos, SEEK_SET);
54 hdr->crc = encode_stored_crc(fp, nafp, hdr->original_size,
55 &v_original_size, &v_packed_size);
57 next_pos = ftell(nafp);
59 if (ftruncate(fileno(nafp), next_pos) == -1)
60 error("cannot truncate archive");
62 if (chsize(fileno(nafp), next_pos) == -1)
63 error("cannot truncate archive");
67 memcpy(hdr->method, LZHUFF0_METHOD, METHOD_TYPE_STORAGE);
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);
77 /* ------------------------------------------------------------------------ */
79 append_it(name, oafp, nafp)
92 boolean directory, symlink;
94 if (GETSTAT(name, &stbuf) < 0) {
95 error("Cannot access file \"%s\"", name); /* See cleaning_files, Why? */
99 directory = is_directory(&stbuf);
101 symlink = is_symlink(&stbuf);
105 init_header(name, &stbuf, &hdr);
108 if (!directory && !symlink && !noexec) {
109 fp = fopen(name, READ_BINARY);
111 error("Cannot open file \"%s\": %s", name, strerror(errno));
116 cmp = 0; /* avoid compiler warnings `uninitialized' */
118 old_header = ftell(oafp);
119 if (!get_header(oafp, &ahdr)) {
120 /* end of archive or error occurred */
126 cmp = strcmp(ahdr.name, hdr.name);
127 if (cmp < 0) { /* SKIP */
128 /* copy old to new */
130 fseek(oafp, old_header, SEEK_SET);
131 copy_old_one(oafp, nafp, &ahdr);
134 fseek(oafp, ahdr.packed_size, SEEK_CUR);
135 } else if (cmp == 0) { /* REPLACE */
136 /* drop old archive's */
137 fseek(oafp, ahdr.packed_size, SEEK_CUR);
139 } else { /* cmp > 0, INSERT */
140 fseek(oafp, old_header, SEEK_SET);
145 if (!oafp || cmp > 0) { /* not in archive */
147 printf("ADD %s\n", name);
149 add_one(fp, nafp, &hdr);
151 else { /* cmp == 0 */
152 if (!update_if_newer ||
153 ahdr.unix_last_modified_stamp < hdr.unix_last_modified_stamp) {
154 /* newer than archive's */
156 printf("REPLACE %s\n", name);
158 add_one(fp, nafp, &hdr);
160 else { /* copy old to new */
162 fseek(oafp, old_header, SEEK_SET);
163 copy_old_one(oafp, nafp, &ahdr);
170 if (directory) { /* recursive call */
171 if (find_files(name, &filec, &filev)) {
172 for (i = 0; i < filec; i++)
173 oafp = append_it(filev[i], oafp, nafp);
174 free_files(filec, filev);
180 /* ------------------------------------------------------------------------ */
182 find_update_files(oafp)
183 FILE *oafp; /* old archive */
185 char name[FILENAME_LENGTH];
186 struct string_pool sp;
195 while (get_header(oafp, &hdr)) {
196 if ((hdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR) {
197 if (stat(hdr.name, &stbuf) >= 0) /* exist ? */
198 add_sp(&sp, hdr.name, strlen(hdr.name) + 1);
200 else if ((hdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY) {
201 strcpy(name, hdr.name);
203 if (len > 0 && name[len - 1] == '/')
204 name[--len] = '\0'; /* strip tail '/' */
205 if (stat(name, &stbuf) >= 0) /* exist ? */
206 add_sp(&sp, name, len + 1);
208 fseek(oafp, hdr.packed_size, SEEK_CUR);
211 fseek(oafp, pos, SEEK_SET);
213 finish_sp(&sp, &cmd_filec, &cmd_filev);
216 /* ------------------------------------------------------------------------ */
224 old_header_pos = ftell(oafp);
225 while (get_header(oafp, &ahdr)) {
226 if (need_file(ahdr.name)) { /* skip */
227 fseek(oafp, ahdr.packed_size, SEEK_CUR);
228 if (noexec || !quiet) {
229 if ((ahdr.unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK)
230 message("delete %s -> %s", ahdr.realname, ahdr.name);
232 message("delete %s", ahdr.name);
237 fseek(oafp, ahdr.packed_size, SEEK_CUR);
240 fseek(oafp, old_header_pos, SEEK_SET);
241 copy_old_one(oafp, nafp, &ahdr);
244 old_header_pos = ftell(oafp);
249 /* ------------------------------------------------------------------------ */
251 /* ------------------------------------------------------------------------ */
253 build_temporary_file()
257 signal(SIGINT, interrupt);
259 signal(SIGHUP, interrupt);
262 remove_temporary_at_error = TRUE;
263 temporary_fd = build_temporary_name();
264 if (temporary_fd == -1)
265 fatal_error("Cannot open temporary file \"%s\"", temporary_name);
267 afp = fdopen(temporary_fd, WRITE_BINARY);
269 fatal_error("Cannot open temporary file \"%s\"", temporary_name);
274 /* ------------------------------------------------------------------------ */
279 build_backup_name(backup_archive_name, archive_name);
281 signal(SIGINT, SIG_IGN);
283 signal(SIGHUP, SIG_IGN);
285 if (rename(archive_name, backup_archive_name) < 0) {
287 /* On MinGW, cannot rename when
288 newfile (backup_archive_name) already exists */
289 if (unlink(backup_archive_name) < 0 ||
290 rename(archive_name, backup_archive_name) < 0)
292 fatal_error("Cannot make backup file \"%s\"", archive_name);
294 recover_archive_when_interrupt = TRUE;
295 signal(SIGINT, interrupt);
297 signal(SIGHUP, interrupt);
302 /* ------------------------------------------------------------------------ */
304 report_archive_name_if_different()
306 if (!quiet && new_archive_name == new_archive_name_buffer) {
307 /* warning at old archive is SFX */
308 message("New archive file is \"%s\"", new_archive_name);
312 /* ------------------------------------------------------------------------ */
314 temporary_to_new_archive_file(new_archive_size)
315 long new_archive_size;
319 if (!strcmp(new_archive_name, "-")) {
321 writing_filename = "starndard output";
323 setmode(fileno(stdout), O_BINARY);
327 unlink(new_archive_name);
328 if (rename(temporary_name, new_archive_name) == 0)
330 nafp = xfopen(new_archive_name, WRITE_BINARY);
331 writing_filename = archive_name;
334 oafp = xfopen(temporary_name, READ_BINARY);
335 reading_filename = temporary_name;
336 copyfile(oafp, nafp, new_archive_size, 0, 0);
341 recover_archive_when_interrupt = FALSE;
342 unlink(temporary_name);
344 remove_temporary_at_error = FALSE;
347 /* ------------------------------------------------------------------------ */
349 set_archive_file_mode()
354 if (archive_file_gid < 0) {
355 umask(umask_value = umask(0));
356 archive_file_mode = (~umask_value) & 0666; /* rw-rw-rw- */
357 if (stat(".", &stbuf) >= 0)
358 archive_file_gid = stbuf.st_gid;
360 if (archive_file_gid >= 0)
361 chown(new_archive_name, getuid(), archive_file_gid);
363 chmod(new_archive_name, archive_file_mode);
366 /* ------------------------------------------------------------------------ */
367 /* REMOVE FILE/DIRECTORY */
368 /* ------------------------------------------------------------------------ */
377 if (GETSTAT(name, &stbuf) < 0) {
378 warning("Cannot access \"%s\": %s", name, strerror(errno));
380 else if (is_directory(&stbuf)) {
381 if (find_files(name, &filec, &filev)) {
382 remove_files(filec, filev);
383 free_files(filec, filev);
386 warning("Cannot open directory \"%s\"", name);
389 message("REMOVE DIRECTORY %s", name);
390 else if (rmdir(name) < 0)
391 warning("Cannot remove directory \"%s\"", name);
393 message("Removed %s.", name);
395 else if (is_regularfile(&stbuf)) {
397 message("REMOVE FILE %s.", name);
398 else if (unlink(name) < 0)
399 warning("Cannot remove \"%s\"", name);
401 message("Removed %s.", name);
404 else if (is_symlink(&stbuf)) {
406 printf("REMOVE SYMBOLIC LINK %s.\n", name);
407 else if (unlink(name) < 0)
408 warning("Cannot remove", name);
410 message("Removed %s.", name);
414 error("Cannot remove file \"%s\" (not a file or directory)", name);
419 remove_files(filec, filev)
425 for (i = 0; i < filec; i++)
426 remove_one(filev[i]);
429 /* ------------------------------------------------------------------------ */
431 /* ------------------------------------------------------------------------ */
439 boolean old_archive_exist;
440 long new_archive_size;
442 /* exit if no operation */
443 if (!update_if_newer && cmd_filec == 0) {
444 error("No files given in argument, do nothing.");
448 /* open old archive if exist */
449 if ((oafp = open_old_archive()) == NULL)
450 old_archive_exist = FALSE;
452 old_archive_exist = TRUE;
454 if (update_if_newer && cmd_filec == 0) {
455 warning("No files given in argument");
457 error("archive file \"%s\" does not exists.",
463 if (new_archive && old_archive_exist) {
468 if (oafp && archive_is_msdos_sfx1(archive_name)) {
469 seek_lha_header(oafp);
470 build_standard_archive_name(new_archive_name_buffer, archive_name);
471 new_archive_name = new_archive_name_buffer;
474 new_archive_name = archive_name;
477 /* build temporary file */
478 nafp = NULL; /* avoid compiler warnings `uninitialized' */
480 nafp = build_temporary_file();
482 /* find needed files when automatic update */
483 if (update_if_newer && cmd_filec == 0)
484 find_update_files(oafp);
486 /* build new archive file */
487 /* cleaning arguments */
488 cleaning_files(&cmd_filec, &cmd_filev);
489 if (cmd_filec == 0) {
497 for (i = 0; i < cmd_filec; i++) {
500 if (strcmp(cmd_filev[i], archive_name) == 0) {
501 /* exclude target archive */
502 warning("specified file \"%s\" is the generating archive. skip",
504 for (j = i; j < cmd_filec-1; j++)
505 cmd_filev[j] = cmd_filev[j+1];
511 /* exclude files specified by -x option */
512 for (j = 0; exclude_files && exclude_files[j]; j++) {
513 if (fnmatch(exclude_files[j], basename(cmd_filev[i]),
514 FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD) == 0)
518 oafp = append_it(cmd_filev[i], oafp, nafp);
524 old_header = ftell(oafp);
525 while (get_header(oafp, &ahdr)) {
527 fseek(oafp, ahdr.packed_size, SEEK_CUR);
529 fseek(oafp, old_header, SEEK_SET);
530 copy_old_one(oafp, nafp, &ahdr);
532 old_header = ftell(oafp);
537 new_archive_size = 0; /* avoid compiler warnings `uninitialized' */
539 write_archive_tail(nafp);
540 new_archive_size = ftell(nafp);
544 /* build backup archive file */
545 if (old_archive_exist && backup_old_archive)
548 report_archive_name_if_different();
550 /* copy temporary file to new archive file */
551 if (!noexec && (!strcmp(new_archive_name, "-") ||
552 rename(temporary_name, new_archive_name) < 0))
553 temporary_to_new_archive_file(new_archive_size);
555 /* set new archive file mode/group */
556 set_archive_file_mode();
558 /* remove archived files */
559 if (delete_after_append)
560 remove_files(cmd_filec, cmd_filev);
565 /* ------------------------------------------------------------------------ */
570 long new_archive_size;
572 /* open old archive if exist */
573 if ((oafp = open_old_archive()) == NULL)
574 fatal_error("Cannot open archive file \"%s\"", archive_name);
576 /* exit if no operation */
577 if (cmd_filec == 0) {
579 warning("No files given in argument, do nothing.");
583 if (archive_is_msdos_sfx1(archive_name)) {
584 seek_lha_header(oafp);
585 build_standard_archive_name(new_archive_name_buffer, archive_name);
586 new_archive_name = new_archive_name_buffer;
589 new_archive_name = archive_name;
592 /* build temporary file */
593 nafp = NULL; /* avoid compiler warnings `uninitialized' */
595 nafp = build_temporary_file();
597 /* build new archive file */
601 new_archive_size = 0; /* avoid compiler warnings `uninitialized' */
603 write_archive_tail(nafp);
604 new_archive_size = ftell(nafp);
608 /* build backup archive file */
609 if (backup_old_archive)
612 /* 1999.5.24 t.oka */
613 if(!noexec && new_archive_size <= 1){
614 unlink(temporary_name);
615 if (!backup_old_archive)
616 unlink(archive_name);
617 warning("The archive file \"%s\" was removed because it would be empty.", new_archive_name);
621 report_archive_name_if_different();
623 /* copy temporary file to new archive file */
624 if (!noexec && rename(temporary_name, new_archive_name) < 0)
625 temporary_to_new_archive_file(new_archive_size);
627 /* set new archive file mode/group */
628 set_archive_file_mode();