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(&reg.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(&reg, &reg) & 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(&reg, &reg);
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