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 char prompt_user(char *filename
);
103 char *get_newname(void);
109 SqshHeader sqsh_header
;
118 ifp
= fopen(archive
, "rb");
121 error("Can not open %s for reading\n", archive
);
127 ofname
= calloc(1, strlen(archive
) + sizeof(",xxx"));
128 /* Output filename is the same as the input filename with
129 * the correct filetype appended */
130 strcpy(ofname
, archive
);
131 /* Strip RISCOS filetype from output filename */
132 p
= ofname
+ (strlen(ofname
) - 4);
133 if (*p
== ',' || *p
== '.')
139 r
= read_sqsh_header(ifp
, &sqsh_header
);
142 error("Invalid squash file");
146 memset(&header
, 0, sizeof(header
));
147 datastart
= ftell(ifp
);
148 fseek(ifp
, 0, SEEK_END
);
151 /* The uncompress code uses Spark entry header structures.
152 * Use the squash header and other info to set up the Spark header
153 * with needed info. */
154 header
.complen
= (Word
)(offset
- datastart
);
155 sqsh_header_to_header(&sqsh_header
, &header
);
156 fseek(ifp
, datastart
, SEEK_SET
);
159 writesize
= header
.origlen
;
163 /* Append the correct filetype to the output filename */
164 append_type(&header
, ofname
);
167 if (!force
&& !to_stdout
)
169 ofp
= fopen(ofname
, "rb");
176 c
= prompt_user(ofname
);
182 newname
= get_newname();
184 ofname
= strdup(newname
);
200 ofp
= fopen(ofname
, "wb");
203 error("Can not open %s for writing\n", ofname
);
208 r
= uncompress(&header
, ifp
, ofp
, UNIX_COMPRESS
);
216 if (stamp
&& !to_stdout
)
218 filestamp(&header
, ofname
);
223 error("Failed to decompress file");
233 FILE *ifp
, *ofp
= NULL
, *lfp
= NULL
;
234 Header
*header
= NULL
;
235 char *pathname
= NULL
;
236 char fullname
[PATHNAMELEN
];
237 int level
= 0, ret
= 0, retrying
= 0;
243 ifp
= fopen(archive
, R_OPENMODE
);
246 ifp
= fopen(name_dot_arc(archive
), R_OPENMODE
);
250 error("cannot open archive \"%s\"", archive
);
253 archive
= name_dot_arc(archive
);
256 arcsize
= filesize(archive
);
257 if (!arcsize
&& !quiet
)
259 error("cannot get size of archive file");
264 /* MU changed to accomodate the -I option */
267 if (!testing
&& !listing
&& logfile
)
269 lfp
= fopen(logfile
, W_OPENMODE
);
271 warning("unable to open logfile \"%s\"", logfile
);
275 if (!quiet
&& verbose
)
277 msg("filename size load/date exec/time type storage");
278 msg("-------- ---- ----------- --------- ---- -------");
282 * read compressed files from archive until end of file...
286 static Header dirheader
;
287 Byte comptype
, first
;
290 if ((arcfs
== 0) && ((first
= read_byte(ifp
)) != STARTBYTE
))
292 if ((first
== 'A') &&
293 (read_byte(ifp
) == 'r') &&
294 (read_byte(ifp
) == 'c') &&
295 (read_byte(ifp
) == 'h') &&
296 (read_byte(ifp
) == 'i') &&
297 (read_byte(ifp
) == 'v') &&
298 (read_byte(ifp
) == 'e') && (read_byte(ifp
) == '\0'))
300 debug("ArcFS format archive\n");
307 header
= read_header(ifp
);
308 comptype
= header
->comptype
& 0x7f;
310 debug("archive file length = %ld level = %d\n", arcsize
,
312 print_header(header
);
313 #endif /* DEBUGGING */
316 * If this is a compress _file_ then check archive size against
317 * compress-file length...
319 if (comptype
&& !(comptype
== CT_NOTCOMP2
&&
320 /* BB changed constants in next line to long */
321 (header
->load
& 0xffffff00l
) == 0xfffddc00l
))
323 if (header
->complen
> arcsize
)
325 debug("compressed len > archive file len");
330 arcsize
-= header
->complen
;
334 { /* end of archive ? */
339 * stamp directory now that all files have
340 * been written into it
342 if (!testing
&& !listing
&& !to_stdout
&& stamp
&& inlist(pathname
))
343 if (filestamp(&dirheader
, pathname
) < 0 && !quiet
)
344 error("error stamping %s", pathname
);
345 pathname
= uplevel();
350 * test for directory or file (file type = &DDC = archive)
352 if (comptype
== CT_NOTCOMP2
&&
353 /* BB changed constants in next line to long */
354 (header
->load
& 0xffffff00l
) == 0xfffddc00l
)
357 pathname
= downlevel(header
->name
);
358 dirheader
= *header
; /* make copy of header */
363 if (!testing
&& !listing
&& !to_stdout
&& inlist(pathname
))
364 switch (exist(pathname
))
367 if (makedir(pathname
) < 0 && !quiet
)
369 msg("error making %s... aborting", pathname
);
377 msg("%s exists as a file... aborting",
389 sprintf(fullname
, "%s%c%s", pathname
, PATHSEP
,
392 strcpy(fullname
, header
->name
);
394 if (!inlist(fullname
))
396 fseek(ifp
, (long) header
->complen
, 1);
401 * print the archive file details...
405 msg("%-30s", fullname
);
407 print_details(header
);
411 nbytes
+= header
->origlen
;
416 /* if listing, nothing more to do */
419 fseek(ifp
, (long) header
->complen
, 1);
426 * append the filetype to the name
428 if (apptype
&& !to_stdout
)
429 append_type(header
, fullname
);
432 * if actually unarchiving then check if the file already exists
434 if (!testing
&& !to_stdout
)
437 switch (exist(fullname
))
442 char c
= prompt_user(fullname
);
447 fseek(ifp
, (long) header
->complen
, 1);
452 char *newname
= get_newname();
454 sprintf(fullname
, "%s%c%s", pathname
,
457 strcpy(fullname
, newname
);
460 /* if (c == 'y') FALLTHROUGH */
465 msg("exists as a directory... skipping");
471 ofp
= fopen(fullname
, W_OPENMODE
);
475 msg("unable to create");
487 crcsize
= writesize
= header
->origlen
;
492 status
= unstore(header
, ifp
, ofp
);
495 status
= uncompress(header
, ifp
, ofp
, CRUNCH
);
498 status
= unpack(header
, ifp
, ofp
);
501 status
= uncompress(header
, ifp
, ofp
, SQUASH
);
504 status
= uncompress(header
, ifp
, ofp
, COMPRESS
);
507 error("unsupported archive type %d", comptype
);
510 fseek(ifp
, (long) header
->complen
, 1);
514 if (!testing
&& !to_stdout
&& ofp
)
521 * check if unarchiving failed.
522 * (RERR check is not in switch() because `break'
523 * needs to escape from while())
528 error("error reading archive");
536 msg("error writing file");
540 msg("failed CRC check");
542 /* BB changed format in next line to long hex */
543 /* debug(" calculated CRC=0x%x", crc); */
545 debug(" calculated CRC=0X%lX", crc
);
547 debug(" calculated CRC=0X%X", crc
);
548 #endif /* __MSDOS__ */
551 if (!testing
&& !to_stdout
&& stamp
)
553 if (filestamp(header
, fullname
) < 0 && !quiet
)
554 msg("\nerror stamping %s", fullname
);
557 * XXX: if the filename has had it's filetype appended to
558 * it, it may be longer than 10 characters long making this
559 * file useless. We could truncate the filename but there is
560 * no need to under UNIX... bit of a mismatch!
566 strcpy(logfile
, fullname
);
567 strcat(logfile
, ".inf");
568 lfp
= fopen(logfile
, W_OPENMODE
);
575 if ((header->load => 0xFFFFFB41) && (header->load <= 0xFFFFFB46))
577 header->load = 0xFFFF1900;
578 header->exec = 0xFFFF802B;
582 if (header->load == 0xFFFFFE41)
584 header->load = 0x00000000;
585 header->exec = 0xFFFFFFFF;
588 fprintf(lfp
, "%s %08lX %08lX\n",
589 riscos_path(fullname
), (long)header
->load
,
601 "SYS \"OS_File\", 1, \"%s\", &%08lX, &%08lX,, &%X\n",
602 riscos_path(fullname
), (long)header
->load
,
603 (long)header
->exec
, header
->attr
);
621 * find out why header wasn't found
624 switch (check_stream(ifp
))
628 msg("bad archive header");
629 if (retry
&& !listing
)
634 while (check_stream(ifp
) == FNOERR
)
635 if (read_byte(ifp
) == STARTBYTE
)
637 Byte byte
= read_byte(ifp
);
646 ungetc((int) byte
, ifp
);
664 msg("error reading archive");
675 msg("total of %ld bytes in %d files\n", (long)nbytes
, nfiles
);
677 if (ofp
&& !to_stdout
)
687 * the file being extracted already exists, so ask user what to do...
690 prompt_user(char *filename
)
697 fprintf(stderr
, "\n\"%s\" exists, overwrite ? (Yes/No/All/Rename): ",
700 if (read(0, buffer
, sizeof(buffer
) - 1)<1) {
704 if (isupper(*buffer
))
705 c
= tolower(*buffer
);
708 if (c
== 'y' || c
== 'n' || c
== 'a' || c
== 'r')
715 * user wants to rename file, so get the leaf name of the new file...
721 static char buffer
[80];
725 fprintf(stderr
, "enter new filename: ");
727 c
= read(0, buffer
, sizeof(buffer
) - 1);
728 buffer
[c
? c
- 1 : 0] = '\0';
731 for (c
= 0; buffer
[c
]; c
++)
732 if (buffer
[c
] == PATHSEP
)
734 msg("*** new file must extract into this directory ***");