1 /*
2 * $Header: /cvsroot/arc/arc/arcio.c,v 1.4 2005/10/12 15:22:18 highlandsun Exp $
3 */
4
5 /* ARC - Archive utility - ARCIO
6
7 Version 2.50, created on 04/22/87 at 13:25:20
8
9 (C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
10
11 By: Thom Henderson
12
13 Description:
14 This file contains the file I/O routines used to manipulate
15 an archive.
16
17 Language:
18 Computer Innovations Optimizing C86
19 */
20 #include <stdio.h>
21 #include "arc.h"
22 #if _MTS
23 #include <mts.h>
24 #endif
25 #include <string.h>
26
27 VOID arcdie();
28
29 int
readhdr(hdr,f)30 readhdr(hdr, f) /* read a header from an archive */
31 struct heads *hdr; /* storage for header */
32 FILE *f; /* archive to read header from */
33 {
34 #if !MSDOS
35 unsigned char dummy[28];
36 int i;
37 #endif
38 char name[FNLEN]; /* filename buffer */
39 int try = 0;/* retry counter */
40 static int first = 1; /* true only on first read */
41
42 if (!f) /* if archive didn't open */
43 return 0; /* then pretend it's the end */
44 hdrver = fgetc(f);
45 if (feof(f)) /* if no more data */
46 return 0; /* then signal end of archive */
47
48 if (hdrver != ARCMARK) { /* check archive validity */
49 if (arcwarn) {
50 printf("An entry in %s has a bad header.\n", arcname);
51 nerrs++;
52 }
53 printf("hdrver: %x\n", hdrver);
54 while (!feof(f)) {
55 try++;
56 if (fgetc(f) == ARCMARK) {
57 int dummy;
58 /* ungetc is guaranteed to succeed for a single char,
59 * no need to check result
60 */
61 dummy = ungetc(hdrver = fgetc(f), f);
62 if (!(hdrver & 0x80) && hdrver <= ARCVER)
63 break;
64 }
65 }
66
67 if (feof(f) && first)
68 arcdie("%s is not an archive", arcname);
69
70 if (changing && arcwarn)
71 arcdie("%s is corrupted -- changes disallowed", arcname);
72
73 if (arcwarn)
74 printf(" %d bytes skipped.\n", try);
75
76 if (feof(f))
77 return 0;
78 }
79 hdrver = fgetc(f); /* get header version */
80 if (hdrver & 0x80) /* sign bit? negative? */
81 arcdie("Invalid header in archive %s", arcname);
82 if (hdrver == 0)
83 return 0; /* note our end of archive marker */
84 if (hdrver > ARCVER) {
85 if (fread(name, sizeof(char), FNLEN, f) != FNLEN)
86 arcdie("%s was truncated", arcname);
87 #if _MTS
88 atoe(name, strlen(name));
89 #endif
90 printf("I don't know how to handle file %s in archive %s\n",
91 name, arcname);
92 printf("I think you need a newer version of ARC.\n");
93 exit(1);
94 }
95 /* amount to read depends on header type */
96
97 if (hdrver == 1) { /* old style is shorter */
98 if (fread(hdr, sizeof(struct heads) - sizeof(long int), 1, f) != 1)
99 arcdie("%s was truncated", arcname);
100 hdrver = 2; /* convert header to new format */
101 hdr->length = hdr->size; /* size is same when not
102 * packed */
103 } else
104 #if MSDOS
105 if (fread(hdr, sizeof(struct heads), 1, f) != 1)
106 arcdie("%s was truncated", arcname);
107 #else
108 if (fread(dummy, 27, 1, f) != 1)
109 arcdie("%s was truncated", arcname);
110
111 for (i = 0; i < FNLEN; hdr->name[i] = dummy[i], i++);
112 #if _MTS
113 (void) atoe(hdr->name, strlen(hdr->name));
114 #endif
115 for (i = 0, hdr->size=0; i<4; hdr->size<<=8, hdr->size += dummy[16-i], i++);
116 hdr->date = (short) ((dummy[18] << 8) + dummy[17]);
117 hdr->time = (short) ((dummy[20] << 8) + dummy[19]);
118 hdr->crc = (short) ((dummy[22] << 8) + dummy[21]);
119 for (i = 0, hdr->length=0; i<4; hdr->length<<=8, hdr->length += dummy[26-i], i++);
120 #endif
121 if (hdr->size < 0)
122 arcdie("Invalid header in archive %s", arcname);
123 if (hdr->date > olddate
124 || (hdr->date == olddate && hdr->time > oldtime)) {
125 olddate = hdr->date;
126 oldtime = hdr->time;
127 }
128 first = 0;
129 return 1; /* we read something */
130 }
131
132 VOID
put_int(number,f)133 put_int(number, f) /* write a 2 byte integer */
134 short number;
135 FILE *f;
136 {
137 fputc((char) (number & 255), f);
138 fputc((char) (number >> 8), f);
139 }
140
141 VOID
put_long(number,f)142 put_long(number, f) /* write a 4 byte integer */
143 long number;
144 FILE *f;
145 {
146 put_int((short) (number & 0xFFFF), f);
147 put_int((short) (number >> 16), f);
148 }
149
150 VOID
writehdr(hdr,f)151 writehdr(hdr, f) /* write a header to an archive */
152 struct heads *hdr; /* header to write */
153 FILE *f; /* archive to write to */
154 {
155 fputc(ARCMARK, f); /* write out the mark of ARC */
156 fputc(hdrver, f); /* write out the header version */
157 if (!hdrver) /* if that's the end */
158 return; /* then write no more */
159 #if MSDOS
160 if (fwrite(hdr, sizeof(struct heads), 1, f) != 1)
161 arcdie("%s out of space", arcname);
162 #else
163 /* byte/word ordering hassles... */
164 #if _MTS
165 etoa(hdr->name, strlen(hdr->name));
166 #endif
167 if (fwrite(hdr->name, 1, FNLEN, f) != FNLEN)
168 arcdie("%s out of space", arcname);
169 put_long(hdr->size, f);
170 put_int(hdr->date, f);
171 put_int(hdr->time, f);
172 put_int(hdr->crc, f);
173 put_long(hdr->length, f);
174 #endif
175
176 /* note the newest file for updating the archive timestamp */
177
178 if (hdr->date > arcdate
179 || (hdr->date == arcdate && hdr->time > arctime)) {
180 arcdate = hdr->date;
181 arctime = hdr->time;
182 }
183 }
184
185 extern char *pinbuf; /* general purpose input buffer */
186
187 /*
188 * NOTE: The filecopy() function is used to move large numbers of bytes from
189 * one file to another. This particular version has been modified to improve
190 * performance in Computer Innovations C86 version 2.3 in the small memory
191 * model. It may not work as expected with other compilers or libraries, or
192 * indeed with different versions of the CI-C86 compiler and library, or with
193 * the same version in a different memory model.
194 *
195 * The following is a functional equivalent to the filecopy() routine that
196 * should work properly on any system using any compiler, albeit at the cost
197 * of reduced performance:
198 *
199 * filecopy(f,t,size)
200 * FILE *f, *t; long size;
201 * {
202 * while(size--)
203 * putc_tst(fgetc(f),t);
204 * }
205 */
206 #if MSDOS
207 #include <fileio2.h>
208
filecopy(f,t,size)209 filecopy(f, t, size) /* bulk file copier */
210 FILE *f, *t; /* files from and to */
211 long size; /* bytes to copy */
212 {
213 unsigned int bufl; /* buffer length */
214 unsigned int coreleft(); /* space available reporter */
215 unsigned int cpy; /* bytes being copied */
216 long floc, tloc, fseek(); /* file pointers, setter */
217 struct regval reg; /* registers for DOS calls */
218
219 bufl = (MYBUF > size) ? (u_int) size : MYBUF;
220
221 floc = fseek(f, 0L, 1); /* reset I/O system */
222 tloc = fseek(t, 0L, 1);
223
224 segread(®.si); /* set segment registers for DOS */
225
226 while (size > 0) { /* while more to copy */
227 reg.ax = 0x3F00;/* read from handle */
228 reg.bx = filehand(f);
229 reg.cx = bufl < size ? bufl : size; /* amount to read */
230 reg.dx = pinbuf;
231 if (sysint21(®, ®) & 1)
232 arcdie("Read fail");
233
234 cpy = reg.ax; /* amount actually read */
235 reg.ax = 0x4000;/* write to handle */
236 reg.bx = filehand(t);
237 reg.cx = cpy;
238 reg.dx = pinbuf;
239 sysint21(®, ®);
240
241 if (reg.ax != cpy)
242 arcdie("Write fail (disk full?)");
243
244 size -= (long) cpy;
245 }
246 }
247 #else
248
249 VOID
filecopy(f,t,size)250 filecopy(f, t, size) /* bulk file copier */
251 FILE *f, *t; /* files from and to */
252 long size; /* bytes to copy */
253 {
254 unsigned int bufl; /* buffer length */
255 unsigned int cpy; /* bytes being copied */
256
257 bufl = (MYBUF > size) ? (u_int) size : MYBUF;
258
259 while (size > 0) {
260 cpy = fread(pinbuf, sizeof(char), bufl, f);
261 if (fwrite(pinbuf, sizeof(char), cpy, t) != cpy)
262 arcdie("Write fail (no space?)");
263 size -= cpy;
264 if (bufl > size)
265 bufl = size;
266 if (ferror(f))
267 arcdie("Unexpected EOF copying archive");
268 if (!cpy) break;
269 }
270 }
271 #endif
272