1 /*
2 
3 Copyright (c) 2011, 2012, Simon Howard
4 
5 Permission to use, copy, modify, and/or distribute this software
6 for any purpose with or without fee is hereby granted, provided
7 that the above copyright notice and this permission notice appear
8 in all copies.
9 
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
14 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
16 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 
19  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "lha_arch.h"
26 #include "lha_decoder.h"
27 #include "lha_basic_reader.h"
28 #include "public/lha_reader.h"
29 #include "macbinary.h"
30 
31 typedef enum {
32 
33 	// Initial state at start of stream:
34 
35 	CURR_FILE_START,
36 
37 	// Current file is a "normal" file (or directory) read from
38 	// the input stream.
39 
40 	CURR_FILE_NORMAL,
41 
42 	// Current file is a directory that has been popped from the
43 	// directory stack.
44 
45 	CURR_FILE_FAKE_DIR,
46 
47 	// Current file is a deferred symbolic link that has been left
48 	// to the end of the input stream to be created.
49 
50 	CURR_FILE_DEFERRED_SYMLINK,
51 
52 	// End of input stream has been reached.
53 
54 	CURR_FILE_EOF,
55 } CurrFileType;
56 
57 struct _LHAReader {
58 	LHABasicReader *reader;
59 
60 	// The current file that we are processing (last file returned
61 	// by lha_reader_next_file).
62 
63 	LHAFileHeader *curr_file;
64 	CurrFileType curr_file_type;
65 
66 	// Pointer to decoder being used to decompress the current file,
67 	// or NULL if we have not yet started decompression.
68 
69 	LHADecoder *decoder;
70 
71 	// Pointer to "inner" decoder. Most of the time,
72 	// decoder == inner_decoder, but when decoding an archive
73 	// generated by MacLHA, inner_decoder points to the actual
74 	// decompressor.
75 
76 	LHADecoder *inner_decoder;
77 
78 	// Policy used to extract directories.
79 
80 	LHAReaderDirPolicy dir_policy;
81 
82 	// Directories that have been created by lha_reader_extract but
83 	// have not yet had their metadata set. This is a linked list
84 	// using the _next field in LHAFileHeader.
85 	// In the case of LHA_READER_DIR_END_OF_DIR this is a stack;
86 	// in the case of LHA_READER_DIR_END_OF_FILE it is a list.
87 
88 	LHAFileHeader *dir_stack;
89 
90 	// Symbolic links containing absolute paths or '..' are not
91 	// created immediately - instead, "placeholder" files are created
92 	// in their place, and the symbolic links created at the end
93 	// of extraction.
94 
95 	LHAFileHeader *deferred_symlinks;
96 };
97 
98 /**
99  * Free the current decoder structure.
100  *
101  * If the reader has an allocated decoder being used to decompress the
102  * current file, the decoder is freed and the decoder pointer reset
103  * to NULL.
104  *
105  * @param reader         Pointer to the LHA reader structure.
106  */
107 
close_decoder(LHAReader * reader)108 static void close_decoder(LHAReader *reader)
109 {
110 	if (reader->decoder != NULL) {
111 		if (reader->inner_decoder == reader->decoder) {
112 			reader->inner_decoder = NULL;
113 		}
114 
115 		lha_decoder_free(reader->decoder);
116 		reader->decoder = NULL;
117 	}
118 
119 	if (reader->inner_decoder != NULL) {
120 		lha_decoder_free(reader->inner_decoder);
121 		reader->inner_decoder = NULL;
122 	}
123 }
124 
125 /**
126  * Create the decoder structure to decompress the data from the
127  * current file.
128  *
129  * @param reader         Pointer to the LHA reader structure.
130  * @param callback       Callback function to invoke to track progress.
131  * @param callback_data  Extra pointer to pass to the callback function.
132  * @return               Non-zero for success, zero for failure.
133  */
134 
open_decoder(LHAReader * reader,LHADecoderProgressCallback callback,void * callback_data)135 static int open_decoder(LHAReader *reader,
136                         LHADecoderProgressCallback callback,
137                         void *callback_data)
138 {
139 	// Can only read from a normal file.
140 
141 	if (reader->curr_file_type != CURR_FILE_NORMAL) {
142 		return 0;
143 	}
144 
145 	reader->inner_decoder = lha_basic_reader_decode(reader->reader);
146 
147 	if (reader->inner_decoder == NULL) {
148 		return 0;
149 	}
150 
151 	// Set progress callback for decoder.
152 
153 	if (callback != NULL) {
154 		lha_decoder_monitor(reader->inner_decoder,
155 		                    callback, callback_data);
156 	}
157 
158 	// Some archives generated by MacLHA have a MacBinary header
159 	// attached to the start, which contains MacOS-specific
160 	// metadata about the compressed file. These are identified
161 	// and stripped off, using a "passthrough" decoder.
162 
163 	if (reader->curr_file->os_type == LHA_OS_TYPE_MACOS) {
164 		reader->decoder = lha_macbinary_passthrough(
165 		    reader->inner_decoder, reader->curr_file);
166 
167 		if (reader->decoder == NULL) {
168 			return 0;
169 		}
170 	} else {
171 		reader->decoder = reader->inner_decoder;
172 	}
173 
174 	return 1;
175 }
176 
lha_reader_new(LHAInputStream * stream)177 LHAReader *lha_reader_new(LHAInputStream *stream)
178 {
179 	LHABasicReader *basic_reader;
180 	LHAReader *reader;
181 
182 	reader = calloc(1, sizeof(LHAReader));
183 
184 	if (reader == NULL) {
185 		return NULL;
186 	}
187 
188 	basic_reader = lha_basic_reader_new(stream);
189 
190 	if (basic_reader == NULL) {
191 		free(reader);
192 		return NULL;
193 	}
194 
195 	reader->reader = basic_reader;
196 	reader->curr_file = NULL;
197 	reader->curr_file_type = CURR_FILE_START;
198 	reader->decoder = NULL;
199 	reader->inner_decoder = NULL;
200 	reader->dir_stack = NULL;
201 	reader->dir_policy = LHA_READER_DIR_END_OF_DIR;
202 	reader->deferred_symlinks = NULL;
203 
204 	return reader;
205 }
206 
lha_reader_free(LHAReader * reader)207 void lha_reader_free(LHAReader *reader)
208 {
209 	LHAFileHeader *header;
210 
211 	// Shut down the current decoder, if there is one.
212 
213 	close_decoder(reader);
214 
215 	// Free any file headers in the stack.
216 
217 	while (reader->dir_stack != NULL) {
218 		header = reader->dir_stack;
219 		reader->dir_stack = header->_next;
220 		lha_file_header_free(header);
221 	}
222 
223 	lha_basic_reader_free(reader->reader);
224 	free(reader);
225 }
226 
lha_reader_set_dir_policy(LHAReader * reader,LHAReaderDirPolicy policy)227 void lha_reader_set_dir_policy(LHAReader *reader,
228                                LHAReaderDirPolicy policy)
229 {
230 	reader->dir_policy = policy;
231 }
232 
233 /**
234  * Check if the directory at the top of the stack should be popped.
235  *
236  * Extracting a directory is a two stage process; after the directory
237  * is created, it is pushed onto the directory stack. Later the
238  * directory must be popped off the stack and its metadata applied.
239  *
240  * @param reader         Pointer to the LHA reader structure.
241  * @return               Non-zero if there is a directory at the top of
242  *                       the stack that should be popped.
243  */
244 
end_of_top_dir(LHAReader * reader)245 static int end_of_top_dir(LHAReader *reader)
246 {
247 	LHAFileHeader *input;
248 
249 	// No directories to pop?
250 
251 	if (reader->dir_stack == NULL) {
252 		return 0;
253 	}
254 
255 	// Once the end of the input stream is reached, all that is
256 	// left to do is pop off the remaining directories.
257 
258 	input = lha_basic_reader_curr_file(reader->reader);
259 
260 	if (input == NULL) {
261 		return 1;
262 	}
263 
264 	switch (reader->dir_policy) {
265 
266 		// Shouldn't happen?
267 
268 		case LHA_READER_DIR_PLAIN:
269 		default:
270 			return 1;
271 
272 		// Don't process directories until we reach the end of
273 		// the input stream.
274 
275 		case LHA_READER_DIR_END_OF_FILE:
276 			return 0;
277 
278 		// Once we reach a file from the input that is not within
279 		// the directory at the top of the stack, we have reached
280 		// the end of that directory, so we can pop it off.
281 
282 		case LHA_READER_DIR_END_OF_DIR:
283 			return input->path == NULL
284 			    || strncmp(input->path,
285 			               reader->dir_stack->path,
286 			               strlen(reader->dir_stack->path)) != 0;
287 	}
288 }
289 
290 // Read the next file from the input stream.
291 
lha_reader_next_file(LHAReader * reader)292 LHAFileHeader *lha_reader_next_file(LHAReader *reader)
293 {
294 	// Free the current decoder if there is one.
295 
296 	close_decoder(reader);
297 
298 	// No point continuing once the end of the input stream has
299 	// been reached.
300 
301 	if (reader->curr_file_type == CURR_FILE_EOF) {
302 		return NULL;
303 	}
304 
305 	// Advance to the next file from the input stream?
306 	// Don't advance until we've done the fake directories first.
307 
308 	if (reader->curr_file_type == CURR_FILE_START
309 	 || reader->curr_file_type == CURR_FILE_NORMAL) {
310 		lha_basic_reader_next_file(reader->reader);
311 	}
312 
313 	// If the last file we returned was a 'fake' directory, we must
314 	// now unreference it.
315 
316 	if (reader->curr_file_type == CURR_FILE_FAKE_DIR) {
317 		lha_file_header_free(reader->curr_file);
318 	}
319 
320 	// Pop off all appropriate directories from the stack first.
321 
322 	if (end_of_top_dir(reader)) {
323 		reader->curr_file = reader->dir_stack;
324 		reader->dir_stack = reader->dir_stack->_next;
325 		reader->curr_file_type = CURR_FILE_FAKE_DIR;
326 	} else {
327 		reader->curr_file = lha_basic_reader_curr_file(reader->reader);
328 		reader->curr_file_type = CURR_FILE_NORMAL;
329 	}
330 
331 	// Once we reach the end of the file, there may be deferred
332 	// symbolic links still to extract, so process those before
333 	// giving up and declaring end of file.
334 
335 	if (reader->curr_file == NULL) {
336 		if (reader->deferred_symlinks != NULL) {
337 			reader->curr_file = reader->deferred_symlinks;
338 			reader->curr_file_type = CURR_FILE_DEFERRED_SYMLINK;
339 
340 			reader->deferred_symlinks =
341 			    reader->deferred_symlinks->_next;
342 			reader->curr_file->_next = NULL;
343 		} else {
344 			reader->curr_file_type = CURR_FILE_EOF;
345 		}
346 	}
347 
348 	return reader->curr_file;
349 }
350 
lha_reader_read(LHAReader * reader,void * buf,size_t buf_len)351 size_t lha_reader_read(LHAReader *reader, void *buf, size_t buf_len)
352 {
353 	// The first time that we try to read the current file, we
354 	// must create the decoder to decompress it.
355 
356 	if (reader->decoder == NULL) {
357 		if (!open_decoder(reader, NULL, NULL)) {
358 			return 0;
359 		}
360 	}
361 
362 	// Read from decoder and return the result.
363 
364 	return lha_decoder_read(reader->decoder, buf, buf_len);
365 }
366 
367 /**
368  * Decompress the current file.
369  *
370  * Assumes that @param open_decoder has already been called to
371  * start the decode process.
372  *
373  * @param reader         Pointer to the LHA reader structure.
374  * @param output         FILE handle to write decompressed data, or NULL
375  *                       if the decompressed data should be discarded.
376  * @return               Non-zero if the file decompressed successfully.
377  */
378 
do_decode(LHAReader * reader,FILE * output)379 static int do_decode(LHAReader *reader, FILE *output)
380 {
381 	uint8_t buf[64];
382 	unsigned int bytes;
383 
384 	// Decompress the current file.
385 
386 	do {
387 		bytes = lha_reader_read(reader, buf, sizeof(buf));
388 
389 		if (output != NULL) {
390 			if (fwrite(buf, 1, bytes, output) < bytes) {
391 				return 0;
392 			}
393 		}
394 
395 	} while (bytes > 0);
396 
397 	// Decoder stores output position and performs running CRC.
398 	// At the end of the stream these should match the header values.
399 
400 	return lha_decoder_get_length(reader->inner_decoder)
401 	         == reader->curr_file->length
402 	    && lha_decoder_get_crc(reader->inner_decoder)
403 	         == reader->curr_file->crc;
404 }
405 
lha_reader_check(LHAReader * reader,LHADecoderProgressCallback callback,void * callback_data)406 int lha_reader_check(LHAReader *reader,
407                      LHADecoderProgressCallback callback,
408                      void *callback_data)
409 {
410 	if (reader->curr_file_type != CURR_FILE_NORMAL) {
411 		return 0;
412 	}
413 
414 	// CRC checking of directories is not necessary.
415 
416 	if (!strcmp(reader->curr_file->compress_method,
417 	            LHA_COMPRESS_TYPE_DIR)) {
418 		return 1;
419 	}
420 
421 	// Decode file.
422 
423 	return open_decoder(reader, callback, callback_data)
424 	    && do_decode(reader, NULL);
425 }
426 
427 /**
428  * Open an output stream into which to decompress the current file.
429  *
430  * @param reader         Pointer to the LHA reader structure.
431  * @param filename       Name of the file to open.
432  * @return               FILE handle of the opened file, or NULL in
433  *                       case of failure.
434  */
435 
open_output_file(LHAReader * reader,char * filename)436 static FILE *open_output_file(LHAReader *reader, char *filename)
437 {
438 	int unix_uid = -1, unix_gid = -1, unix_perms = -1;
439 
440 	if (LHA_FILE_HAVE_EXTRA(reader->curr_file, LHA_FILE_UNIX_UID_GID)) {
441 		unix_uid = reader->curr_file->unix_uid;
442 		unix_gid = reader->curr_file->unix_gid;
443 	}
444 
445 	if (LHA_FILE_HAVE_EXTRA(reader->curr_file, LHA_FILE_UNIX_PERMS)) {
446 		unix_perms = reader->curr_file->unix_perms;
447 	}
448 
449 	return lha_arch_fopen(filename, unix_uid, unix_gid, unix_perms);
450 }
451 
452 /**
453  * Set file timestamps for the specified file.
454  *
455  * If possible, the more accurate Windows timestamp values are used;
456  * otherwise normal Unix timestamps are used.
457  *
458  * @param path     Path to the file or directory to set.
459  * @param header   Pointer to file header structure containing the
460  *                 timestamps to set.
461  * @return         Non-zero if the timestamps were set successfully,
462  *                 or zero for failure.
463  */
464 
set_timestamps_from_header(char * path,LHAFileHeader * header)465 static int set_timestamps_from_header(char *path, LHAFileHeader *header)
466 {
467 #if LHA_ARCH == LHA_ARCH_WINDOWS
468 	if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_WINDOWS_TIMESTAMPS)) {
469 		return lha_arch_set_windows_timestamps(
470 		    path,
471 		    header->win_creation_time,
472 		    header->win_modification_time,
473 		    header->win_access_time
474 		);
475 	} else // ....
476 #endif
477 	if (header->timestamp != 0) {
478 		return lha_arch_utime(path, header->timestamp);
479 	} else {
480 		return 1;
481 	}
482 }
483 
484 /**
485  * Set directory metadata.
486  *
487  * This is the second stage of directory extraction. Metadata (timestamps
488  * and permissions) should be set on a dictory after the contents of
489  * the directory has been extracted.
490  *
491  * @param header     Pointer to file header structure containing the
492  *                   metadata to set.
493  * @param path       Path to the directory on which to set the metadata.
494  * @return           Non-zero for success, or zero for failure.
495  */
496 
set_directory_metadata(LHAFileHeader * header,char * path)497 static int set_directory_metadata(LHAFileHeader *header, char *path)
498 {
499 	// Set timestamp:
500 
501 	set_timestamps_from_header(path, header);
502 
503 	// Set owner and group:
504 
505 	if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_UNIX_UID_GID)) {
506 		if (!lha_arch_chown(path, header->unix_uid,
507 		                    header->unix_gid)) {
508 			// On most Unix systems, only root can change
509 			// ownership. But if we can't change ownership,
510 			// it isn't a fatal error. Ignore the failure
511 			// and continue.
512 
513 			// TODO: Implement some kind of alternate handling
514 			// here?
515 			/* return 0; */
516 		}
517 	}
518 
519 	// Set permissions on directory:
520 
521 	if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_UNIX_PERMS)) {
522 		if (!lha_arch_chmod(path, header->unix_perms)) {
523 			return 0;
524 		}
525 	}
526 
527 	return 1;
528 }
529 
530 /**
531  * "Extract" (create) a directory.
532  *
533  * The current file is assumed to be a directory. This is the first
534  * stage in extracting a directory; after the directory is created,
535  * it is added to the directory stack so that the metadata apply stage
536  * runs later. (If the LHA_READER_DIR_PLAIN policy is used, metadata
537  * is just applied now).
538  *
539  * @param reader    Pointer to the LHA reader structure.
540  * @param path      Path to the directory, or NULL to use the path from
541  *                  the file header.
542  * @return          Non-zero for success, or zero for failure.
543  */
544 
extract_directory(LHAReader * reader,char * path)545 static int extract_directory(LHAReader *reader, char *path)
546 {
547 	LHAFileHeader *header;
548 	unsigned int mode;
549 
550 	header = reader->curr_file;
551 
552 	// If path is not specified, use the path from the file header.
553 
554 	if (path == NULL) {
555 		path = header->path;
556 	}
557 
558 	// Create directory. If there are permissions to be set, create
559 	// the directory with minimal permissions limited to the running
560 	// user. Otherwise use the default umask.
561 
562 	if (LHA_FILE_HAVE_EXTRA(header, LHA_FILE_UNIX_PERMS)) {
563 		mode = 0700;
564 	} else {
565 		mode = 0777;
566 	}
567 
568 	if (!lha_arch_mkdir(path, mode)) {
569 
570 		// If the attempt to create the directory failed, it may
571 		// be because the directory already exists. Return success
572 		// if this is the case; it isn't really an error.
573 
574 		return lha_arch_exists(path) == LHA_FILE_DIRECTORY;
575 	}
576 
577 	// The directory has been created, but the metadata has not yet
578 	// been applied. It depends on the directory policy how this
579 	// is handled. If we are using LHA_READER_DIR_PLAIN, set
580 	// metadata now. Otherwise, save the directory for later.
581 
582 	if (reader->dir_policy == LHA_READER_DIR_PLAIN) {
583 		set_directory_metadata(header, path);
584 	} else {
585 		lha_file_header_add_ref(header);
586 		header->_next = reader->dir_stack;
587 		reader->dir_stack = header;
588 	}
589 
590 	return 1;
591 }
592 
593 /**
594  * Extract the current file.
595  *
596  * @param reader         Pointer to the LHA reader structure.
597  * @param filename       Filename into which to extract the file, or NULL
598  *                       to use the filename from the file header.
599  * @param callback       Callback function to invoke to track progress.
600  * @param callback_data  Extra pointer to pass to the callback function.
601  * @return               Non-zero if the file was successfully extracted,
602  *                       or zero for failure.
603  */
604 
extract_file(LHAReader * reader,char * filename,LHADecoderProgressCallback callback,void * callback_data)605 static int extract_file(LHAReader *reader, char *filename,
606                         LHADecoderProgressCallback callback,
607                         void *callback_data)
608 {
609 	FILE *fstream;
610 	char *tmp_filename = NULL;
611 	int result;
612 
613 	// Construct filename?
614 
615 	if (filename == NULL) {
616 		tmp_filename = lha_file_header_full_path(reader->curr_file);
617 
618 		if (tmp_filename == NULL) {
619 			return 0;
620 		}
621 
622 		filename = tmp_filename;
623 	}
624 
625 	// Create decoder. If the file cannot be created, there is no
626 	// need to even create an output file. If successful, open the
627 	// output file and decode.
628 
629 	result = 0;
630 
631 	if (open_decoder(reader, callback, callback_data)) {
632 
633 		fstream = open_output_file(reader, filename);
634 
635 		if (fstream != NULL) {
636 			result = do_decode(reader, fstream);
637 			fclose(fstream);
638 		}
639 	}
640 
641 	// Set timestamp on file:
642 
643 	if (result) {
644 		set_timestamps_from_header(filename, reader->curr_file);
645 	}
646 
647 	free(tmp_filename);
648 
649 	return result;
650 }
651 
652 /**
653  * Determine whether a header contains a "dangerous" symbolic link.
654  *
655  * Symbolic links that begin with '/' or contain '..' as a path are
656  * Potentially dangerous and could potentially be used to overwrite
657  * arbitrary files on the filesystem. They therefore need to be
658  * treated specially.
659  *
660  * @param header         Pointer to a header structure defining a symbolic
661  *                       link.
662  * @return               Non-zero if the symbolic link is potentially
663  *                       dangerous.
664  */
665 
is_dangerous_symlink(LHAFileHeader * header)666 static int is_dangerous_symlink(LHAFileHeader *header)
667 {
668 	char *path_start;
669 	char *p;
670 
671 	if (header->symlink_target == NULL) {
672 		return 0;
673 	}
674 
675 	// Absolute path symlinks could be used to point to arbitrary
676 	// filesystem locations.
677 
678 	if (header->symlink_target[0] == '/') {
679 		return 1;
680 	}
681 
682 	// Check for paths containing '..'.
683 
684 	path_start = header->symlink_target;
685 
686 	for (p = header->symlink_target; *p != '\0'; ++p) {
687 		if (*p == '/') {
688 			if ((p - path_start) == 2
689 			 && path_start[0] == '.' && path_start[1] == '.') {
690 				return 1;
691 			}
692 
693 			path_start = p + 1;
694 		}
695 	}
696 
697 	// The path might also end with '..' (no terminating /)
698 
699 	if ((p - path_start) == 2
700 	 && path_start[0] == '.' && path_start[1] == '.') {
701 		return 1;
702 	}
703 
704 	return 0;
705 }
706 
707 /**
708  * Get the length of a path defined by a file header.
709  *
710  * @param header         The file header structure.
711  * @return               Length of the header in bytes.
712  */
713 
file_header_path_len(LHAFileHeader * header)714 static size_t file_header_path_len(LHAFileHeader *header)
715 {
716 	size_t result;
717 
718 	result = 0;
719 
720 	if (header->path != NULL) {
721 		result += strlen(header->path);
722 	}
723 	if (header->filename != NULL) {
724 		result += strlen(header->filename);
725 	}
726 
727 	return result;
728 }
729 
730 /**
731  * Create a "placeholder" symbolic link.
732  *
733  * When a "dangerous" symbolic link is extracted, instead of creating it
734  * immediately, create a "placeholder" empty file to go in its place, and
735  * place it into the deferred_symlinks list to be created later.
736  *
737  * @param reader         Pointer to the LHA reader structure.
738  * @param filename       Filename into which to extract the symlink.
739  * @return               Non-zero if the symlink was extracted successfully,
740  *                       or zero for failure.
741  */
742 
extract_placeholder_symlink(LHAReader * reader,char * filename)743 static int extract_placeholder_symlink(LHAReader *reader, char *filename)
744 {
745 	LHAFileHeader **rover;
746 	FILE *f;
747 
748 	f = lha_arch_fopen(filename, -1, -1, 0600);
749 
750 	if (f == NULL) {
751 		return 0;
752 	}
753 
754 	fclose(f);
755 
756 	// Insert this header into the list of deferred symbolic links.
757 	// The list must be maintained in order of decreasing path length,
758 	// so that one symbolic link cannot depend on another. For example:
759 	//
760 	//    etc  ->  /etc
761 	//    etc/passwd  -> /malicious_path/passwd
762 
763 	rover = &reader->deferred_symlinks;
764 
765 	while (*rover != NULL
766 	    && file_header_path_len(*rover)
767 	     > file_header_path_len(reader->curr_file)) {
768 		rover = &(*rover)->_next;
769 	}
770 
771 	reader->curr_file->_next = *rover;
772 	*rover = reader->curr_file;
773 
774 	// Save reference to the header so it won't be freed.
775 
776 	lha_file_header_add_ref(reader->curr_file);
777 
778 	return 1;
779 }
780 
781 /**
782  * Extract a Unix symbolic link.
783  *
784  * @param reader         Pointer to the LHA reader structure.
785  * @param filename       Filename into which to extract the symlink, or NULL
786  *                       to use the filename from the file header.
787  * @return               Non-zero if the symlink was extracted successfully,
788  *                       or zero for failure.
789  */
790 
extract_symlink(LHAReader * reader,char * filename)791 static int extract_symlink(LHAReader *reader, char *filename)
792 {
793 	char *tmp_filename = NULL;
794 	int result;
795 
796 	// Construct filename?
797 
798 	if (filename == NULL) {
799 		tmp_filename = lha_file_header_full_path(reader->curr_file);
800 
801 		if (tmp_filename == NULL) {
802 			return 0;
803 		}
804 
805 		filename = tmp_filename;
806 	}
807 
808 	if (reader->curr_file_type == CURR_FILE_NORMAL
809 	 && is_dangerous_symlink(reader->curr_file)) {
810 		return extract_placeholder_symlink(reader, filename);
811 	}
812 
813 	result = lha_arch_symlink(filename, reader->curr_file->symlink_target);
814 
815 	// TODO: Set symlink timestamp.
816 
817 	free(tmp_filename);
818 
819 	return result;
820 }
821 
822 /**
823  * Extract a "normal" file.
824  *
825  * This just extracts the file header most recently read by the
826  * BasicReader.
827  *
828  * @param reader         Pointer to the LHA reader structure.
829  * @param filename       Filename into which to extract the file, or NULL
830  *                       to use the filename from the file header.
831  * @param callback       Callback function to invoke to track progress.
832  * @param callback_data  Extra pointer to pass to the callback function.
833  * @return               Non-zero if the file was successfully extracted,
834  *                       or zero for failure.
835  */
836 
extract_normal(LHAReader * reader,char * filename,LHADecoderProgressCallback callback,void * callback_data)837 static int extract_normal(LHAReader *reader,
838                           char *filename,
839                           LHADecoderProgressCallback callback,
840                           void *callback_data)
841 {
842 	if (strcmp(reader->curr_file->compress_method,
843 	           LHA_COMPRESS_TYPE_DIR) != 0) {
844 		return extract_file(reader, filename, callback, callback_data);
845 	} else if (reader->curr_file->symlink_target != NULL) {
846 		return extract_symlink(reader, filename);
847 	} else {
848 		return extract_directory(reader, filename);
849 	}
850 }
851 
lha_reader_extract(LHAReader * reader,char * filename,LHADecoderProgressCallback callback,void * callback_data)852 int lha_reader_extract(LHAReader *reader,
853                        char *filename,
854                        LHADecoderProgressCallback callback,
855                        void *callback_data)
856 {
857 	switch (reader->curr_file_type) {
858 
859 		case CURR_FILE_NORMAL:
860 			return extract_normal(reader, filename, callback,
861 			                      callback_data);
862 
863 		case CURR_FILE_FAKE_DIR:
864 			if (filename == NULL) {
865 				filename = reader->curr_file->path;
866 			}
867 			set_directory_metadata(reader->curr_file, filename);
868 			return 1;
869 
870 		case CURR_FILE_DEFERRED_SYMLINK:
871 			return extract_symlink(reader, filename);
872 
873 		case CURR_FILE_START:
874 		case CURR_FILE_EOF:
875 			break;
876 	}
877 
878 	return 0;
879 }
880 
lha_reader_current_is_fake(LHAReader * reader)881 int lha_reader_current_is_fake(LHAReader *reader)
882 {
883 	return reader->curr_file_type == CURR_FILE_FAKE_DIR
884 	    || reader->curr_file_type == CURR_FILE_DEFERRED_SYMLINK;
885 }
886 
887