Remove pseudocode from VOP_* manual pages. It was out of date anyway.

Reviewed by:	scottl
Approved by:	rwatson (mentor)
This commit is contained in:
Edward Tomasz Napierala 2009-03-30 20:56:37 +00:00
parent 584f7327f1
commit 6283502e20
16 changed files with 0 additions and 1075 deletions

View File

@ -68,40 +68,6 @@ The vnode will be locked on entry and should remain locked on return.
.Sh RETURN VALUES
If the file is accessible in the specified way, then zero is returned,
otherwise an appropriate error code is returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_access(struct vnode *vp, accmode_t accmode, struct ucred *cred, struct thread *td)
{
int error;
/*
* Disallow write attempts on read-only file systems;
* unless the file is a socket, fifo, or a block or
* character device resident on the filesystem.
*/
if (accmode & VWRITE) {
switch (vp->v_type) {
case VDIR:
case VLNK:
case VREG:
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return EROFS;
break;
}
}
/* If immutable bit set, nobody gets to write it. */
if ((accmode & VWRITE) && vp has immutable bit set)
return (EPERM);
error = vaccess(vp->v_type, mode of vp, owner of vp,
group of vp, ap->a_accmode, ap->a_cred, NULL);
return (error);
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EPERM

View File

@ -84,68 +84,6 @@ otherwise an appropriate error is returned.
.Fn VOP_SETATTR
returns zero if the attributes were changed successfully, otherwise an
appropriate error is returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_getattr(struct vnode *vp, struct vattr *vap, struct ucred *cred)
{
/*
* Fill in the contents of *vap with information from
* the file system.
*/
...;
return 0;
}
int
vop_setattr(struct vnode *vp, struct vattr *vap, struct ucred *cred)
{
/*
* Check for unsettable attributes.
*/
if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
(vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
(vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
return (EINVAL);
}
if (vap->va_flags != VNOVAL) {
/*
* Set the immutable and append flags of the file.
*/
}
if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
/*
* Change owner and/or group of the file.
*/
}
if (vap->va_size != VNOVAL) {
/*
* Truncate the file to the specified size.
*/
}
if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
/*
* Change access and/or modification time of file.
*/
}
if (vap->va_mode != (mode_t)VNOVAL) {
/*
* Change permissions of file.
*/
}
return 0;
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EPERM

View File

@ -80,67 +80,6 @@ If successful, the vnode for the new object is placed in
.Fa *vpp
and zero is returned.
Otherwise, an appropriate error is returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_create(struct vnode *dvp,
struct vnode **vpp,
struct componentname *cnp
struct vattr *vap)
{
int mode = MAKEIMODE(vap->va_type, vap->va_mode);
struct vnode *vp;
int error;
*vpp = NULL;
if ((mode & IFMT) == 0)
mode |= IFREG;
error = SOMEFS_VALLOC(dvp, mode, cnp->cn_cred, &vp);
if (error)
return error;
/*
* Update the permissions for the new vnode, including
* copying the group from the directory.
*/
...;
#ifdef QUOTA
/*
* Possibly check quota information.
*/
...;
#endif
/*
* Enter new vnode in directory, taking care that the vnode
* hits the disk before the directory contents are changed.
*/
error = ...;
if (error)
goto bad;
*vpp = vp;
return 0;
bad:
/*
* Write error occurred trying to update the inode
* or the directory so must deallocate the inode.
*/
vput(vp);
/*
* Deallocate file system resources for vp.
*/
...;
return error;
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er ENOSPC

View File

@ -79,61 +79,6 @@ The file should be locked on entry.
.Sh RETURN VALUES
Zero is returned if the call is successful, otherwise an appropriate
error code is returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_fsync(struct vnode *vp, int waitfor, struct thread *td)
{
struct buf *bp;
struct buf *nbp;
struct timeval tv;
int s;
loop:
s = splbio();
for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
nbp = bp->b_vnbufs.le_next;
/*
* Ignore buffers which are already being written.
*/
if (bp->b_flags & B_BUSY)
continue;
/*
* Make sure the buffer is dirty.
*/
if ((bp->b_flags & B_DELWRI) == 0)
panic("vop_fsync: not dirty");
vfs_bio_awrite(bp);
splx(s);
goto loop;
}
splx(s);
if (waitfor == MNT_WAIT) {
s = splbio();
while (vp->v_numoutput) {
vp->v_flag |= VBWAIT;
tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "vopfsn");
}
splx(s);
#ifdef DIAGNOSTIC
if (vp->v_dirtyblkhd.lh_first) {
vprint("vop_fsync: dirty", vp);
goto loop;
}
#endif
}
/*
* Write out the on-disc version of the vnode.
*/
tv = time;
return VOP_UPDATE(vp, &tv, &tv, waitfor == MNT_WAIT);
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er ENOSPC

View File

@ -74,38 +74,6 @@ prior to returning.
For VOP_RECLAIM, the
.Fa vp
will not be locked on entry and should be left unlocked on return.
.Sh PSEUDOCODE
.Bd -literal
int
vop_inactive(struct vnode *vp, struct thread *td)
{
if (link count of vp == 0) {
/*
* Reclaim space in file system for vp.
*/
...;
}
VOP_UNLOCK(vp, 0, td);
return 0;
}
int
vop_reclaim(struct vnode *vp, struct thread *td)
{
/*
* Clean out the name cache.
*/
cache_purge(vp);
/*
* Free file system related data.
*/
...;
return 0;
}
.Ed
.Sh SEE ALSO
.Xr vnode 9
.Sh AUTHORS

View File

@ -67,16 +67,6 @@ If successful, zero is returned, otherwise an appropriate error code.
If the ioctl is not recognized or not handled,
.Er ENOTTY
should be returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_ioctl(struct vnode *vp, int command, caddr_t data, int fflag,
struct ucred *cred, struct thread *td)
{
return ENOTTY;
}
.Ed
.Sh SEE ALSO
.Xr vnode 9
.Sh AUTHORS

View File

@ -66,37 +66,6 @@ the vnodes locked on return.
.Sh RETURN VALUES
Zero is returned if the file was linked successfully, otherwise an
error is returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_link(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
{
int error = 0;
if (vp->v_mount != dvp->v_mount)
return (EXDEV);
if (vp would have too many links)
return (EMLINK);
if (vp is immutable)
return (EPERM);
/*
* Increment link count of vp and write back the on-disc version of it.
*/
...;
if (!error) {
/*
* Add the new name to the directory.
*/
...;
}
return error;
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EMLINK

View File

@ -116,72 +116,6 @@ also does not want a thread specified as argument but it
assumes curthread to be used.
.Sh RETURN VALUES
Zero is returned on success, otherwise an error is returned.
.Sh PSEUDOCODE
.Bd -literal
struct vopnode {
int von_flag;
/*
* Other file system specific data.
*/
...;
};
#define VON_LOCKED 1
#define VON_WANTED 2
#define VTOVON(vp) ((struct vopnode *) (vp)->v_data)
int
vop_lock(struct vnode *vp)
{
struct vopnode* vop;
start:
while (vp->v_flag & VXLOCK) {
vp->v_flag |= VXWANT;
tsleep((caddr_t)vp, PINOD, "voplk1", 0);
}
if (vp->v_tag == VT_NON)
return ENOENT;
vop = VTOVON(vp);
if (vop->von_flag & VON_LOCKED) {
vop->von_flag |= VON_WANTED;
tsleep((caddr_t) vop, PINOD, "voplk2", 0);
goto start;
}
vop->von_flag |= VON_LOCKED;
return 0;
}
int
vop_unlock(struct vnode *vp)
{
struct vopnode *vop = VTOVON(vp);
if ((vop->von_flag & VON_LOCKED) == 0) {
panic("vop_unlock not locked");
}
vop->von_flag &= ~VON_LOCKED;
if (vop->von_flag & VON_WANTED) {
vop->von_flag &= ~VON_WANTED;
wakeup((caddr_t) vop);
}
return 0;
}
int
vop_islocked(struct vnode *vp)
{
struct vopnode *vop = VTOVON(vp);
if (vop->von_flag & VON_LOCKED)
return 1;
else
return 0;
}
.Ed
.Sh SEE ALSO
.Xr vnode 9
.Sh AUTHORS

View File

@ -156,260 +156,6 @@ is specified and the operation would succeed, the special return value
.Er EJUSTRETURN
is returned.
Otherwise, an appropriate error code is returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_lookup(struct vnode *dvp,
struct vnode **vpp,
struct componentname *cnp)
{
int error;
int nameiop = cnp->cn_nameiop;
int flags = cnp->cn_flags;
int lockparent = flags & LOCKPARENT;
int islastcn = flags & ISLASTCN;
struct vnode *vp = NULL;
/*
* Check accessibility of directory.
*/
if (dvp->v_type != VDIR)
return ENOTDIR;
error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_thread);
if (error)
return (error);
if (islastcn && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
(cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
return (EROFS);
/*
* Check name cache for directory/name pair. This returns ENOENT
* if the name is known not to exist, -1 if the name was found, or
* zero if not.
*/
error = cache_lookup(dvp, vpp, cnp);
if (error) {
int vpid;
if (error = ENOENT)
return error;
vp = *vpp;
if (dvp == vp) { /* lookup on "." */
VREF(vp);
error = 0;
} else if (flags & ISDOTDOT) {
/*
* We need to unlock the directory before getting
* the locked vnode for ".." to avoid deadlocks.
*/
VOP_UNLOCK(dvp);
error = vget(vp, 1);
if (!error) {
if (lockparent && islastcn)
error = VOP_LOCK(dvp);
}
} else {
error = vget(vp, 1);
if (error || !(lockparent && islastcn)) {
VOP_UNLOCK(dvp);
}
}
/*
* Check that the capability number did not change
* while we were waiting for the lock.
*/
if (!error) {
if (vpid == vp->v_id) {
/*
* dvp is locked if lockparent && islastcn.
* vp is locked.
*/
return (0);
}
vput(vp);
if (dvp != vp && lockparent && islastcn)
VOP_UNLOCK(pdp);
}
/*
* Re-lock dvp for the directory search below.
*/
error = VOP_LOCK(dvp);
if (error) {
return (error);
}
*vpp = NULL;
}
/*
* Search dvp for the component cnp->cn_nameptr.
*/
...;
if (!found) {
if ((nameiop == CREATE || nameiop == RENAME)
&& islastcn
&& directory dvp has not been removed) {
/*
* Check for write access on directory.
*/
/*
* Possibly record the position of a slot in the directory
* large enough for the new component name. This can be
* recorded in the vnode private data for dvp.
* Set the SAVENAME flag to hold onto the pathname for use
* later in VOP_CREATE or VOP_RENAME.
*/
cnp->cn_flags |= SAVENAME;
if (!lockparent)
/*
* Note that the extra data recorded above is only
* useful if lockparent is specified.
*/
VOP_UNLOCK(dvp);
return EJUSTRETURN;
}
/*
* Consider inserting name into cache.
*/
if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
cache_enter(dvp, NULL, cnp);
return ENOENT;
} else {
/*
* If deleting, and at end of pathname, return parameters
* which can be used to remove file. If the wantparent flag
* isn't set, we return only the directory, otherwise we go on
* and lock the inode, being careful with ".".
*/
if (nameiop == DELETE && islastcn) {
/*
* Check for write access on directory.
*/
error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_thread);
if (error)
return (error);
if (found entry is same as dvp) {
VREF(dvp);
*vpp = dvp;
return 0;
}
error = VFS_VGET(dvp->v_mount, ..., &vp);
if (error)
return error;
if (directory is sticky
&& cred->cr_uid != 0
&& cred->cr_uid != owner of dvp
&& owner of vp != cred->cr_uid) {
vput(vp);
return EPERM;
}
*vpp = vp;
if (!lockparent)
VOP_UNLOCK(dvp);
return 0;
}
/*
* If rewriting (RENAME), return the inode and the
* information required to rewrite the present directory
* Must get inode of directory entry to verify it's a
* regular file, or empty directory.
*/
if (nameiop == RENAME && wantparent && islastcn) {
error = VOP_ACCESS(dvp, VWRITE, cred, cnp->cn_thread);
if (error)
return (error);
/*
* Check for "."
*/
if (found entry is same as dvp)
return EISDIR;
error = VFS_VGET(dvp->v_mount, ..., &vp);
if (error)
return error;
*vpp = vp;
/*
* Save the name for use in VOP_RENAME later.
*/
cnp->cn_flags |= SAVENAME;
if (!lockparent)
VOP_UNLOCK(dvp);
return 0;
}
/*
* Step through the translation in the name. We do not `vput' the
* directory because we may need it again if a symbolic link
* is relative to the current directory. Instead we save it
* unlocked as "pdp". We must get the target inode before unlocking
* the directory to insure that the inode will not be removed
* before we get it. We prevent deadlock by always fetching
* inodes from the root, moving down the directory tree. Thus
* when following backward pointers ".." we must unlock the
* parent directory before getting the requested directory.
* There is a potential race condition here if both the current
* and parent directories are removed before the VFS_VGET for the
* inode associated with ".." returns. We hope that this occurs
* infrequently since we cannot avoid this race condition without
* implementing a sophisticated deadlock detection algorithm.
* Note also that this simple deadlock detection scheme will not
* work if the file system has any hard links other than ".."
* that point backwards in the directory structure.
*/
if (flags & ISDOTDOT) {
VOP_UNLOCK(dvp); /* race to get the inode */
error = VFS_VGET(dvp->v_mount, ..., &vp);
if (error) {
VOP_LOCK(dvp);
return (error);
}
if (lockparent && islastcn) {
error = VOP_LOCK(dvp);
if (error) {
vput(vp);
return error;
}
}
*vpp = vp;
} else if (found entry is same as dvp) {
VREF(dvp); /* we want ourself, ie "." */
*vpp = dvp;
} else {
error = VFS_VGET(dvp->v_mount, ..., &vp);
if (error)
return (error);
if (!lockparent || !islastcn)
VOP_UNLOCK(dvp);
*vpp = vp;
}
/*
* Insert name into cache if appropriate.
*/
if (cnp->cn_flags & MAKEENTRY)
cache_enter(dvp, *vpp, cnp);
return (0);
}
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er ENOTDIR

View File

@ -94,18 +94,6 @@ expects an unlocked, referenced vnode and will dereference the vnode prior
to returning.
.Sh RETURN VALUES
Zero is returned on success, otherwise an error code is returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_open(struct vnode *vp, int mode, struct ucred *cred, struct thread *td,
struct file *fp)
{
/*
* Most file systems don't do much here.
*/
return 0;
}
.Ed
.Sh SEE ALSO
.Xr vnode 9 ,
.Xr VOP_LOOKUP 9

View File

@ -85,141 +85,6 @@ Data already in VMIO space.
The file should be locked on entry and will still be locked on exit.
.Sh RETURN VALUES
Zero is returned on success, otherwise an error code is returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_read(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
{
struct buf *bp;
off_t bytesinfile;
daddr_t lbn, nextlbn;
long size, xfersize, blkoffset;
int error;
size = block size of file system;
for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
bytesinfile = size of file - uio->uio_offset;
if (bytesinfile <= 0)
break;
lbn = uio->uio_offset / size;
blkoffset = uio->uio_offset - lbn * size;
xfersize = size - blkoffset;
if (uio->uio_resid < xfersize)
xfersize = uio->uio_resid;
if (bytesinfile < xfersize)
xfersize = bytesinfile;
error = bread(vp, lbn, size, NOCRED, &bp);
if (error) {
brelse(bp);
bp = NULL;
break;
}
/*
* We should only get non-zero b_resid when an I/O error
* has occurred, which should cause us to break above.
* However, if the short read did not cause an error,
* then we want to ensure that we do not uiomove bad
* or uninitialized data.
*/
size -= bp->b_resid;
if (size < xfersize) {
if (size == 0)
break;
xfersize = size;
}
error = uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
if (error)
break;
bqrelse(bp);
}
if (bp != NULL)
bqrelse(bp);
return (error);
}
int
vop_write(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
{
struct buf *bp;
off_t bytesinfile;
daddr_t lbn, nextlbn;
off_t osize;
long size, resid, xfersize, blkoffset;
int flags;
int error;
osize = size of file;
size = block size of file system;
resid = uio->uio_resid;
if (ioflag & IO_SYNC)
flags = B_SYNC;
else
flags = 0;
for (error = 0; uio->uio_resid > 0;) {
lbn = uio->uio_offset / size;
blkoffset = uio->uio_offset - lbn * size;
xfersize = size - blkoffset;
if (uio->uio_resid < xfersize)
xfersize = uio->uio_resid;
if (uio->uio_offset + xfersize > size of file)
vnode_pager_setsize(vp, uio->uio_offset + xfersize);
if (size > xfersize)
flags |= B_CLRBUF;
else
flags &= ~B_CLRBUF;
error = find_block_in_file(vp, lbn, blkoffset + xfersize,
cred, &bp, flags);
if (error)
break;
if (uio->uio_offset + xfersize > size of file)
set size of file to uio->uio_offset + xfersize;
error = uiomove((char *)bp->b_data + blkoffset, (int) xfersize, uio);
/* XXX ufs does not check the error here. Why? */
if (ioflag & IO_VMIO)
bp->b_flags |= B_RELBUF; /* ??? */
if (ioflag & IO_SYNC)
bwrite(bp);
else if (xfersize + blkoffset == size)
bawrite(bp);
else
bdwrite(bp);
if (error || xfersize == 0)
break;
}
if (error) {
if (ioflag & IO_UNIT) {
/* call private routine to truncate file. */
your_truncate(vp, osize, ioflag & IO_SYNC, cred, uio->uio_td);
uio->uio_offset -= resid - uio->uio_resid;
uio->uio_resid = resid;
}
} else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
struct timeval tv;
error = VOP_UPDATE(vp, &tv, &tv, 1); /* XXX what does this do? */
}
return (error);
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EFBIG

View File

@ -96,70 +96,6 @@ Memory for the cookies should be allocated using:
*cookies = (u_int*)#
malloc(*ncookies * sizeof(u_int), M_TEMP, M_WAITOK);
.Ed
.Sh PSEUDOCODE
.Bd -literal
int
vop_readdir(struct vnode *vp, struct uio *uio, struct ucred *cred,
int *eofflag, int *ncookies, u_int **cookies)
{
off_t off;
int error = 0;
/*
* Remember the original offset to use later in generating cookies.
*/
off = uio->uio_offset;
/*
* Read directory contents starting at uio->uio_offset into buffer
* pointed to by uio.
*/
...;
if (!error && ncookies != NULL) {
struct dirent *dpStart;
struct dirent *dpEnd;
struct dirent *dp;
int count;
u_int *cookiebuf;
u_int *cookiep;
if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
panic("vop_readdir: unexpected uio from NFS server");
/*
* Parse the stuff just read into the uio.
*/
dpStart = (struct dirent *)
((char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
dpEnd = (struct dirent *) uio->uio_iov->iov_base;
/*
* Count number of entries.
*/
for (dp = dpStart, count = 0;
dp < dpEnd;
dp = (struct dirent *)((caddr_t) dp + dp->d_reclen))
count++;
cookiebuf = (u_int *) malloc(count * sizeof(u_int), M_TEMP, M_WAITOK);
for (dp = dpStart; cookiep = cookiebuf;
dp < dpEnd;
dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
off += dp->d_reclen;
*cookiep++ = (u_int) off;
}
*ncookies = count;
*cookies = cookiebuf;
}
if (eofflag && uio->uio_offset is past the end of the directory) {
*eofflag = TRUE;
}
return error;
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EINVAL

View File

@ -54,21 +54,6 @@ The credentials of the caller.
The vnode should be locked on entry and will still be locked on exit.
.Sh RETURN VALUES
Zero is returned on success, otherwise an error code is returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_readlink(struct vnode *vp, struct uio *uio, struct ucred *cred)
{
int error = 0;
/*
* Read the target of the symlink.
*/
...;
return error;
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EIO

View File

@ -62,27 +62,6 @@ and
should be locked on entry and remain locked on return.
.Sh RETURN VALUES
Zero is returned on success, otherwise an error code is returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_remove(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
{
int error = 0;
if (vp is immutable) {
error = EPERM;
goto out;
}
/*
* Remove name cnp->cn_nameptr from directory and update link count
* of vp.
*/
...;
return error;
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EPERM

View File

@ -72,205 +72,6 @@ The VOP routine is expected to
.Xr vput 9
both prior to
returning.
.Sh PSEUDOCODE
.Bd -literal
int
vop_rename(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp)
{
int doingdirectory = 0;
int error = 0;
/*
* Check for cross-device rename.
*/
if (fvp->v_mount != tdvp->v_mount) {
error = EXDEV;
abortit:
if (tdvp == tvp)
vrele(tdvp);
else
vput(tdvp);
if (tvp)
vput(tvp);
vrele(fdvp);
vrele(fvp);
return error;
}
if (tvp exists and is immutable) {
error = EPERM;
goto abortit;
}
/*
* POSIX: "If the old argument and the new argument
* both refer to links to the same existing file,
* the rename() function shall return successfully
* and perform no other action."
* The upper layers already handle this case.
*/
KASSERT(fvp != tvp, ("vop_rename: source and destination are the same"));
if (fvp is immutable) {
error = EPERM;
goto abortit;
}
error = VOP_LOCK(fvp);
if (error)
goto abortit;
if (vp is a directory) {
/*
* Avoid ".", "..", and aliases of "." for obvious reasons.
*/
if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')
|| fdvp == fvp
|| ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT)) {
VOP_UNLOCK(fvp);
error = EINVAL;
goto abortit;
}
doingdirectory = 1;
}
vrele(fdvp);
/*
* Bump link count on fvp while we are moving stuff around. If we
* crash before completing the work, the link count may be wrong
* but correctable.
*/
...;
/*
* If ".." must be changed (ie the directory gets a new
* parent) then the source directory must not be in the
* directory hierarchy above the target, as this would
* orphan everything below the source directory. Also
* the user must have write permission in the source so
* as to be able to change "..".
*/
error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread);
VOP_UNLOCK(fvp);
if (doingdirectory && fdvp != tdvp) {
/*
* Check for pathname conflict.
*/
...;
}
/*
* If the target doesn't exist, link the target to the source and
* unlink the source. Otherwise, rewrite the target directory to
* reference the source and remove the original entry.
*/
if (tvp == NULL) {
/*
* Account for ".." in new directory.
*/
if (doingdirectory && fdvp != tdvp) {
/*
* Increase link count of tdvp.
*/
...;
}
/*
* Add name in new directory.
*/
...;
if (error) {
if (doingdirectory && fdvp != tdvp) {
/*
* Decrease link count if tdvp.
*/
...;
}
goto bad;
}
vput(tdvp);
} else {
/*
* Target must be empty if a directory and have no links
* to it. Also, ensure source and target are compatible
* (both directories, or both not directories).
*/
if (tvp is a directory) {
if (tvp is not empty) {
error = ENOTEMPTY;
goto bad;
}
if (!doingdirectory) {
error = ENOTDIR;
goto bad;
}
/*
* Update name cache since directory is going away.
*/
cache_purge(tdvp);
} else if (doingdirectory) {
error = ENOTDIR;
goto bad;
}
/*
* Change name tcnp in tdvp to point at fvp.
*/
...;
/*
* If the target directory is in same directory as the source
* directory, decrement the link count on the parent of the
* target directory. This accounts for the fact that a
* directory links back to its parent with "..".
*/
if (doingdirectory && fdvp == tdvp) {
/*
* Decrement link count of tdvp.
*/
...;
}
vput(tdvp);
/*
* Decrement the link count of tvp since the directory no
* longer points at it.
*/
...;
if (doingdirectory) {
/*
* Clean up the old directory tvp.
*/
...;
}
vput(tvp);
}
/*
* Unlink the source. If a directory was moved to a new parent,
* update its ".." entry. Gobs of ugly UFS code omitted here.
*/
...;
bad:
if (tvp)
vput(tvp);
vput(tdvp);
out:
if (VOP_LOCK(fvp) == 0) {
/*
* Decrement link count of fvp.
*/
...;
vput(fvp);
} else
vrele(fvp);
return error;
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EPERM

View File

@ -70,30 +70,6 @@ parent directory vnode will be unlocked on a successful exit. However, it
will have its hold count incremented.
.Sh RETURN VALUES
Zero is returned on success, otherwise an error code is returned.
.Sh PSEUDOCODE
.Bd -literal
int
vop_vptocnp(struct vnode *vp, struct vnode **dvp, char *buf, int *buflen)
{
int error = 0;
/*
* Translate the vnode to its component name.
*
* Decrement the component name's length from buflen.
*
* Obtain the vnode's parent directory vnode.
*/
...;
/*
* Increment the parent directory's hold count.
*/
vhold(*dvp);
return error;
}
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er ENOMEM