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);
110 SqshHeader sqsh_header
;
119 ifp
= fopen(archive
, "rb");
122 error("Can not open %s for reading\n", archive
);
128 ofname
= calloc(1, strlen(archive
) + sizeof(",xxx"));
129 /* Output filename is the same as the input filename with
130 * the correct filetype appended */
131 strcpy(ofname
, archive
);
132 /* Strip RISCOS filetype from output filename */
133 p
= ofname
+ (strlen(ofname
) - 4);
134 if (*p
== ',' || *p
== '.')
140 r
= read_sqsh_header(ifp
, &sqsh_header
);
143 error("Invalid squash file");
147 memset(&header
, 0, sizeof(header
));
148 datastart
= ftell(ifp
);
149 fseek(ifp
, 0, SEEK_END
);
152 /* The uncompress code uses Spark entry header structures.
153 * Use the squash header and other info to set up the Spark header
154 * with needed info. */
155 header
.complen
= (Word
)(offset
- datastart
);
156 sqsh_header_to_header(&sqsh_header
, &header
);
157 fseek(ifp
, datastart
, SEEK_SET
);
160 writesize
= header
.origlen
;
164 /* Append the correct filetype to the output filename */
165 append_type(&header
, ofname
);
168 if (!force
&& !to_stdout
)
170 ofp
= fopen(ofname
, "rb");
177 c
= prompt_user(ofname
);
183 newname
= get_newname();
185 ofname
= strdup(newname
);
201 ofp
= fopen(ofname
, "wb");
204 error("Can not open %s for writing\n", ofname
);
209 r
= uncompress(&header
, ifp
, ofp
, UNIX_COMPRESS
);
217 if (stamp
&& !to_stdout
)
219 filestamp(&header
, ofname
);
224 error("Failed to decompress file");
235 FILE *ifp
, *ofp
= NULL
, *lfp
= NULL
;
236 Header
*header
= NULL
;
237 char *pathname
= NULL
;
238 char fullname
[PATHNAMELEN
];
239 int level
= 0, ret
= 0, retrying
= 0;
245 ifp
= fopen(archive
, R_OPENMODE
);
248 ifp
= fopen(name_dot_arc(archive
), R_OPENMODE
);
252 error("cannot open archive \"%s\"", archive
);
255 archive
= name_dot_arc(archive
);
258 arcsize
= filesize(archive
);
259 if (!arcsize
&& !quiet
)
261 error("cannot get size of archive file");
266 /* MU changed to accomodate the -I option */
269 if (!testing
&& !listing
&& logfile
)
271 lfp
= fopen(logfile
, W_OPENMODE
);
273 warning("unable to open logfile \"%s\"", logfile
);
277 if (!quiet
&& verbose
)
279 msg("filename size load/date exec/time type storage");
280 msg("-------- ---- ----------- --------- ---- -------");
284 * read compressed files from archive until end of file...
288 static Header dirheader
;
289 Byte comptype
, first
;
292 if ((arcfs
== 0) && ((first
= read_byte(ifp
)) != STARTBYTE
))
294 if ((first
== 'A') &&
295 (read_byte(ifp
) == 'r') &&
296 (read_byte(ifp
) == 'c') &&
297 (read_byte(ifp
) == 'h') &&
298 (read_byte(ifp
) == 'i') &&
299 (read_byte(ifp
) == 'v') &&
300 (read_byte(ifp
) == 'e') && (read_byte(ifp
) == '\0'))
302 debug("ArcFS format archive\n");
309 header
= read_header(ifp
);
310 comptype
= header
->comptype
& 0x7f;
312 debug("archive file length = %ld level = %d\n", arcsize
,
314 print_header(header
);
315 #endif /* DEBUGGING */
318 * If this is a compress _file_ then check archive size against
319 * compress-file length...
321 if (comptype
&& !(comptype
== CT_NOTCOMP2
&&
322 /* BB changed constants in next line to long */
323 (header
->load
& 0xffffff00l
) == 0xfffddc00l
))
325 if (header
->complen
> arcsize
)
327 debug("compressed len > archive file len");
332 arcsize
-= header
->complen
;
336 { /* end of archive ? */
341 * stamp directory now that all files have
342 * been written into it
344 if (!testing
&& !listing
&& !to_stdout
&& stamp
&& inlist(pathname
))
345 if (filestamp(&dirheader
, pathname
) < 0 && !quiet
)
346 error("error stamping %s", pathname
);
347 pathname
= uplevel();
352 * test for directory or file (file type = &DDC = archive)
354 if (comptype
== CT_NOTCOMP2
&&
355 /* BB changed constants in next line to long */
356 (header
->load
& 0xffffff00l
) == 0xfffddc00l
)
359 pathname
= downlevel(header
->name
);
360 dirheader
= *header
; /* make copy of header */
365 if (!testing
&& !listing
&& !to_stdout
&& inlist(pathname
))
366 switch (exist(pathname
))
369 if (makedir(pathname
) < 0 && !quiet
)
371 msg("error making %s... aborting", pathname
);
379 msg("%s exists as a file... aborting",
391 sprintf(fullname
, "%s%c%s", pathname
, PATHSEP
,
394 strcpy(fullname
, header
->name
);
396 if (!inlist(fullname
))
398 fseek(ifp
, (long) header
->complen
, 1);
403 * print the archive file details...
407 msg("%-30s", fullname
);
409 print_details(header
);
413 nbytes
+= header
->origlen
;
418 /* if listing, nothing more to do */
421 fseek(ifp
, (long) header
->complen
, 1);
428 * append the filetype to the name
430 if (apptype
&& !to_stdout
)
431 append_type(header
, fullname
);
434 * if actually unarchiving then check if the file already exists
436 if (!testing
&& !to_stdout
)
439 switch (exist(fullname
))
444 char c
= prompt_user(fullname
);
449 fseek(ifp
, (long) header
->complen
, 1);
454 char *newname
= get_newname();
456 sprintf(fullname
, "%s%c%s", pathname
,
459 strcpy(fullname
, newname
);
462 /* if (c == 'y') FALLTHROUGH */
467 msg("exists as a directory... skipping");
473 ofp
= fopen(fullname
, W_OPENMODE
);
477 msg("unable to create");
489 crcsize
= writesize
= header
->origlen
;
494 status
= unstore(header
, ifp
, ofp
);
497 status
= uncompress(header
, ifp
, ofp
, CRUNCH
);
500 status
= unpack(header
, ifp
, ofp
);
503 status
= uncompress(header
, ifp
, ofp
, SQUASH
);
506 status
= uncompress(header
, ifp
, ofp
, COMPRESS
);
509 error("unsupported archive type %d", comptype
);
512 fseek(ifp
, (long) header
->complen
, 1);
516 if (!testing
&& !to_stdout
&& ofp
)
523 * check if unarchiving failed.
524 * (RERR check is not in switch() because `break'
525 * needs to escape from while())
530 error("error reading archive");
538 msg("error writing file");
542 msg("failed CRC check");
544 /* BB changed format in next line to long hex */
545 /* debug(" calculated CRC=0x%x", crc); */
547 debug(" calculated CRC=0X%lX", crc
);
549 debug(" calculated CRC=0X%X", crc
);
550 #endif /* __MSDOS__ */
553 if (!testing
&& !to_stdout
&& stamp
)
555 if (filestamp(header
, fullname
) < 0 && !quiet
)
556 msg("\nerror stamping %s", fullname
);
559 * XXX: if the filename has had it's filetype appended to
560 * it, it may be longer than 10 characters long making this
561 * file useless. We could truncate the filename but there is
562 * no need to under UNIX... bit of a mismatch!
568 strcpy(logfile
, fullname
);
569 strcat(logfile
, ".inf");
570 lfp
= fopen(logfile
, W_OPENMODE
);
577 if ((header->load => 0xFFFFFB41) && (header->load <= 0xFFFFFB46))
579 header->load = 0xFFFF1900;
580 header->exec = 0xFFFF802B;
584 if (header->load == 0xFFFFFE41)
586 header->load = 0x00000000;
587 header->exec = 0xFFFFFFFF;
590 fprintf(lfp
, "%s %08lX %08lX\n",
591 riscos_path(fullname
), (long)header
->load
,
603 "SYS \"OS_File\", 1, \"%s\", &%08lX, &%08lX,, &%X\n",
604 riscos_path(fullname
), (long)header
->load
,
605 (long)header
->exec
, header
->attr
);
623 * find out why header wasn't found
626 switch (check_stream(ifp
))
630 msg("bad archive header");
631 if (retry
&& !listing
)
636 while (check_stream(ifp
) == FNOERR
)
637 if (read_byte(ifp
) == STARTBYTE
)
639 Byte byte
= read_byte(ifp
);
648 ungetc((int) byte
, ifp
);
666 msg("error reading archive");
677 msg("total of %ld bytes in %d files\n", (long)nbytes
, nfiles
);
679 if (ofp
&& !to_stdout
)
689 * the file being extracted already exists, so ask user what to do...
692 prompt_user(char *filename
)
699 fprintf(stderr
, "\n\"%s\" exists, overwrite ? (Yes/No/All/Rename): ",
702 if (read(0, buffer
, sizeof(buffer
) - 1)<1) {
706 if (isupper(*buffer
))
707 c
= tolower(*buffer
);
710 if (c
== 'y' || c
== 'n' || c
== 'a' || c
== 'r')
717 * user wants to rename file, so get the leaf name of the new file...
723 static char buffer
[80];
727 fprintf(stderr
, "enter new filename: ");
729 c
= read(0, buffer
, sizeof(buffer
) - 1);
730 buffer
[c
? c
- 1 : 0] = '\0';
733 for (c
= 0; buffer
[c
]; c
++)
734 if (buffer
[c
] == PATHSEP
)
736 msg("*** new file must extract into this directory ***");