ufs_lookup.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,062 行 · 第 1/3 页
C
1,062 行
/* * Common entry point for directory entry removal used by ufs_direnter * and ufs_whiteout */intufs_direnter2(dvp, dirp, cr, p) struct vnode *dvp; struct direct *dirp; struct ucred *cr; struct proc *p;{ int newentrysize; struct inode *dp; struct buf *bp; struct iovec aiov; struct uio auio; u_int dsize; struct direct *ep, *nep; int error, loc, spacefree; char *dirbuf; dp = VTOI(dvp); newentrysize = DIRSIZ(FSFMT(dvp), dirp); if (dp->i_count == 0) { /* * If dp->i_count is 0, then namei could find no * space in the directory. Here, dp->i_offset will * be on a directory block boundary and we will write the * new entry into a fresh block. */ if (dp->i_offset & (DIRBLKSIZ - 1)) panic("ufs_direnter2: newblk"); auio.uio_offset = dp->i_offset; dirp->d_reclen = DIRBLKSIZ; auio.uio_resid = newentrysize; aiov.iov_len = newentrysize; aiov.iov_base = (caddr_t)dirp; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_rw = UIO_WRITE; auio.uio_segflg = UIO_SYSSPACE; auio.uio_procp = (struct proc *)0; error = VOP_WRITE(dvp, &auio, IO_SYNC, cr); if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) /* XXX should grow with balloc() */ panic("ufs_direnter2: frag size"); else if (!error) { dp->i_size = roundup(dp->i_size, DIRBLKSIZ); dp->i_flag |= IN_CHANGE; } return (error); } /* * If dp->i_count is non-zero, then namei found space * for the new entry in the range dp->i_offset to * dp->i_offset + dp->i_count in the directory. * To use this space, we may have to compact the entries located * there, by copying them together towards the beginning of the * block, leaving the free space in one usable chunk at the end. */ /* * Increase size of directory if entry eats into new space. * This should never push the size past a new multiple of * DIRBLKSIZE. * * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. */ if (dp->i_offset + dp->i_count > dp->i_size) dp->i_size = dp->i_offset + dp->i_count; /* * Get the block containing the space for the new directory entry. */ error = VOP_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp); if (error) return (error); /* * Find space for the new entry. In the simple case, the entry at * offset base will have the space. If it does not, then namei * arranged that compacting the region dp->i_offset to * dp->i_offset + dp->i_count would yield the * space. */ ep = (struct direct *)dirbuf; dsize = DIRSIZ(FSFMT(dvp), ep); 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; } dsize = DIRSIZ(FSFMT(dvp), nep); spacefree += 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 || (ep->d_ino == WINO && bcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) { if (spacefree + dsize < newentrysize) panic("ufs_direnter2: compact1"); dirp->d_reclen = spacefree + dsize; } else { if (spacefree < newentrysize) panic("ufs_direnter2: compact2"); dirp->d_reclen = spacefree; ep->d_reclen = dsize; ep = (struct direct *)((char *)ep + dsize); } bcopy((caddr_t)dirp, (caddr_t)ep, (u_int)newentrysize); error = VOP_BWRITE(bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; if (!error && dp->i_endoff && dp->i_endoff < dp->i_size) error = VOP_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr, p); return (error);}/* * Remove a directory entry after a call to namei, using * the parameters which it left in nameidata. The entry * dp->i_offset contains the offset into the directory of the * entry to be eliminated. The dp->i_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 is not 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. */intufs_dirremove(dvp, cnp) struct vnode *dvp; struct componentname *cnp;{ register struct inode *dp; struct direct *ep; struct buf *bp; int error; dp = VTOI(dvp); if (cnp->cn_flags & DOWHITEOUT) { /* * Whiteout entry: set d_ino to WINO. */ error = VOP_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp); if (error) return (error); ep->d_ino = WINO; ep->d_type = DT_WHT; error = VOP_BWRITE(bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; return (error); } if (dp->i_count == 0) { /* * First entry in block: set d_ino to zero. */ error = VOP_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp); if (error) return (error); ep->d_ino = 0; error = VOP_BWRITE(bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; return (error); } /* * Collapse new free space into previous entry. */ error = VOP_BLKATOFF(dvp, (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp); if (error) return (error); ep->d_reclen += dp->i_reclen; error = VOP_BWRITE(bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; return (error);}/* * 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. */intufs_dirrewrite(dp, ip, cnp) struct inode *dp, *ip; struct componentname *cnp;{ struct buf *bp; struct direct *ep; struct vnode *vdp = ITOV(dp); int error; error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp); if (error) return (error); ep->d_ino = ip->i_number; if (vdp->v_mount->mnt_maxsymlinklen > 0) ep->d_type = IFTODT(ip->i_mode); error = VOP_BWRITE(bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; return (error);}/* * Check if a directory is empty or not. * Inode supplied must be locked. * * Using a struct dirtemplate here is not precisely * what we want, but better than using a struct direct. * * NB: does not handle corrupted directories. */intufs_dirempty(ip, parentino, cred) register struct inode *ip; ino_t parentino; struct ucred *cred;{ register off_t off; struct dirtemplate dbuf; register struct direct *dp = (struct direct *)&dbuf; int error, count, namlen;#define MINDIRSIZ (sizeof (struct dirtemplate) / 2) for (off = 0; off < ip->i_size; off += dp->d_reclen) { error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off, UIO_SYSSPACE, IO_NODELOCKED, cred, &count, (struct proc *)0); /* * Since we read MINDIRSIZ, residual must * be 0 unless we're at end of file. */ if (error || count != 0) return (0); /* avoid infinite loops */ if (dp->d_reclen == 0) return (0); /* skip empty entries */ if (dp->d_ino == 0 || dp->d_ino == WINO) continue; /* accept only "." and ".." */# if (BYTE_ORDER == LITTLE_ENDIAN) if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0) namlen = dp->d_namlen; else namlen = dp->d_type;# else namlen = dp->d_namlen;# endif if (namlen > 2) return (0); if (dp->d_name[0] != '.') return (0); /* * At this point namlen must be 1 or 2. * 1 implies ".", 2 implies ".." if second * char is also "." */ if (namlen == 1) continue; if (dp->d_name[1] == '.' && dp->d_ino == parentino) continue; return (0); } return (1);}/* * Check if source directory is in the path of the target directory. * Target is supplied locked, source is unlocked. * The target is always vput before returning. */intufs_checkpath(source, target, cred) struct inode *source, *target; struct ucred *cred;{ struct vnode *vp; int error, rootino, namlen; struct dirtemplate dirbuf; vp = ITOV(target); if (target->i_number == source->i_number) { error = EEXIST; goto out; } rootino = ROOTINO; error = 0; if (target->i_number == rootino) goto out; for (;;) { if (vp->v_type != VDIR) { error = ENOTDIR; break; } error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, IO_NODELOCKED, cred, (int *)0, (struct proc *)0); if (error != 0) break;# if (BYTE_ORDER == LITTLE_ENDIAN) if (vp->v_mount->mnt_maxsymlinklen > 0) namlen = dirbuf.dotdot_namlen; else namlen = dirbuf.dotdot_type;# else namlen = dirbuf.dotdot_namlen;# endif if (namlen != 2 || dirbuf.dotdot_name[0] != '.' || dirbuf.dotdot_name[1] != '.') { error = ENOTDIR; break; } if (dirbuf.dotdot_ino == source->i_number) { error = EINVAL; break; } if (dirbuf.dotdot_ino == rootino) break; vput(vp); error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, &vp); if (error) { vp = NULL; break; } }out: if (error == ENOTDIR) printf("checkpath: .. not a directory\n"); if (vp != NULL) vput(vp); return (error);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?