- LzHeader hdr;
- long pos;
- FILE *afp;
-
- /* open archive file */
- if ((afp = open_old_archive()) == NULL)
- fatal_error(archive_name);
-
- if (archive_is_msdos_sfx1(archive_name))
- skip_msdos_sfx1_code(afp);
-
- /* extract each files */
- while (get_header(afp, &hdr)) {
- if (need_file(hdr.name)) {
- pos = ftell(afp);
- extract_one(afp, &hdr);
- fseek(afp, pos + hdr.packed_size, SEEK_SET);
- }
- else {
- if (afp != stdin)
- fseek(afp, hdr.packed_size, SEEK_CUR);
- else {
- int i = hdr.packed_size;
- while (i--)
- fgetc(afp);
- }
- }
- }
-
- /* close archive file */
- fclose(afp);
-
- return;
+ LzHeader hdr;
+ off_t pos;
+ FILE *afp;
+ off_t read_size;
+
+ /* open archive file */
+ if ((afp = open_old_archive()) == NULL)
+ fatal_error("Cannot open archive file \"%s\"", archive_name);
+
+ if (archive_is_msdos_sfx1(archive_name))
+ seek_lha_header(afp);
+
+ /* extract each files */
+ while (get_header(afp, &hdr)) {
+ pos = ftello(afp);
+ if (need_file(hdr.name)) {
+ read_size = extract_one(afp, &hdr);
+ if (read_size != hdr.packed_size) {
+ /* when error occurred in extract_one(), should adjust
+ point of file stream */
+ if (skip_to_nextpos(afp, pos, hdr.packed_size, read_size) == -1) {
+ fatal_error("Cannot seek to next header position from \"%s\"", hdr.name);
+ }
+ }
+ } else {
+ if (skip_to_nextpos(afp, pos, hdr.packed_size, 0) == -1) {
+ fatal_error("Cannot seek to next header position from \"%s\"", hdr.name);
+ }
+ }
+ }
+
+ /* close archive file */
+ fclose(afp);
+
+ /* adjust directory information */
+ adjust_dirinfo();
+
+ return;
+}
+
+int
+is_directory_traversal(char *path)
+{
+ int state = 0;
+
+ for (; *path; path++) {
+ switch (state) {
+ case 0:
+ if (*path == '.') state = 1;
+ else state = 3;
+ break;
+ case 1:
+ if (*path == '.') state = 2;
+ else if (*path == '/') state = 0;
+ else state = 3;
+ break;
+ case 2:
+ if (*path == '/') return 1;
+ else state = 3;
+ break;
+ case 3:
+ if (*path == '/') state = 0;
+ break;
+ }
+ }
+
+ return state == 2;
+}
+
+/*
+ * restore directory information (timestamp, permission and uid/gid).
+ * added by A.Iriyama 2003.12.12
+ */
+
+typedef struct LzHeaderList_t {
+ struct LzHeaderList_t *next;
+ LzHeader hdr;
+} LzHeaderList;
+
+static LzHeaderList *dirinfo;
+
+static void add_dirinfo(char *name, LzHeader *hdr)
+{
+ LzHeaderList *p, *tmp, top;
+
+ if (memcmp(hdr->method, LZHDIRS_METHOD, 5) != 0)
+ return;
+
+ p = xmalloc(sizeof(LzHeaderList));
+
+ memcpy(&p->hdr, hdr, sizeof(LzHeader));
+ strncpy(p->hdr.name, name, sizeof(p->hdr.name));
+ p->hdr.name[sizeof(p->hdr.name)-1] = 0;
+
+#if 0
+ /* push front */
+ {
+ tmp = dirinfo;
+ dirinfo = p;
+ dirinfo->next = tmp;
+ }
+#else
+
+ /*
+ reverse sorted by pathname order
+
+ p->hdr.name = "a"
+
+ dirinfo->hdr.name = "a/b/d"
+ dirinfo->next->hdr.name = "a/b/c"
+ dirinfo->next->next->hdr.name = "a/b"
+
+ result:
+
+ dirinfo->hdr.name = "a/b/d"
+ dirinfo->next->hdr.name = "a/b/c"
+ dirinfo->next->next->hdr.name = "a/b"
+ dirinfo->next->next->next->hdr.name = "a"
+ */
+
+ top.next = dirinfo;
+
+ for (tmp = ⊤ tmp->next; tmp = tmp->next) {
+ if (strcmp(p->hdr.name, tmp->next->hdr.name) > 0) {
+ p->next = tmp->next;
+ tmp->next = p;
+ break;
+ }
+ }
+ if (tmp->next == NULL) {
+ p->next = NULL;
+ tmp->next = p;
+ }
+
+ dirinfo = top.next;
+#endif
+}
+
+static void adjust_dirinfo()
+{
+ while (dirinfo) {
+ /* message("adjusting [%s]", dirinfo->hdr.name); */
+ adjust_info(dirinfo->hdr.name, &dirinfo->hdr);
+
+ {
+ LzHeaderList *tmp = dirinfo;
+ dirinfo = dirinfo->next;
+ free(tmp);
+ }
+ }
+}
+
+#if HAVE_LIBAPPLEFILE
+static boolean
+decode_macbinary(ofp, size, outPath)
+ FILE *ofp;
+ off_t size;
+ const char *outPath;
+{
+ af_file_t *afp = NULL;
+ FILE *ifp = NULL;
+ unsigned char *datap;
+ size_t dlen;
+
+ if ((afp = af_open(temporary_name)) != NULL) {
+ /* fetch datafork */
+ datap = af_data(afp, &dlen);
+ fwrite(datap, sizeof(unsigned char), dlen, ofp);
+ af_close(afp);
+ return TRUE;
+ } else { /* it may be not encoded in MacBinary */
+ /* try to copy */
+ if ((ifp = fopen(temporary_name, READ_BINARY)) == NULL) {
+ error("Cannot open a temporary file \"%s\"", temporary_name);
+ return FALSE;
+ }
+ copyfile(ifp, ofp, size, 0, 0);
+ fclose(ifp);
+ return TRUE;
+ }
+
+ return FALSE;