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