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
28struct byteorder_ctx *
29byteorder_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
39void
40byteorder_destroy(struct byteorder_ctx *ctx)
41{
42	if (ctx != NULL)
43		(void) free((char *)ctx);
44}
45
46void
47byteorder_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 */
65void
66swabst(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
98uint32_t
99swabl(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
108static int
109checksum(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
157int
158normspcl(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
254void
255normdirect(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
265void
266normacls(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