Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/msdosfs/msdosfs_vnops.c
Show First 20 Lines • Show All 931 Lines • ▼ Show 20 Lines | |||||
* destination file or directory is locked if it exists | * destination file or directory is locked if it exists | ||||
* | * | ||||
* On exit: | * On exit: | ||||
* all denodes should be released | * all denodes should be released | ||||
*/ | */ | ||||
static int | static int | ||||
msdosfs_rename(struct vop_rename_args *ap) | msdosfs_rename(struct vop_rename_args *ap) | ||||
{ | { | ||||
struct vnode *tdvp = ap->a_tdvp; | struct vnode *fdvp, *fvp, *tdvp, *tvp, *vp; | ||||
struct vnode *fvp = ap->a_fvp; | struct componentname *fcnp, *tcnp; | ||||
struct vnode *fdvp = ap->a_fdvp; | struct denode *fdip, *fip, *tdip, *tip, *nip; | ||||
struct vnode *tvp = ap->a_tvp; | |||||
struct componentname *tcnp = ap->a_tcnp; | |||||
struct componentname *fcnp = ap->a_fcnp; | |||||
struct denode *ip, *xp, *dp, *zp; | |||||
u_char toname[12], oldname[11]; | u_char toname[12], oldname[11]; | ||||
u_long from_diroffset, to_diroffset; | u_long from_diroffset, to_diroffset; | ||||
bool checkpath_locked, doingdirectory, newparent; | |||||
u_char to_count; | u_char to_count; | ||||
int doingdirectory = 0, newparent = 0; | |||||
int error; | int error; | ||||
u_long cn, pcl; | u_long cn, pcl, blkoff; | ||||
daddr_t bn; | daddr_t bn, wait_scn, scn; | ||||
struct msdosfsmount *pmp; | struct msdosfsmount *pmp; | ||||
struct mount *mp; | |||||
struct direntry *dotdotp; | struct direntry *dotdotp; | ||||
struct buf *bp; | struct buf *bp; | ||||
tdvp = ap->a_tdvp; | |||||
fvp = ap->a_fvp; | |||||
fdvp = ap->a_fdvp; | |||||
tvp = ap->a_tvp; | |||||
tcnp = ap->a_tcnp; | |||||
fcnp = ap->a_fcnp; | |||||
pmp = VFSTOMSDOSFS(fdvp->v_mount); | pmp = VFSTOMSDOSFS(fdvp->v_mount); | ||||
#ifdef DIAGNOSTIC | #ifdef DIAGNOSTIC | ||||
if ((tcnp->cn_flags & HASBUF) == 0 || | if ((tcnp->cn_flags & HASBUF) == 0 || | ||||
(fcnp->cn_flags & HASBUF) == 0) | (fcnp->cn_flags & HASBUF) == 0) | ||||
panic("msdosfs_rename: no name"); | panic("msdosfs_rename: no name"); | ||||
#endif | #endif | ||||
/* | /* | ||||
* Check for cross-device rename. | * Check for cross-device rename. | ||||
*/ | */ | ||||
mp = fvp->v_mount; | |||||
if (fvp->v_mount != tdvp->v_mount || | if (fvp->v_mount != tdvp->v_mount || | ||||
(tvp && fvp->v_mount != tvp->v_mount)) { | (tvp != NULL && fvp->v_mount != tvp->v_mount)) { | ||||
error = EXDEV; | error = EXDEV; | ||||
abortit: | goto abortit; | ||||
if (tdvp == tvp) | |||||
vrele(tdvp); | |||||
else | |||||
vput(tdvp); | |||||
if (tvp) | |||||
vput(tvp); | |||||
vrele(fdvp); | |||||
vrele(fvp); | |||||
return (error); | |||||
} | } | ||||
/* | /* | ||||
* If source and dest are the same, do nothing. | * If source and dest are the same, do nothing. | ||||
*/ | */ | ||||
if (tvp == fvp) { | if (tvp == fvp) { | ||||
error = 0; | error = 0; | ||||
goto abortit; | goto abortit; | ||||
} | } | ||||
error = vn_lock(fvp, LK_EXCLUSIVE); | /* | ||||
if (error) | * When the target exists, both the directory | ||||
goto abortit; | * and target vnodes are passed locked. | ||||
dp = VTODE(fdvp); | */ | ||||
ip = VTODE(fvp); | VOP_UNLOCK(tdvp); | ||||
if (tvp != NULL && tvp != tdvp) | |||||
VOP_UNLOCK(tvp); | |||||
checkpath_locked = false; | |||||
relock: | |||||
doingdirectory = newparent = false; | |||||
error = vn_lock(fdvp, LK_EXCLUSIVE); | |||||
if (error != 0) | |||||
goto releout; | |||||
if (vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) { | |||||
VOP_UNLOCK(fdvp); | |||||
error = vn_lock(tdvp, LK_EXCLUSIVE); | |||||
if (error != 0) | |||||
goto releout; | |||||
VOP_UNLOCK(tdvp); | |||||
goto relock; | |||||
} | |||||
error = msdosfs_lookup_ino(fdvp, NULL, fcnp, &scn, &blkoff); | |||||
if (error != 0) { | |||||
VOP_UNLOCK(fdvp); | |||||
VOP_UNLOCK(tdvp); | |||||
goto releout; | |||||
} | |||||
error = deget(pmp, scn, blkoff, LK_EXCLUSIVE | LK_NOWAIT, &nip); | |||||
if (error != 0) { | |||||
VOP_UNLOCK(fdvp); | |||||
VOP_UNLOCK(tdvp); | |||||
if (error != EBUSY) | |||||
goto releout; | |||||
error = deget(pmp, scn, blkoff, LK_EXCLUSIVE, &nip); | |||||
if (error != 0) | |||||
goto releout; | |||||
vp = fvp; | |||||
fvp = DETOV(nip); | |||||
VOP_UNLOCK(fvp); | |||||
vrele(vp); | |||||
goto relock; | |||||
} | |||||
vrele(fvp); | |||||
fvp = DETOV(nip); | |||||
from_diroffset = fdip->de_fndoffset; | |||||
error = msdosfs_lookup_ino(tdvp, NULL, tcnp, &scn, &blkoff); | |||||
if (error != 0 && error != EJUSTRETURN) { | |||||
VOP_UNLOCK(fdvp); | |||||
VOP_UNLOCK(tdvp); | |||||
VOP_UNLOCK(fvp); | |||||
goto releout; | |||||
} | |||||
if (error == EJUSTRETURN && tvp != NULL) { | |||||
vrele(tvp); | |||||
tvp = NULL; | |||||
} | |||||
if (error == 0) { | |||||
nip = NULL; | |||||
error = deget(pmp, scn, blkoff, LK_EXCLUSIVE | LK_NOWAIT, | |||||
&nip); | |||||
if (tvp != NULL) { | |||||
vrele(tvp); | |||||
tvp = NULL; | |||||
} | |||||
if (error != 0) { | |||||
VOP_UNLOCK(fdvp); | |||||
VOP_UNLOCK(tdvp); | |||||
VOP_UNLOCK(fvp); | |||||
if (error != EBUSY) | |||||
goto releout; | |||||
error = deget(pmp, scn, blkoff, LK_EXCLUSIVE, | |||||
&nip); | |||||
if (error != 0) | |||||
goto releout; | |||||
vput(DETOV(nip)); | |||||
goto relock; | |||||
} | |||||
tvp = DETOV(nip); | |||||
} | |||||
fdip = VTODE(fdvp); | |||||
fip = VTODE(fvp); | |||||
tdip = VTODE(tdvp); | |||||
tip = tvp != NULL ? VTODE(tvp) : NULL; | |||||
/* | /* | ||||
* Remember direntry place to use for destination | |||||
*/ | |||||
to_diroffset = tdip->de_fndoffset; | |||||
to_count = tdip->de_fndcnt; | |||||
/* | |||||
* Be sure we are not renaming ".", "..", or an alias of ".". This | * Be sure we are not renaming ".", "..", or an alias of ".". This | ||||
* leads to a crippled directory tree. It's pretty tough to do a | * leads to a crippled directory tree. It's pretty tough to do a | ||||
* "ls" or "pwd" with the "." directory entry missing, and "cd .." | * "ls" or "pwd" with the "." directory entry missing, and "cd .." | ||||
* doesn't work if the ".." entry is missing. | * doesn't work if the ".." entry is missing. | ||||
*/ | */ | ||||
if (ip->de_Attributes & ATTR_DIRECTORY) { | if ((fip->de_Attributes & ATTR_DIRECTORY) != 0) { | ||||
/* | /* | ||||
* Avoid ".", "..", and aliases of "." for obvious reasons. | * Avoid ".", "..", and aliases of "." for obvious reasons. | ||||
*/ | */ | ||||
if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || | if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') || | ||||
dp == ip || | fdip == fip || | ||||
(fcnp->cn_flags & ISDOTDOT) || | (fcnp->cn_flags & ISDOTDOT) != 0 || | ||||
(tcnp->cn_flags & ISDOTDOT) || | (tcnp->cn_flags & ISDOTDOT) != 0) { | ||||
(ip->de_flag & DE_RENAME)) { | |||||
VOP_UNLOCK(fvp); | |||||
error = EINVAL; | error = EINVAL; | ||||
goto abortit; | goto unlock; | ||||
} | } | ||||
ip->de_flag |= DE_RENAME; | doingdirectory = true; | ||||
doingdirectory++; | |||||
} | } | ||||
/* | /* | ||||
* When the target exists, both the directory | |||||
* and target vnodes are returned locked. | |||||
*/ | |||||
dp = VTODE(tdvp); | |||||
xp = tvp ? VTODE(tvp) : NULL; | |||||
/* | |||||
* Remember direntry place to use for destination | |||||
*/ | |||||
to_diroffset = dp->de_fndoffset; | |||||
to_count = dp->de_fndcnt; | |||||
/* | |||||
* If ".." must be changed (ie the directory gets a new | * If ".." must be changed (ie the directory gets a new | ||||
* parent) then the source directory must not be in the | * parent) then the source directory must not be in the | ||||
* directory hierarchy above the target, as this would | * directory hierarchy above the target, as this would | ||||
* orphan everything below the source directory. Also | * orphan everything below the source directory. Also | ||||
* the user must have write permission in the source so | * the user must have write permission in the source so | ||||
* as to be able to change "..". We must repeat the call | * as to be able to change "..". We must repeat the call | ||||
* to namei, as the parent directory is unlocked by the | * to namei, as the parent directory is unlocked by the | ||||
* call to doscheckpath(). | * call to doscheckpath(). | ||||
*/ | */ | ||||
error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread); | error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread); | ||||
VOP_UNLOCK(fvp); | if (fdip->de_StartCluster != tdip->de_StartCluster) | ||||
if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster) | newparent = true; | ||||
newparent = 1; | |||||
if (doingdirectory && newparent) { | if (doingdirectory && newparent) { | ||||
if (error) /* write access check above */ | if (error != 0) /* write access check above */ | ||||
goto bad; | goto unlock; | ||||
if (xp != NULL) | lockmgr(&pmp->pm_checkpath_lock, LK_EXCLUSIVE, NULL); | ||||
vput(tvp); | checkpath_locked = true; | ||||
/* | error = doscheckpath(fip, tdip, &wait_scn); | ||||
* doscheckpath() vput()'s dp, | if (wait_scn != 0) { | ||||
* so we have to do a relookup afterwards | lockmgr(&pmp->pm_checkpath_lock, LK_RELEASE, NULL); | ||||
*/ | checkpath_locked = false; | ||||
error = doscheckpath(ip, dp); | VOP_UNLOCK(fdvp); | ||||
if (error) | VOP_UNLOCK(tdvp); | ||||
goto out; | VOP_UNLOCK(fvp); | ||||
if (tvp != NULL && tvp != tdvp) | |||||
VOP_UNLOCK(tvp); | |||||
error = deget(pmp, wait_scn, 0, LK_EXCLUSIVE, | |||||
&nip); | |||||
if (error == 0) { | |||||
vput(DETOV(nip)); | |||||
goto relock; | |||||
} | |||||
} | |||||
if (error != 0) | |||||
goto unlock; | |||||
if ((tcnp->cn_flags & SAVESTART) == 0) | if ((tcnp->cn_flags & SAVESTART) == 0) | ||||
panic("msdosfs_rename: lost to startdir"); | panic("msdosfs_rename: lost to startdir"); | ||||
error = relookup(tdvp, &tvp, tcnp); | |||||
if (error) | |||||
goto out; | |||||
dp = VTODE(tdvp); | |||||
xp = tvp ? VTODE(tvp) : NULL; | |||||
} | } | ||||
if (xp != NULL) { | if (tip != NULL) { | ||||
/* | /* | ||||
* Target must be empty if a directory and have no links | * Target must be empty if a directory and have no links | ||||
* to it. Also, ensure source and target are compatible | * to it. Also, ensure source and target are compatible | ||||
* (both directories, or both not directories). | * (both directories, or both not directories). | ||||
*/ | */ | ||||
if (xp->de_Attributes & ATTR_DIRECTORY) { | if ((tip->de_Attributes & ATTR_DIRECTORY) != 0) { | ||||
if (!dosdirempty(xp)) { | if (!dosdirempty(tip)) { | ||||
error = ENOTEMPTY; | error = ENOTEMPTY; | ||||
goto bad; | goto unlock; | ||||
} | } | ||||
if (!doingdirectory) { | if (!doingdirectory) { | ||||
error = ENOTDIR; | error = ENOTDIR; | ||||
goto bad; | goto unlock; | ||||
} | } | ||||
cache_purge(tdvp); | cache_purge(tdvp); | ||||
} else if (doingdirectory) { | } else if (doingdirectory) { | ||||
error = EISDIR; | error = EISDIR; | ||||
goto bad; | goto unlock; | ||||
} | } | ||||
error = removede(dp, xp); | error = msdosfs_lookup_ino(tdvp, NULL, tcnp, &scn, &blkoff); | ||||
if (error) | MPASS(error == 0); | ||||
goto bad; | error = removede(tdip, tip); | ||||
if (error != 0) | |||||
goto unlock; | |||||
vput(tvp); | vput(tvp); | ||||
xp = NULL; | tvp = NULL; | ||||
tip = NULL; | |||||
} | } | ||||
/* | /* | ||||
* Convert the filename in tcnp into a dos filename. We copy this | * Convert the filename in tcnp into a dos filename. We copy this | ||||
* into the denode and directory entry for the destination | * into the denode and directory entry for the destination | ||||
* file/directory. | * file/directory. | ||||
*/ | */ | ||||
error = uniqdosname(VTODE(tdvp), tcnp, toname); | error = uniqdosname(tdip, tcnp, toname); | ||||
if (error) | if (error != 0) | ||||
goto abortit; | goto unlock; | ||||
/* | /* | ||||
* Since from wasn't locked at various places above, | |||||
* have to do a relookup here. | |||||
*/ | |||||
fcnp->cn_flags &= ~MODMASK; | |||||
fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; | |||||
if ((fcnp->cn_flags & SAVESTART) == 0) | |||||
panic("msdosfs_rename: lost from startdir"); | |||||
if (!newparent) | |||||
VOP_UNLOCK(tdvp); | |||||
if (relookup(fdvp, &fvp, fcnp) == 0) | |||||
vrele(fdvp); | |||||
if (fvp == NULL) { | |||||
/* | |||||
* From name has disappeared. | |||||
*/ | |||||
if (doingdirectory) | |||||
panic("rename: lost dir entry"); | |||||
if (newparent) | |||||
VOP_UNLOCK(tdvp); | |||||
vrele(tdvp); | |||||
vrele(ap->a_fvp); | |||||
/* | |||||
* fdvp may be locked and has a reference. We need to | |||||
* release the lock and reference, unless to and from | |||||
* directories are the same. In that case it is already | |||||
* unlocked. | |||||
*/ | |||||
if (tdvp != fdvp) | |||||
vput(fdvp); | |||||
return 0; | |||||
} | |||||
xp = VTODE(fvp); | |||||
zp = VTODE(fdvp); | |||||
from_diroffset = zp->de_fndoffset; | |||||
/* | |||||
* Ensure that the directory entry still exists and has not | |||||
* changed till now. If the source is a file the entry may | |||||
* have been unlinked or renamed. In either case there is | |||||
* no further work to be done. If the source is a directory | |||||
* then it cannot have been rmdir'ed or renamed; this is | |||||
* prohibited by the DE_RENAME flag. | |||||
*/ | |||||
if (xp != ip) { | |||||
if (doingdirectory) | |||||
panic("rename: lost dir entry"); | |||||
if (newparent) | |||||
VOP_UNLOCK(fdvp); | |||||
vrele(ap->a_fvp); | |||||
xp = NULL; | |||||
} else { | |||||
vrele(fvp); | |||||
xp = NULL; | |||||
/* | |||||
* First write a new entry in the destination | * First write a new entry in the destination | ||||
* directory and mark the entry in the source directory | * directory and mark the entry in the source directory | ||||
* as deleted. Then move the denode to the correct hash | * as deleted. Then move the denode to the correct hash | ||||
* chain for its new location in the filesystem. And, if | * chain for its new location in the filesystem. And, if | ||||
* we moved a directory, then update its .. entry to point | * we moved a directory, then update its .. entry to point | ||||
* to the new parent directory. | * to the new parent directory. | ||||
*/ | */ | ||||
memcpy(oldname, ip->de_Name, 11); | memcpy(oldname, fip->de_Name, 11); | ||||
memcpy(ip->de_Name, toname, 11); /* update denode */ | memcpy(fip->de_Name, toname, 11); /* update denode */ | ||||
dp->de_fndoffset = to_diroffset; | error = msdosfs_lookup_ino(tdvp, NULL, tcnp, &scn, &blkoff); | ||||
dp->de_fndcnt = to_count; | MPASS(error == EJUSTRETURN); | ||||
error = createde(ip, dp, (struct denode **)0, tcnp); | error = createde(fip, tdip, NULL, tcnp); | ||||
if (error) { | if (error != 0) { | ||||
memcpy(ip->de_Name, oldname, 11); | memcpy(fip->de_Name, oldname, 11); | ||||
if (newparent) | goto unlock; | ||||
VOP_UNLOCK(fdvp); | |||||
VOP_UNLOCK(fvp); | |||||
goto bad; | |||||
} | } | ||||
/* | /* | ||||
* If ip is for a directory, then its name should always | * If fip is for a directory, then its name should always | ||||
* be "." since it is for the directory entry in the | * be "." since it is for the directory entry in the | ||||
* directory itself (msdosfs_lookup() always translates | * directory itself (msdosfs_lookup() always translates | ||||
* to the "." entry so as to get a unique denode, except | * to the "." entry so as to get a unique denode, except | ||||
* for the root directory there are different | * for the root directory there are different | ||||
* complications). However, we just corrupted its name | * complications). However, we just corrupted its name | ||||
* to pass the correct name to createde(). Undo this. | * to pass the correct name to createde(). Undo this. | ||||
*/ | */ | ||||
if ((ip->de_Attributes & ATTR_DIRECTORY) != 0) | if ((fip->de_Attributes & ATTR_DIRECTORY) != 0) | ||||
memcpy(ip->de_Name, oldname, 11); | memcpy(fip->de_Name, oldname, 11); | ||||
ip->de_refcnt++; | fip->de_refcnt++; | ||||
zp->de_fndoffset = from_diroffset; | error = msdosfs_lookup_ino(fdvp, NULL, fcnp, &scn, &blkoff); | ||||
error = removede(zp, ip); | MPASS(error == 0); | ||||
if (error) { | error = removede(fdip, fip); | ||||
if (error != 0) { | |||||
/* XXX should downgrade to ro here, fs is corrupt */ | /* XXX should downgrade to ro here, fs is corrupt */ | ||||
if (newparent) | goto unlock; | ||||
VOP_UNLOCK(fdvp); | |||||
VOP_UNLOCK(fvp); | |||||
goto bad; | |||||
} | } | ||||
if (!doingdirectory) { | if (!doingdirectory) { | ||||
error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0, | error = pcbmap(tdip, de_cluster(pmp, to_diroffset), 0, | ||||
&ip->de_dirclust, 0); | &fip->de_dirclust, 0); | ||||
if (error) { | if (error != 0) { | ||||
/* XXX should downgrade to ro here, fs is corrupt */ | /* | ||||
if (newparent) | * XXX should downgrade to ro here, | ||||
VOP_UNLOCK(fdvp); | * fs is corrupt | ||||
VOP_UNLOCK(fvp); | */ | ||||
goto bad; | goto unlock; | ||||
} | } | ||||
if (ip->de_dirclust == MSDOSFSROOT) | if (fip->de_dirclust == MSDOSFSROOT) | ||||
ip->de_diroffset = to_diroffset; | fip->de_diroffset = to_diroffset; | ||||
else | else | ||||
ip->de_diroffset = to_diroffset & pmp->pm_crbomask; | fip->de_diroffset = to_diroffset & pmp->pm_crbomask; | ||||
} | } | ||||
reinsert(ip); | reinsert(fip); | ||||
if (newparent) | |||||
VOP_UNLOCK(fdvp); | |||||
} | |||||
/* | /* | ||||
* If we moved a directory to a new parent directory, then we must | * If we moved a directory to a new parent directory, then we must | ||||
* fixup the ".." entry in the moved directory. | * fixup the ".." entry in the moved directory. | ||||
*/ | */ | ||||
if (doingdirectory && newparent) { | if (doingdirectory && newparent) { | ||||
cn = ip->de_StartCluster; | cn = fip->de_StartCluster; | ||||
if (cn == MSDOSFSROOT) { | if (cn == MSDOSFSROOT) { | ||||
/* this should never happen */ | /* this should never happen */ | ||||
panic("msdosfs_rename(): updating .. in root directory?"); | panic("msdosfs_rename(): updating .. in root directory?"); | ||||
} else | } else | ||||
bn = cntobn(pmp, cn); | bn = cntobn(pmp, cn); | ||||
error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, | error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, | ||||
NOCRED, &bp); | NOCRED, &bp); | ||||
if (error) { | if (error != 0) { | ||||
/* XXX should downgrade to ro here, fs is corrupt */ | /* XXX should downgrade to ro here, fs is corrupt */ | ||||
VOP_UNLOCK(fvp); | goto unlock; | ||||
goto bad; | |||||
} | } | ||||
dotdotp = (struct direntry *)bp->b_data + 1; | dotdotp = (struct direntry *)bp->b_data + 1; | ||||
pcl = dp->de_StartCluster; | pcl = tdip->de_StartCluster; | ||||
if (FAT32(pmp) && pcl == pmp->pm_rootdirblk) | if (FAT32(pmp) && pcl == pmp->pm_rootdirblk) | ||||
pcl = MSDOSFSROOT; | pcl = MSDOSFSROOT; | ||||
putushort(dotdotp->deStartCluster, pcl); | putushort(dotdotp->deStartCluster, pcl); | ||||
if (FAT32(pmp)) | if (FAT32(pmp)) | ||||
putushort(dotdotp->deHighClust, pcl >> 16); | putushort(dotdotp->deHighClust, pcl >> 16); | ||||
if (DOINGASYNC(fvp)) | if (DOINGASYNC(fvp)) | ||||
bdwrite(bp); | bdwrite(bp); | ||||
else if ((error = bwrite(bp)) != 0) { | else if ((error = bwrite(bp)) != 0) { | ||||
/* XXX should downgrade to ro here, fs is corrupt */ | /* XXX should downgrade to ro here, fs is corrupt */ | ||||
VOP_UNLOCK(fvp); | goto unlock; | ||||
goto bad; | |||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* The msdosfs lookup is case insensitive. Several aliases may | * The msdosfs lookup is case insensitive. Several aliases may | ||||
* be inserted for a single directory entry. As a consequnce, | * be inserted for a single directory entry. As a consequnce, | ||||
* name cache purge done by lookup for fvp when DELETE op for | * name cache purge done by lookup for fvp when DELETE op for | ||||
* namei is specified, might be not enough to expunge all | * namei is specified, might be not enough to expunge all | ||||
* namecache entries that were installed for this direntry. | * namecache entries that were installed for this direntry. | ||||
*/ | */ | ||||
cache_purge(fvp); | cache_purge(fvp); | ||||
VOP_UNLOCK(fvp); | |||||
bad: | unlock: | ||||
if (xp) | if (checkpath_locked) | ||||
lockmgr(&pmp->pm_checkpath_lock, LK_RELEASE, NULL); | |||||
vput(fdvp); | |||||
vput(fvp); | |||||
if (tvp != NULL) { | |||||
if (tvp != tdvp) | |||||
vput(tvp); | vput(tvp); | ||||
else | |||||
vrele(tvp); | |||||
} | |||||
vput(tdvp); | vput(tdvp); | ||||
out: | return (error); | ||||
ip->de_flag &= ~DE_RENAME; | releout: | ||||
MPASS(!checkpath_locked); | |||||
vrele(tdvp); | |||||
if (tvp != NULL) | |||||
vrele(tvp); | |||||
vrele(fdvp); | vrele(fdvp); | ||||
vrele(fvp); | vrele(fvp); | ||||
return (error); | return (error); | ||||
abortit: | |||||
if (tdvp == tvp) | |||||
vrele(tdvp); | |||||
else | |||||
vput(tdvp); | |||||
if (tvp != NULL) | |||||
vput(tvp); | |||||
vrele(fdvp); | |||||
vrele(fvp); | |||||
return (error); | |||||
} | } | ||||
static struct { | static struct { | ||||
struct direntry dot; | struct direntry dot; | ||||
struct direntry dotdot; | struct direntry dotdot; | ||||
} dosdirtemplate = { | } dosdirtemplate = { | ||||
{ ". ", /* the . entry */ | { ". ", /* the . entry */ | ||||
ATTR_DIRECTORY, /* file attribute */ | ATTR_DIRECTORY, /* file attribute */ | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | msdosfs_rmdir(struct vop_rmdir_args *ap) | ||||
/* | /* | ||||
* Verify the directory is empty (and valid). | * Verify the directory is empty (and valid). | ||||
* (Rmdir ".." won't be valid since | * (Rmdir ".." won't be valid since | ||||
* ".." will contain a reference to | * ".." will contain a reference to | ||||
* the current directory and thus be | * the current directory and thus be | ||||
* non-empty.) | * non-empty.) | ||||
*/ | */ | ||||
error = 0; | error = 0; | ||||
if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) { | if (!dosdirempty(ip)) { | ||||
error = ENOTEMPTY; | error = ENOTEMPTY; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* Delete the entry from the directory. For dos filesystems this | * Delete the entry from the directory. For dos filesystems this | ||||
* gets rid of the directory entry on disk, the in memory copy | * gets rid of the directory entry on disk, the in memory copy | ||||
* still exists but the de_refcnt is <= 0. This prevents it from | * still exists but the de_refcnt is <= 0. This prevents it from | ||||
* being found by deget(). When the vput() on dep is done we give | * being found by deget(). When the vput() on dep is done we give | ||||
▲ Show 20 Lines • Show All 535 Lines • Show Last 20 Lines |