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);
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 msg("filename size load/date exec/time type storage");
284 msg("-------- ---- ----------- --------- ---- -------");
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'))
306 debug("ArcFS format archive\n");
313 header
= read_header(ifp
);
314 comptype
= header
->comptype
& 0x7f;
316 debug("archive file length = %ld level = %d\n", arcsize
,
318 print_header(header
);
319 #endif /* DEBUGGING */
322 * If this is a compress _file_ then check archive size against
323 * compress-file length...
325 if (comptype
&& !(comptype
== CT_NOTCOMP2
&&
326 /* BB changed constants in next line to long */
327 (header
->load
& 0xffffff00l
) == 0xfffddc00l
))
329 if (header
->complen
> arcsize
)
331 debug("compressed len > archive file len");
336 arcsize
-= header
->complen
;
340 { /* end of archive ? */
345 * stamp directory now that all files have
346 * been written into it
348 if (!testing
&& !listing
&& !to_stdout
&& stamp
&& inlist(pathname
))
349 if (filestamp(&dirheader
, pathname
) < 0 && !quiet
)
350 error("error stamping %s", pathname
);
351 pathname
= uplevel();
356 * test for directory or file (file type = &DDC = archive)
358 if (comptype
== CT_NOTCOMP2
&&
359 /* BB changed constants in next line to long */
360 (header
->load
& 0xffffff00l
) == 0xfffddc00l
)
363 pathname
= downlevel(header
->name
);
364 dirheader
= *header
; /* make copy of header */
369 if (!testing
&& !listing
&& !to_stdout
&& inlist(pathname
))
370 switch (exist(pathname
))
373 if (makedir(pathname
) < 0 && !quiet
)
375 msg("error making %s... aborting", pathname
);
383 msg("%s exists as a file... aborting",
395 sprintf(fullname
, "%s%c%s", pathname
, PATHSEP
,
398 strcpy(fullname
, header
->name
);
400 if (!inlist(fullname
))
402 fseek(ifp
, (long) header
->complen
, 1);
407 * print the archive file details...
411 msg("%-30s", fullname
);
413 print_details(header
);
417 nbytes
+= header
->origlen
;
422 /* if listing, nothing more to do */
425 fseek(ifp
, (long) header
->complen
, 1);
432 * append the filetype to the name
434 if (apptype
&& !to_stdout
)
435 append_type(header
, fullname
);
438 * if actually unarchiving then check if the file already exists
440 if (!testing
&& !to_stdout
)
443 switch (exist(fullname
))
448 char c
= prompt_user(fullname
);
453 fseek(ifp
, (long) header
->complen
, 1);
458 char *newname
= get_newname();
460 sprintf(fullname
, "%s%c%s", pathname
,
463 strcpy(fullname
, newname
);
466 /* if (c == 'y') FALLTHROUGH */
471 msg("exists as a directory... skipping");
477 ofp
= fopen(fullname
, W_OPENMODE
);
481 msg("unable to create");
493 crcsize
= writesize
= header
->origlen
;
498 status
= unstore(header
, ifp
, ofp
);
501 status
= uncompress(header
, ifp
, ofp
, CRUNCH
);
504 status
= unpack(header
, ifp
, ofp
);
507 status
= uncompress(header
, ifp
, ofp
, SQUASH
);
510 status
= uncompress(header
, ifp
, ofp
, COMPRESS
);
513 error("unsupported archive type %d", comptype
);
516 fseek(ifp
, (long) header
->complen
, 1);
520 if (!testing
&& !to_stdout
&& ofp
)
527 * check if unarchiving failed.
528 * (RERR check is not in switch() because `break'
529 * needs to escape from while())
534 error("error reading archive");
542 msg("error writing file");
546 msg("failed CRC check");
548 /* BB changed format in next line to long hex */
549 /* debug(" calculated CRC=0x%x", crc); */
551 debug(" calculated CRC=0X%lX", crc
);
553 debug(" calculated CRC=0X%X", crc
);
554 #endif /* __MSDOS__ */
557 if (!testing
&& !to_stdout
&& stamp
)
559 if (filestamp(header
, fullname
) < 0 && !quiet
)
560 msg("\nerror stamping %s", fullname
);
563 * XXX: if the filename has had it's filetype appended to
564 * it, it may be longer than 10 characters long making this
565 * file useless. We could truncate the filename but there is
566 * no need to under UNIX... bit of a mismatch!
572 strcpy(logfile
, fullname
);
573 strcat(logfile
, ".inf");
574 lfp
= fopen(logfile
, W_OPENMODE
);
581 if ((header->load => 0xFFFFFB41) && (header->load <= 0xFFFFFB46))
583 header->load = 0xFFFF1900;
584 header->exec = 0xFFFF802B;
588 if (header->load == 0xFFFFFE41)
590 header->load = 0x00000000;
591 header->exec = 0xFFFFFFFF;
594 fprintf(lfp
, "%s %08lX %08lX\n",
595 riscos_path(fullname
), (long)header
->load
,
607 "SYS \"OS_File\", 1, \"%s\", &%08lX, &%08lX,, &%X\n",
608 riscos_path(fullname
), (long)header
->load
,
609 (long)header
->exec
, header
->attr
);
627 * find out why header wasn't found
630 switch (check_stream(ifp
))
634 msg("bad archive header");
635 if (retry
&& !listing
)
640 while (check_stream(ifp
) == FNOERR
)
641 if (read_byte(ifp
) == STARTBYTE
)
643 Byte byte
= read_byte(ifp
);
652 ungetc((int) byte
, ifp
);
670 msg("error reading archive");
681 msg("total of %ld bytes in %d files\n", (long)nbytes
, nfiles
);
683 if (ofp
&& !to_stdout
)
693 * the file being extracted already exists, so ask user what to do...
696 prompt_user(char *filename
)
703 fprintf(stderr
, "\n\"%s\" exists, overwrite ? (Yes/No/All/Rename): ",
706 if (read(0, buffer
, sizeof(buffer
) - 1)<1) {
710 if (isupper(*buffer
))
711 c
= tolower(*buffer
);
714 if (c
== 'y' || c
== 'n' || c
== 'a' || c
== 'r')
721 * user wants to rename file, so get the leaf name of the new file...
727 static char buffer
[80];
731 fprintf(stderr
, "enter new filename: ");
733 c
= read(0, buffer
, sizeof(buffer
) - 1);
734 buffer
[c
? c
- 1 : 0] = '\0';
737 for (c
= 0; buffer
[c
]; c
++)
738 if (buffer
[c
] == PATHSEP
)
740 msg("*** new file must extract into this directory ***");