- bcopy((caddr_t)ep, (caddr_t)&u.u_dent, sizeof(struct direct));
- if(bp != NULL)
- brelse(bp);
- if(flag==2 && c=='\0') {
- if(access(dp, IWRITE))
- goto out;
- return(dp);
- }
- d = dp->i_dev;
- if(u.u_dent.d_ino == ROOTINO)
- if(dp->i_number == ROOTINO)
- if(u.u_dent.d_name[1] == '.')
- for(i=1; i<NMOUNT; i++)
- if(mount[i].m_bufp != NULL)
- if(mount[i].m_dev == d) {
- iput(dp);
- dp = mount[i].m_inodp;
- dp->i_count++;
- plock(dp);
- goto seloop;
- }
- iput(dp);
- dp = iget(d, u.u_dent.d_ino);
- if(dp == NULL)
- return(NULL);
- goto cloop;
+ ep = (struct direct *)dirbuf;
+ dsize = DIRSIZ(ep);
+ freespace = ep->d_reclen - dsize;
+ for (loc = ep->d_reclen; loc < u.u_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 */
+ freespace += dsize;
+ }
+ dsize = DIRSIZ(nep);
+ freespace += nep->d_reclen - dsize;
+ loc += nep->d_reclen;
+ bcopy((caddr_t)nep, (caddr_t)ep, dsize);
+ }
+ /*
+ * Update the pointer fields in the previous entry (if any),
+ * copy in the new entry, and write out the block.
+ */
+ if (ep->d_ino == 0) {
+ if (freespace + dsize < newentrysize)
+ panic("wdir: compact1");
+ u.u_dent.d_reclen = freespace + dsize;
+ } else {
+ if (freespace < newentrysize)
+ panic("wdir: compact2");
+ u.u_dent.d_reclen = freespace;
+ ep->d_reclen = dsize;
+ ep = (struct direct *)((char *)ep + dsize);
+ }
+ bcopy((caddr_t)&u.u_dent, (caddr_t)ep, (u_int)newentrysize);
+ bwrite(bp);
+ u.u_pdir->i_flag |= IUPD|ICHG;
+ iput(u.u_pdir);
+ return (error);
+}
+
+/*
+ * Remove a directory entry after a call to namei, using the
+ * parameters which it left in the u. area. The u. entry
+ * u_offset contains the offset into the directory of the
+ * entry to be eliminated. The u_count field contains the
+ * size of the previous record in the directory. If this
+ * is 0, the first entry is being deleted, so we need only
+ * zero the inode number to mark the entry as free. If the
+ * entry isn't the first in the directory, we must reclaim
+ * the space of the now empty record by adding the record size
+ * to the size of the previous entry.
+ */
+dirremove()
+{
+ register struct inode *dp = u.u_pdir;
+ register struct buf *bp;
+ struct direct *ep;
+
+ if (u.u_count == 0) {
+ /*
+ * First entry in block: set d_ino to zero.
+ */
+ u.u_dent.d_ino = 0;
+ (void) rdwri(UIO_WRITE, dp, (caddr_t)&u.u_dent,
+ (int)DIRSIZ(&u.u_dent), u.u_offset, 1, (int *)0);
+ } else {
+ /*
+ * Collapse new free space into previous entry.
+ */
+ bp = blkatoff(dp, (int)(u.u_offset - u.u_count), (char **)&ep);
+ if (bp == 0)
+ return (0);
+ ep->d_reclen += u.u_dent.d_reclen;
+ bwrite(bp);
+ dp->i_flag |= IUPD|ICHG;
+ }
+ return (1);
+}
+
+/*
+ * Rewrite an existing directory entry to point at the inode
+ * supplied. The parameters describing the directory entry are
+ * set up by a call to namei.
+ */
+dirrewrite(dp, ip)
+ struct inode *dp, *ip;
+{