xref: /plan9/sys/src/ape/cmd/pax/create.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier /* $Source: /u/mark/src/pax/RCS/create.c,v $
2*9a747e4fSDavid du Colombier  *
3*9a747e4fSDavid du Colombier  * $Revision: 1.3 $
4*9a747e4fSDavid du Colombier  *
5*9a747e4fSDavid du Colombier  * create.c - Create a tape archive.
6*9a747e4fSDavid du Colombier  *
7*9a747e4fSDavid du Colombier  * DESCRIPTION
8*9a747e4fSDavid du Colombier  *
9*9a747e4fSDavid du Colombier  *	These functions are used to create/write and archive from an set of
10*9a747e4fSDavid du Colombier  *	named files.
11*9a747e4fSDavid du Colombier  *
12*9a747e4fSDavid du Colombier  * AUTHOR
13*9a747e4fSDavid du Colombier  *
14*9a747e4fSDavid du Colombier  *     	Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
15*9a747e4fSDavid du Colombier  *
16*9a747e4fSDavid du Colombier  * Sponsored by The USENIX Association for public distribution.
17*9a747e4fSDavid du Colombier  *
18*9a747e4fSDavid du Colombier  * Copyright (c) 1989 Mark H. Colburn.
19*9a747e4fSDavid du Colombier  * All rights reserved.
20*9a747e4fSDavid du Colombier  *
21*9a747e4fSDavid du Colombier  * Redistribution and use in source and binary forms are permitted
22*9a747e4fSDavid du Colombier  * provided that the above copyright notice is duplicated in all such
23*9a747e4fSDavid du Colombier  * forms and that any documentation, advertising materials, and other
24*9a747e4fSDavid du Colombier  * materials related to such distribution and use acknowledge that the
25*9a747e4fSDavid du Colombier  * software was developed * by Mark H. Colburn and sponsored by The
26*9a747e4fSDavid du Colombier  * USENIX Association.
27*9a747e4fSDavid du Colombier  *
28*9a747e4fSDavid du Colombier  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29*9a747e4fSDavid du Colombier  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30*9a747e4fSDavid du Colombier  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31*9a747e4fSDavid du Colombier  *
32*9a747e4fSDavid du Colombier  * $Log:	create.c,v $
33*9a747e4fSDavid du Colombier  * Revision 1.3  89/02/12  10:29:37  mark
34*9a747e4fSDavid du Colombier  * Fixed misspelling of Replstr
35*9a747e4fSDavid du Colombier  *
36*9a747e4fSDavid du Colombier  * Revision 1.2  89/02/12  10:04:17  mark
37*9a747e4fSDavid du Colombier  * 1.2 release fixes
38*9a747e4fSDavid du Colombier  *
39*9a747e4fSDavid du Colombier  * Revision 1.1  88/12/23  18:02:06  mark
40*9a747e4fSDavid du Colombier  * Initial revision
41*9a747e4fSDavid du Colombier  *
42*9a747e4fSDavid du Colombier  */
43*9a747e4fSDavid du Colombier 
44*9a747e4fSDavid du Colombier #ifndef lint
45*9a747e4fSDavid du Colombier static char *ident = "$Id: create.c,v 1.3 89/02/12 10:29:37 mark Exp Locker: mark $";
46*9a747e4fSDavid du Colombier static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
47*9a747e4fSDavid du Colombier #endif /* ! lint */
48*9a747e4fSDavid du Colombier 
49*9a747e4fSDavid du Colombier 
50*9a747e4fSDavid du Colombier /* Headers */
51*9a747e4fSDavid du Colombier 
52*9a747e4fSDavid du Colombier #include "pax.h"
53*9a747e4fSDavid du Colombier 
54*9a747e4fSDavid du Colombier 
55*9a747e4fSDavid du Colombier /* Function Prototypes */
56*9a747e4fSDavid du Colombier 
57*9a747e4fSDavid du Colombier #ifdef __STDC__
58*9a747e4fSDavid du Colombier 
59*9a747e4fSDavid du Colombier static void writetar(char *, Stat *);
60*9a747e4fSDavid du Colombier static void writecpio(char *, Stat *);
61*9a747e4fSDavid du Colombier static char tartype(int);
62*9a747e4fSDavid du Colombier 
63*9a747e4fSDavid du Colombier #else /* !__STDC__ */
64*9a747e4fSDavid du Colombier 
65*9a747e4fSDavid du Colombier static void writetar();
66*9a747e4fSDavid du Colombier static void writecpio();
67*9a747e4fSDavid du Colombier static char tartype();
68*9a747e4fSDavid du Colombier 
69*9a747e4fSDavid du Colombier #endif /* __STDC__ */
70*9a747e4fSDavid du Colombier 
71*9a747e4fSDavid du Colombier 
72*9a747e4fSDavid du Colombier /* create_archive - create a tar archive.
73*9a747e4fSDavid du Colombier  *
74*9a747e4fSDavid du Colombier  * DESCRIPTION
75*9a747e4fSDavid du Colombier  *
76*9a747e4fSDavid du Colombier  *	Create_archive is used as an entry point to both create and append
77*9a747e4fSDavid du Colombier  *	archives.  Create archive goes through the files specified by the
78*9a747e4fSDavid du Colombier  *	user and writes each one to the archive if it can.  Create_archive
79*9a747e4fSDavid du Colombier  *	knows how to write both cpio and tar headers and the padding which
80*9a747e4fSDavid du Colombier  *	is needed for each type of archive.
81*9a747e4fSDavid du Colombier  *
82*9a747e4fSDavid du Colombier  * RETURNS
83*9a747e4fSDavid du Colombier  *
84*9a747e4fSDavid du Colombier  *	Always returns 0
85*9a747e4fSDavid du Colombier  */
86*9a747e4fSDavid du Colombier 
87*9a747e4fSDavid du Colombier #ifdef __STDC__
88*9a747e4fSDavid du Colombier 
create_archive(void)89*9a747e4fSDavid du Colombier int create_archive(void)
90*9a747e4fSDavid du Colombier 
91*9a747e4fSDavid du Colombier #else
92*9a747e4fSDavid du Colombier 
93*9a747e4fSDavid du Colombier int create_archive()
94*9a747e4fSDavid du Colombier 
95*9a747e4fSDavid du Colombier #endif
96*9a747e4fSDavid du Colombier {
97*9a747e4fSDavid du Colombier     char            name[PATH_MAX + 1];
98*9a747e4fSDavid du Colombier     Stat            sb;
99*9a747e4fSDavid du Colombier     int             fd;
100*9a747e4fSDavid du Colombier 
101*9a747e4fSDavid du Colombier     while (name_next(name, &sb) != -1) {
102*9a747e4fSDavid du Colombier 	if ((fd = openin(name, &sb)) < 0) {
103*9a747e4fSDavid du Colombier 	    /* FIXME: pax wants to exit here??? */
104*9a747e4fSDavid du Colombier 	    continue;
105*9a747e4fSDavid du Colombier 	}
106*9a747e4fSDavid du Colombier 
107*9a747e4fSDavid du Colombier 	if (rplhead != (Replstr *)NULL) {
108*9a747e4fSDavid du Colombier 	    rpl_name(name);
109*9a747e4fSDavid du Colombier 	    if (strlen(name) == 0) {
110*9a747e4fSDavid du Colombier 		continue;
111*9a747e4fSDavid du Colombier 	    }
112*9a747e4fSDavid du Colombier 	}
113*9a747e4fSDavid du Colombier 	if (get_disposition("add", name) || get_newname(name, sizeof(name))) {
114*9a747e4fSDavid du Colombier 	    /* skip file... */
115*9a747e4fSDavid du Colombier 	    if (fd) {
116*9a747e4fSDavid du Colombier 		close(fd);
117*9a747e4fSDavid du Colombier 	    }
118*9a747e4fSDavid du Colombier 	    continue;
119*9a747e4fSDavid du Colombier 	}
120*9a747e4fSDavid du Colombier 
121*9a747e4fSDavid du Colombier 	if (!f_link && sb.sb_nlink > 1) {
122*9a747e4fSDavid du Colombier 	    if (islink(name, &sb)) {
123*9a747e4fSDavid du Colombier 		sb.sb_size = 0;
124*9a747e4fSDavid du Colombier 	    }
125*9a747e4fSDavid du Colombier 	    linkto(name, &sb);
126*9a747e4fSDavid du Colombier 	}
127*9a747e4fSDavid du Colombier 	if (ar_format == TAR) {
128*9a747e4fSDavid du Colombier 	    writetar(name, &sb);
129*9a747e4fSDavid du Colombier 	} else {
130*9a747e4fSDavid du Colombier 	    writecpio(name, &sb);
131*9a747e4fSDavid du Colombier 	}
132*9a747e4fSDavid du Colombier 	if (fd) {
133*9a747e4fSDavid du Colombier 	    outdata(fd, name, sb.sb_size);
134*9a747e4fSDavid du Colombier 	}
135*9a747e4fSDavid du Colombier 	if (f_verbose) {
136*9a747e4fSDavid du Colombier 	    print_entry(name, &sb);
137*9a747e4fSDavid du Colombier 	}
138*9a747e4fSDavid du Colombier     }
139*9a747e4fSDavid du Colombier 
140*9a747e4fSDavid du Colombier     write_eot();
141*9a747e4fSDavid du Colombier     close_archive();
142*9a747e4fSDavid du Colombier     return (0);
143*9a747e4fSDavid du Colombier }
144*9a747e4fSDavid du Colombier 
145*9a747e4fSDavid du Colombier 
146*9a747e4fSDavid du Colombier /* writetar - write a header block for a tar file
147*9a747e4fSDavid du Colombier  *
148*9a747e4fSDavid du Colombier  * DESCRIPTION
149*9a747e4fSDavid du Colombier  *
150*9a747e4fSDavid du Colombier  * 	Make a header block for the file name whose stat info is in st.
151*9a747e4fSDavid du Colombier  *	Return header pointer for success, NULL if the name is too long.
152*9a747e4fSDavid du Colombier  *
153*9a747e4fSDavid du Colombier  * 	The tar header block is structured as follows:
154*9a747e4fSDavid du Colombier  *
155*9a747e4fSDavid du Colombier  *		FIELD NAME	OFFSET		SIZE
156*9a747e4fSDavid du Colombier  *      	-------------|---------------|------
157*9a747e4fSDavid du Colombier  *		name		  0		100
158*9a747e4fSDavid du Colombier  *		mode		100		  8
159*9a747e4fSDavid du Colombier  *		uid		108		  8
160*9a747e4fSDavid du Colombier  *		gid		116		  8
161*9a747e4fSDavid du Colombier  *		size		124		 12
162*9a747e4fSDavid du Colombier  *		mtime		136		 12
163*9a747e4fSDavid du Colombier  *		chksum		148		  8
164*9a747e4fSDavid du Colombier  *		typeflag	156		  1
165*9a747e4fSDavid du Colombier  *		linkname	157		100
166*9a747e4fSDavid du Colombier  *		magic		257		  6
167*9a747e4fSDavid du Colombier  *		version		263		  2
168*9a747e4fSDavid du Colombier  *		uname		265		 32
169*9a747e4fSDavid du Colombier  *		gname		297		 32
170*9a747e4fSDavid du Colombier  *		devmajor	329		  8
171*9a747e4fSDavid du Colombier  *		devminor	337		  8
172*9a747e4fSDavid du Colombier  *		prefix		345		155
173*9a747e4fSDavid du Colombier  *
174*9a747e4fSDavid du Colombier  * PARAMETERS
175*9a747e4fSDavid du Colombier  *
176*9a747e4fSDavid du Colombier  *	char	*name	- name of file to create a header block for
177*9a747e4fSDavid du Colombier  *	Stat	*asb	- pointer to the stat structure for the named file
178*9a747e4fSDavid du Colombier  *
179*9a747e4fSDavid du Colombier  */
180*9a747e4fSDavid du Colombier 
181*9a747e4fSDavid du Colombier #ifdef __STDC__
182*9a747e4fSDavid du Colombier 
writetar(char * name,Stat * asb)183*9a747e4fSDavid du Colombier static void writetar(char *name, Stat *asb)
184*9a747e4fSDavid du Colombier 
185*9a747e4fSDavid du Colombier #else
186*9a747e4fSDavid du Colombier 
187*9a747e4fSDavid du Colombier static void writetar(name, asb)
188*9a747e4fSDavid du Colombier char           *name;
189*9a747e4fSDavid du Colombier Stat           *asb;
190*9a747e4fSDavid du Colombier 
191*9a747e4fSDavid du Colombier #endif
192*9a747e4fSDavid du Colombier {
193*9a747e4fSDavid du Colombier     char	   *p;
194*9a747e4fSDavid du Colombier     char           *prefix = (char *)NULL;
195*9a747e4fSDavid du Colombier     int             i;
196*9a747e4fSDavid du Colombier     int             sum;
197*9a747e4fSDavid du Colombier     char            hdr[BLOCKSIZE];
198*9a747e4fSDavid du Colombier     Link           *from;
199*9a747e4fSDavid du Colombier 
200*9a747e4fSDavid du Colombier     memset(hdr, 0, BLOCKSIZE);
201*9a747e4fSDavid du Colombier     if (strlen(name) > 255) {
202*9a747e4fSDavid du Colombier 	warn(name, "name too long");
203*9a747e4fSDavid du Colombier 	return;
204*9a747e4fSDavid du Colombier     }
205*9a747e4fSDavid du Colombier 
206*9a747e4fSDavid du Colombier     /*
207*9a747e4fSDavid du Colombier      * If the pathname is longer than TNAMLEN, but less than 255, then
208*9a747e4fSDavid du Colombier      * we can split it up into the prefix and the filename.
209*9a747e4fSDavid du Colombier      */
210*9a747e4fSDavid du Colombier     if (strlen(name) > 100) {
211*9a747e4fSDavid du Colombier 	prefix = name;
212*9a747e4fSDavid du Colombier 	name += 155;
213*9a747e4fSDavid du Colombier 	while (name > prefix && *name != '/') {
214*9a747e4fSDavid du Colombier 	    name--;
215*9a747e4fSDavid du Colombier 	}
216*9a747e4fSDavid du Colombier 
217*9a747e4fSDavid du Colombier 	/* no slash found....hmmm.... */
218*9a747e4fSDavid du Colombier 	if (name == prefix) {
219*9a747e4fSDavid du Colombier 	    warn(prefix, "Name too long");
220*9a747e4fSDavid du Colombier 	    return;
221*9a747e4fSDavid du Colombier 	}
222*9a747e4fSDavid du Colombier 	*name++ = '\0';
223*9a747e4fSDavid du Colombier     }
224*9a747e4fSDavid du Colombier 
225*9a747e4fSDavid du Colombier #ifdef S_IFLNK
226*9a747e4fSDavid du Colombier     if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
227*9a747e4fSDavid du Colombier 	strcpy(&hdr[157], asb->sb_link);
228*9a747e4fSDavid du Colombier 	asb->sb_size = 0;
229*9a747e4fSDavid du Colombier     }
230*9a747e4fSDavid du Colombier #endif
231*9a747e4fSDavid du Colombier     strcpy(hdr, name);
232*9a747e4fSDavid du Colombier     sprintf(&hdr[100], "%06o \0", asb->sb_mode & ~S_IFMT);
233*9a747e4fSDavid du Colombier     sprintf(&hdr[108], "%06o \0", asb->sb_uid);
234*9a747e4fSDavid du Colombier     sprintf(&hdr[116], "%06o \0", asb->sb_gid);
235*9a747e4fSDavid du Colombier     sprintf(&hdr[124], "%011lo ", (long) asb->sb_size);
236*9a747e4fSDavid du Colombier     sprintf(&hdr[136], "%011lo ", (long) asb->sb_mtime);
237*9a747e4fSDavid du Colombier     strncpy(&hdr[148], "        ", 8);
238*9a747e4fSDavid du Colombier     hdr[156] = tartype(asb->sb_mode);
239*9a747e4fSDavid du Colombier     if (asb->sb_nlink > 1 && (from = linkfrom(name, asb)) != (Link *)NULL) {
240*9a747e4fSDavid du Colombier 	strcpy(&hdr[157], from->l_name);
241*9a747e4fSDavid du Colombier 	hdr[156] = LNKTYPE;
242*9a747e4fSDavid du Colombier     }
243*9a747e4fSDavid du Colombier     strcpy(&hdr[257], TMAGIC);
244*9a747e4fSDavid du Colombier     strncpy(&hdr[263], TVERSION, 2);
245*9a747e4fSDavid du Colombier     strcpy(&hdr[265], finduname((int) asb->sb_uid));
246*9a747e4fSDavid du Colombier     strcpy(&hdr[297], findgname((int) asb->sb_gid));
247*9a747e4fSDavid du Colombier     sprintf(&hdr[329], "%06o \0", major(asb->sb_rdev));
248*9a747e4fSDavid du Colombier     sprintf(&hdr[337], "%06o \0", minor(asb->sb_rdev));
249*9a747e4fSDavid du Colombier     if (prefix != (char *)NULL) {
250*9a747e4fSDavid du Colombier 	strncpy(&hdr[345], prefix, 155);
251*9a747e4fSDavid du Colombier     }
252*9a747e4fSDavid du Colombier 
253*9a747e4fSDavid du Colombier     /* Calculate the checksum */
254*9a747e4fSDavid du Colombier 
255*9a747e4fSDavid du Colombier     sum = 0;
256*9a747e4fSDavid du Colombier     p = hdr;
257*9a747e4fSDavid du Colombier     for (i = 0; i < 500; i++) {
258*9a747e4fSDavid du Colombier 	sum += 0xFF & *p++;
259*9a747e4fSDavid du Colombier     }
260*9a747e4fSDavid du Colombier 
261*9a747e4fSDavid du Colombier     /* Fill in the checksum field. */
262*9a747e4fSDavid du Colombier 
263*9a747e4fSDavid du Colombier     sprintf(&hdr[148], "%06o \0", sum);
264*9a747e4fSDavid du Colombier 
265*9a747e4fSDavid du Colombier     outwrite(hdr, BLOCKSIZE);
266*9a747e4fSDavid du Colombier }
267*9a747e4fSDavid du Colombier 
268*9a747e4fSDavid du Colombier 
269*9a747e4fSDavid du Colombier /* tartype - return tar file type from file mode
270*9a747e4fSDavid du Colombier  *
271*9a747e4fSDavid du Colombier  * DESCRIPTION
272*9a747e4fSDavid du Colombier  *
273*9a747e4fSDavid du Colombier  *	tartype returns the character which represents the type of file
274*9a747e4fSDavid du Colombier  *	indicated by "mode".
275*9a747e4fSDavid du Colombier  *
276*9a747e4fSDavid du Colombier  * PARAMETERS
277*9a747e4fSDavid du Colombier  *
278*9a747e4fSDavid du Colombier  *	int	mode	- file mode from a stat block
279*9a747e4fSDavid du Colombier  *
280*9a747e4fSDavid du Colombier  * RETURNS
281*9a747e4fSDavid du Colombier  *
282*9a747e4fSDavid du Colombier  *	The character which represents the particular file type in the
283*9a747e4fSDavid du Colombier  *	ustar standard headers.
284*9a747e4fSDavid du Colombier  */
285*9a747e4fSDavid du Colombier 
286*9a747e4fSDavid du Colombier #ifdef __STDC__
287*9a747e4fSDavid du Colombier 
tartype(int mode)288*9a747e4fSDavid du Colombier static char tartype(int mode)
289*9a747e4fSDavid du Colombier 
290*9a747e4fSDavid du Colombier #else
291*9a747e4fSDavid du Colombier 
292*9a747e4fSDavid du Colombier static char tartype(mode)
293*9a747e4fSDavid du Colombier int	    mode;
294*9a747e4fSDavid du Colombier 
295*9a747e4fSDavid du Colombier #endif
296*9a747e4fSDavid du Colombier {
297*9a747e4fSDavid du Colombier     switch (mode & S_IFMT) {
298*9a747e4fSDavid du Colombier 
299*9a747e4fSDavid du Colombier #ifdef S_IFCTG
300*9a747e4fSDavid du Colombier     case S_IFCTG:
301*9a747e4fSDavid du Colombier 	return(CONTTYPE);
302*9a747e4fSDavid du Colombier #endif
303*9a747e4fSDavid du Colombier 
304*9a747e4fSDavid du Colombier     case S_IFDIR:
305*9a747e4fSDavid du Colombier 	return (DIRTYPE);
306*9a747e4fSDavid du Colombier 
307*9a747e4fSDavid du Colombier #ifdef S_IFLNK
308*9a747e4fSDavid du Colombier     case S_IFLNK:
309*9a747e4fSDavid du Colombier 	return (SYMTYPE);
310*9a747e4fSDavid du Colombier #endif
311*9a747e4fSDavid du Colombier 
312*9a747e4fSDavid du Colombier #ifdef S_IFFIFO
313*9a747e4fSDavid du Colombier     case S_IFIFO:
314*9a747e4fSDavid du Colombier 	return (FIFOTYPE);
315*9a747e4fSDavid du Colombier #endif
316*9a747e4fSDavid du Colombier 
317*9a747e4fSDavid du Colombier #ifdef S_IFCHR
318*9a747e4fSDavid du Colombier     case S_IFCHR:
319*9a747e4fSDavid du Colombier 	return (CHRTYPE);
320*9a747e4fSDavid du Colombier #endif
321*9a747e4fSDavid du Colombier 
322*9a747e4fSDavid du Colombier #ifdef S_IFBLK
323*9a747e4fSDavid du Colombier     case S_IFBLK:
324*9a747e4fSDavid du Colombier 	return (BLKTYPE);
325*9a747e4fSDavid du Colombier #endif
326*9a747e4fSDavid du Colombier 
327*9a747e4fSDavid du Colombier     default:
328*9a747e4fSDavid du Colombier 	return (REGTYPE);
329*9a747e4fSDavid du Colombier     }
330*9a747e4fSDavid du Colombier }
331*9a747e4fSDavid du Colombier 
332*9a747e4fSDavid du Colombier 
333*9a747e4fSDavid du Colombier /* writecpio - write a cpio archive header
334*9a747e4fSDavid du Colombier  *
335*9a747e4fSDavid du Colombier  * DESCRIPTION
336*9a747e4fSDavid du Colombier  *
337*9a747e4fSDavid du Colombier  *	Writes a new CPIO style archive header for the file specified.
338*9a747e4fSDavid du Colombier  *
339*9a747e4fSDavid du Colombier  * PARAMETERS
340*9a747e4fSDavid du Colombier  *
341*9a747e4fSDavid du Colombier  *	char	*name	- name of file to create a header block for
342*9a747e4fSDavid du Colombier  *	Stat	*asb	- pointer to the stat structure for the named file
343*9a747e4fSDavid du Colombier  */
344*9a747e4fSDavid du Colombier 
345*9a747e4fSDavid du Colombier #ifdef __STDC__
346*9a747e4fSDavid du Colombier 
writecpio(char * name,Stat * asb)347*9a747e4fSDavid du Colombier static void writecpio(char *name, Stat *asb)
348*9a747e4fSDavid du Colombier 
349*9a747e4fSDavid du Colombier #else
350*9a747e4fSDavid du Colombier 
351*9a747e4fSDavid du Colombier static void writecpio(name, asb)
352*9a747e4fSDavid du Colombier char           *name;
353*9a747e4fSDavid du Colombier Stat           *asb;
354*9a747e4fSDavid du Colombier 
355*9a747e4fSDavid du Colombier #endif
356*9a747e4fSDavid du Colombier {
357*9a747e4fSDavid du Colombier     uint            namelen;
358*9a747e4fSDavid du Colombier     char            header[M_STRLEN + H_STRLEN + 1];
359*9a747e4fSDavid du Colombier 
360*9a747e4fSDavid du Colombier     namelen = (uint) strlen(name) + 1;
361*9a747e4fSDavid du Colombier     strcpy(header, M_ASCII);
362*9a747e4fSDavid du Colombier     sprintf(header + M_STRLEN, "%06o%06o%06o%06o%06o",
363*9a747e4fSDavid du Colombier 	    USH(asb->sb_dev), USH(asb->sb_ino), USH(asb->sb_mode),
364*9a747e4fSDavid du Colombier 	    USH(asb->sb_uid), USH(asb->sb_gid));
365*9a747e4fSDavid du Colombier     sprintf(header + M_STRLEN + 30, "%06o%06o%011lo%06o%011lo",
366*9a747e4fSDavid du Colombier #ifdef _POSIX_SOURCE
367*9a747e4fSDavid du Colombier 	    USH(asb->sb_nlink), USH(0),
368*9a747e4fSDavid du Colombier #else
369*9a747e4fSDavid du Colombier 	    USH(asb->sb_nlink), USH(asb->sb_rdev),
370*9a747e4fSDavid du Colombier #endif
371*9a747e4fSDavid du Colombier 	    f_mtime ? asb->sb_mtime : time((time_t *) 0),
372*9a747e4fSDavid du Colombier 	    namelen, asb->sb_size);
373*9a747e4fSDavid du Colombier     outwrite(header, M_STRLEN + H_STRLEN);
374*9a747e4fSDavid du Colombier     outwrite(name, namelen);
375*9a747e4fSDavid du Colombier #ifdef	S_IFLNK
376*9a747e4fSDavid du Colombier     if ((asb->sb_mode & S_IFMT) == S_IFLNK) {
377*9a747e4fSDavid du Colombier 	outwrite(asb->sb_link, (uint) asb->sb_size);
378*9a747e4fSDavid du Colombier     }
379*9a747e4fSDavid du Colombier #endif	/* S_IFLNK */
380*9a747e4fSDavid du Colombier }
381