]> git.lizzy.rs Git - plan9front.git/blob - sys/src/ape/cmd/pax/create.c
ape: bring strtod() in line with plan9's libc version
[plan9front.git] / sys / src / ape / cmd / pax / create.c
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
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
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
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
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 }