/* * Copyright 2000, International Business Machines Corporation and others. * All Rights Reserved. * * This software has been released under the terms of the IBM Public * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ #include #include #include #define VICE /* control whether AFS changes are present */ #ifdef AFS_OSF_ENV #include #include #include #include #include #include #define _BSD #define _KERNEL #include #undef _KERNEL #undef _BSD #include #include "fsck.h" struct prop_entry_desc { struct prop_entry_desc *next; int flags; #define PROP_ENTRY_BAD 0x1 #define PROP_ENTRY_DUP 0x2 daddr_t blkno; int blksize; long offset; long size; char name[PROPLIST_NAME_MAX]; }; int proplist_scan(dp, idesc) struct dinode *dp; struct inodesc *idesc; { struct proplist_desc1 *pl_descp; struct bufarea *bp; struct dinode *ndp; long code; int offsetinbuf, blksize; struct prop_entry_desc *entry_list, *next; code = proplist_blkscan(dp, idesc, &entry_list); if (code & STOP) goto out; proplist_markdup(entry_list); code = proplist_updateblks(dp, idesc, entry_list); if (code & STOP) goto out; ndp = ginode(idesc->id_number); if ((ndp->di_flags & IC_PROPLIST) == 0) { code = 0; goto out; } if ((ndp->di_flags & (IC_PROPLIST_BLOCK | IC_PROPLIST_FRAG)) == (IC_PROPLIST_BLOCK | IC_PROPLIST_FRAG)) { code = 0; goto out; } if (ndp->di_flags & IC_PROPLIST_FRAG) { idesc->id_numfrags = 1; blksize = sblock.fs_fsize; } else { idesc->id_numfrags = sblock.fs_frag; blksize = sblock.fs_bsize; } idesc->id_blkno = ndp->di_proplb; for (;;) { code = (*idesc->id_func) (idesc); if (code & STOP) goto out; bp = getdatablk(idesc->id_blkno, blksize); for (offsetinbuf = 0; offsetinbuf < blksize;) { pl_descp = (struct proplist_desc1 *)(bp->b_un.b_buf + offsetinbuf); offsetinbuf += pl_descp->pl_nextentry; } if (pl_descp->pl_nextfsb > 0) { daddr_t save_blkno; save_blkno = pl_descp->pl_nextfsb; bp->b_flags &= ~B_INUSE; idesc->id_blkno = save_blkno; blksize = sblock.fs_bsize; idesc->id_numfrags = sblock.fs_frag; continue; } bp->b_flags &= ~B_INUSE; break; } out: for (next = entry_list; entry_list != NULL;) { next = entry_list->next; free(entry_list); entry_list = next; } return (code); } int proplist_blkscan(dp, idesc, entry_list) struct dinode *dp; struct inodesc *idesc; struct prop_entry_desc **entry_list; { struct proplist_desc1 *pl_descp; struct bufarea *bp; struct prop_entry_desc *entry, *lastentry; int blksize; long code, valueresid; *entry_list = NULL; idesc->id_blkno = dp->di_proplb; if (dp->di_flags & IC_PROPLIST_FRAG) { blksize = sblock.fs_fsize; idesc->id_numfrags = 1; } else { blksize = sblock.fs_bsize; idesc->id_numfrags = sblock.fs_frag; } idesc->id_loc = 0; valueresid = 0; for (;;) { if (idesc->id_loc == 0) { if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { code = proplist_blkdel(dp, idesc, 0); return (code); } bp = getdatablk(idesc->id_blkno, blksize); if (proplist_chkblock(bp, blksize)) { bp->b_flags &= ~B_INUSE; pwarn("PROPERTY LIST BLOCK CORRUPTED I=%u", idesc->id_number); if (preen) printf(" (CLEARED)\n"); else if (reply("CLEAR") == 0) return (SKIP); code = proplist_blkdel(dp, idesc, 0); return (code); } } pl_descp = (struct proplist_desc1 *)(bp->b_un.b_buf + idesc->id_loc); if (pl_descp->pl_entrysize) { if (valueresid < 0 || (valueresid && strcmp((char *)&pl_descp[1], entry->name))) { entry->flags |= PROP_ENTRY_BAD; valueresid = 0; } if (valueresid == 0) { entry = malloc(sizeof(struct prop_entry_desc)); if (entry == NULL) return (SKIP); entry->next = NULL; entry->flags = 0; memcpy(entry->name, (char *)&pl_descp[1], pl_descp->pl_namelen); entry->blkno = idesc->id_blkno; entry->blksize = blksize; entry->offset = idesc->id_loc; entry->size = 0; if (*entry_list != NULL) lastentry->next = entry; else *entry_list = entry; lastentry = entry; valueresid = pl_descp->pl_valuelen; } entry->size += pl_descp->pl_entrysize; valueresid -= pl_descp->pl_valuelen_entry; } if (pl_descp->pl_nextfsb > 0) { daddr_t save_blkno; save_blkno = pl_descp->pl_nextfsb; bp->b_flags &= ~B_INUSE; idesc->id_blkno = save_blkno; idesc->id_numfrags = sblock.fs_frag; blksize = sblock.fs_bsize; idesc->id_loc = 0; continue; } idesc->id_loc += pl_descp->pl_nextentry; if (idesc->id_loc == blksize) { bp->b_flags &= ~B_INUSE; if (valueresid) { entry->flags |= PROP_ENTRY_BAD; } break; } } return (0); } int proplist_markdup(entry_list) struct prop_entry_desc *entry_list; { struct prop_entry_desc *start, *cur; int bad_entries, dup_entries; for (start = entry_list; start != NULL; start = start->next) { if (start->flags & (PROP_ENTRY_BAD | PROP_ENTRY_DUP)) continue; for (cur = start->next; cur != NULL; cur = cur->next) { if (!strcmp(start->name, cur->name)) cur->flags |= PROP_ENTRY_DUP; } } return (0); } int proplist_updateblks(dp, idesc, entry_list) struct dinode *dp; struct inodesc *idesc; struct prop_entry_desc *entry_list; { struct proplist_desc1 *pl_descp, *prev_pl_descp; struct bufarea *bp; struct prop_entry_desc *cur; long code; daddr_t next_blkno; int resid, offset, free, blksize; for (cur = entry_list; cur != NULL; cur = cur->next) { if (cur->flags == 0) continue; idesc->id_blkno = cur->blkno; idesc->id_loc = cur->offset; blksize = cur->blksize; if (cur->flags & PROP_ENTRY_BAD) pwarn("BAD PROPERTY LIST ENTRY FOUND I=%u NAME %0.10s", idesc->id_number, cur->name); else pwarn("DUP PROPERTY LIST ENTRY FOUND I=%u NAME %0.10s", idesc->id_number, cur->name); if (preen) printf(" (FIXED)\n"); else if (reply("FIX") == 0) continue; for (resid = cur->size; resid > 0;) { bp = getdatablk(idesc->id_blkno, blksize); pl_descp = (struct proplist_desc1 *)(bp->b_un.b_buf + idesc->id_loc); if (strcmp((char *)&pl_descp[1], cur->name)) { bp->b_flags &= ~B_INUSE; break; } if (idesc->id_loc) { prev_pl_descp = (struct proplist_desc1 *)bp->b_un.b_buf; for (offset = 0; offset < cur->offset;) { prev_pl_descp = (struct proplist_desc1 *)(bp->b_un.b_buf + offset); offset += prev_pl_descp->pl_nextentry; } /* * prev_pl_descp now points to the entry * before the one we need to delete * * Coalesce into previous entry */ prev_pl_descp->pl_nextentry += pl_descp->pl_nextentry; prev_pl_descp->pl_nextfsb = pl_descp->pl_nextfsb; } resid -= pl_descp->pl_entrysize; pl_descp->pl_entrysize = 0; pl_descp->pl_namelen = 0; pl_descp->pl_valuelen = 0; next_blkno = pl_descp->pl_nextfsb; free = prop_avail(bp, blksize); dirty(bp); if (free == blksize) proplist_blkdel(dp, idesc, next_blkno); if (next_blkno && resid > 0) { idesc->id_blkno = next_blkno; blksize = sblock.fs_bsize; idesc->id_loc = 0; continue; } break; } } return (0); } int prop_avail(bp, blksize) struct bufarea *bp; int blksize; { struct proplist_desc1 *pl_descp; int offsetinbuf, total_avail; total_avail = 0; for (offsetinbuf = 0; offsetinbuf < blksize;) { pl_descp = (struct proplist_desc1 *)(bp->b_un.b_buf + offsetinbuf); total_avail += (pl_descp->pl_nextentry - pl_descp->pl_entrysize); offsetinbuf += pl_descp->pl_nextentry; } return (total_avail); } int proplist_chkblock(bp, blksize) struct bufarea *bp; int blksize; { struct proplist_desc1 *pl_descp; int offsetinbuf; for (offsetinbuf = 0; offsetinbuf < blksize;) { pl_descp = (struct proplist_desc1 *)(bp->b_un.b_buf + offsetinbuf); if (pl_descp->pl_magic != PROP_LIST_MAGIC_VERS1) { return (1); } if (pl_descp->pl_entrysize % 8 || pl_descp->pl_nextentry % 8 || pl_descp->pl_nextentry < UFSPROPLIST_STRUCT || pl_descp->pl_nextentry + offsetinbuf > blksize) { return (1); } if (pl_descp->pl_entrysize && (pl_descp->pl_namelen > PROPLIST_NAME_MAX || pl_descp->pl_valuelen_entry > pl_descp->pl_valuelen || pl_descp->pl_entrysize > pl_descp->pl_nextentry || pl_descp->pl_entrysize != UFSPROPLIST_SIZE(pl_descp->pl_namelen, pl_descp->pl_valuelen_entry) || strlen((char *)&pl_descp[1]) > pl_descp->pl_namelen)) { return (1); } offsetinbuf += pl_descp->pl_nextentry; if (offsetinbuf == blksize) { bp->b_flags &= ~B_INUSE; break; } } if (offsetinbuf != blksize) { return (1); } return (0); } int proplist_blkdel(dp, idesc, nextblk) struct dinode *dp; struct inodesc *idesc; daddr_t nextblk; { struct proplist_desc1 *pl_descp; struct bufarea *bp; int blksize; daddr_t badblkno; badblkno = idesc->id_blkno; if (dp->di_proplb == badblkno) { dp = ginode(idesc->id_number); dp->di_proplb = nextblk; dp->di_flags &= ~IC_PROPLIST; if (nextblk) dp->di_flags |= IC_PROPLIST_BLOCK; inodirty(); return (ALTERED); } idesc->id_blkno = dp->di_proplb; if (dp->di_flags & IC_PROPLIST_FRAG) { blksize = sblock.fs_fsize; idesc->id_numfrags = 1; } else { blksize = sblock.fs_bsize; idesc->id_numfrags = sblock.fs_frag; } bp = getdatablk(idesc->id_blkno, blksize); idesc->id_loc = 0; for (;;) { pl_descp = (struct proplist_desc1 *)(bp->b_un.b_buf + idesc->id_loc); if (pl_descp->pl_nextfsb > 0) { daddr_t save_blkno; if (pl_descp->pl_nextfsb == badblkno) { pl_descp->pl_nextfsb = nextblk; dirty(bp); return (ALTERED); } save_blkno = pl_descp->pl_nextfsb; bp->b_flags &= ~B_INUSE; idesc->id_blkno = save_blkno; idesc->id_numfrags = sblock.fs_frag; blksize = sblock.fs_bsize; bp = getdatablk(save_blkno, blksize); idesc->id_loc = 0; continue; } idesc->id_loc += pl_descp->pl_nextentry; if (idesc->id_loc == blksize) { bp->b_flags &= ~B_INUSE; break; } } return (SKIP); } #endif /* AFS_OSF_ENV */