xref: /plan9/sys/src/ape/cmd/pax/extract.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier /* $Source: /u/mark/src/pax/RCS/extract.c,v $
2*9a747e4fSDavid du Colombier  *
3*9a747e4fSDavid du Colombier  * $Revision: 1.3 $
4*9a747e4fSDavid du Colombier  *
5*9a747e4fSDavid du Colombier  * extract.c - Extract files from a tar archive.
6*9a747e4fSDavid du Colombier  *
7*9a747e4fSDavid du Colombier  * DESCRIPTION
8*9a747e4fSDavid du Colombier  *
9*9a747e4fSDavid du Colombier  * AUTHOR
10*9a747e4fSDavid du Colombier  *
11*9a747e4fSDavid du Colombier  *	Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
12*9a747e4fSDavid du Colombier  *
13*9a747e4fSDavid du Colombier  * Sponsored by The USENIX Association for public distribution.
14*9a747e4fSDavid du Colombier  *
15*9a747e4fSDavid du Colombier  * Copyright (c) 1989 Mark H. Colburn.
16*9a747e4fSDavid du Colombier  * All rights reserved.
17*9a747e4fSDavid du Colombier  *
18*9a747e4fSDavid du Colombier  * Redistribution and use in source and binary forms are permitted
19*9a747e4fSDavid du Colombier  * provided that the above copyright notice is duplicated in all such
20*9a747e4fSDavid du Colombier  * forms and that any documentation, advertising materials, and other
21*9a747e4fSDavid du Colombier  * materials related to such distribution and use acknowledge that the
22*9a747e4fSDavid du Colombier  * software was developed * by Mark H. Colburn and sponsored by The
23*9a747e4fSDavid du Colombier  * USENIX Association.
24*9a747e4fSDavid du Colombier  *
25*9a747e4fSDavid du Colombier  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
26*9a747e4fSDavid du Colombier  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
27*9a747e4fSDavid du Colombier  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28*9a747e4fSDavid du Colombier  *
29*9a747e4fSDavid du Colombier  * $Log:	extract.c,v $
30*9a747e4fSDavid du Colombier  * Revision 1.3  89/02/12  10:29:43  mark
31*9a747e4fSDavid du Colombier  * Fixed misspelling of Replstr
32*9a747e4fSDavid du Colombier  *
33*9a747e4fSDavid du Colombier  * Revision 1.2  89/02/12  10:04:24  mark
34*9a747e4fSDavid du Colombier  * 1.2 release fixes
35*9a747e4fSDavid du Colombier  *
36*9a747e4fSDavid du Colombier  * Revision 1.1  88/12/23  18:02:07  mark
37*9a747e4fSDavid du Colombier  * Initial revision
38*9a747e4fSDavid du Colombier  *
39*9a747e4fSDavid du Colombier  */
40*9a747e4fSDavid du Colombier 
41*9a747e4fSDavid du Colombier #ifndef lint
42*9a747e4fSDavid du Colombier static char *ident = "$Id: extract.c,v 1.3 89/02/12 10:29:43 mark Exp Locker: mark $";
43*9a747e4fSDavid du Colombier static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
44*9a747e4fSDavid du Colombier #endif /* ! lint */
45*9a747e4fSDavid du Colombier 
46*9a747e4fSDavid du Colombier 
47*9a747e4fSDavid du Colombier /* Headers */
48*9a747e4fSDavid du Colombier 
49*9a747e4fSDavid du Colombier #include "pax.h"
50*9a747e4fSDavid du Colombier 
51*9a747e4fSDavid du Colombier 
52*9a747e4fSDavid du Colombier /* Defines */
53*9a747e4fSDavid du Colombier 
54*9a747e4fSDavid du Colombier /*
55*9a747e4fSDavid du Colombier  * Swap bytes.
56*9a747e4fSDavid du Colombier  */
57*9a747e4fSDavid du Colombier #define	SWAB(n)	((((ushort)(n) >> 8) & 0xff) | (((ushort)(n) << 8) & 0xff00))
58*9a747e4fSDavid du Colombier 
59*9a747e4fSDavid du Colombier 
60*9a747e4fSDavid du Colombier /* Function Prototypes */
61*9a747e4fSDavid du Colombier 
62*9a747e4fSDavid du Colombier #ifdef __STDC__
63*9a747e4fSDavid du Colombier 
64*9a747e4fSDavid du Colombier static int inbinary(char *, char *, Stat *);
65*9a747e4fSDavid du Colombier static int inascii(char *, char *, Stat *);
66*9a747e4fSDavid du Colombier static int inswab(char *, char *, Stat *);
67*9a747e4fSDavid du Colombier static int readtar(char *, Stat *);
68*9a747e4fSDavid du Colombier static int readcpio(char *, Stat *);
69*9a747e4fSDavid du Colombier 
70*9a747e4fSDavid du Colombier #else /* !__STDC__ */
71*9a747e4fSDavid du Colombier 
72*9a747e4fSDavid du Colombier static int inbinary();
73*9a747e4fSDavid du Colombier static int inascii();
74*9a747e4fSDavid du Colombier static int inswab();
75*9a747e4fSDavid du Colombier static int readtar();
76*9a747e4fSDavid du Colombier static int readcpio();
77*9a747e4fSDavid du Colombier 
78*9a747e4fSDavid du Colombier #endif /* __STDC__ */
79*9a747e4fSDavid du Colombier 
80*9a747e4fSDavid du Colombier 
81*9a747e4fSDavid du Colombier /* read_archive - read in an archive
82*9a747e4fSDavid du Colombier  *
83*9a747e4fSDavid du Colombier  * DESCRIPTION
84*9a747e4fSDavid du Colombier  *
85*9a747e4fSDavid du Colombier  *	Read_archive is the central entry point for reading archives.
86*9a747e4fSDavid du Colombier  *	Read_archive determines the proper archive functions to call
87*9a747e4fSDavid du Colombier  *	based upon the archive type being processed.
88*9a747e4fSDavid du Colombier  *
89*9a747e4fSDavid du Colombier  * RETURNS
90*9a747e4fSDavid du Colombier  *
91*9a747e4fSDavid du Colombier  */
92*9a747e4fSDavid du Colombier 
93*9a747e4fSDavid du Colombier #ifdef __STDC__
94*9a747e4fSDavid du Colombier 
read_archive(void)95*9a747e4fSDavid du Colombier int read_archive(void)
96*9a747e4fSDavid du Colombier 
97*9a747e4fSDavid du Colombier #else
98*9a747e4fSDavid du Colombier 
99*9a747e4fSDavid du Colombier int read_archive()
100*9a747e4fSDavid du Colombier 
101*9a747e4fSDavid du Colombier #endif
102*9a747e4fSDavid du Colombier {
103*9a747e4fSDavid du Colombier     Stat            sb;
104*9a747e4fSDavid du Colombier     char            name[PATH_MAX + 1];
105*9a747e4fSDavid du Colombier     int             match;
106*9a747e4fSDavid du Colombier     int		    pad;
107*9a747e4fSDavid du Colombier 
108*9a747e4fSDavid du Colombier     name_gather();		/* get names from command line */
109*9a747e4fSDavid du Colombier     name[0] = '\0';
110*9a747e4fSDavid du Colombier     while (get_header(name, &sb) == 0) {
111*9a747e4fSDavid du Colombier 	match = name_match(name) ^ f_reverse_match;
112*9a747e4fSDavid du Colombier 	if (f_list) {		/* only wanted a table of contents */
113*9a747e4fSDavid du Colombier 	    if (match) {
114*9a747e4fSDavid du Colombier 		print_entry(name, &sb);
115*9a747e4fSDavid du Colombier 	    }
116*9a747e4fSDavid du Colombier 	    if (((ar_format == TAR)
117*9a747e4fSDavid du Colombier 		? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE))
118*9a747e4fSDavid du Colombier 		: buf_skip((OFFSET) sb.sb_size)) < 0) {
119*9a747e4fSDavid du Colombier 		warn(name, "File data is corrupt");
120*9a747e4fSDavid du Colombier 	    }
121*9a747e4fSDavid du Colombier 	} else if (match) {
122*9a747e4fSDavid du Colombier 	    if (rplhead != (Replstr *)NULL) {
123*9a747e4fSDavid du Colombier 		rpl_name(name);
124*9a747e4fSDavid du Colombier 		if (strlen(name) == 0) {
125*9a747e4fSDavid du Colombier 		    continue;
126*9a747e4fSDavid du Colombier 		}
127*9a747e4fSDavid du Colombier 	    }
128*9a747e4fSDavid du Colombier 	    if (get_disposition("extract", name) ||
129*9a747e4fSDavid du Colombier                 get_newname(name, sizeof(name))) {
130*9a747e4fSDavid du Colombier 		/* skip file... */
131*9a747e4fSDavid du Colombier 		if (((ar_format == TAR)
132*9a747e4fSDavid du Colombier 		    ? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE))
133*9a747e4fSDavid du Colombier 		    : buf_skip((OFFSET) sb.sb_size)) < 0) {
134*9a747e4fSDavid du Colombier 		    warn(name, "File data is corrupt");
135*9a747e4fSDavid du Colombier 		}
136*9a747e4fSDavid du Colombier 		continue;
137*9a747e4fSDavid du Colombier 	    }
138*9a747e4fSDavid du Colombier 	    if (inentry(name, &sb) < 0) {
139*9a747e4fSDavid du Colombier 		warn(name, "File data is corrupt");
140*9a747e4fSDavid du Colombier 	    }
141*9a747e4fSDavid du Colombier 	    if (f_verbose) {
142*9a747e4fSDavid du Colombier 		print_entry(name, &sb);
143*9a747e4fSDavid du Colombier 	    }
144*9a747e4fSDavid du Colombier 	    if (ar_format == TAR && sb.sb_nlink > 1) {
145*9a747e4fSDavid du Colombier 		/*
146*9a747e4fSDavid du Colombier 		 * This kludge makes sure that the link table is cleared
147*9a747e4fSDavid du Colombier 		 * before attempting to process any other links.
148*9a747e4fSDavid du Colombier 		 */
149*9a747e4fSDavid du Colombier 		if (sb.sb_nlink > 1) {
150*9a747e4fSDavid du Colombier 		    linkfrom(name, &sb);
151*9a747e4fSDavid du Colombier 		}
152*9a747e4fSDavid du Colombier 	    }
153*9a747e4fSDavid du Colombier 	    if (ar_format == TAR && (pad = sb.sb_size % BLOCKSIZE) != 0) {
154*9a747e4fSDavid du Colombier 		pad = BLOCKSIZE - pad;
155*9a747e4fSDavid du Colombier 		buf_skip((OFFSET) pad);
156*9a747e4fSDavid du Colombier 	    }
157*9a747e4fSDavid du Colombier 	} else {
158*9a747e4fSDavid du Colombier 	    if (((ar_format == TAR)
159*9a747e4fSDavid du Colombier 		? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE))
160*9a747e4fSDavid du Colombier 		: buf_skip((OFFSET) sb.sb_size)) < 0) {
161*9a747e4fSDavid du Colombier 		warn(name, "File data is corrupt");
162*9a747e4fSDavid du Colombier 	    }
163*9a747e4fSDavid du Colombier 	}
164*9a747e4fSDavid du Colombier     }
165*9a747e4fSDavid du Colombier 
166*9a747e4fSDavid du Colombier     close_archive();
167*9a747e4fSDavid du Colombier }
168*9a747e4fSDavid du Colombier 
169*9a747e4fSDavid du Colombier 
170*9a747e4fSDavid du Colombier 
171*9a747e4fSDavid du Colombier /* get_header - figures which type of header needs to be read.
172*9a747e4fSDavid du Colombier  *
173*9a747e4fSDavid du Colombier  * DESCRIPTION
174*9a747e4fSDavid du Colombier  *
175*9a747e4fSDavid du Colombier  *	This is merely a single entry point for the two types of archive
176*9a747e4fSDavid du Colombier  *	headers which are supported.  The correct header is selected
177*9a747e4fSDavid du Colombier  *	depending on the archive type.
178*9a747e4fSDavid du Colombier  *
179*9a747e4fSDavid du Colombier  * PARAMETERS
180*9a747e4fSDavid du Colombier  *
181*9a747e4fSDavid du Colombier  *	char	*name	- name of the file (passed to header routine)
182*9a747e4fSDavid du Colombier  *	Stat	*asb	- Stat block for the file (passed to header routine)
183*9a747e4fSDavid du Colombier  *
184*9a747e4fSDavid du Colombier  * RETURNS
185*9a747e4fSDavid du Colombier  *
186*9a747e4fSDavid du Colombier  *	Returns the value which was returned by the proper header
187*9a747e4fSDavid du Colombier  *	function.
188*9a747e4fSDavid du Colombier  */
189*9a747e4fSDavid du Colombier 
190*9a747e4fSDavid du Colombier #ifdef __STDC__
191*9a747e4fSDavid du Colombier 
get_header(char * name,Stat * asb)192*9a747e4fSDavid du Colombier int get_header(char *name, Stat *asb)
193*9a747e4fSDavid du Colombier 
194*9a747e4fSDavid du Colombier #else
195*9a747e4fSDavid du Colombier 
196*9a747e4fSDavid du Colombier int get_header(name, asb)
197*9a747e4fSDavid du Colombier char *name;
198*9a747e4fSDavid du Colombier Stat *asb;
199*9a747e4fSDavid du Colombier 
200*9a747e4fSDavid du Colombier #endif
201*9a747e4fSDavid du Colombier {
202*9a747e4fSDavid du Colombier     if (ar_format == TAR) {
203*9a747e4fSDavid du Colombier 	return(readtar(name, asb));
204*9a747e4fSDavid du Colombier     } else {
205*9a747e4fSDavid du Colombier 	return(readcpio(name, asb));
206*9a747e4fSDavid du Colombier     }
207*9a747e4fSDavid du Colombier }
208*9a747e4fSDavid du Colombier 
209*9a747e4fSDavid du Colombier 
210*9a747e4fSDavid du Colombier /* readtar - read a tar header
211*9a747e4fSDavid du Colombier  *
212*9a747e4fSDavid du Colombier  * DESCRIPTION
213*9a747e4fSDavid du Colombier  *
214*9a747e4fSDavid du Colombier  *	Tar_head read a tar format header from the archive.  The name
215*9a747e4fSDavid du Colombier  *	and asb parameters are modified as appropriate for the file listed
216*9a747e4fSDavid du Colombier  *	in the header.   Name is assumed to be a pointer to an array of
217*9a747e4fSDavid du Colombier  *	at least PATH_MAX bytes.
218*9a747e4fSDavid du Colombier  *
219*9a747e4fSDavid du Colombier  * PARAMETERS
220*9a747e4fSDavid du Colombier  *
221*9a747e4fSDavid du Colombier  *	char	*name 	- name of the file for which the header is
222*9a747e4fSDavid du Colombier  *			  for.  This is modified and passed back to
223*9a747e4fSDavid du Colombier  *			  the caller.
224*9a747e4fSDavid du Colombier  *	Stat	*asb	- Stat block for the file for which the header
225*9a747e4fSDavid du Colombier  *			  is for.  The fields of the stat structure are
226*9a747e4fSDavid du Colombier  *			  extracted from the archive header.  This is
227*9a747e4fSDavid du Colombier  *			  also passed back to the caller.
228*9a747e4fSDavid du Colombier  *
229*9a747e4fSDavid du Colombier  * RETURNS
230*9a747e4fSDavid du Colombier  *
231*9a747e4fSDavid du Colombier  *	Returns 0 if a valid header was found, or -1 if EOF is
232*9a747e4fSDavid du Colombier  *	encountered.
233*9a747e4fSDavid du Colombier  */
234*9a747e4fSDavid du Colombier 
235*9a747e4fSDavid du Colombier #ifdef __STDC__
236*9a747e4fSDavid du Colombier 
readtar(char * name,Stat * asb)237*9a747e4fSDavid du Colombier static int readtar(char *name, Stat *asb)
238*9a747e4fSDavid du Colombier 
239*9a747e4fSDavid du Colombier #else
240*9a747e4fSDavid du Colombier 
241*9a747e4fSDavid du Colombier static int readtar(name, asb)
242*9a747e4fSDavid du Colombier char	*name;
243*9a747e4fSDavid du Colombier Stat    *asb;
244*9a747e4fSDavid du Colombier 
245*9a747e4fSDavid du Colombier #endif
246*9a747e4fSDavid du Colombier {
247*9a747e4fSDavid du Colombier     int             status = 3;	/* Initial status at start of archive */
248*9a747e4fSDavid du Colombier     static int      prev_status;
249*9a747e4fSDavid du Colombier 
250*9a747e4fSDavid du Colombier     for (;;) {
251*9a747e4fSDavid du Colombier 	prev_status = status;
252*9a747e4fSDavid du Colombier 	status = read_header(name, asb);
253*9a747e4fSDavid du Colombier 	switch (status) {
254*9a747e4fSDavid du Colombier 	case 1:		/* Valid header */
255*9a747e4fSDavid du Colombier 		return(0);
256*9a747e4fSDavid du Colombier 	case 0:		/* Invalid header */
257*9a747e4fSDavid du Colombier 	    switch (prev_status) {
258*9a747e4fSDavid du Colombier 	    case 3:		/* Error on first record */
259*9a747e4fSDavid du Colombier 		warn(ar_file, "This doesn't look like a tar archive");
260*9a747e4fSDavid du Colombier 		/* FALLTHRU */
261*9a747e4fSDavid du Colombier 	    case 2:		/* Error after record of zeroes */
262*9a747e4fSDavid du Colombier 	    case 1:		/* Error after header rec */
263*9a747e4fSDavid du Colombier 		warn(ar_file, "Skipping to next file...");
264*9a747e4fSDavid du Colombier 		/* FALLTHRU */
265*9a747e4fSDavid du Colombier 	    default:
266*9a747e4fSDavid du Colombier 	    case 0:		/* Error after error */
267*9a747e4fSDavid du Colombier 		break;
268*9a747e4fSDavid du Colombier 	    }
269*9a747e4fSDavid du Colombier 	    break;
270*9a747e4fSDavid du Colombier 
271*9a747e4fSDavid du Colombier 	case 2:			/* Record of zeroes */
272*9a747e4fSDavid du Colombier 	case EOF:		/* End of archive */
273*9a747e4fSDavid du Colombier 	default:
274*9a747e4fSDavid du Colombier 	    return(-1);
275*9a747e4fSDavid du Colombier 	}
276*9a747e4fSDavid du Colombier     }
277*9a747e4fSDavid du Colombier }
278*9a747e4fSDavid du Colombier 
279*9a747e4fSDavid du Colombier 
280*9a747e4fSDavid du Colombier /* readcpio - read a CPIO header
281*9a747e4fSDavid du Colombier  *
282*9a747e4fSDavid du Colombier  * DESCRIPTION
283*9a747e4fSDavid du Colombier  *
284*9a747e4fSDavid du Colombier  *	Read in a cpio header.  Understands how to determine and read ASCII,
285*9a747e4fSDavid du Colombier  *	binary and byte-swapped binary headers.  Quietly translates
286*9a747e4fSDavid du Colombier  *	old-fashioned binary cpio headers (and arranges to skip the possible
287*9a747e4fSDavid du Colombier  *	alignment byte). Returns zero if successful, -1 upon archive trailer.
288*9a747e4fSDavid du Colombier  *
289*9a747e4fSDavid du Colombier  * PARAMETERS
290*9a747e4fSDavid du Colombier  *
291*9a747e4fSDavid du Colombier  *	char	*name 	- name of the file for which the header is
292*9a747e4fSDavid du Colombier  *			  for.  This is modified and passed back to
293*9a747e4fSDavid du Colombier  *			  the caller.
294*9a747e4fSDavid du Colombier  *	Stat	*asb	- Stat block for the file for which the header
295*9a747e4fSDavid du Colombier  *			  is for.  The fields of the stat structure are
296*9a747e4fSDavid du Colombier  *			  extracted from the archive header.  This is
297*9a747e4fSDavid du Colombier  *			  also passed back to the caller.
298*9a747e4fSDavid du Colombier  *
299*9a747e4fSDavid du Colombier  * RETURNS
300*9a747e4fSDavid du Colombier  *
301*9a747e4fSDavid du Colombier  *	Returns 0 if a valid header was found, or -1 if EOF is
302*9a747e4fSDavid du Colombier  *	encountered.
303*9a747e4fSDavid du Colombier  */
304*9a747e4fSDavid du Colombier 
305*9a747e4fSDavid du Colombier #ifdef __STDC__
306*9a747e4fSDavid du Colombier 
readcpio(char * name,Stat * asb)307*9a747e4fSDavid du Colombier static int readcpio(char *name, Stat *asb)
308*9a747e4fSDavid du Colombier 
309*9a747e4fSDavid du Colombier #else
310*9a747e4fSDavid du Colombier 
311*9a747e4fSDavid du Colombier static int readcpio(name, asb)
312*9a747e4fSDavid du Colombier char           *name;
313*9a747e4fSDavid du Colombier Stat           *asb;
314*9a747e4fSDavid du Colombier 
315*9a747e4fSDavid du Colombier #endif
316*9a747e4fSDavid du Colombier {
317*9a747e4fSDavid du Colombier     OFFSET          skipped;
318*9a747e4fSDavid du Colombier     char            magic[M_STRLEN];
319*9a747e4fSDavid du Colombier     static int      align;
320*9a747e4fSDavid du Colombier 
321*9a747e4fSDavid du Colombier     if (align > 0) {
322*9a747e4fSDavid du Colombier 	buf_skip((OFFSET) align);
323*9a747e4fSDavid du Colombier     }
324*9a747e4fSDavid du Colombier     align = 0;
325*9a747e4fSDavid du Colombier     for (;;) {
326*9a747e4fSDavid du Colombier 	buf_read(magic, M_STRLEN);
327*9a747e4fSDavid du Colombier 	skipped = 0;
328*9a747e4fSDavid du Colombier 	while ((align = inascii(magic, name, asb)) < 0
329*9a747e4fSDavid du Colombier 	       && (align = inbinary(magic, name, asb)) < 0
330*9a747e4fSDavid du Colombier 	       && (align = inswab(magic, name, asb)) < 0) {
331*9a747e4fSDavid du Colombier 	    if (++skipped == 1) {
332*9a747e4fSDavid du Colombier 		if (total - sizeof(magic) == 0) {
333*9a747e4fSDavid du Colombier 		    fatal("Unrecognizable archive");
334*9a747e4fSDavid du Colombier 		}
335*9a747e4fSDavid du Colombier 		warnarch("Bad magic number", (OFFSET) sizeof(magic));
336*9a747e4fSDavid du Colombier 		if (name[0]) {
337*9a747e4fSDavid du Colombier 		    warn(name, "May be corrupt");
338*9a747e4fSDavid du Colombier 		}
339*9a747e4fSDavid du Colombier 	    }
340*9a747e4fSDavid du Colombier 	    memcpy(magic, magic + 1, sizeof(magic) - 1);
341*9a747e4fSDavid du Colombier 	    buf_read(magic + sizeof(magic) - 1, 1);
342*9a747e4fSDavid du Colombier 	}
343*9a747e4fSDavid du Colombier 	if (skipped) {
344*9a747e4fSDavid du Colombier 	    warnarch("Apparently resynchronized", (OFFSET) sizeof(magic));
345*9a747e4fSDavid du Colombier 	    warn(name, "Continuing");
346*9a747e4fSDavid du Colombier 	}
347*9a747e4fSDavid du Colombier 	if (strcmp(name, TRAILER) == 0) {
348*9a747e4fSDavid du Colombier 	    return (-1);
349*9a747e4fSDavid du Colombier 	}
350*9a747e4fSDavid du Colombier 	if (nameopt(name) >= 0) {
351*9a747e4fSDavid du Colombier 	    break;
352*9a747e4fSDavid du Colombier 	}
353*9a747e4fSDavid du Colombier 	buf_skip((OFFSET) asb->sb_size + align);
354*9a747e4fSDavid du Colombier     }
355*9a747e4fSDavid du Colombier #ifdef	S_IFLNK
356*9a747e4fSDavid du Colombier     if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
357*9a747e4fSDavid du Colombier 	if (buf_read(asb->sb_link, (uint) asb->sb_size) < 0) {
358*9a747e4fSDavid du Colombier 	    warn(name, "Corrupt symbolic link");
359*9a747e4fSDavid du Colombier 	    return (readcpio(name, asb));
360*9a747e4fSDavid du Colombier 	}
361*9a747e4fSDavid du Colombier 	asb->sb_link[asb->sb_size] = '\0';
362*9a747e4fSDavid du Colombier 	asb->sb_size = 0;
363*9a747e4fSDavid du Colombier     }
364*9a747e4fSDavid du Colombier #endif				/* S_IFLNK */
365*9a747e4fSDavid du Colombier 
366*9a747e4fSDavid du Colombier     /* destroy absolute pathnames for security reasons */
367*9a747e4fSDavid du Colombier     if (name[0] == '/') {
368*9a747e4fSDavid du Colombier 	if (name[1]) {
369*9a747e4fSDavid du Colombier 	    while (name[0] = name[1]) {
370*9a747e4fSDavid du Colombier 		++name;
371*9a747e4fSDavid du Colombier 	    }
372*9a747e4fSDavid du Colombier 	} else {
373*9a747e4fSDavid du Colombier 	    name[0] = '.';
374*9a747e4fSDavid du Colombier 	}
375*9a747e4fSDavid du Colombier     }
376*9a747e4fSDavid du Colombier     asb->sb_atime = asb->sb_ctime = asb->sb_mtime;
377*9a747e4fSDavid du Colombier     if (asb->sb_nlink > 1) {
378*9a747e4fSDavid du Colombier 	linkto(name, asb);
379*9a747e4fSDavid du Colombier     }
380*9a747e4fSDavid du Colombier     return (0);
381*9a747e4fSDavid du Colombier }
382*9a747e4fSDavid du Colombier 
383*9a747e4fSDavid du Colombier 
384*9a747e4fSDavid du Colombier /* inswab - read a reversed by order binary header
385*9a747e4fSDavid du Colombier  *
386*9a747e4fSDavid du Colombier  * DESCRIPTIONS
387*9a747e4fSDavid du Colombier  *
388*9a747e4fSDavid du Colombier  *	Reads a byte-swapped CPIO binary archive header
389*9a747e4fSDavid du Colombier  *
390*9a747e4fSDavid du Colombier  * PARMAMETERS
391*9a747e4fSDavid du Colombier  *
392*9a747e4fSDavid du Colombier  *	char	*magic	- magic number to match
393*9a747e4fSDavid du Colombier  *	char	*name	- name of the file which is stored in the header.
394*9a747e4fSDavid du Colombier  *			  (modified and passed back to caller).
395*9a747e4fSDavid du Colombier  *	Stat	*asb	- stat block for the file (modified and passed back
396*9a747e4fSDavid du Colombier  *			  to the caller).
397*9a747e4fSDavid du Colombier  *
398*9a747e4fSDavid du Colombier  *
399*9a747e4fSDavid du Colombier  * RETURNS
400*9a747e4fSDavid du Colombier  *
401*9a747e4fSDavid du Colombier  * 	Returns the number of trailing alignment bytes to skip; -1 if
402*9a747e4fSDavid du Colombier  *	unsuccessful.
403*9a747e4fSDavid du Colombier  *
404*9a747e4fSDavid du Colombier  */
405*9a747e4fSDavid du Colombier 
406*9a747e4fSDavid du Colombier #ifdef __STDC__
407*9a747e4fSDavid du Colombier 
inswab(char * magic,char * name,Stat * asb)408*9a747e4fSDavid du Colombier static int inswab(char *magic, char *name, Stat *asb)
409*9a747e4fSDavid du Colombier 
410*9a747e4fSDavid du Colombier #else
411*9a747e4fSDavid du Colombier 
412*9a747e4fSDavid du Colombier static int inswab(magic, name, asb)
413*9a747e4fSDavid du Colombier char           *magic;
414*9a747e4fSDavid du Colombier char           *name;
415*9a747e4fSDavid du Colombier Stat           *asb;
416*9a747e4fSDavid du Colombier 
417*9a747e4fSDavid du Colombier #endif
418*9a747e4fSDavid du Colombier {
419*9a747e4fSDavid du Colombier     ushort          namesize;
420*9a747e4fSDavid du Colombier     uint            namefull;
421*9a747e4fSDavid du Colombier     Binary          binary;
422*9a747e4fSDavid du Colombier 
423*9a747e4fSDavid du Colombier     if (*((ushort *) magic) != SWAB(M_BINARY)) {
424*9a747e4fSDavid du Colombier 	return (-1);
425*9a747e4fSDavid du Colombier     }
426*9a747e4fSDavid du Colombier     memcpy((char *) &binary,
427*9a747e4fSDavid du Colombier 		  magic + sizeof(ushort),
428*9a747e4fSDavid du Colombier 		  M_STRLEN - sizeof(ushort));
429*9a747e4fSDavid du Colombier     if (buf_read((char *) &binary + M_STRLEN - sizeof(ushort),
430*9a747e4fSDavid du Colombier 		 sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0) {
431*9a747e4fSDavid du Colombier 	warnarch("Corrupt swapped header",
432*9a747e4fSDavid du Colombier 		 (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort)));
433*9a747e4fSDavid du Colombier 	return (-1);
434*9a747e4fSDavid du Colombier     }
435*9a747e4fSDavid du Colombier     asb->sb_dev = (dev_t) SWAB(binary.b_dev);
436*9a747e4fSDavid du Colombier     asb->sb_ino = (ino_t) SWAB(binary.b_ino);
437*9a747e4fSDavid du Colombier     asb->sb_mode = SWAB(binary.b_mode);
438*9a747e4fSDavid du Colombier     asb->sb_uid = SWAB(binary.b_uid);
439*9a747e4fSDavid du Colombier     asb->sb_gid = SWAB(binary.b_gid);
440*9a747e4fSDavid du Colombier     asb->sb_nlink = SWAB(binary.b_nlink);
441*9a747e4fSDavid du Colombier #ifndef _POSIX_SOURCE
442*9a747e4fSDavid du Colombier     asb->sb_rdev = (dev_t) SWAB(binary.b_rdev);
443*9a747e4fSDavid du Colombier #endif
444*9a747e4fSDavid du Colombier     asb->sb_mtime = SWAB(binary.b_mtime[0]) << 16 | SWAB(binary.b_mtime[1]);
445*9a747e4fSDavid du Colombier     asb->sb_size = SWAB(binary.b_size[0]) << 16 | SWAB(binary.b_size[1]);
446*9a747e4fSDavid du Colombier     if ((namesize = SWAB(binary.b_name)) == 0 || namesize >= PATH_MAX) {
447*9a747e4fSDavid du Colombier 	warnarch("Bad swapped pathname length",
448*9a747e4fSDavid du Colombier 		 (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort)));
449*9a747e4fSDavid du Colombier 	return (-1);
450*9a747e4fSDavid du Colombier     }
451*9a747e4fSDavid du Colombier     if (buf_read(name, namefull = namesize + namesize % 2) < 0) {
452*9a747e4fSDavid du Colombier 	warnarch("Corrupt swapped pathname", (OFFSET) namefull);
453*9a747e4fSDavid du Colombier 	return (-1);
454*9a747e4fSDavid du Colombier     }
455*9a747e4fSDavid du Colombier     if (name[namesize - 1] != '\0') {
456*9a747e4fSDavid du Colombier 	warnarch("Bad swapped pathname", (OFFSET) namefull);
457*9a747e4fSDavid du Colombier 	return (-1);
458*9a747e4fSDavid du Colombier     }
459*9a747e4fSDavid du Colombier     return (asb->sb_size % 2);
460*9a747e4fSDavid du Colombier }
461*9a747e4fSDavid du Colombier 
462*9a747e4fSDavid du Colombier 
463*9a747e4fSDavid du Colombier /* inascii - read in an ASCII cpio header
464*9a747e4fSDavid du Colombier  *
465*9a747e4fSDavid du Colombier  * DESCRIPTION
466*9a747e4fSDavid du Colombier  *
467*9a747e4fSDavid du Colombier  *	Reads an ASCII format cpio header
468*9a747e4fSDavid du Colombier  *
469*9a747e4fSDavid du Colombier  * PARAMETERS
470*9a747e4fSDavid du Colombier  *
471*9a747e4fSDavid du Colombier  *	char	*magic	- magic number to match
472*9a747e4fSDavid du Colombier  *	char	*name	- name of the file which is stored in the header.
473*9a747e4fSDavid du Colombier  *			  (modified and passed back to caller).
474*9a747e4fSDavid du Colombier  *	Stat	*asb	- stat block for the file (modified and passed back
475*9a747e4fSDavid du Colombier  *			  to the caller).
476*9a747e4fSDavid du Colombier  *
477*9a747e4fSDavid du Colombier  * RETURNS
478*9a747e4fSDavid du Colombier  *
479*9a747e4fSDavid du Colombier  * 	Returns zero if successful; -1 otherwise. Assumes that  the entire
480*9a747e4fSDavid du Colombier  *	magic number has been read.
481*9a747e4fSDavid du Colombier  */
482*9a747e4fSDavid du Colombier 
483*9a747e4fSDavid du Colombier #ifdef __STDC__
484*9a747e4fSDavid du Colombier 
inascii(char * magic,char * name,Stat * asb)485*9a747e4fSDavid du Colombier static int inascii(char *magic, char *name, Stat *asb)
486*9a747e4fSDavid du Colombier 
487*9a747e4fSDavid du Colombier #else
488*9a747e4fSDavid du Colombier 
489*9a747e4fSDavid du Colombier static int inascii(magic, name, asb)
490*9a747e4fSDavid du Colombier char           *magic;
491*9a747e4fSDavid du Colombier char           *name;
492*9a747e4fSDavid du Colombier Stat           *asb;
493*9a747e4fSDavid du Colombier 
494*9a747e4fSDavid du Colombier #endif
495*9a747e4fSDavid du Colombier {
496*9a747e4fSDavid du Colombier     uint            namelen;
497*9a747e4fSDavid du Colombier     char            header[H_STRLEN + 1];
498*9a747e4fSDavid du Colombier #ifdef _POSIX_SOURCE
499*9a747e4fSDavid du Colombier     dev_t	    dummyrdev;
500*9a747e4fSDavid du Colombier #endif
501*9a747e4fSDavid du Colombier 
502*9a747e4fSDavid du Colombier     if (strncmp(magic, M_ASCII, M_STRLEN) != 0) {
503*9a747e4fSDavid du Colombier 	return (-1);
504*9a747e4fSDavid du Colombier     }
505*9a747e4fSDavid du Colombier     if (buf_read(header, H_STRLEN) < 0) {
506*9a747e4fSDavid du Colombier 	warnarch("Corrupt ASCII header", (OFFSET) H_STRLEN);
507*9a747e4fSDavid du Colombier 	return (-1);
508*9a747e4fSDavid du Colombier     }
509*9a747e4fSDavid du Colombier     header[H_STRLEN] = '\0';
510*9a747e4fSDavid du Colombier     if (sscanf(header, H_SCAN, &asb->sb_dev,
511*9a747e4fSDavid du Colombier 	       &asb->sb_ino, &asb->sb_mode, &asb->sb_uid,
512*9a747e4fSDavid du Colombier #ifdef _POSIX_SOURCE
513*9a747e4fSDavid du Colombier 	       &asb->sb_gid, &asb->sb_nlink, &dummyrdev,
514*9a747e4fSDavid du Colombier #else
515*9a747e4fSDavid du Colombier 	       &asb->sb_gid, &asb->sb_nlink, &asb->sb_rdev,
516*9a747e4fSDavid du Colombier #endif
517*9a747e4fSDavid du Colombier 	       &asb->sb_mtime, &namelen, &asb->sb_size) != H_COUNT) {
518*9a747e4fSDavid du Colombier 	warnarch("Bad ASCII header", (OFFSET) H_STRLEN);
519*9a747e4fSDavid du Colombier 	return (-1);
520*9a747e4fSDavid du Colombier     }
521*9a747e4fSDavid du Colombier     if (namelen == 0 || namelen >= PATH_MAX) {
522*9a747e4fSDavid du Colombier 	warnarch("Bad ASCII pathname length", (OFFSET) H_STRLEN);
523*9a747e4fSDavid du Colombier 	return (-1);
524*9a747e4fSDavid du Colombier     }
525*9a747e4fSDavid du Colombier     if (buf_read(name, namelen) < 0) {
526*9a747e4fSDavid du Colombier 	warnarch("Corrupt ASCII pathname", (OFFSET) namelen);
527*9a747e4fSDavid du Colombier 	return (-1);
528*9a747e4fSDavid du Colombier     }
529*9a747e4fSDavid du Colombier     if (name[namelen - 1] != '\0') {
530*9a747e4fSDavid du Colombier 	warnarch("Bad ASCII pathname", (OFFSET) namelen);
531*9a747e4fSDavid du Colombier 	return (-1);
532*9a747e4fSDavid du Colombier     }
533*9a747e4fSDavid du Colombier     return (0);
534*9a747e4fSDavid du Colombier }
535*9a747e4fSDavid du Colombier 
536*9a747e4fSDavid du Colombier 
537*9a747e4fSDavid du Colombier /* inbinary - read a binary header
538*9a747e4fSDavid du Colombier  *
539*9a747e4fSDavid du Colombier  * DESCRIPTION
540*9a747e4fSDavid du Colombier  *
541*9a747e4fSDavid du Colombier  *	Reads a CPIO format binary header.
542*9a747e4fSDavid du Colombier  *
543*9a747e4fSDavid du Colombier  * PARAMETERS
544*9a747e4fSDavid du Colombier  *
545*9a747e4fSDavid du Colombier  *	char	*magic	- magic number to match
546*9a747e4fSDavid du Colombier  *	char	*name	- name of the file which is stored in the header.
547*9a747e4fSDavid du Colombier  *			  (modified and passed back to caller).
548*9a747e4fSDavid du Colombier  *	Stat	*asb	- stat block for the file (modified and passed back
549*9a747e4fSDavid du Colombier  *			  to the caller).
550*9a747e4fSDavid du Colombier  *
551*9a747e4fSDavid du Colombier  * RETURNS
552*9a747e4fSDavid du Colombier  *
553*9a747e4fSDavid du Colombier  * 	Returns the number of trailing alignment bytes to skip; -1 if
554*9a747e4fSDavid du Colombier  *	unsuccessful.
555*9a747e4fSDavid du Colombier  */
556*9a747e4fSDavid du Colombier 
557*9a747e4fSDavid du Colombier #ifdef __STDC__
558*9a747e4fSDavid du Colombier 
inbinary(char * magic,char * name,Stat * asb)559*9a747e4fSDavid du Colombier static int inbinary(char *magic, char *name, Stat *asb)
560*9a747e4fSDavid du Colombier 
561*9a747e4fSDavid du Colombier #else
562*9a747e4fSDavid du Colombier 
563*9a747e4fSDavid du Colombier static int inbinary(magic, name, asb)
564*9a747e4fSDavid du Colombier char           *magic;
565*9a747e4fSDavid du Colombier char           *name;
566*9a747e4fSDavid du Colombier Stat           *asb;
567*9a747e4fSDavid du Colombier 
568*9a747e4fSDavid du Colombier #endif
569*9a747e4fSDavid du Colombier {
570*9a747e4fSDavid du Colombier     uint            namefull;
571*9a747e4fSDavid du Colombier     Binary          binary;
572*9a747e4fSDavid du Colombier 
573*9a747e4fSDavid du Colombier     if (*((ushort *) magic) != M_BINARY) {
574*9a747e4fSDavid du Colombier 	return (-1);
575*9a747e4fSDavid du Colombier     }
576*9a747e4fSDavid du Colombier     memcpy((char *) &binary,
577*9a747e4fSDavid du Colombier 		  magic + sizeof(ushort),
578*9a747e4fSDavid du Colombier 		  M_STRLEN - sizeof(ushort));
579*9a747e4fSDavid du Colombier     if (buf_read((char *) &binary + M_STRLEN - sizeof(ushort),
580*9a747e4fSDavid du Colombier 		 sizeof(binary) - (M_STRLEN - sizeof(ushort))) < 0) {
581*9a747e4fSDavid du Colombier 	warnarch("Corrupt binary header",
582*9a747e4fSDavid du Colombier 		 (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort)));
583*9a747e4fSDavid du Colombier 	return (-1);
584*9a747e4fSDavid du Colombier     }
585*9a747e4fSDavid du Colombier     asb->sb_dev = binary.b_dev;
586*9a747e4fSDavid du Colombier     asb->sb_ino = binary.b_ino;
587*9a747e4fSDavid du Colombier     asb->sb_mode = binary.b_mode;
588*9a747e4fSDavid du Colombier     asb->sb_uid = binary.b_uid;
589*9a747e4fSDavid du Colombier     asb->sb_gid = binary.b_gid;
590*9a747e4fSDavid du Colombier     asb->sb_nlink = binary.b_nlink;
591*9a747e4fSDavid du Colombier #ifndef _POSIX_SOURCE
592*9a747e4fSDavid du Colombier     asb->sb_rdev = binary.b_rdev;
593*9a747e4fSDavid du Colombier #endif
594*9a747e4fSDavid du Colombier     asb->sb_mtime = binary.b_mtime[0] << 16 | binary.b_mtime[1];
595*9a747e4fSDavid du Colombier     asb->sb_size = binary.b_size[0] << 16 | binary.b_size[1];
596*9a747e4fSDavid du Colombier     if (binary.b_name == 0 || binary.b_name >= PATH_MAX) {
597*9a747e4fSDavid du Colombier 	warnarch("Bad binary pathname length",
598*9a747e4fSDavid du Colombier 		 (OFFSET) sizeof(binary) - (M_STRLEN - sizeof(ushort)));
599*9a747e4fSDavid du Colombier 	return (-1);
600*9a747e4fSDavid du Colombier     }
601*9a747e4fSDavid du Colombier     if (buf_read(name, namefull = binary.b_name + binary.b_name % 2) < 0) {
602*9a747e4fSDavid du Colombier 	warnarch("Corrupt binary pathname", (OFFSET) namefull);
603*9a747e4fSDavid du Colombier 	return (-1);
604*9a747e4fSDavid du Colombier     }
605*9a747e4fSDavid du Colombier     if (name[binary.b_name - 1] != '\0') {
606*9a747e4fSDavid du Colombier 	warnarch("Bad binary pathname", (OFFSET) namefull);
607*9a747e4fSDavid du Colombier 	return (-1);
608*9a747e4fSDavid du Colombier     }
609*9a747e4fSDavid du Colombier     return (asb->sb_size % 2);
610*9a747e4fSDavid du Colombier }
611