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 *
byteorder_create(void)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
byteorder_destroy(struct byteorder_ctx * ctx)40 byteorder_destroy(struct byteorder_ctx *ctx)
41 {
42 if (ctx != NULL)
43 (void) free((char *)ctx);
44 }
45
46 void
byteorder_banner(struct byteorder_ctx * ctx,FILE * filep)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
swabst(char * cp,uchar_t * sp)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
swabl(uint32_t x)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
checksum(struct byteorder_ctx * ctx,int * b,int size)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
normspcl(struct byteorder_ctx * ctx,struct s_spcl * sp,int * cs,int css,int magic)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
normdirect(ctx,d)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
normacls(struct byteorder_ctx * ctx,ufs_acl_t * acl,int n)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