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/* ------------------------------------------------------------------------ */
12static void     remove_files();
13
14static char     new_archive_name_buffer[FILENAME_LENGTH];
15static char    *new_archive_name;
16/* ------------------------------------------------------------------------ */
17static void
18add_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#ifndef NOFTRUNCATE
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/* ------------------------------------------------------------------------ */
78FILE           *
79append_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/* ------------------------------------------------------------------------ */
194static void
195find_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/* ------------------------------------------------------------------------ */
230static void
231delete(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/* ------------------------------------------------------------------------ */
268static FILE    *
269build_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/* ------------------------------------------------------------------------ */
288static void
289build_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/* ------------------------------------------------------------------------ */
305static void
306report_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
316void
317temporary_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
343temporary_to_new_archive_file(new_archive_size)
344	long            new_archive_size;
345{
346	char           *p;
347	p = (char *) rindex(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/* ------------------------------------------------------------------------ */
358static void
359set_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/* ------------------------------------------------------------------------ */
379static void
380remove_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
428static void
429remove_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/* ------------------------------------------------------------------------ */
442void
443cmd_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/* ------------------------------------------------------------------------ */
545void
546cmd_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 */
609int strcmp_filename( str1, str2 )
610char *str1;
611char *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: */
635