diff options
author | Ted Unangst <tedu@cvs.openbsd.org> | 2004-04-16 22:41:51 +0000 |
---|---|---|
committer | Ted Unangst <tedu@cvs.openbsd.org> | 2004-04-16 22:41:51 +0000 |
commit | aae057ae37a105bb20cfa4cc5c837f48a1d42aef (patch) | |
tree | 99784f8fe5e9f709710d9b0cd4f503b24747b15d /sys | |
parent | e035055229a8d39c664af93893868ce56b6b35f3 (diff) |
fix niklas's panic and pr3672 with freebsd rev 1.54 (don't trust DIRSIZ)
extra testing otto@ sturm@ tdeval@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/ufs/ufs/ufs_lookup.c | 37 |
1 files changed, 27 insertions, 10 deletions
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index 0b05f1dd2ef..9358b73429d 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ufs_lookup.c,v 1.25 2004/01/09 03:01:03 tedu Exp $ */ +/* $OpenBSD: ufs_lookup.c,v 1.26 2004/04/16 22:41:50 tedu Exp $ */ /* $NetBSD: ufs_lookup.c,v 1.7 1996/02/09 22:36:06 christos Exp $ */ /* @@ -855,21 +855,33 @@ ufs_direnter(dvp, tvp, dirp, cnp, newdirbp) * dp->i_offset + dp->i_count would yield the space. */ ep = (struct direct *)dirbuf; - dsize = DIRSIZ(FSFMT(dvp), ep); + dsize = ep->d_ino ? DIRSIZ(FSFMT(dvp), ep) : 0; spacefree = ep->d_reclen - dsize; for (loc = ep->d_reclen; loc < dp->i_count; ) { nep = (struct direct *)(dirbuf + loc); - if (ep->d_ino) { - /* trim the existing slot */ - ep->d_reclen = dsize; - ep = (struct direct *)((char *)ep + dsize); - } else { - /* overwrite; nothing there; header is ours */ - spacefree += dsize; + + /* Trim the existing slot (NB: dsize may be zero). */ + ep->d_reclen = dsize; + ep = (struct direct *)((char *)ep + dsize); + + /* Read nep->d_reclen now as the bcopy() may clobber it. */ + loc += nep->d_reclen; + if (nep->d_ino == 0) { + /* + * A mid-block unused entry. Such entries are + * never created by the kernel, but fsck_ffs + * can create them (and it doesn't fix them). + * + * Add up the free space, and initialise the + * relocated entry since we don't bcopy it. + */ + spacefree += nep->d_reclen; + ep->d_ino = 0; + dsize = 0; + continue; } dsize = DIRSIZ(FSFMT(dvp), nep); spacefree += nep->d_reclen - dsize; - loc += nep->d_reclen; #ifdef UFS_DIRHASH if (dp->i_dirhash != NULL) ufsdirhash_move(dp, nep, @@ -883,6 +895,11 @@ ufs_direnter(dvp, tvp, dirp, cnp, newdirbp) bcopy((caddr_t)nep, (caddr_t)ep, dsize); } /* + * Here, `ep' points to a directory entry containing `dsize' in-use + * bytes followed by `spacefree' unused bytes. If ep->d_ino == 0, + * then the entry is completely unused (dsize == 0). The value + * of ep->d_reclen is always indeterminate. + * * Update the pointer fields in the previous entry (if any), * copy in the new entry, and write out the block. */ |