5 * Revision 1.21 99/03/17 MU
6 * Added support for extraction with .inf files
7 * Also capitilised the hexadecimal output strings.
9 * $Header: unarc.c 1.19 95/08/01 $
11 * Revision 1.20 95/08/01 xx:xx:xx BB
12 * Fixed for Borland C/C++
14 * Revision 1.19 94/12/12 17:29:30 arb
15 * Added support for ArcFS writesize
17 * Revision 1.18 93/08/20 12:30:02 arb
18 * Added support for ArcFS archive detection
20 * Revision 1.17 93/08/20 11:54:55 arb
21 * Prevent printing of spaces and LF if in quiet mode
23 * Revision 1.16 93/03/05 14:45:43 arb
24 * Added <string.h> for RISCOS, needed for strcpy
26 * Revision 1.15 92/12/23 13:26:05 duplain
27 * Added total-printing if in verbose mode.
29 * Revision 1.14 92/12/08 10:20:33 duplain
30 * Added call to append_type() if apptype non zero.
32 * Revision 1.13 92/12/07 17:19:21 duplain
35 * Revision 1.12 92/11/04 16:56:35 duplain
36 * Added printing of CRC value if debugging.
38 * Revision 1.11 92/10/29 13:40:05 duplain
39 * Fixed prompt_user function definition.
41 * Revision 1.10 92/10/23 14:31:28 duplain
42 * Changed prompt_user() output text.
44 * Revision 1.9 92/10/06 12:17:49 duplain
45 * Changed header used with verbose option.
47 * Revision 1.8 92/10/05 11:00:37 duplain
48 * Recoded user-prompt when files already exists during unarchiving.
50 * Revision 1.7 92/10/02 17:41:14 duplain
51 * Fix "end-of-subarchive" problem.
53 * Revision 1.6 92/10/02 10:03:20 duplain
54 * Changed "OS_FILE" to "OS_File" for log file entry.
56 * Revision 1.5 92/10/01 13:39:30 duplain
57 * Removed "goto do_retry" when header->complen > arcsize.
59 * Revision 1.4 92/10/01 12:17:16 duplain
60 * Fixed calculation of archive file size when unpacking/testing.
62 * Revision 1.3 92/10/01 11:22:59 duplain
63 * Added retry processing.
65 * Revision 1.2 92/09/30 10:27:51 duplain
66 * Added logfile processing.
68 * Revision 1.1 92/09/29 18:02:27 duplain
82 /* BB changed next line because of conflict with Borland's io.h */
87 /* BB added next line */
88 #if defined(__MSDOS__) || defined(_WIN32)
89 #include <io.h> /* for read() */
94 #endif /* __MSDOS__ */
102 #if defined(RISCOS) || defined(__MSDOS__)
103 #include <string.h> /* for strcpy */
104 #endif /* RISCOS || __MSDOS__ */
106 char prompt_user(char *filename
);
107 char *get_newname(void);
112 do_unsquash(int to_stdout
)
114 SqshHeader sqsh_header
;
123 ifp
= fopen(archive
, "rb");
126 error("Can not open %s for reading\n", archive
);
132 ofname
= calloc(1, strlen(archive
) + sizeof(",xxx"));
133 /* Output filename is the same as the input filename with
134 * the correct filetype appended */
135 strcpy(ofname
, archive
);
136 /* Strip RISCOS filetype from output filename */
137 p
= ofname
+ (strlen(ofname
) - 4);
138 if (*p
== ',' || *p
== '.')
144 r
= read_sqsh_header(ifp
, &sqsh_header
);
147 error("Invalid squash file");
151 memset(&header
, 0, sizeof(header
));
152 datastart
= ftell(ifp
);
153 fseek(ifp
, 0, SEEK_END
);
156 /* The uncompress code uses Spark entry header structures.
157 * Use the squash header and other info to set up the Spark header
158 * with needed info. */
159 header
.complen
= (Word
)(offset
- datastart
);
160 sqsh_header_to_header(&sqsh_header
, &header
);
161 fseek(ifp
, datastart
, SEEK_SET
);
164 writesize
= header
.origlen
;
168 /* Append the correct filetype to the output filename */
169 append_type(&header
, ofname
);
172 if (!force
&& !to_stdout
)
174 ofp
= fopen(ofname
, "rb");
181 c
= prompt_user(ofname
);
187 newname
= get_newname();
189 ofname
= strdup(newname
);
205 ofp
= fopen(ofname
, "wb");
208 error("Can not open %s for writing\n", ofname
);
213 r
= uncompress(&header
, ifp
, ofp
, UNIX_COMPRESS
);
221 if (stamp
&& !to_stdout
)
223 filestamp(&header
, ofname
);
228 error("Failed to decompress file");
239 FILE *ifp
, *ofp
= NULL
, *lfp
= NULL
;
240 Header
*header
= NULL
;
241 char *pathname
= NULL
;
242 char fullname
[PATHNAMELEN
];
243 int level
= 0, ret
= 0, retrying
= 0;
249 ifp
= fopen(archive
, R_OPENMODE
);
252 ifp
= fopen(name_dot_arc(archive
), R_OPENMODE
);
256 error("cannot open archive \"%s\"", archive
);
259 archive
= name_dot_arc(archive
);
262 arcsize
= filesize(archive
);
263 if (!arcsize
&& !quiet
)
265 error("cannot get size of archive file");
270 /* MU changed to accomodate the -I option */
273 if (!testing
&& !listing
&& logfile
)
275 lfp
= fopen(logfile
, W_OPENMODE
);
277 warning("unable to open logfile \"%s\"", logfile
);
281 if (!quiet
&& verbose
)
283 puts("filename size load/date exec/time type storage");
284 puts("-------- ---- ----------- --------- ---- -------");
288 * read compressed files from archive until end of file...
292 static Header dirheader
;
293 Byte comptype
, first
;
296 if ((arcfs
== 0) && ((first
= read_byte(ifp
)) != STARTBYTE
))
298 if ((first
== 'A') &&
299 (read_byte(ifp
) == 'r') &&
300 (read_byte(ifp
) == 'c') &&
301 (read_byte(ifp
) == 'h') &&
302 (read_byte(ifp
) == 'i') &&
303 (read_byte(ifp
) == 'v') &&
304 (read_byte(ifp
) == 'e') && (read_byte(ifp
) == '\0'))
308 printf("ArcFS format archive\n");
309 #endif /* DEBUGGING */
316 header
= read_header(ifp
);
317 comptype
= header
->comptype
& 0x7f;
321 printf("archive file length = %ld level = %d\n", arcsize
,
323 print_header(header
);
325 #endif /* DEBUGGING */
328 * If this is a compress _file_ then check archive size against
329 * compress-file length...
331 if (comptype
&& !(comptype
== CT_NOTCOMP2
&&
332 /* BB changed constants in next line to long */
333 (header
->load
& 0xffffff00l
) == 0xfffddc00l
))
335 if (header
->complen
> arcsize
)
339 puts("compressed len > archive file len");
340 #endif /* DEBUGGING */
345 arcsize
-= header
->complen
;
349 { /* end of archive ? */
354 * stamp directory now that all files have
355 * been written into it
357 if (!testing
&& !listing
&& stamp
&& inlist(pathname
))
358 if (filestamp(&dirheader
, pathname
) < 0 && !quiet
)
359 printf("error stamping %s\n", pathname
);
360 pathname
= uplevel();
365 * test for directory or file (file type = &DDC = archive)
367 if (comptype
== CT_NOTCOMP2
&&
368 /* BB changed constants in next line to long */
369 (header
->load
& 0xffffff00l
) == 0xfffddc00l
)
372 pathname
= downlevel(header
->name
);
373 dirheader
= *header
; /* make copy of header */
378 if (!testing
&& !listing
&& inlist(pathname
))
379 switch (exist(pathname
))
382 if (makedir(pathname
) < 0 && !quiet
)
384 printf("error making %s... aborting", pathname
);
392 printf("%s exists as a file... aborting",
404 sprintf(fullname
, "%s%c%s", pathname
, PATHSEP
,
407 strcpy(fullname
, header
->name
);
409 if (!inlist(fullname
))
411 fseek(ifp
, (long) header
->complen
, 1);
416 * print the archive file details...
420 printf("%-30s", fullname
);
422 print_details(header
);
426 nbytes
+= header
->origlen
;
431 /* if listing, nothing more to do */
434 fseek(ifp
, (long) header
->complen
, 1);
441 * append the filetype to the name
444 append_type(header
, fullname
);
447 * if actually unarchiving then check if the file already exists
452 switch (exist(fullname
))
457 char c
= prompt_user(fullname
);
462 fseek(ifp
, (long) header
->complen
, 1);
467 char *newname
= get_newname();
469 sprintf(fullname
, "%s%c%s", pathname
,
472 strcpy(fullname
, newname
);
475 /* if (c == 'y') FALLTHROUGH */
480 puts("exists as a directory... skipping");
486 ofp
= fopen(fullname
, W_OPENMODE
);
490 printf("unable to create");
498 crcsize
= writesize
= header
->origlen
;
503 status
= unstore(header
, ifp
, ofp
);
506 status
= uncompress(header
, ifp
, ofp
, CRUNCH
);
509 status
= unpack(header
, ifp
, ofp
);
512 status
= uncompress(header
, ifp
, ofp
, SQUASH
);
515 status
= uncompress(header
, ifp
, ofp
, COMPRESS
);
518 printf("unsupported archive type %d\n", comptype
);
521 fseek(ifp
, (long) header
->complen
, 1);
532 * check if unarchiving failed.
533 * (RERR check is not in switch() because `break'
534 * needs to escape from while())
539 error("error reading archive");
547 printf("error writing file");
551 printf("failed CRC check");
555 /* BB changed format in next line to long hex */
556 /* printf(" calculated CRC=0x%x", crc); */
558 printf(" calculated CRC=0X%lX", crc
);
560 printf(" calculated CRC=0X%X", crc
);
561 #endif /* __MSDOS__ */
563 #endif /* DEBUGGING */
566 if (!testing
&& stamp
)
568 if (filestamp(header
, fullname
) < 0 && !quiet
)
569 printf("\nerror stamping %s", fullname
);
572 * XXX: if the filename has had it's filetype appended to
573 * it, it may be longer than 10 characters long making this
574 * file useless. We could truncate the filename but there is
575 * no need to under UNIX... bit of a mismatch!
581 strcpy(logfile
, fullname
);
582 strcat(logfile
, ".inf");
583 lfp
= fopen(logfile
, W_OPENMODE
);
590 if ((header->load => 0xFFFFFB41) && (header->load <= 0xFFFFFB46))
592 header->load = 0xFFFF1900;
593 header->exec = 0xFFFF802B;
597 if (header->load == 0xFFFFFE41)
599 header->load = 0x00000000;
600 header->exec = 0xFFFFFFFF;
603 fprintf(lfp
, "%s %08lX %08lX\n",
604 riscos_path(fullname
), (long)header
->load
,
616 "SYS \"OS_File\", 1, \"%s\", &%08lX, &%08lX,, &%X\n",
617 riscos_path(fullname
), (long)header
->load
,
618 (long)header
->exec
, header
->attr
);
636 * find out why header wasn't found
639 switch (check_stream(ifp
))
643 printf("bad archive header");
644 if (retry
&& !listing
)
646 puts("... retrying");
649 while (check_stream(ifp
) == FNOERR
)
650 if (read_byte(ifp
) == STARTBYTE
)
652 Byte byte
= read_byte(ifp
);
661 ungetc((int) byte
, ifp
);
679 puts("error reading archive");
690 printf("total of %ld bytes in %d files\n", (long)nbytes
, nfiles
);
702 * the file being extracted already exists, so ask user what to do...
705 prompt_user(char *filename
)
712 printf("\n\"%s\" exists, overwrite ? (Yes/No/All/Rename): ",
715 if (read(0, buffer
, sizeof(buffer
) - 1)<1) {
719 if (isupper(*buffer
))
720 c
= tolower(*buffer
);
723 if (c
== 'y' || c
== 'n' || c
== 'a' || c
== 'r')
730 * user wants to rename file, so get the leaf name of the new file...
736 static char buffer
[80];
740 printf("enter new filename: ");
742 c
= read(0, buffer
, sizeof(buffer
) - 1);
743 buffer
[c
? c
- 1 : 0] = '\0';
746 for (c
= 0; buffer
[c
]; c
++)
747 if (buffer
[c
] == PATHSEP
)
749 puts("*** new file must extract into this directory ***");