venus: fix memory leak
[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 */