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