xref: /original-bsd/usr.bin/ar/header.c (revision b30b9691)
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.2 (Berkeley) 01/21/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.name[len] = 0;
88 		chdr.size -= (chdr.lname = len);
89 	} else {
90 		bcopy(hdr->ar_name, chdr.name, sizeof(hdr->ar_name));
91 
92 		/* Only strip off trailing spaces. */
93 		for (p = chdr.name + sizeof(hdr->ar_name) - 1; *p == ' '; --p);
94 		*++p = '\0';
95 		chdr.lname = 0;
96 	}
97 	return(1);
98 }
99 
100 /*
101  * put_header --
102  *	Write the archive member header to a file.
103  */
104 put_header(cfp, sb)
105 	CF *cfp;
106 	struct stat *sb;
107 {
108 	register int lname;
109 	register char *name;
110 	struct ar_hdr *hdr;
111 	char *rname();
112 
113 	/*
114 	 * If passed an sb structure, reading a file from disk.  Get stat(2)
115 	 * information, build a name and construct a header.  (Files are named
116 	 * by their last component in the archive.)  If not, then just write
117 	 * the last header read.
118 	 */
119 	if (sb) {
120 		name = rname(cfp->rname);
121 		(void)fstat(cfp->rfd, sb);
122 
123 		if ((lname = strlen(name)) > sizeof(hdr->ar_name) ||
124 		    index(name, ' ')) {
125 			(void)sprintf(hb, HDR1, AR_EFMT1, lname, sb->st_mtime,
126 			    sb->st_uid, sb->st_gid, sb->st_mode,
127 			    sb->st_size + lname, ARFMAG);
128 		} else {
129 			lname = 0;
130 			(void)sprintf(hb, HDR2, name, sb->st_mtime, sb->st_uid,
131 			    sb->st_gid, sb->st_mode, sb->st_size, ARFMAG);
132 		}
133 	} else {
134 		lname = chdr.lname;
135 		name = chdr.name;
136 	}
137 
138 	if (write(cfp->wfd, hb, sizeof(HDR)) != sizeof(HDR) ||
139 	    lname && write(cfp->wfd, name, lname) != lname)
140 		error(cfp->wname);
141 }
142