Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / vfsck / proplist.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #define VICE /* control whether AFS changes are present */
16
17 #ifdef AFS_OSF_ENV
18
19 #include <sys/mount.h>
20 #include <sys/vnode.h>
21 #include <ufs/inode.h>
22 #include <ufs/dinode.h>
23 #include <sys/proplist.h>
24 #include <ufs/fs.h>
25 #define _BSD
26 #define _KERNEL
27 #include <ufs/dir.h>
28 #undef _KERNEL
29 #undef _BSD
30
31 #include <afs/osi_inode.h>
32 #include "fsck.h"
33
34 struct prop_entry_desc {
35 struct prop_entry_desc *next;
36 int flags;
37 #define PROP_ENTRY_BAD 0x1
38 #define PROP_ENTRY_DUP 0x2
39 daddr_t blkno;
40 int blksize;
41 long offset;
42 long size;
43 char name[PROPLIST_NAME_MAX];
44 };
45
46 int
47 proplist_scan(dp, idesc)
48 struct dinode *dp;
49 struct inodesc *idesc;
50 {
51 struct proplist_desc1 *pl_descp;
52 struct bufarea *bp;
53 struct dinode *ndp;
54 long code;
55 int offsetinbuf, blksize;
56 struct prop_entry_desc *entry_list, *next;
57
58 code = proplist_blkscan(dp, idesc, &entry_list);
59 if (code & STOP)
60 goto out;
61
62 proplist_markdup(entry_list);
63
64 code = proplist_updateblks(dp, idesc, entry_list);
65 if (code & STOP)
66 goto out;
67
68 ndp = ginode(idesc->id_number);
69 if ((ndp->di_flags & IC_PROPLIST) == 0) {
70 code = 0;
71 goto out;
72 }
73 if ((ndp->di_flags & (IC_PROPLIST_BLOCK | IC_PROPLIST_FRAG)) ==
74 (IC_PROPLIST_BLOCK | IC_PROPLIST_FRAG)) {
75 code = 0;
76 goto out;
77 }
78 if (ndp->di_flags & IC_PROPLIST_FRAG) {
79 idesc->id_numfrags = 1;
80 blksize = sblock.fs_fsize;
81 } else {
82 idesc->id_numfrags = sblock.fs_frag;
83 blksize = sblock.fs_bsize;
84 }
85 idesc->id_blkno = ndp->di_proplb;
86 for (;;) {
87 code = (*idesc->id_func) (idesc);
88 if (code & STOP)
89 goto out;
90
91 bp = getdatablk(idesc->id_blkno, blksize);
92 for (offsetinbuf = 0; offsetinbuf < blksize;) {
93 pl_descp =
94 (struct proplist_desc1 *)(bp->b_un.b_buf + offsetinbuf);
95 offsetinbuf += pl_descp->pl_nextentry;
96 }
97 if (pl_descp->pl_nextfsb > 0) {
98 daddr_t save_blkno;
99
100 save_blkno = pl_descp->pl_nextfsb;
101 bp->b_flags &= ~B_INUSE;
102 idesc->id_blkno = save_blkno;
103 blksize = sblock.fs_bsize;
104 idesc->id_numfrags = sblock.fs_frag;
105 continue;
106 }
107 bp->b_flags &= ~B_INUSE;
108 break;
109 }
110 out:
111 for (next = entry_list; entry_list != NULL;) {
112 next = entry_list->next;
113 free(entry_list);
114 entry_list = next;
115 }
116 return (code);
117 }
118
119 int
120 proplist_blkscan(dp, idesc, entry_list)
121 struct dinode *dp;
122 struct inodesc *idesc;
123 struct prop_entry_desc **entry_list;
124 {
125 struct proplist_desc1 *pl_descp;
126 struct bufarea *bp;
127 struct prop_entry_desc *entry, *lastentry;
128 int blksize;
129 long code, valueresid;
130
131 *entry_list = NULL;
132 idesc->id_blkno = dp->di_proplb;
133 if (dp->di_flags & IC_PROPLIST_FRAG) {
134 blksize = sblock.fs_fsize;
135 idesc->id_numfrags = 1;
136 } else {
137 blksize = sblock.fs_bsize;
138 idesc->id_numfrags = sblock.fs_frag;
139 }
140 idesc->id_loc = 0;
141 valueresid = 0;
142 for (;;) {
143 if (idesc->id_loc == 0) {
144 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
145 code = proplist_blkdel(dp, idesc, 0);
146 return (code);
147 }
148 bp = getdatablk(idesc->id_blkno, blksize);
149 if (proplist_chkblock(bp, blksize)) {
150 bp->b_flags &= ~B_INUSE;
151 pwarn("PROPERTY LIST BLOCK CORRUPTED I=%u", idesc->id_number);
152 if (preen)
153 printf(" (CLEARED)\n");
154 else if (reply("CLEAR") == 0)
155 return (SKIP);
156 code = proplist_blkdel(dp, idesc, 0);
157 return (code);
158 }
159 }
160 pl_descp = (struct proplist_desc1 *)(bp->b_un.b_buf + idesc->id_loc);
161 if (pl_descp->pl_entrysize) {
162 if (valueresid < 0
163 || (valueresid
164 && strcmp((char *)&pl_descp[1], entry->name))) {
165 entry->flags |= PROP_ENTRY_BAD;
166 valueresid = 0;
167 }
168 if (valueresid == 0) {
169 entry = malloc(sizeof(struct prop_entry_desc));
170 if (entry == NULL)
171 return (SKIP);
172 entry->next = NULL;
173 entry->flags = 0;
174 memcpy(entry->name, (char *)&pl_descp[1],
175 pl_descp->pl_namelen);
176 entry->blkno = idesc->id_blkno;
177 entry->blksize = blksize;
178 entry->offset = idesc->id_loc;
179 entry->size = 0;
180 if (*entry_list != NULL)
181 lastentry->next = entry;
182 else
183 *entry_list = entry;
184 lastentry = entry;
185 valueresid = pl_descp->pl_valuelen;
186 }
187 entry->size += pl_descp->pl_entrysize;
188 valueresid -= pl_descp->pl_valuelen_entry;
189 }
190 if (pl_descp->pl_nextfsb > 0) {
191 daddr_t save_blkno;
192
193 save_blkno = pl_descp->pl_nextfsb;
194 bp->b_flags &= ~B_INUSE;
195 idesc->id_blkno = save_blkno;
196 idesc->id_numfrags = sblock.fs_frag;
197 blksize = sblock.fs_bsize;
198 idesc->id_loc = 0;
199 continue;
200 }
201 idesc->id_loc += pl_descp->pl_nextentry;
202 if (idesc->id_loc == blksize) {
203 bp->b_flags &= ~B_INUSE;
204 if (valueresid) {
205 entry->flags |= PROP_ENTRY_BAD;
206 }
207 break;
208 }
209 }
210 return (0);
211 }
212
213 int
214 proplist_markdup(entry_list)
215 struct prop_entry_desc *entry_list;
216 {
217 struct prop_entry_desc *start, *cur;
218 int bad_entries, dup_entries;
219
220 for (start = entry_list; start != NULL; start = start->next) {
221 if (start->flags & (PROP_ENTRY_BAD | PROP_ENTRY_DUP))
222 continue;
223 for (cur = start->next; cur != NULL; cur = cur->next) {
224 if (!strcmp(start->name, cur->name))
225 cur->flags |= PROP_ENTRY_DUP;
226 }
227 }
228 return (0);
229 }
230
231 int
232 proplist_updateblks(dp, idesc, entry_list)
233 struct dinode *dp;
234 struct inodesc *idesc;
235 struct prop_entry_desc *entry_list;
236 {
237 struct proplist_desc1 *pl_descp, *prev_pl_descp;
238 struct bufarea *bp;
239 struct prop_entry_desc *cur;
240 long code;
241 daddr_t next_blkno;
242 int resid, offset, free, blksize;
243
244 for (cur = entry_list; cur != NULL; cur = cur->next) {
245 if (cur->flags == 0)
246 continue;
247 idesc->id_blkno = cur->blkno;
248 idesc->id_loc = cur->offset;
249 blksize = cur->blksize;
250
251 if (cur->flags & PROP_ENTRY_BAD)
252 pwarn("BAD PROPERTY LIST ENTRY FOUND I=%u NAME %0.10s",
253 idesc->id_number, cur->name);
254 else
255 pwarn("DUP PROPERTY LIST ENTRY FOUND I=%u NAME %0.10s",
256 idesc->id_number, cur->name);
257 if (preen)
258 printf(" (FIXED)\n");
259 else if (reply("FIX") == 0)
260 continue;
261 for (resid = cur->size; resid > 0;) {
262 bp = getdatablk(idesc->id_blkno, blksize);
263 pl_descp =
264 (struct proplist_desc1 *)(bp->b_un.b_buf + idesc->id_loc);
265 if (strcmp((char *)&pl_descp[1], cur->name)) {
266 bp->b_flags &= ~B_INUSE;
267 break;
268 }
269 if (idesc->id_loc) {
270 prev_pl_descp = (struct proplist_desc1 *)bp->b_un.b_buf;
271 for (offset = 0; offset < cur->offset;) {
272 prev_pl_descp =
273 (struct proplist_desc1 *)(bp->b_un.b_buf + offset);
274 offset += prev_pl_descp->pl_nextentry;
275 }
276 /*
277 * prev_pl_descp now points to the entry
278 * before the one we need to delete
279 *
280 * Coalesce into previous entry
281 */
282 prev_pl_descp->pl_nextentry += pl_descp->pl_nextentry;
283 prev_pl_descp->pl_nextfsb = pl_descp->pl_nextfsb;
284 }
285 resid -= pl_descp->pl_entrysize;
286 pl_descp->pl_entrysize = 0;
287 pl_descp->pl_namelen = 0;
288 pl_descp->pl_valuelen = 0;
289
290 next_blkno = pl_descp->pl_nextfsb;
291 free = prop_avail(bp, blksize);
292 dirty(bp);
293 if (free == blksize)
294 proplist_blkdel(dp, idesc, next_blkno);
295
296 if (next_blkno && resid > 0) {
297 idesc->id_blkno = next_blkno;
298 blksize = sblock.fs_bsize;
299 idesc->id_loc = 0;
300 continue;
301 }
302 break;
303 }
304 }
305 return (0);
306 }
307
308 int
309 prop_avail(bp, blksize)
310 struct bufarea *bp;
311 int blksize;
312 {
313 struct proplist_desc1 *pl_descp;
314 int offsetinbuf, total_avail;
315
316 total_avail = 0;
317 for (offsetinbuf = 0; offsetinbuf < blksize;) {
318 pl_descp = (struct proplist_desc1 *)(bp->b_un.b_buf + offsetinbuf);
319 total_avail += (pl_descp->pl_nextentry - pl_descp->pl_entrysize);
320 offsetinbuf += pl_descp->pl_nextentry;
321 }
322 return (total_avail);
323 }
324
325 int
326 proplist_chkblock(bp, blksize)
327 struct bufarea *bp;
328 int blksize;
329 {
330 struct proplist_desc1 *pl_descp;
331 int offsetinbuf;
332
333 for (offsetinbuf = 0; offsetinbuf < blksize;) {
334 pl_descp = (struct proplist_desc1 *)(bp->b_un.b_buf + offsetinbuf);
335 if (pl_descp->pl_magic != PROP_LIST_MAGIC_VERS1) {
336 return (1);
337 }
338 if (pl_descp->pl_entrysize % 8 || pl_descp->pl_nextentry % 8
339 || pl_descp->pl_nextentry < UFSPROPLIST_STRUCT
340 || pl_descp->pl_nextentry + offsetinbuf > blksize) {
341 return (1);
342 }
343 if (pl_descp->pl_entrysize
344 && (pl_descp->pl_namelen > PROPLIST_NAME_MAX
345 || pl_descp->pl_valuelen_entry > pl_descp->pl_valuelen
346 || pl_descp->pl_entrysize > pl_descp->pl_nextentry
347 || pl_descp->pl_entrysize !=
348 UFSPROPLIST_SIZE(pl_descp->pl_namelen,
349 pl_descp->pl_valuelen_entry)
350 || strlen((char *)&pl_descp[1]) > pl_descp->pl_namelen)) {
351 return (1);
352 }
353 offsetinbuf += pl_descp->pl_nextentry;
354 if (offsetinbuf == blksize) {
355 bp->b_flags &= ~B_INUSE;
356 break;
357 }
358 }
359 if (offsetinbuf != blksize) {
360 return (1);
361 }
362 return (0);
363 }
364
365
366 int
367 proplist_blkdel(dp, idesc, nextblk)
368 struct dinode *dp;
369 struct inodesc *idesc;
370 daddr_t nextblk;
371 {
372 struct proplist_desc1 *pl_descp;
373 struct bufarea *bp;
374 int blksize;
375 daddr_t badblkno;
376
377 badblkno = idesc->id_blkno;
378 if (dp->di_proplb == badblkno) {
379 dp = ginode(idesc->id_number);
380 dp->di_proplb = nextblk;
381 dp->di_flags &= ~IC_PROPLIST;
382 if (nextblk)
383 dp->di_flags |= IC_PROPLIST_BLOCK;
384 inodirty();
385 return (ALTERED);
386 }
387 idesc->id_blkno = dp->di_proplb;
388 if (dp->di_flags & IC_PROPLIST_FRAG) {
389 blksize = sblock.fs_fsize;
390 idesc->id_numfrags = 1;
391 } else {
392 blksize = sblock.fs_bsize;
393 idesc->id_numfrags = sblock.fs_frag;
394 }
395 bp = getdatablk(idesc->id_blkno, blksize);
396 idesc->id_loc = 0;
397 for (;;) {
398 pl_descp = (struct proplist_desc1 *)(bp->b_un.b_buf + idesc->id_loc);
399 if (pl_descp->pl_nextfsb > 0) {
400 daddr_t save_blkno;
401
402 if (pl_descp->pl_nextfsb == badblkno) {
403 pl_descp->pl_nextfsb = nextblk;
404 dirty(bp);
405 return (ALTERED);
406 }
407 save_blkno = pl_descp->pl_nextfsb;
408 bp->b_flags &= ~B_INUSE;
409 idesc->id_blkno = save_blkno;
410 idesc->id_numfrags = sblock.fs_frag;
411 blksize = sblock.fs_bsize;
412 bp = getdatablk(save_blkno, blksize);
413 idesc->id_loc = 0;
414 continue;
415 }
416 idesc->id_loc += pl_descp->pl_nextentry;
417 if (idesc->id_loc == blksize) {
418 bp->b_flags &= ~B_INUSE;
419 break;
420 }
421 }
422 return (SKIP);
423 }
424
425 #endif /* AFS_OSF_ENV */