mirror of
https://github.com/opnsense/src.git
synced 2026-06-17 04:29:12 -04:00
parent
7b81dd6f3d
commit
2c9cbc2d45
4 changed files with 276 additions and 243 deletions
|
|
@ -267,7 +267,7 @@ int msdosfs_lookup(struct vop_cachedlookup_args *);
|
|||
int msdosfs_inactive(struct vop_inactive_args *);
|
||||
int msdosfs_reclaim(struct vop_reclaim_args *);
|
||||
int msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp,
|
||||
struct componentname *cnp, uint64_t *inum);
|
||||
struct componentname *cnp, daddr_t *scnp, u_long *blkoffp);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
@ -286,6 +286,7 @@ int createde(struct denode *dep, struct denode *ddep, struct denode **depp, stru
|
|||
int deupdat(struct denode *dep, int waitfor);
|
||||
int removede(struct denode *pdep, struct denode *dep);
|
||||
int detrunc(struct denode *dep, u_long length, int flags, struct ucred *cred);
|
||||
int doscheckpath( struct denode *source, struct denode *target);
|
||||
int doscheckpath( struct denode *source, struct denode *target,
|
||||
daddr_t *wait_scn);
|
||||
#endif /* _KERNEL || MAKEFS */
|
||||
#endif /* !_FS_MSDOSFS_DENODE_H_ */
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
|
|||
ldep->de_diroffset = diroffset;
|
||||
ldep->de_inode = inode;
|
||||
lockmgr(nvp->v_vnlock, LK_EXCLUSIVE, NULL);
|
||||
VN_LOCK_AREC(nvp); /* for doscheckpath */
|
||||
fc_purge(ldep, 0); /* init the FAT cache for this denode */
|
||||
error = insmntque(nvp, mntp);
|
||||
if (error != 0) {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ int
|
|||
msdosfs_lookup(struct vop_cachedlookup_args *ap)
|
||||
{
|
||||
|
||||
return (msdosfs_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL));
|
||||
return (msdosfs_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL,
|
||||
NULL));
|
||||
}
|
||||
|
||||
struct deget_dotdot {
|
||||
|
|
@ -109,8 +110,8 @@ msdosfs_deget_dotdot(struct mount *mp, void *arg, int lkflags,
|
|||
* memory denode's will be in synch.
|
||||
*/
|
||||
int
|
||||
msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp,
|
||||
struct componentname *cnp, uint64_t *dd_inum)
|
||||
msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp, struct componentname
|
||||
*cnp, daddr_t *scnp, u_long *blkoffp)
|
||||
{
|
||||
struct mbnambuf nb;
|
||||
daddr_t bn;
|
||||
|
|
@ -119,11 +120,11 @@ msdosfs_lookup_ino(struct vnode *vdp, struct vnode **vpp,
|
|||
int slotoffset = 0;
|
||||
int frcn;
|
||||
u_long cluster;
|
||||
int blkoff;
|
||||
u_long blkoff;
|
||||
int diroff;
|
||||
int blsize;
|
||||
int isadir; /* ~0 if found direntry is a directory */
|
||||
u_long scn; /* starting cluster number */
|
||||
daddr_t scn; /* starting cluster number */
|
||||
struct vnode *pdp;
|
||||
struct denode *dp;
|
||||
struct denode *tdp;
|
||||
|
|
@ -464,8 +465,9 @@ foundroot:
|
|||
if (FAT32(pmp) && scn == MSDOSFSROOT)
|
||||
scn = pmp->pm_rootdirblk;
|
||||
|
||||
if (dd_inum != NULL) {
|
||||
*dd_inum = (uint64_t)pmp->pm_bpcluster * scn + blkoff;
|
||||
if (scnp != NULL) {
|
||||
*scnp = cluster;
|
||||
*blkoffp = blkoff;
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -557,12 +559,15 @@ foundroot:
|
|||
* Recheck that ".." still points to the inode we
|
||||
* looked up before pdp lock was dropped.
|
||||
*/
|
||||
error = msdosfs_lookup_ino(pdp, NULL, cnp, &inode1);
|
||||
error = msdosfs_lookup_ino(pdp, NULL, cnp, &scn, &blkoff);
|
||||
if (error) {
|
||||
vput(*vpp);
|
||||
*vpp = NULL;
|
||||
return (error);
|
||||
}
|
||||
if (FAT32(pmp) && scn == MSDOSFSROOT)
|
||||
scn = pmp->pm_rootdirblk;
|
||||
inode1 = scn * pmp->pm_bpcluster + blkoff;
|
||||
if (VTODE(*vpp)->de_inode != inode1) {
|
||||
vput(*vpp);
|
||||
goto restart;
|
||||
|
|
@ -794,10 +799,9 @@ dosdirempty(struct denode *dep)
|
|||
*
|
||||
* Returns 0 if target is NOT a subdirectory of source.
|
||||
* Otherwise returns a non-zero error number.
|
||||
* The target inode is always unlocked on return.
|
||||
*/
|
||||
int
|
||||
doscheckpath(struct denode *source, struct denode *target)
|
||||
doscheckpath(struct denode *source, struct denode *target, daddr_t *wait_scn)
|
||||
{
|
||||
daddr_t scn;
|
||||
struct msdosfsmount *pmp;
|
||||
|
|
@ -806,26 +810,25 @@ doscheckpath(struct denode *source, struct denode *target)
|
|||
struct buf *bp = NULL;
|
||||
int error = 0;
|
||||
|
||||
dep = target;
|
||||
if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
|
||||
(source->de_Attributes & ATTR_DIRECTORY) == 0) {
|
||||
error = ENOTDIR;
|
||||
goto out;
|
||||
}
|
||||
if (dep->de_StartCluster == source->de_StartCluster) {
|
||||
error = EEXIST;
|
||||
goto out;
|
||||
}
|
||||
if (dep->de_StartCluster == MSDOSFSROOT)
|
||||
goto out;
|
||||
pmp = dep->de_pmp;
|
||||
#ifdef DIAGNOSTIC
|
||||
if (pmp != source->de_pmp)
|
||||
panic("doscheckpath: source and target on different filesystems");
|
||||
#endif
|
||||
if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
|
||||
goto out;
|
||||
*wait_scn = 0;
|
||||
|
||||
pmp = target->de_pmp;
|
||||
KASSERT(pmp == source->de_pmp,
|
||||
("doscheckpath: source and target on different filesystems"));
|
||||
|
||||
if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
|
||||
(source->de_Attributes & ATTR_DIRECTORY) == 0)
|
||||
return (ENOTDIR);
|
||||
|
||||
if (target->de_StartCluster == source->de_StartCluster)
|
||||
return (EEXIST);
|
||||
|
||||
if (target->de_StartCluster == MSDOSFSROOT ||
|
||||
(FAT32(pmp) && target->de_StartCluster == pmp->pm_rootdirblk))
|
||||
return (0);
|
||||
|
||||
dep = target;
|
||||
vget(DETOV(dep), LK_EXCLUSIVE);
|
||||
for (;;) {
|
||||
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
|
||||
error = ENOTDIR;
|
||||
|
|
@ -833,19 +836,22 @@ doscheckpath(struct denode *source, struct denode *target)
|
|||
}
|
||||
scn = dep->de_StartCluster;
|
||||
error = bread(pmp->pm_devvp, cntobn(pmp, scn),
|
||||
pmp->pm_bpcluster, NOCRED, &bp);
|
||||
if (error)
|
||||
pmp->pm_bpcluster, NOCRED, &bp);
|
||||
if (error != 0)
|
||||
break;
|
||||
|
||||
ep = (struct direntry *) bp->b_data + 1;
|
||||
ep = (struct direntry *)bp->b_data + 1;
|
||||
if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
|
||||
bcmp(ep->deName, ".. ", 11) != 0) {
|
||||
error = ENOTDIR;
|
||||
brelse(bp);
|
||||
break;
|
||||
}
|
||||
|
||||
scn = getushort(ep->deStartCluster);
|
||||
if (FAT32(pmp))
|
||||
scn |= getushort(ep->deHighClust) << 16;
|
||||
brelse(bp);
|
||||
|
||||
if (scn == source->de_StartCluster) {
|
||||
error = EINVAL;
|
||||
|
|
@ -862,15 +868,14 @@ doscheckpath(struct denode *source, struct denode *target)
|
|||
}
|
||||
|
||||
vput(DETOV(dep));
|
||||
brelse(bp);
|
||||
bp = NULL;
|
||||
dep = NULL;
|
||||
/* NOTE: deget() clears dep on error */
|
||||
if ((error = deget(pmp, scn, 0, LK_EXCLUSIVE, &dep)) != 0)
|
||||
error = deget(pmp, scn, 0, LK_EXCLUSIVE | LK_NOWAIT, &dep);
|
||||
if (error != 0) {
|
||||
*wait_scn = scn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:;
|
||||
if (bp)
|
||||
brelse(bp);
|
||||
#ifdef MSDOSFS_DEBUG
|
||||
if (error == ENOTDIR)
|
||||
printf("doscheckpath(): .. not a directory?\n");
|
||||
|
|
|
|||
|
|
@ -937,24 +937,27 @@ msdosfs_link(struct vop_link_args *ap)
|
|||
static int
|
||||
msdosfs_rename(struct vop_rename_args *ap)
|
||||
{
|
||||
struct vnode *tdvp = ap->a_tdvp;
|
||||
struct vnode *fvp = ap->a_fvp;
|
||||
struct vnode *fdvp = ap->a_fdvp;
|
||||
struct vnode *tvp = ap->a_tvp;
|
||||
struct componentname *tcnp = ap->a_tcnp;
|
||||
struct componentname *fcnp = ap->a_fcnp;
|
||||
struct denode *ip, *xp, *dp, *zp;
|
||||
struct vnode *fdvp, *fvp, *tdvp, *tvp, *vp;
|
||||
struct componentname *fcnp, *tcnp;
|
||||
struct denode *fdip, *fip, *tdip, *tip, *nip;
|
||||
u_char toname[12], oldname[11];
|
||||
u_long from_diroffset, to_diroffset;
|
||||
bool doingdirectory, newparent;
|
||||
u_char to_count;
|
||||
int doingdirectory = 0, newparent = 0;
|
||||
int error;
|
||||
u_long cn, pcl;
|
||||
daddr_t bn;
|
||||
u_long cn, pcl, blkoff;
|
||||
daddr_t bn, wait_scn, scn;
|
||||
struct msdosfsmount *pmp;
|
||||
struct mount *mp;
|
||||
struct direntry *dotdotp;
|
||||
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);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
|
|
@ -965,19 +968,11 @@ msdosfs_rename(struct vop_rename_args *ap)
|
|||
/*
|
||||
* Check for cross-device rename.
|
||||
*/
|
||||
mp = fvp->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;
|
||||
abortit:
|
||||
if (tdvp == tvp)
|
||||
vrele(tdvp);
|
||||
else
|
||||
vput(tdvp);
|
||||
if (tvp)
|
||||
vput(tvp);
|
||||
vrele(fdvp);
|
||||
vrele(fvp);
|
||||
return (error);
|
||||
goto abortit;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -988,11 +983,99 @@ abortit:
|
|||
goto abortit;
|
||||
}
|
||||
|
||||
error = vn_lock(fvp, LK_EXCLUSIVE);
|
||||
if (error)
|
||||
goto abortit;
|
||||
dp = VTODE(fdvp);
|
||||
ip = VTODE(fvp);
|
||||
/*
|
||||
* When the target exists, both the directory
|
||||
* and target vnodes are passed locked.
|
||||
*/
|
||||
VOP_UNLOCK(tdvp);
|
||||
if (tvp != NULL && tvp != tdvp)
|
||||
VOP_UNLOCK(tvp);
|
||||
|
||||
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
|
||||
|
|
@ -1000,35 +1083,20 @@ abortit:
|
|||
* "ls" or "pwd" with the "." directory entry missing, and "cd .."
|
||||
* 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.
|
||||
*/
|
||||
if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
|
||||
dp == ip ||
|
||||
(fcnp->cn_flags & ISDOTDOT) ||
|
||||
(tcnp->cn_flags & ISDOTDOT) ||
|
||||
(ip->de_flag & DE_RENAME)) {
|
||||
VOP_UNLOCK(fvp);
|
||||
fdip == fip ||
|
||||
(fcnp->cn_flags & ISDOTDOT) != 0 ||
|
||||
(tcnp->cn_flags & ISDOTDOT) != 0) {
|
||||
error = EINVAL;
|
||||
goto abortit;
|
||||
goto unlock;
|
||||
}
|
||||
ip->de_flag |= DE_RENAME;
|
||||
doingdirectory++;
|
||||
doingdirectory = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* parent) then the source directory must not be in the
|
||||
|
|
@ -1040,55 +1108,59 @@ abortit:
|
|||
* call to doscheckpath().
|
||||
*/
|
||||
error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread);
|
||||
VOP_UNLOCK(fvp);
|
||||
if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
|
||||
newparent = 1;
|
||||
if (fdip->de_StartCluster != tdip->de_StartCluster)
|
||||
newparent = true;
|
||||
if (doingdirectory && newparent) {
|
||||
if (error) /* write access check above */
|
||||
goto bad;
|
||||
if (xp != NULL)
|
||||
vput(tvp);
|
||||
/*
|
||||
* doscheckpath() vput()'s dp,
|
||||
* so we have to do a relookup afterwards
|
||||
*/
|
||||
error = doscheckpath(ip, dp);
|
||||
if (error)
|
||||
goto out;
|
||||
if (error != 0) /* write access check above */
|
||||
goto unlock;
|
||||
error = doscheckpath(fip, tdip, &wait_scn);
|
||||
if (wait_scn != 0) {
|
||||
VOP_UNLOCK(fdvp);
|
||||
VOP_UNLOCK(tdvp);
|
||||
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)
|
||||
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
|
||||
* to it. Also, ensure source and target are compatible
|
||||
* (both directories, or both not directories).
|
||||
*/
|
||||
if (xp->de_Attributes & ATTR_DIRECTORY) {
|
||||
if (!dosdirempty(xp)) {
|
||||
if ((tip->de_Attributes & ATTR_DIRECTORY) != 0) {
|
||||
if (!dosdirempty(tip)) {
|
||||
error = ENOTEMPTY;
|
||||
goto bad;
|
||||
goto unlock;
|
||||
}
|
||||
if (!doingdirectory) {
|
||||
error = ENOTDIR;
|
||||
goto bad;
|
||||
goto unlock;
|
||||
}
|
||||
cache_purge(tdvp);
|
||||
} else if (doingdirectory) {
|
||||
error = EISDIR;
|
||||
goto bad;
|
||||
goto unlock;
|
||||
}
|
||||
error = removede(dp, xp);
|
||||
if (error)
|
||||
goto bad;
|
||||
error = msdosfs_lookup_ino(tdvp, NULL, tcnp, &scn, &blkoff);
|
||||
MPASS(error == 0);
|
||||
error = removede(tdip, tip);
|
||||
if (error != 0)
|
||||
goto unlock;
|
||||
vput(tvp);
|
||||
xp = NULL;
|
||||
tvp = NULL;
|
||||
tip = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1096,146 +1168,83 @@ abortit:
|
|||
* into the denode and directory entry for the destination
|
||||
* file/directory.
|
||||
*/
|
||||
error = uniqdosname(VTODE(tdvp), tcnp, toname);
|
||||
if (error)
|
||||
goto abortit;
|
||||
error = uniqdosname(tdip, tcnp, toname);
|
||||
if (error != 0)
|
||||
goto unlock;
|
||||
|
||||
/*
|
||||
* Since from wasn't locked at various places above,
|
||||
* have to do a relookup here.
|
||||
* First write a new entry in the destination
|
||||
* directory and mark the entry in the source directory
|
||||
* as deleted. Then move the denode to the correct hash
|
||||
* chain for its new location in the filesystem. And, if
|
||||
* we moved a directory, then update its .. entry to point
|
||||
* to the new parent directory.
|
||||
*/
|
||||
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;
|
||||
memcpy(oldname, fip->de_Name, 11);
|
||||
memcpy(fip->de_Name, toname, 11); /* update denode */
|
||||
error = msdosfs_lookup_ino(tdvp, NULL, tcnp, &scn, &blkoff);
|
||||
MPASS(error == EJUSTRETURN);
|
||||
error = createde(fip, tdip, NULL, tcnp);
|
||||
if (error != 0) {
|
||||
memcpy(fip->de_Name, oldname, 11);
|
||||
goto unlock;
|
||||
}
|
||||
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 fip is for a directory, then its name should always
|
||||
* be "." since it is for the directory entry in the
|
||||
* directory itself (msdosfs_lookup() always translates
|
||||
* to the "." entry so as to get a unique denode, except
|
||||
* for the root directory there are different
|
||||
* complications). However, we just corrupted its name
|
||||
* to pass the correct name to createde(). Undo this.
|
||||
*/
|
||||
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
|
||||
* directory and mark the entry in the source directory
|
||||
* as deleted. Then move the denode to the correct hash
|
||||
* chain for its new location in the filesystem. And, if
|
||||
* we moved a directory, then update its .. entry to point
|
||||
* to the new parent directory.
|
||||
*/
|
||||
memcpy(oldname, ip->de_Name, 11);
|
||||
memcpy(ip->de_Name, toname, 11); /* update denode */
|
||||
dp->de_fndoffset = to_diroffset;
|
||||
dp->de_fndcnt = to_count;
|
||||
error = createde(ip, dp, (struct denode **)0, tcnp);
|
||||
if (error) {
|
||||
memcpy(ip->de_Name, oldname, 11);
|
||||
if (newparent)
|
||||
VOP_UNLOCK(fdvp);
|
||||
VOP_UNLOCK(fvp);
|
||||
goto bad;
|
||||
}
|
||||
/*
|
||||
* If ip is for a directory, then its name should always
|
||||
* be "." since it is for the directory entry in the
|
||||
* directory itself (msdosfs_lookup() always translates
|
||||
* to the "." entry so as to get a unique denode, except
|
||||
* for the root directory there are different
|
||||
* complications). However, we just corrupted its name
|
||||
* to pass the correct name to createde(). Undo this.
|
||||
*/
|
||||
if ((ip->de_Attributes & ATTR_DIRECTORY) != 0)
|
||||
memcpy(ip->de_Name, oldname, 11);
|
||||
ip->de_refcnt++;
|
||||
zp->de_fndoffset = from_diroffset;
|
||||
error = removede(zp, ip);
|
||||
if (error) {
|
||||
/* XXX should downgrade to ro here, fs is corrupt */
|
||||
if (newparent)
|
||||
VOP_UNLOCK(fdvp);
|
||||
VOP_UNLOCK(fvp);
|
||||
goto bad;
|
||||
}
|
||||
if (!doingdirectory) {
|
||||
error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
|
||||
&ip->de_dirclust, 0);
|
||||
if (error) {
|
||||
/* XXX should downgrade to ro here, fs is corrupt */
|
||||
if (newparent)
|
||||
VOP_UNLOCK(fdvp);
|
||||
VOP_UNLOCK(fvp);
|
||||
goto bad;
|
||||
}
|
||||
if (ip->de_dirclust == MSDOSFSROOT)
|
||||
ip->de_diroffset = to_diroffset;
|
||||
else
|
||||
ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
|
||||
}
|
||||
reinsert(ip);
|
||||
if (newparent)
|
||||
VOP_UNLOCK(fdvp);
|
||||
if ((fip->de_Attributes & ATTR_DIRECTORY) != 0)
|
||||
memcpy(fip->de_Name, oldname, 11);
|
||||
fip->de_refcnt++;
|
||||
error = msdosfs_lookup_ino(fdvp, NULL, fcnp, &scn, &blkoff);
|
||||
MPASS(error == 0);
|
||||
error = removede(fdip, fip);
|
||||
if (error != 0) {
|
||||
/* XXX should downgrade to ro here, fs is corrupt */
|
||||
goto unlock;
|
||||
}
|
||||
if (!doingdirectory) {
|
||||
error = pcbmap(tdip, de_cluster(pmp, to_diroffset), 0,
|
||||
&fip->de_dirclust, 0);
|
||||
if (error != 0) {
|
||||
/*
|
||||
* XXX should downgrade to ro here,
|
||||
* fs is corrupt
|
||||
*/
|
||||
goto unlock;
|
||||
}
|
||||
if (fip->de_dirclust == MSDOSFSROOT)
|
||||
fip->de_diroffset = to_diroffset;
|
||||
else
|
||||
fip->de_diroffset = to_diroffset & pmp->pm_crbomask;
|
||||
}
|
||||
reinsert(fip);
|
||||
|
||||
/*
|
||||
* If we moved a directory to a new parent directory, then we must
|
||||
* fixup the ".." entry in the moved directory.
|
||||
*/
|
||||
if (doingdirectory && newparent) {
|
||||
cn = ip->de_StartCluster;
|
||||
cn = fip->de_StartCluster;
|
||||
if (cn == MSDOSFSROOT) {
|
||||
/* this should never happen */
|
||||
panic("msdosfs_rename(): updating .. in root directory?");
|
||||
} else
|
||||
bn = cntobn(pmp, cn);
|
||||
error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
|
||||
NOCRED, &bp);
|
||||
if (error) {
|
||||
NOCRED, &bp);
|
||||
if (error != 0) {
|
||||
/* XXX should downgrade to ro here, fs is corrupt */
|
||||
VOP_UNLOCK(fvp);
|
||||
goto bad;
|
||||
goto unlock;
|
||||
}
|
||||
dotdotp = (struct direntry *)bp->b_data + 1;
|
||||
pcl = dp->de_StartCluster;
|
||||
pcl = tdip->de_StartCluster;
|
||||
if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
|
||||
pcl = MSDOSFSROOT;
|
||||
putushort(dotdotp->deStartCluster, pcl);
|
||||
|
|
@ -1245,8 +1254,7 @@ abortit:
|
|||
bdwrite(bp);
|
||||
else if ((error = bwrite(bp)) != 0) {
|
||||
/* XXX should downgrade to ro here, fs is corrupt */
|
||||
VOP_UNLOCK(fvp);
|
||||
goto bad;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1258,17 +1266,35 @@ abortit:
|
|||
* namecache entries that were installed for this direntry.
|
||||
*/
|
||||
cache_purge(fvp);
|
||||
VOP_UNLOCK(fvp);
|
||||
bad:
|
||||
if (xp)
|
||||
vput(tvp);
|
||||
|
||||
unlock:
|
||||
vput(fdvp);
|
||||
vput(fvp);
|
||||
if (tvp != NULL) {
|
||||
if (tvp != tdvp)
|
||||
vput(tvp);
|
||||
else
|
||||
vrele(tvp);
|
||||
}
|
||||
vput(tdvp);
|
||||
out:
|
||||
ip->de_flag &= ~DE_RENAME;
|
||||
return (error);
|
||||
releout:
|
||||
vrele(tdvp);
|
||||
if (tvp != NULL)
|
||||
vrele(tvp);
|
||||
vrele(fdvp);
|
||||
vrele(fvp);
|
||||
return (error);
|
||||
abortit:
|
||||
if (tdvp == tvp)
|
||||
vrele(tdvp);
|
||||
else
|
||||
vput(tdvp);
|
||||
if (tvp != NULL)
|
||||
vput(tvp);
|
||||
vrele(fdvp);
|
||||
vrele(fvp);
|
||||
return (error);
|
||||
|
||||
}
|
||||
|
||||
static struct {
|
||||
|
|
@ -1428,7 +1454,7 @@ msdosfs_rmdir(struct vop_rmdir_args *ap)
|
|||
* non-empty.)
|
||||
*/
|
||||
error = 0;
|
||||
if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
|
||||
if (!dosdirempty(ip)) {
|
||||
error = ENOTEMPTY;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue