xref: /original-bsd/usr.bin/ar/header.c (revision 767d859e)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Hugh Smith at The University of Guelph.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char sccsid[] = "@(#)header.c	5.1 (Berkeley) 01/17/91";
13 #endif /* not lint */
14 
15 #include <sys/param.h>
16 #include <sys/errno.h>
17 #include <sys/stat.h>
18 #include <dirent.h>
19 #include <stdio.h>
20 #include <ar.h>
21 #include "archive.h"
22 
23 typedef struct ar_hdr HDR;
24 extern CHDR chdr;			/* converted header */
25 static char hb[sizeof(HDR) + 1];	/* real header */
26 extern char *archive;			/* archive name */
27 
28 /* Convert ar header field to an integer. */
29 #define	AR_ATOI(from, to, len, base) { \
30 	bcopy(from, buf, len); \
31 	buf[len] = '\0'; \
32 	to = strtol(buf, (char **)NULL, base); \
33 }
34 
35 /*
36  * get_header --
37  *	read the archive header for this member
38  */
39 get_header(fd)
40 	int fd;
41 {
42 	struct ar_hdr *hdr;
43 	register int len, nr;
44 	register char *p, buf[20];
45 
46 	nr = read(fd, hb, sizeof(HDR));
47 	if (nr != sizeof(HDR)) {
48 		if (!nr)
49 			return(0);
50 		if (nr < 0)
51 			error(archive);
52 		badfmt();
53 	}
54 
55 	hdr = (struct ar_hdr *)hb;
56 	if (strncmp(hdr->ar_fmag, ARFMAG, sizeof(ARFMAG) - 1))
57 		badfmt();
58 
59 	/* Convert the header into the internal format. */
60 #define	DECIMAL	10
61 #define	OCTAL	 8
62 
63 	AR_ATOI(hdr->ar_date, chdr.date, sizeof(hdr->ar_date), DECIMAL);
64 	AR_ATOI(hdr->ar_uid, chdr.uid, sizeof(hdr->ar_uid), DECIMAL);
65 	AR_ATOI(hdr->ar_gid, chdr.gid, sizeof(hdr->ar_gid), DECIMAL);
66 	AR_ATOI(hdr->ar_mode, chdr.mode, sizeof(hdr->ar_mode), OCTAL);
67 	AR_ATOI(hdr->ar_size, chdr.size, sizeof(hdr->ar_size), DECIMAL);
68 
69 	/* Leading spaces should never happen. */
70 	if (hdr->ar_name[0] == ' ')
71 		badfmt();
72 
73 	/*
74 	 * Long name support.  Set the "real" size of the file, and the
75 	 * long name flag/size.
76 	 */
77 	if (!bcmp(hdr->ar_name, AR_EFMT1, sizeof(AR_EFMT1) - 1)) {
78 		len = atoi(hdr->ar_name + sizeof(AR_EFMT1) - 1);
79 		if (len <= 0 || len > MAXNAMLEN)
80 			badfmt();
81 		nr = read(fd, chdr.name, len);
82 		if (nr != len) {
83 			if (nr < 0)
84 				error(archive);
85 			badfmt();
86 		}
87 		chdr.size -= (chdr.lname = len);
88 	} else {
89 		bcopy(hdr->ar_name, chdr.name, sizeof(hdr->ar_name));
90 
91 		/* Only strip off trailing spaces. */
92 		for (p = chdr.name + sizeof(hdr->ar_name) - 1; *p == ' '; --p);
93 		*++p = '\0';
94 		chdr.lname = 0;
95 	}
96 	return(1);
97 }
98 
99 /*
100  * put_header --
101  *	Write the archive member header to a file.
102  */
103 put_header(cfp, sb)
104 	CF *cfp;
105 	struct stat *sb;
106 {
107 	register int lname;
108 	register char *name;
109 	struct ar_hdr *hdr;
110 	char *rname();
111 
112 	/*
113 	 * If passed an sb structure, reading a file from disk.  Get stat(2)
114 	 * information, build a name and construct a header.  (Files are named
115 	 * by their last component in the archive.)  If not, then just write
116 	 * the last header read.
117 	 */
118 	if (sb) {
119 		name = rname(cfp->rname);
120 		(void)fstat(cfp->rfd, sb);
121 
122 		if ((lname = strlen(name)) > sizeof(hdr->ar_name) ||
123 		    index(name, ' ')) {
124 			(void)sprintf(hb, HDR1, AR_EFMT1, lname, sb->st_mtime,
125 			    sb->st_uid, sb->st_gid, sb->st_mode,
126 			    sb->st_size + lname, ARFMAG);
127 		} else {
128 			lname = 0;
129 			(void)sprintf(hb, HDR2, name, sb->st_mtime, sb->st_uid,
130 			    sb->st_gid, sb->st_mode, sb->st_size, ARFMAG);
131 		}
132 	} else {
133 		lname = chdr.lname;
134 		name = chdr.name;
135 	}
136 
137 	if (write(cfp->wfd, hb, sizeof(HDR)) != sizeof(HDR) ||
138 	    lname && write(cfp->wfd, name, lname) != lname)
139 		error(cfp->wname);
140 }
141