1/* ------------------------------------------------------------------------ */
2/* LHa for UNIX    															*/
3/*				lhext.c -- LHarc extract									*/
4/*																			*/
5/*		Copyright (C) MCMLXXXIX Yooichi.Tagawa								*/
6/*		Modified          		Nobutaka Watazaki							*/
7/*																			*/
8/*  Ver. 0.00  Original								1988.05.23  Y.Tagawa	*/
9/*  Ver. 1.00  Fixed								1989.09.22  Y.Tagawa	*/
10/*  Ver. 0.03  LHa for UNIX							1991.12.17  M.Oki		*/
11/*  Ver. 1.12  LHa for UNIX							1993.10.01	N.Watazaki	*/
12/*  Ver. 1.13b Symbolic Link Update Bug Fix			1994.06.21	N.Watazaki	*/
13/*	Ver. 1.14  Source All chagned					1995.01.14	N.Watazaki	*/
14/*  Ver. 1.14e bugfix                               1999.04.30  T.Okamoto   */
15/* ------------------------------------------------------------------------ */
16#include "lha.h"
17/* ------------------------------------------------------------------------ */
18static int      skip_flg = FALSE;	/* FALSE..No Skip , TRUE..Skip */
19static char	   *methods[] =
20{
21	LZHUFF0_METHOD, LZHUFF1_METHOD, LZHUFF2_METHOD, LZHUFF3_METHOD,
22	LZHUFF4_METHOD, LZHUFF5_METHOD, LZHUFF6_METHOD, LZHUFF7_METHOD,
23	LARC_METHOD, LARC5_METHOD, LARC4_METHOD,
24	LZHDIRS_METHOD,
25	NULL
26};
27
28/* ------------------------------------------------------------------------ */
29static          boolean
30inquire_extract(name)
31	char           *name;
32{
33	struct stat     stbuf;
34
35	skip_flg = FALSE;
36	if (stat(name, &stbuf) >= 0) {
37		if (!is_regularfile(&stbuf)) {
38			error("Already exist (not a file)", name);
39			return FALSE;
40		}
41
42		if (noexec) {
43			printf("EXTRACT %s but file is exist.\n", name);
44			return FALSE;
45		}
46		else if (!force) {
47			if (!isatty(0))
48				return FALSE;
49
50			switch (inquire("OverWrite ?(Yes/[No]/All/Skip)", name, "YyNnAaSs\n")) {
51			case 0:
52			case 1:/* Y/y */
53				break;
54			case 2:
55			case 3:/* N/n */
56			case 8:/* Return */
57				return FALSE;
58			case 4:
59			case 5:/* A/a */
60				force = TRUE;
61				break;
62			case 6:
63			case 7:/* S/s */
64				skip_flg = TRUE;
65				break;
66			}
67		}
68	}
69	if (noexec)
70		printf("EXTRACT %s\n", name);
71
72	return TRUE;
73}
74
75/* ------------------------------------------------------------------------ */
76static          boolean
77make_parent_path(name)
78	char           *name;
79{
80	char            path[FILENAME_LENGTH];
81	struct stat     stbuf;
82	register char  *p;
83
84	/* make parent directory name into PATH for recursive call */
85	strcpy(path, name);
86	for (p = path + strlen(path); p > path; p--)
87		if (p[-1] == '/') {
88			*--p = '\0';
89			break;
90		}
91
92	if (p == path) {
93		message("Why?", "ROOT");
94		return FALSE;	/* no more parent. */
95	}
96
97	if (GETSTAT(path, &stbuf) >= 0) {
98		if (is_directory(&stbuf))
99			return TRUE;
100		error("Not a directory", path);
101		return FALSE;
102	}
103	errno = 0;
104
105	if (verbose)
106		printf("Making directory \"%s\".\n", path);
107
108	if (mkdir(path, 0777) >= 0)	/* try */
109		return TRUE;	/* successful done. */
110	errno = 0;
111
112	if (!make_parent_path(path))
113		return FALSE;
114
115	if (mkdir(path, 0777) < 0) {	/* try again */
116		message("Cannot make directory", path);
117		return FALSE;
118	}
119
120	return TRUE;
121}
122
123/* ------------------------------------------------------------------------ */
124static FILE    *
125open_with_make_path(name)
126	char           *name;
127{
128	FILE           *fp;
129
130	if ((fp = fopen(name, WRITE_BINARY)) == NULL) {
131		errno = 0;
132		if (!make_parent_path(name) ||
133		    (fp = fopen(name, WRITE_BINARY)) == NULL)
134			error("Cannot extract", name);
135		errno = 0;
136	}
137	return fp;
138}
139
140/* ------------------------------------------------------------------------ */
141static void
142adjust_info(name, hdr)
143	char           *name;
144	LzHeader       *hdr;
145{
146	time_t          utimebuf[2];
147
148	/* adjust file stamp */
149	utimebuf[0] = utimebuf[1] = hdr->unix_last_modified_stamp;
150
151	if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) != UNIX_FILE_SYMLINK)
152		utime(name, utimebuf);
153
154	if (hdr->extend_type == EXTEND_UNIX
155	    || hdr->extend_type == EXTEND_OS68K
156	    || hdr->extend_type == EXTEND_XOSK) {
157#ifdef NOT_COMPATIBLE_MODE
158		Please need your modification in this space.
159#else
160		if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) != UNIX_FILE_SYMLINK)
161			chmod(name, hdr->unix_mode);
162#endif
163		if (!getuid()) {
164#ifndef HAVE_NO_LCHOWN
165			if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK)
166				lchown(name, hdr->unix_uid, hdr->unix_gid);
167			else
168#endif /* HAVE_NO_LCHWON */
169				chown(name, hdr->unix_uid, hdr->unix_gid);
170		}
171		errno = 0;
172	}
173}
174
175/* ------------------------------------------------------------------------ */
176static void
177extract_one(afp, hdr)
178	FILE           *afp;	/* archive file */
179	LzHeader       *hdr;
180{
181	FILE           *fp;	/* output file */
182	struct stat     stbuf;
183	char            name[257];
184	int             crc;
185	int             method;
186	boolean         save_quiet, save_verbose, up_flag;
187	char           *q = hdr->name, c;
188
189	if (ignore_directory && rindex(hdr->name, '/')) {
190		q = (char *) rindex(hdr->name, '/') + 1;
191	}
192	else {
193		if (*q == '/') {
194			q++;
195			/*
196			 * if OSK then strip device name
197			 */
198			if (hdr->extend_type == EXTEND_OS68K
199			    || hdr->extend_type == EXTEND_XOSK) {
200				do
201					c = (*q++);
202				while (c && c != '/');
203				if (!c || !*q)
204					q = ".";	/* if device name only */
205			}
206		}
207	}
208
209	if (extract_directory)
210		sprintf(name, "%s/%s", extract_directory, q);
211	else
212		strcpy(name, q);
213
214
215	/* LZHDIRS_METHOD����ĥإå�������å����� */
216	/* 1999.4.30 t.okamoto */
217	for (method = 0;; method++) {
218		if (methods[method] == NULL) {
219			error("Unknown method skiped ...", name);
220			return;
221		}
222		if (bcmp(hdr->method, methods[method], 5) == 0)
223			break;
224	}
225
226	if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_REGULAR
227		&& method != LZHDIRS_METHOD_NUM) {
228#if 0
229		for (method = 0;; method++) {
230			if (methods[method] == NULL) {
231				error("Unknown method skiped ...", name);
232				return;
233			}
234			if (bcmp(hdr->method, methods[method], 5) == 0)
235				break;
236		}
237#endif
238
239		reading_filename = archive_name;
240		writting_filename = name;
241		if (output_to_stdout || verify_mode) {
242			if (noexec) {
243				printf("%s %s\n", verify_mode ? "VERIFY" : "EXTRACT", name);
244				if (afp == stdin) {
245					int             i = hdr->packed_size;
246					while (i--)
247						fgetc(afp);
248				}
249				return;
250			}
251
252			save_quiet = quiet;
253			save_verbose = verbose;
254			if (!quiet && output_to_stdout) {
255				printf("::::::::\n%s\n::::::::\n", name);
256				quiet = TRUE;
257				verbose = FALSE;
258			}
259			else if (verify_mode) {
260				quiet = FALSE;
261				verbose = TRUE;
262			}
263
264			crc = decode_lzhuf
265				(afp, stdout, hdr->original_size, hdr->packed_size, name, method);
266			quiet = save_quiet;
267			verbose = save_verbose;
268		}
269		else {
270			if (skip_flg == FALSE)  {
271				up_flag = inquire_extract(name);
272				if (up_flag == FALSE && force == FALSE) {
273					return;
274				}
275			}
276
277			if (skip_flg == TRUE) {	/* if skip_flg */
278				if (stat(name, &stbuf) == 0 && force != TRUE) {
279					if (stbuf.st_mtime >= hdr->unix_last_modified_stamp) {
280						if (quiet != TRUE)
281							printf("%s : Skipped...\n", name);
282						return;
283					}
284				}
285			}
286			if (noexec) {
287				if (afp == stdin) {
288					int i = hdr->packed_size;
289					while (i--)
290						fgetc(afp);
291				}
292				return;
293			}
294
295			signal(SIGINT, interrupt);
296			signal(SIGHUP, interrupt);
297
298			unlink(name);
299			errno = 0;
300			remove_extracting_file_when_interrupt = TRUE;
301
302			if ((fp = open_with_make_path(name)) != NULL) {
303				crc = decode_lzhuf
304					(afp, fp, hdr->original_size, hdr->packed_size, name, method);
305				fclose(fp);
306			}
307			remove_extracting_file_when_interrupt = FALSE;
308			signal(SIGINT, SIG_DFL);
309			signal(SIGHUP, SIG_DFL);
310
311			if (!fp)
312				return;
313		}
314
315		errno = 0;
316		if (hdr->has_crc && crc != hdr->crc)
317			error("CRC error", name);
318	}
319	else if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_DIRECTORY
320			 || (hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK
321			 || method == LZHDIRS_METHOD_NUM) {
322		/* ������ǡ�Symblic Link �ϡ�����פ��� */
323		if (!ignore_directory && !verify_mode) {
324			if (noexec) {
325				if (quiet != TRUE)
326					printf("EXTRACT %s (directory)\n", name);
327				return;
328			}
329			/* NAME has trailing SLASH '/', (^_^) */
330			if ((hdr->unix_mode & UNIX_FILE_TYPEMASK) == UNIX_FILE_SYMLINK) {
331				char            buf[256], *bb1, *bb2;
332				int             l_code;
333				strcpy(buf, name);
334				bb1 = strtok(buf, "|");
335				bb2 = strtok(NULL, "|");
336
337#ifdef S_IFLNK
338				if (skip_flg == FALSE)  {
339					up_flag = inquire_extract(name);
340					if (up_flag == FALSE && force == FALSE) {
341						return;
342					}
343				} else {
344					if (GETSTAT(bb1, &stbuf) == 0 && force != TRUE) {
345						if (stbuf.st_mtime >= hdr->unix_last_modified_stamp) {
346							if (quiet != TRUE)
347								printf("%s : Skipped...\n", bb1);
348							return;
349						}
350					}
351				}
352
353				unlink(bb1);
354				l_code = symlink(bb2, bb1);
355				if (l_code < 0) {
356					if (quiet != TRUE)
357						warning("Can't make Symbolic Link : ");
358				}
359				if (quiet != TRUE) {
360					printf("Symbolic Link %s -> %s\n", bb1, bb2);
361				}
362				strcpy(name, bb1);	/* Symbolic's name set */
363#else
364				sprintf(buf, "%s -> %s", bb1, bb2);
365				warning("Can't make Symbolic Link", buf);
366				return;
367#endif
368			} else { /* make directory */
369				if (!output_to_stdout && !make_parent_path(name))
370					return;
371			}
372		}
373	}
374	else {
375		error("Unknown information", name);
376	}
377
378	if (!output_to_stdout)
379		adjust_info(name, hdr);
380}
381
382/* ------------------------------------------------------------------------ */
383/* EXTRACT COMMAND MAIN														*/
384/* ------------------------------------------------------------------------ */
385void
386cmd_extract()
387{
388	LzHeader        hdr;
389	long            pos;
390	FILE           *afp;
391
392	/* open archive file */
393	if ((afp = open_old_archive()) == NULL)
394		fatal_error(archive_name);
395
396	if (archive_is_msdos_sfx1(archive_name))
397		skip_msdos_sfx1_code(afp);
398
399	/* extract each files */
400	while (get_header(afp, &hdr)) {
401		if (need_file(hdr.name)) {
402			pos = ftell(afp);
403			extract_one(afp, &hdr);
404			fseek(afp, pos + hdr.packed_size, SEEK_SET);
405		} else {
406			if (afp != stdin)
407				fseek(afp, hdr.packed_size, SEEK_CUR);
408			else {
409				int             i = hdr.packed_size;
410				while (i--)
411					fgetc(afp);
412			}
413		}
414	}
415
416	/* close archive file */
417	fclose(afp);
418
419	return;
420}
421
422/* Local Variables: */
423/* mode:c */
424/* tab-width:4 */
425/* End: */
426