xref: /illumos-gate/usr/src/cmd/backup/lib/byteorder.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * Copyright 1996, 1998, 2002-2003 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
7 /*	  All Rights Reserved	*/
8 
9 /*
10  * Copyright (c) 1983 Regents of the University of California.
11  * All rights reserved.  The Berkeley software License Agreement
12  * specifies the terms and conditions for redistribution.
13  */
14 
15 #pragma ident	"%Z%%M%	%I%	%E% SMI"
16 
17 #include <stdio.h>
18 #include <sys/types.h>
19 #include <sys/time.h>
20 #include <sys/vnode.h>
21 #include <locale.h>
22 #include <stdlib.h>
23 #include <sys/fs/ufs_inode.h>
24 #include <sys/fs/ufs_fsdir.h>
25 #include <sys/fs/ufs_acl.h>
26 #include <byteorder.h>
27 
28 struct byteorder_ctx *
29 byteorder_create(void)
30 {
31 	struct byteorder_ctx *rc;
32 
33 	/* LINTED: assignment value is used */
34 	if ((rc = (struct byteorder_ctx *)calloc(1, sizeof (*rc))) == NULL)
35 		return (NULL);
36 	return (rc);
37 }
38 
39 void
40 byteorder_destroy(struct byteorder_ctx *ctx)
41 {
42 	if (ctx != NULL)
43 		(void) free((char *)ctx);
44 }
45 
46 void
47 byteorder_banner(struct byteorder_ctx *ctx, FILE *filep)
48 {
49 	if ((! ctx->initialized) || (filep == NULL))
50 		return;
51 
52 	if (ctx->Bcvt)
53 		(void) fprintf(filep, gettext("Note: doing byte swapping\n"));
54 }
55 
56 /*
57  * Control string (cp) is a sequence of optional numeric repeat counts
58  * and format specifiers.  s/w/h indicate a 16-bit quantity is to be
59  * byte-swapped, l indicates a 32-bit quantity.  A repeat count is
60  * identical in effect to having the following format character appear
61  * N times (e.g., "3h" is equivalent to "hhh").
62  *
63  * The byte-swapping is performed in-place, in the buffer sp.
64  */
65 void
66 swabst(char *cp, uchar_t *sp)
67 {
68 	int n = 0;
69 	uchar_t c;
70 
71 	while (*cp) {
72 		switch (*cp) {
73 		case '0': case '1': case '2': case '3': case '4':
74 		case '5': case '6': case '7': case '8': case '9':
75 			n = (n * 10) + (*cp++ - '0');
76 			continue;
77 
78 		case 's': case 'w': case 'h':
79 			/* LINTED: type punning ok here */
80 			c = sp[0]; sp[0] = sp[1]; sp[1] = c;
81 			sp++;
82 			break;
83 
84 		case 'l':
85 			c = sp[0]; sp[0] = sp[3]; sp[3] = c;
86 			c = sp[2]; sp[2] = sp[1]; sp[1] = c;
87 			sp += 3;
88 		}
89 		/* Any other character, like 'b' counts as byte. */
90 		sp++;
91 		if (n <= 1) {
92 			n = 0; cp++;
93 		} else
94 			n--;
95 	}
96 }
97 
98 uint32_t
99 swabl(uint32_t x)
100 {
101 	uint32_t l = x;
102 
103 	swabst("l", (uchar_t *)&l);
104 	/* LINTED: type punning ok here */
105 	return (l);
106 }
107 
108 static int
109 checksum(struct byteorder_ctx *ctx, int *b, int size)
110 {
111 	uint_t i, j;
112 
113 	if (! ctx->initialized)
114 		return (-1);
115 
116 	/*
117 	 * We should only be called on to checksum u_spcl's, so make
118 	 * sure that's what we got.
119 	 */
120 	if ((unsigned)size < tp_bsize)
121 		return (-1);
122 
123 	j = tp_bsize / sizeof (int);
124 	i = 0;
125 	if (!ctx->Bcvt) {
126 		do
127 			i += (uint_t)*b++;
128 		while (--j);
129 	} else {
130 		/*
131 		 * What happens if we want to read restore tapes
132 		 * for a 16bit int machine???
133 		 */
134 		do
135 			i += swabl(*b++);
136 		while (--j);
137 	}
138 
139 	return (i != CHECKSUM);
140 }
141 
142 /*
143  * normspcl() checks that a spclrec is valid.  it does byte/quad
144  * swapping if necessary, and checks the checksum.  it does NOT convert
145  * from the old filesystem format; gethead() in tape.c does that.
146  *
147  * ctx is the context for this package
148  * sp is a pointer to a current-format spclrec, that may need to be
149  *	byteswapped.
150  * cs is a pointer to the thing we want to checksum.  if we're
151  *	converting from the old filesystem format, it might be different
152  *	from sp.
153  * css is the size of the thing we want to checksum.
154  * magic is the magic number we compare against.
155  */
156 
157 int
158 normspcl(struct byteorder_ctx *ctx, struct s_spcl *sp, int *cs,
159     int css, int magic)
160 {
161 	u_offset_t sv;
162 
163 	if ((! ctx->initialized) && (sp->c_magic != magic)) {
164 		if (swabl(sp->c_magic) != (uint32_t)magic)
165 			return (-1);
166 		ctx->Bcvt = 1;
167 	}
168 	ctx->initialized = 1;
169 
170 	if (checksum(ctx, cs, css))
171 		return (-1);
172 
173 	/*
174 	 * Unless our caller is actively trying to break us, a
175 	 * successful checksum() means that *sp is at least as
176 	 * big as what we think it should be as far as byte
177 	 * swapping goes.  Therefore, we don't need to do any
178 	 * more size checks here.
179 	 */
180 
181 	/* handle byte swapping */
182 	if (ctx->Bcvt) {
183 		/*
184 		 * byteswap
185 		 *	c_type, c_date, c_ddate, c_volume, c_tapea, c_inumber,
186 		 *	c_magic, c_checksum,
187 		 *	all of c_dinode, and c_count.
188 		 */
189 
190 		swabst("8l4s31l", (uchar_t *)sp);
191 
192 		/*
193 		 * byteswap
194 		 *	c_flags, c_firstrec, and c_spare.
195 		 */
196 
197 		swabst("34l", (uchar_t *)&(sp->c_flags));
198 
199 		/* byteswap the inodes if necessary. */
200 
201 #ifndef	lint	/* lint won't shut up about sprintf below */
202 		if (sp->c_flags & DR_INODEINFO) {
203 			char buffy[BUFSIZ];
204 			/* Can't overflow, max len is %d format (20)+`l'+\0 */
205 			/* LINTED lint can't tell diff between %ld and %dl */
206 			(void) sprintf(buffy, "%dl", TP_NINOS);
207 			swabst(buffy, (uchar_t *)sp->c_data.s_inos);
208 		}
209 #endif	/* lint */
210 
211 		/* if no metadata, byteswap the level */
212 
213 		if (! (sp->c_flags & DR_HASMETA))
214 			swabst("1l", (uchar_t *)&(sp->c_level));
215 	}
216 
217 	/* handle quad swapping (note -- we no longer perform this check */
218 	/*	we now do quad swapping iff we're doing byte swapping.)  */
219 
220 	/*
221 	 * 	the following code is being changed during the large file
222 	 *	project. This code needed to be changed because ic_size
223 	 *	is no longer a quad, it has been changed to ic_lsize, which is
224 	 *	an offset_t, and the field "val" doesn't exist anymore.
225 	 */
226 
227 /*
228  * This is the old code. (before large file project.)
229  *
230  *	sv = sp->c_dinode.di_ic.ic_size.val;
231  *
232  *	if (ctx->Bcvt) {
233  *		long foo;
234  *
235  *		foo = sv[1];
236  *		sv[1] = sv[0];
237  *		sv[0] = foo;
238  *	}
239  */
240 
241 	/* swap the upper 32 bits of ic_lsize with the lower 32 bits */
242 
243 	if (ctx->Bcvt) {
244 		sv = sp->c_dinode.di_ic.ic_lsize;
245 		sv = (sv << 32) | (sv >> 32);
246 		sp->c_dinode.di_ic.ic_lsize = sv;
247 	}
248 
249 	if (sp->c_magic != magic)
250 		return (-1);
251 	return (0);
252 }
253 
254 void
255 normdirect(ctx, d)
256 	struct byteorder_ctx *ctx;
257 	struct direct *d;
258 {
259 	assert(ctx->initialized);
260 
261 	if (ctx->Bcvt)
262 		swabst("l2s", (uchar_t *)d);
263 }
264 
265 void
266 normacls(struct byteorder_ctx *ctx, ufs_acl_t *acl, int n)
267 {
268 	static int complained = 0;
269 	int i;
270 	uid32_t uid;
271 
272 	assert(ctx->initialized);
273 
274 	if (! ctx->Bcvt)
275 		return;
276 
277 	for (i = 0; i < n; i++) {
278 		swabst("1s", (uchar_t *)&(acl[i].acl_tag));  /* u_short */
279 		swabst("1s", (uchar_t *)&(acl[i].acl_perm)); /* o_mode_t */
280 
281 		/* LINTED explicitly checking for truncation below */
282 		uid = (uid32_t)(acl[i].acl_who);
283 		if (!complained && ((uid_t)uid) != acl[i].acl_who) {
284 			/*
285 			 * The problem is that acl_who is a uid_t,
286 			 * and we know that the on-tape version is
287 			 * definitely 32 bits.  To avoid getting
288 			 * burned if/when uid_t becomes bigger
289 			 * than that, we need to do the explicit
290 			 * conversion and check.
291 			 */
292 			(void) fprintf(stderr,
293 			    "Some ACL uids have been truncated\n");
294 			complained = 1;
295 		}
296 		swabst("1l", (uchar_t *)&(uid));	/* uid32_t */
297 	}
298 }
299