+ newsize = DIRSIZ(&u.u_dent);
+ /*
+ * if u.u_count == 0, a new directory block must be allocated.
+ */
+ if (u.u_count == 0) {
+ u.u_dent.d_reclen = DIRBLKSIZ;
+ u.u_count = newsize;
+ u.u_base = (caddr_t)&u.u_dent;
+ writei(u.u_pdir);
+ iput(u.u_pdir);
+ return;
+ }
+ /*
+ * must read in an existing directory block
+ * to prepare to place the new entry into it.
+ */
+ fs = u.u_pdir->i_fs;
+ lbn = lblkno(fs, u.u_offset);
+ base = blkoff(fs, u.u_offset);
+ bn = fsbtodb(fs, bmap(u.u_pdir, lbn, B_WRITE, base + u.u_count));
+ if (u.u_offset + u.u_count > u.u_pdir->i_size)
+ u.u_pdir->i_size = u.u_offset + u.u_count;
+ bp = bread(u.u_pdir->i_dev, bn, blksize(fs, u.u_pdir, lbn));
+ if (bp->b_flags & B_ERROR) {
+ brelse(bp);
+ return;
+ }
+ dirbuf = bp->b_un.b_addr + base;
+ dp = (struct direct *)dirbuf;
+ dsize = DIRSIZ(dp);
+ spccnt = dp->d_reclen - dsize;
+ /*
+ * if there is insufficient room to make an entry at this point
+ * namei insures that compacting from u.u_offset for u.u_count
+ * bytes will provide the necessary space.
+ */
+ for (loc = dp->d_reclen; loc < u.u_count; ) {
+ ndp = (struct direct *)(dirbuf + loc);
+ if (dp->d_ino == 0) {
+ spccnt += dsize;
+ } else {
+ dp->d_reclen = dsize;
+ dp = (struct direct *)((char *)dp + dsize);
+ }
+ dsize = DIRSIZ(ndp);
+ spccnt += ndp->d_reclen - dsize;
+ loc += ndp->d_reclen;
+ bcopy(ndp, dp, dsize);
+ }
+ /*
+ * Update the pointer fields in the previous entry (if any),
+ * copy in the new entry, and write out the block.
+ */
+ if (dp->d_ino == 0) {
+ if (spccnt + dsize < newsize)
+ panic("wdir: compact failed");
+ u.u_dent.d_reclen = spccnt + dsize;
+ } else {
+ if (spccnt < newsize)
+ panic("wdir: compact failed");
+ u.u_dent.d_reclen = spccnt;
+ dp->d_reclen = dsize;
+ dp = (struct direct *)((char *)dp + dsize);
+ }
+ bcopy(&u.u_dent, dp, newsize);
+ bwrite(bp);
+ u.u_pdir->i_flag |= IUPD|ICHG;