version 1.19, 2005/09/10 18:35:56 |
version 1.61.4.3, 2010/07/03 01:19:50 |
Line 60 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 60 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/buf.h> |
#include <sys/buf.h> |
#include <sys/proc.h> |
#include <sys/proc.h> |
#include <sys/mount.h> |
#include <sys/mount.h> |
|
#include <sys/fstrans.h> |
#include <sys/vnode.h> |
#include <sys/vnode.h> |
#include <sys/signalvar.h> |
#include <sys/signalvar.h> |
#include <sys/malloc.h> |
#include <sys/malloc.h> |
#include <sys/dirent.h> |
#include <sys/dirent.h> |
#include <sys/lockf.h> |
#include <sys/lockf.h> |
|
#include <sys/kauth.h> |
|
|
#include <miscfs/genfs/genfs.h> |
#include <miscfs/genfs/genfs.h> |
#include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */ |
#include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */ |
Line 102 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 104 __KERNEL_RCSID(0, "$NetBSD$"); |
|
* only if the SAVESTART bit in cn_flags is clear on success. |
* only if the SAVESTART bit in cn_flags is clear on success. |
*/ |
*/ |
int |
int |
msdosfs_create(v) |
msdosfs_create(void *v) |
void *v; |
|
{ |
{ |
struct vop_create_args /* { |
struct vop_create_args /* { |
struct vnode *a_dvp; |
struct vnode *a_dvp; |
Line 116 msdosfs_create(v) |
|
Line 117 msdosfs_create(v) |
|
struct denode *dep; |
struct denode *dep; |
struct denode *pdep = VTODE(ap->a_dvp); |
struct denode *pdep = VTODE(ap->a_dvp); |
int error; |
int error; |
struct timespec ts; |
|
|
|
#ifdef MSDOSFS_DEBUG |
#ifdef MSDOSFS_DEBUG |
printf("msdosfs_create(cnp %p, vap %p\n", cnp, ap->a_vap); |
printf("msdosfs_create(cnp %p, vap %p\n", cnp, ap->a_vap); |
#endif |
#endif |
|
|
|
fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); |
/* |
/* |
* If this is the root directory and there is no space left we |
* If this is the root directory and there is no space left we |
* can't do anything. This is because the root directory can not |
* can't do anything. This is because the root directory can not |
Line 155 msdosfs_create(v) |
|
Line 156 msdosfs_create(v) |
|
ndirent.de_devvp = pdep->de_devvp; |
ndirent.de_devvp = pdep->de_devvp; |
ndirent.de_pmp = pdep->de_pmp; |
ndirent.de_pmp = pdep->de_pmp; |
ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; |
ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; |
TIMEVAL_TO_TIMESPEC(&time, &ts); |
DETIMES(&ndirent, NULL, NULL, NULL, pdep->de_pmp->pm_gmtoff); |
DETIMES(&ndirent, &ts, &ts, &ts, pdep->de_pmp->pm_gmtoff); |
|
if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0) |
if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0) |
goto bad; |
goto bad; |
if ((cnp->cn_flags & SAVESTART) == 0) |
if ((cnp->cn_flags & SAVESTART) == 0) |
PNBUF_PUT(cnp->cn_pnbuf); |
PNBUF_PUT(cnp->cn_pnbuf); |
|
fstrans_done(ap->a_dvp->v_mount); |
VN_KNOTE(ap->a_dvp, NOTE_WRITE); |
VN_KNOTE(ap->a_dvp, NOTE_WRITE); |
vput(ap->a_dvp); |
vput(ap->a_dvp); |
*ap->a_vpp = DETOV(dep); |
*ap->a_vpp = DETOV(dep); |
return (0); |
return (0); |
|
|
bad: |
bad: |
|
fstrans_done(ap->a_dvp->v_mount); |
PNBUF_PUT(cnp->cn_pnbuf); |
PNBUF_PUT(cnp->cn_pnbuf); |
vput(ap->a_dvp); |
vput(ap->a_dvp); |
return (error); |
return (error); |
} |
} |
|
|
int |
int |
msdosfs_mknod(v) |
msdosfs_close(void *v) |
void *v; |
|
{ |
|
struct vop_mknod_args /* { |
|
struct vnode *a_dvp; |
|
struct vnode **a_vpp; |
|
struct componentname *a_cnp; |
|
struct vattr *a_vap; |
|
} */ *ap = v; |
|
|
|
PNBUF_PUT(ap->a_cnp->cn_pnbuf); |
|
vput(ap->a_dvp); |
|
return (EINVAL); |
|
} |
|
|
|
int |
|
msdosfs_open(v) |
|
void *v; |
|
{ |
|
#if 0 |
|
struct vop_open_args /* { |
|
struct vnode *a_vp; |
|
int a_mode; |
|
struct ucred *a_cred; |
|
struct proc *a_p; |
|
} */ *ap; |
|
#endif |
|
|
|
return (0); |
|
} |
|
|
|
int |
|
msdosfs_close(v) |
|
void *v; |
|
{ |
{ |
struct vop_close_args /* { |
struct vop_close_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
int a_fflag; |
int a_fflag; |
struct ucred *a_cred; |
kauth_cred_t a_cred; |
struct proc *a_p; |
|
} */ *ap = v; |
} */ *ap = v; |
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
struct denode *dep = VTODE(vp); |
struct denode *dep = VTODE(vp); |
struct timespec ts; |
|
|
|
simple_lock(&vp->v_interlock); |
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
if (vp->v_usecount > 1) { |
mutex_enter(vp->v_interlock); |
TIMEVAL_TO_TIMESPEC(&time, &ts); |
if (vp->v_usecount > 1) |
DETIMES(dep, &ts, &ts, &ts, dep->de_pmp->pm_gmtoff); |
DETIMES(dep, NULL, NULL, NULL, dep->de_pmp->pm_gmtoff); |
} |
mutex_exit(vp->v_interlock); |
simple_unlock(&vp->v_interlock); |
fstrans_done(vp->v_mount); |
return (0); |
return (0); |
} |
} |
|
|
int |
static int |
msdosfs_access(v) |
msdosfs_check_possible(struct vnode *vp, struct denode *dep, mode_t mode) |
void *v; |
|
{ |
{ |
struct vop_access_args /* { |
|
struct vnode *a_vp; |
|
int a_mode; |
|
struct ucred *a_cred; |
|
struct proc *a_p; |
|
} */ *ap = v; |
|
struct vnode *vp = ap->a_vp; |
|
struct denode *dep = VTODE(vp); |
|
struct msdosfsmount *pmp = dep->de_pmp; |
|
mode_t mode = ap->a_mode; |
|
|
|
/* |
/* |
* Disallow write attempts on read-only file systems; |
* Disallow write attempts on read-only file systems; |
Line 259 msdosfs_access(v) |
|
Line 215 msdosfs_access(v) |
|
} |
} |
} |
} |
|
|
|
return 0; |
|
} |
|
|
|
static int |
|
msdosfs_check_permitted(struct vnode *vp, struct denode *dep, mode_t mode, |
|
kauth_cred_t cred) |
|
{ |
|
struct msdosfsmount *pmp = dep->de_pmp; |
|
mode_t file_mode; |
|
|
if ((dep->de_Attributes & ATTR_READONLY) == 0) |
if ((dep->de_Attributes & ATTR_READONLY) == 0) |
mode = S_IRWXU|S_IRWXG|S_IRWXO; |
file_mode = S_IRWXU|S_IRWXG|S_IRWXO; |
else |
else |
mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; |
file_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; |
return (vaccess(ap->a_vp->v_type, |
|
mode & (vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask), |
return genfs_can_access(vp->v_type, |
pmp->pm_uid, pmp->pm_gid, ap->a_mode, ap->a_cred)); |
file_mode & (vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask), |
|
pmp->pm_uid, pmp->pm_gid, mode, cred); |
|
} |
|
|
|
int |
|
msdosfs_access(void *v) |
|
{ |
|
struct vop_access_args /* { |
|
struct vnode *a_vp; |
|
int a_mode; |
|
kauth_cred_t a_cred; |
|
} */ *ap = v; |
|
struct vnode *vp = ap->a_vp; |
|
struct denode *dep = VTODE(vp); |
|
int error; |
|
|
|
error = msdosfs_check_possible(vp, dep, ap->a_mode); |
|
if (error) |
|
return error; |
|
|
|
error = msdosfs_check_permitted(vp, dep, ap->a_mode, ap->a_cred); |
|
|
|
return error; |
} |
} |
|
|
int |
int |
msdosfs_getattr(v) |
msdosfs_getattr(void *v) |
void *v; |
|
{ |
{ |
struct vop_getattr_args /* { |
struct vop_getattr_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
struct vattr *a_vap; |
struct vattr *a_vap; |
struct ucred *a_cred; |
kauth_cred_t a_cred; |
struct proc *a_p; |
|
} */ *ap = v; |
} */ *ap = v; |
struct denode *dep = VTODE(ap->a_vp); |
struct denode *dep = VTODE(ap->a_vp); |
struct msdosfsmount *pmp = dep->de_pmp; |
struct msdosfsmount *pmp = dep->de_pmp; |
struct vattr *vap = ap->a_vap; |
struct vattr *vap = ap->a_vap; |
mode_t mode; |
mode_t mode; |
struct timespec ts; |
|
u_long dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry); |
u_long dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry); |
ino_t fileid; |
ino_t fileid; |
|
|
TIMEVAL_TO_TIMESPEC(&time, &ts); |
fstrans_start(ap->a_vp->v_mount, FSTRANS_SHARED); |
DETIMES(dep, &ts, &ts, &ts, pmp->pm_gmtoff); |
DETIMES(dep, NULL, NULL, NULL, pmp->pm_gmtoff); |
vap->va_fsid = dep->de_dev; |
vap->va_fsid = dep->de_dev; |
/* |
/* |
* The following computation of the fileid must be the same as that |
* The following computation of the fileid must be the same as that |
Line 335 msdosfs_getattr(v) |
|
Line 320 msdosfs_getattr(v) |
|
vap->va_bytes = |
vap->va_bytes = |
(dep->de_FileSize + pmp->pm_crbomask) & ~pmp->pm_crbomask; |
(dep->de_FileSize + pmp->pm_crbomask) & ~pmp->pm_crbomask; |
vap->va_type = ap->a_vp->v_type; |
vap->va_type = ap->a_vp->v_type; |
|
fstrans_done(ap->a_vp->v_mount); |
return (0); |
return (0); |
} |
} |
|
|
int |
int |
msdosfs_setattr(v) |
msdosfs_setattr(void *v) |
void *v; |
|
{ |
{ |
struct vop_setattr_args /* { |
struct vop_setattr_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
struct vattr *a_vap; |
struct vattr *a_vap; |
struct ucred *a_cred; |
kauth_cred_t a_cred; |
struct proc *a_p; |
|
} */ *ap = v; |
} */ *ap = v; |
int error = 0, de_changed = 0; |
int error = 0, de_changed = 0; |
struct denode *dep = VTODE(ap->a_vp); |
struct denode *dep = VTODE(ap->a_vp); |
struct msdosfsmount *pmp = dep->de_pmp; |
struct msdosfsmount *pmp = dep->de_pmp; |
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
struct vattr *vap = ap->a_vap; |
struct vattr *vap = ap->a_vap; |
struct ucred *cred = ap->a_cred; |
kauth_cred_t cred = ap->a_cred; |
|
|
#ifdef MSDOSFS_DEBUG |
#ifdef MSDOSFS_DEBUG |
printf("msdosfs_setattr(): vp %p, vap %p, cred %p, p %p\n", |
printf("msdosfs_setattr(): vp %p, vap %p, cred %p\n", |
ap->a_vp, vap, cred, ap->a_p); |
ap->a_vp, vap, cred); |
#endif |
#endif |
/* |
/* |
* Note we silently ignore uid or gid changes. |
* Note we silently ignore uid or gid changes. |
Line 370 msdosfs_setattr(v) |
|
Line 354 msdosfs_setattr(v) |
|
(vap->va_gid != VNOVAL && vap->va_gid != pmp->pm_gid)) { |
(vap->va_gid != VNOVAL && vap->va_gid != pmp->pm_gid)) { |
#ifdef MSDOSFS_DEBUG |
#ifdef MSDOSFS_DEBUG |
printf("msdosfs_setattr(): returning EINVAL\n"); |
printf("msdosfs_setattr(): returning EINVAL\n"); |
printf(" va_type %d, va_nlink %x, va_fsid %lx, va_fileid %llx\n", |
printf(" va_type %d, va_nlink %x, va_fsid %"PRIx64", va_fileid %llx\n", |
vap->va_type, vap->va_nlink, vap->va_fsid, |
vap->va_type, vap->va_nlink, vap->va_fsid, |
(unsigned long long)vap->va_fileid); |
(unsigned long long)vap->va_fileid); |
printf(" va_blocksize %lx, va_rdev %x, va_bytes %qx, va_gen %lx\n", |
printf(" va_blocksize %lx, va_rdev %"PRIx64", va_bytes %"PRIx64", va_gen %lx\n", |
vap->va_blocksize, vap->va_rdev, (long long)vap->va_bytes, vap->va_gen); |
vap->va_blocksize, vap->va_rdev, (long long)vap->va_bytes, vap->va_gen); |
#endif |
#endif |
return (EINVAL); |
return (EINVAL); |
Line 384 msdosfs_setattr(v) |
|
Line 368 msdosfs_setattr(v) |
|
if (ap->a_vp->v_type == VDIR) |
if (ap->a_vp->v_type == VDIR) |
return 0; |
return 0; |
|
|
|
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
if (vap->va_size != VNOVAL) { |
if (vap->va_size != VNOVAL) { |
if (vp->v_mount->mnt_flag & MNT_RDONLY) |
if (vp->v_mount->mnt_flag & MNT_RDONLY) { |
return (EROFS); |
error = EROFS; |
error = detrunc(dep, (u_long)vap->va_size, 0, cred, ap->a_p); |
goto bad; |
|
} |
|
error = detrunc(dep, (u_long)vap->va_size, 0, cred); |
if (error) |
if (error) |
return (error); |
goto bad; |
de_changed = 1; |
de_changed = 1; |
} |
} |
if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { |
if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { |
if (vp->v_mount->mnt_flag & MNT_RDONLY) |
if (vp->v_mount->mnt_flag & MNT_RDONLY) { |
return (EROFS); |
error = EROFS; |
if (cred->cr_uid != pmp->pm_uid && |
goto bad; |
(error = suser(cred, &ap->a_p->p_acflag)) && |
} |
((vap->va_vaflags & VA_UTIMES_NULL) == 0 || |
error = genfs_can_chtimes(ap->a_vp, vap->va_vaflags, |
(error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p)))) |
pmp->pm_uid, cred); |
return (error); |
if (error) |
|
goto bad; |
if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 && |
if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 && |
vap->va_atime.tv_sec != VNOVAL) |
vap->va_atime.tv_sec != VNOVAL) |
unix2dostime(&vap->va_atime, pmp->pm_gmtoff, &dep->de_ADate, NULL, NULL); |
unix2dostime(&vap->va_atime, pmp->pm_gmtoff, &dep->de_ADate, NULL, NULL); |
Line 415 msdosfs_setattr(v) |
|
Line 403 msdosfs_setattr(v) |
|
* attribute. |
* attribute. |
*/ |
*/ |
if (vap->va_mode != (mode_t)VNOVAL) { |
if (vap->va_mode != (mode_t)VNOVAL) { |
if (vp->v_mount->mnt_flag & MNT_RDONLY) |
if (vp->v_mount->mnt_flag & MNT_RDONLY) { |
return (EROFS); |
error = EROFS; |
if (cred->cr_uid != pmp->pm_uid && |
goto bad; |
(error = suser(cred, &ap->a_p->p_acflag))) |
} |
return (error); |
if (kauth_cred_geteuid(cred) != pmp->pm_uid && |
|
(error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, |
|
NULL))) |
|
goto bad; |
/* We ignore the read and execute bits. */ |
/* We ignore the read and execute bits. */ |
if (vap->va_mode & S_IWUSR) |
if (vap->va_mode & S_IWUSR) |
dep->de_Attributes &= ~ATTR_READONLY; |
dep->de_Attributes &= ~ATTR_READONLY; |
Line 432 msdosfs_setattr(v) |
|
Line 423 msdosfs_setattr(v) |
|
* Allow the `archived' bit to be toggled. |
* Allow the `archived' bit to be toggled. |
*/ |
*/ |
if (vap->va_flags != VNOVAL) { |
if (vap->va_flags != VNOVAL) { |
if (vp->v_mount->mnt_flag & MNT_RDONLY) |
if (vp->v_mount->mnt_flag & MNT_RDONLY) { |
return (EROFS); |
error = EROFS; |
if (cred->cr_uid != pmp->pm_uid && |
goto bad; |
(error = suser(cred, &ap->a_p->p_acflag))) |
} |
return (error); |
if (kauth_cred_geteuid(cred) != pmp->pm_uid && |
|
(error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, |
|
NULL))) |
|
goto bad; |
if (vap->va_flags & SF_ARCHIVED) |
if (vap->va_flags & SF_ARCHIVED) |
dep->de_Attributes &= ~ATTR_ARCHIVE; |
dep->de_Attributes &= ~ATTR_ARCHIVE; |
else |
else |
Line 447 msdosfs_setattr(v) |
|
Line 441 msdosfs_setattr(v) |
|
|
|
if (de_changed) { |
if (de_changed) { |
VN_KNOTE(vp, NOTE_ATTRIB); |
VN_KNOTE(vp, NOTE_ATTRIB); |
return (deupdat(dep, 1)); |
error = deupdat(dep, 1); |
} else |
if (error) |
return (0); |
goto bad; |
|
} |
|
|
|
bad: |
|
fstrans_done(vp->v_mount); |
|
return error; |
} |
} |
|
|
int |
int |
msdosfs_read(v) |
msdosfs_read(void *v) |
void *v; |
|
{ |
{ |
struct vop_read_args /* { |
struct vop_read_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
struct uio *a_uio; |
struct uio *a_uio; |
int a_ioflag; |
int a_ioflag; |
struct ucred *a_cred; |
kauth_cred_t a_cred; |
} */ *ap = v; |
} */ *ap = v; |
int error = 0, flags; |
int error = 0; |
int64_t diff; |
int64_t diff; |
int blsize; |
int blsize; |
long n; |
long n; |
long on; |
long on; |
daddr_t lbn; |
daddr_t lbn; |
void *win; |
|
vsize_t bytelen; |
vsize_t bytelen; |
struct buf *bp; |
struct buf *bp; |
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
|
|
if (uio->uio_offset >= dep->de_FileSize) |
if (uio->uio_offset >= dep->de_FileSize) |
return (0); |
return (0); |
|
|
|
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
if (vp->v_type == VREG) { |
if (vp->v_type == VREG) { |
|
const int advice = IO_ADV_DECODE(ap->a_ioflag); |
|
|
while (uio->uio_resid > 0) { |
while (uio->uio_resid > 0) { |
bytelen = MIN(dep->de_FileSize - uio->uio_offset, |
bytelen = MIN(dep->de_FileSize - uio->uio_offset, |
uio->uio_resid); |
uio->uio_resid); |
|
|
if (bytelen == 0) |
if (bytelen == 0) |
break; |
break; |
win = ubc_alloc(&vp->v_uobj, uio->uio_offset, |
error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice, |
&bytelen, UBC_READ); |
UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp)); |
error = uiomove(win, bytelen, uio); |
|
flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; |
|
ubc_release(win, flags); |
|
if (error) |
if (error) |
break; |
break; |
} |
} |
|
|
if (diff < n) |
if (diff < n) |
n = (long) diff; |
n = (long) diff; |
|
|
/* convert cluster # to block # */ |
/* convert cluster # to sector # */ |
error = pcbmap(dep, lbn, &lbn, 0, &blsize); |
error = pcbmap(dep, lbn, &lbn, 0, &blsize); |
if (error) |
if (error) |
return (error); |
goto bad; |
|
|
/* |
/* |
* If we are operating on a directory file then be sure to |
* If we are operating on a directory file then be sure to |
* do i/o with the vnode for the filesystem instead of the |
* do i/o with the vnode for the filesystem instead of the |
* vnode for the directory. |
* vnode for the directory. |
*/ |
*/ |
error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp); |
error = bread(pmp->pm_devvp, de_bn2kb(pmp, lbn), blsize, |
|
NOCRED, 0, &bp); |
n = MIN(n, pmp->pm_bpcluster - bp->b_resid); |
n = MIN(n, pmp->pm_bpcluster - bp->b_resid); |
if (error) { |
if (error) { |
brelse(bp); |
brelse(bp, 0); |
return (error); |
goto bad; |
} |
} |
error = uiomove(bp->b_data + on, (int) n, uio); |
error = uiomove((char *)bp->b_data + on, (int) n, uio); |
brelse(bp); |
brelse(bp, 0); |
} while (error == 0 && uio->uio_resid > 0 && n != 0); |
} while (error == 0 && uio->uio_resid > 0 && n != 0); |
|
|
out: |
out: |
if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) |
if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) |
error = deupdat(dep, 1); |
error = deupdat(dep, 1); |
|
bad: |
|
fstrans_done(vp->v_mount); |
return (error); |
return (error); |
} |
} |
|
|
|
|
* Write data to a file or directory. |
* Write data to a file or directory. |
*/ |
*/ |
int |
int |
msdosfs_write(v) |
msdosfs_write(void *v) |
void *v; |
|
{ |
{ |
struct vop_write_args /* { |
struct vop_write_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
struct uio *a_uio; |
struct uio *a_uio; |
int a_ioflag; |
int a_ioflag; |
struct ucred *a_cred; |
kauth_cred_t a_cred; |
} */ *ap = v; |
} */ *ap = v; |
int resid, flags, extended = 0; |
int resid, extended = 0; |
int error = 0; |
int error = 0; |
int ioflag = ap->a_ioflag; |
int ioflag = ap->a_ioflag; |
u_long osize; |
u_long osize; |
u_long count; |
u_long count; |
void *win; |
|
vsize_t bytelen; |
vsize_t bytelen; |
off_t oldoff; |
off_t oldoff; |
struct uio *uio = ap->a_uio; |
struct uio *uio = ap->a_uio; |
struct proc *p = uio->uio_procp; |
|
struct vnode *vp = ap->a_vp; |
struct vnode *vp = ap->a_vp; |
struct denode *dep = VTODE(vp); |
struct denode *dep = VTODE(vp); |
struct msdosfsmount *pmp = dep->de_pmp; |
struct msdosfsmount *pmp = dep->de_pmp; |
struct ucred *cred = ap->a_cred; |
kauth_cred_t cred = ap->a_cred; |
boolean_t async; |
bool async; |
|
|
#ifdef MSDOSFS_DEBUG |
#ifdef MSDOSFS_DEBUG |
printf("msdosfs_write(vp %p, uio %p, ioflag %x, cred %p\n", |
printf("msdosfs_write(vp %p, uio %p, ioflag %x, cred %p\n", |
Line 601 msdosfs_write(v) |
|
Line 598 msdosfs_write(v) |
|
if (uio->uio_offset + uio->uio_resid > MSDOSFS_FILESIZE_MAX) |
if (uio->uio_offset + uio->uio_resid > MSDOSFS_FILESIZE_MAX) |
return (EFBIG); |
return (EFBIG); |
|
|
/* |
fstrans_start(vp->v_mount, FSTRANS_SHARED); |
* If they've exceeded their filesize limit, tell them about it. |
|
*/ |
|
if (p && |
|
((uio->uio_offset + uio->uio_resid) > |
|
p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) { |
|
psignal(p, SIGXFSZ); |
|
return (EFBIG); |
|
} |
|
|
|
/* |
/* |
* If the offset we are starting the write at is beyond the end of |
* If the offset we are starting the write at is beyond the end of |
* the file, then they've done a seek. Unix filesystems allow |
* the file, then they've done a seek. Unix filesystems allow |
Line 618 msdosfs_write(v) |
|
Line 606 msdosfs_write(v) |
|
* with zeroed blocks. |
* with zeroed blocks. |
*/ |
*/ |
if (uio->uio_offset > dep->de_FileSize) { |
if (uio->uio_offset > dep->de_FileSize) { |
if ((error = deextend(dep, uio->uio_offset, cred)) != 0) |
if ((error = deextend(dep, uio->uio_offset, cred)) != 0) { |
|
fstrans_done(vp->v_mount); |
return (error); |
return (error); |
|
} |
} |
} |
|
|
/* |
/* |
Line 636 msdosfs_write(v) |
|
Line 626 msdosfs_write(v) |
|
if (uio->uio_offset + resid > osize) { |
if (uio->uio_offset + resid > osize) { |
count = de_clcount(pmp, uio->uio_offset + resid) - |
count = de_clcount(pmp, uio->uio_offset + resid) - |
de_clcount(pmp, osize); |
de_clcount(pmp, osize); |
if ((error = extendfile(dep, count, NULL, NULL, 0)) && |
if ((error = extendfile(dep, count, NULL, NULL, 0))) |
(error != ENOSPC || (ioflag & IO_UNIT))) |
|
goto errexit; |
goto errexit; |
} |
|
|
|
if (dep->de_FileSize < uio->uio_offset + resid) { |
|
dep->de_FileSize = uio->uio_offset + resid; |
dep->de_FileSize = uio->uio_offset + resid; |
uvm_vnp_setsize(vp, dep->de_FileSize); |
/* hint uvm to not read in extended part */ |
|
uvm_vnp_setwritesize(vp, dep->de_FileSize); |
extended = 1; |
extended = 1; |
} |
} |
|
|
Line 651 msdosfs_write(v) |
|
Line 639 msdosfs_write(v) |
|
oldoff = uio->uio_offset; |
oldoff = uio->uio_offset; |
bytelen = uio->uio_resid; |
bytelen = uio->uio_resid; |
|
|
win = ubc_alloc(&vp->v_uobj, oldoff, &bytelen, UBC_WRITE); |
error = ubc_uiomove(&vp->v_uobj, uio, bytelen, |
error = uiomove(win, bytelen, uio); |
IO_ADV_DECODE(ioflag), UBC_WRITE | UBC_UNMAP_FLAG(vp)); |
flags = UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0; |
if (error) |
ubc_release(win, flags); |
|
if (error) { |
|
break; |
break; |
} |
|
|
|
/* |
/* |
* flush what we just wrote if necessary. |
* flush what we just wrote if necessary. |
Line 665 msdosfs_write(v) |
|
Line 650 msdosfs_write(v) |
|
*/ |
*/ |
|
|
if (!async && oldoff >> 16 != uio->uio_offset >> 16) { |
if (!async && oldoff >> 16 != uio->uio_offset >> 16) { |
simple_lock(&vp->v_interlock); |
mutex_enter(vp->v_interlock); |
error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16, |
error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16, |
(uio->uio_offset >> 16) << 16, PGO_CLEANIT); |
(uio->uio_offset >> 16) << 16, PGO_CLEANIT); |
} |
} |
} while (error == 0 && uio->uio_resid > 0); |
} while (error == 0 && uio->uio_resid > 0); |
|
|
|
/* set final size */ |
|
uvm_vnp_setsize(vp, dep->de_FileSize); |
if (error == 0 && ioflag & IO_SYNC) { |
if (error == 0 && ioflag & IO_SYNC) { |
simple_lock(&vp->v_interlock); |
mutex_enter(vp->v_interlock); |
error = VOP_PUTPAGES(vp, trunc_page(oldoff), |
error = VOP_PUTPAGES(vp, trunc_page(oldoff), |
round_page(oldoff + bytelen), PGO_CLEANIT | PGO_SYNCIO); |
round_page(oldoff + bytelen), PGO_CLEANIT | PGO_SYNCIO); |
} |
} |
|
|
if (resid > uio->uio_resid) |
if (resid > uio->uio_resid) |
VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0)); |
VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0)); |
if (error) { |
if (error) { |
detrunc(dep, osize, ioflag & IO_SYNC, NOCRED, NULL); |
detrunc(dep, osize, ioflag & IO_SYNC, NOCRED); |
uio->uio_offset -= resid - uio->uio_resid; |
uio->uio_offset -= resid - uio->uio_resid; |
uio->uio_resid = resid; |
uio->uio_resid = resid; |
} else if ((ioflag & IO_SYNC) == IO_SYNC) |
} else if ((ioflag & IO_SYNC) == IO_SYNC) |
error = deupdat(dep, 1); |
error = deupdat(dep, 1); |
|
fstrans_done(vp->v_mount); |
KASSERT(vp->v_size == dep->de_FileSize); |
KASSERT(vp->v_size == dep->de_FileSize); |
return (error); |
return (error); |
} |
} |
|
|
int |
int |
msdosfs_update(v) |
msdosfs_update(struct vnode *vp, const struct timespec *acc, |
void *v; |
const struct timespec *mod, int flags) |
{ |
{ |
struct vop_update_args /* { |
|
struct vnode *a_vp; |
|
struct timespec *a_access; |
|
struct timespec *a_modify; |
|
int a_flags; |
|
} */ *ap = v; |
|
struct buf *bp; |
struct buf *bp; |
struct direntry *dirp; |
struct direntry *dirp; |
struct denode *dep; |
struct denode *dep; |
int error; |
int error; |
struct timespec ts; |
|
|
|
if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) |
if (vp->v_mount->mnt_flag & MNT_RDONLY) |
return (0); |
return (0); |
dep = VTODE(ap->a_vp); |
dep = VTODE(vp); |
TIMEVAL_TO_TIMESPEC(&time, &ts); |
DETIMES(dep, acc, mod, NULL, dep->de_pmp->pm_gmtoff); |
DETIMES(dep, |
|
ap->a_access ? ap->a_access : &ts, |
|
ap->a_modify ? ap->a_modify : &ts, &ts, dep->de_pmp->pm_gmtoff); |
|
if ((dep->de_flag & DE_MODIFIED) == 0) |
if ((dep->de_flag & DE_MODIFIED) == 0) |
return (0); |
return (0); |
dep->de_flag &= ~DE_MODIFIED; |
dep->de_flag &= ~DE_MODIFIED; |
Line 728 msdosfs_update(v) |
|
Line 707 msdosfs_update(v) |
|
if (error) |
if (error) |
return (error); |
return (error); |
DE_EXTERNALIZE(dirp, dep); |
DE_EXTERNALIZE(dirp, dep); |
if (ap->a_flags & (UPDATE_WAIT|UPDATE_DIROP)) |
if (flags & (UPDATE_WAIT|UPDATE_DIROP)) |
return (bwrite(bp)); |
return (bwrite(bp)); |
else { |
else { |
bdwrite(bp); |
bdwrite(bp); |
Line 743 msdosfs_update(v) |
|
Line 722 msdosfs_update(v) |
|
* could just do a sync if they try an fsync on a directory file. |
* could just do a sync if they try an fsync on a directory file. |
*/ |
*/ |
int |
int |
msdosfs_remove(v) |
msdosfs_remove(void *v) |
void *v; |
|
{ |
{ |
struct vop_remove_args /* { |
struct vop_remove_args /* { |
struct vnode *a_dvp; |
struct vnode *a_dvp; |
Line 755 msdosfs_remove(v) |
|
Line 733 msdosfs_remove(v) |
|
struct denode *ddep = VTODE(ap->a_dvp); |
struct denode *ddep = VTODE(ap->a_dvp); |
int error; |
int error; |
|
|
|
fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); |
if (ap->a_vp->v_type == VDIR) |
if (ap->a_vp->v_type == VDIR) |
error = EPERM; |
error = EPERM; |
else |
else |
Line 771 msdosfs_remove(v) |
|
Line 750 msdosfs_remove(v) |
|
vput(ap->a_vp); /* causes msdosfs_inactive() to be called |
vput(ap->a_vp); /* causes msdosfs_inactive() to be called |
* via vrele() */ |
* via vrele() */ |
vput(ap->a_dvp); |
vput(ap->a_dvp); |
|
fstrans_done(ap->a_dvp->v_mount); |
return (error); |
return (error); |
} |
} |
|
|
/* |
/* |
* DOS filesystems don't know what links are. But since we already called |
|
* msdosfs_lookup() with create and lockparent, the parent is locked so we |
|
* have to free it before we return the error. |
|
*/ |
|
int |
|
msdosfs_link(v) |
|
void *v; |
|
{ |
|
struct vop_link_args /* { |
|
struct vnode *a_dvp; |
|
struct vnode *a_vp; |
|
struct componentname *a_cnp; |
|
} */ *ap = v; |
|
|
|
VOP_ABORTOP(ap->a_dvp, ap->a_cnp); |
|
vput(ap->a_dvp); |
|
return (EOPNOTSUPP); |
|
} |
|
|
|
/* |
|
* Renames on files require moving the denode to a new hash queue since the |
* Renames on files require moving the denode to a new hash queue since the |
* denode's location is used to compute which hash queue to put the file |
* denode's location is used to compute which hash queue to put the file |
* in. Unless it is a rename in place. For example "mv a b". |
* in. Unless it is a rename in place. For example "mv a b". |
|
|
* I'm not sure how the memory containing the pathnames pointed at by the |
* I'm not sure how the memory containing the pathnames pointed at by the |
* componentname structures is freed, there may be some memory bleeding |
* componentname structures is freed, there may be some memory bleeding |
* for each rename done. |
* for each rename done. |
|
* |
|
* --More-- Notes: |
|
* This routine needs help. badly. |
*/ |
*/ |
int |
int |
msdosfs_rename(v) |
msdosfs_rename(void *v) |
void *v; |
|
{ |
{ |
struct vop_rename_args /* { |
struct vop_rename_args /* { |
struct vnode *a_fdvp; |
struct vnode *a_fdvp; |
Line 865 msdosfs_rename(v) |
|
Line 827 msdosfs_rename(v) |
|
struct vnode *fdvp = ap->a_fdvp; |
struct vnode *fdvp = ap->a_fdvp; |
struct componentname *tcnp = ap->a_tcnp; |
struct componentname *tcnp = ap->a_tcnp; |
struct componentname *fcnp = ap->a_fcnp; |
struct componentname *fcnp = ap->a_fcnp; |
struct proc *p = tcnp->cn_proc; |
|
struct denode *ip, *xp, *dp, *zp; |
struct denode *ip, *xp, *dp, *zp; |
u_char toname[11], oldname[11]; |
u_char toname[11], oldname[11]; |
u_long from_diroffset, to_diroffset; |
u_long from_diroffset, to_diroffset; |
|
|
goto abortit; |
goto abortit; |
} |
} |
|
|
/* */ |
/* |
|
* XXX: This can deadlock since we hold tdvp/tvp locked. |
|
* But I'm not going to fix it now. |
|
*/ |
if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) |
if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0) |
goto abortit; |
goto abortit; |
dp = VTODE(fdvp); |
dp = VTODE(fdvp); |
|
|
(fcnp->cn_flags & ISDOTDOT) || |
(fcnp->cn_flags & ISDOTDOT) || |
(tcnp->cn_flags & ISDOTDOT) || |
(tcnp->cn_flags & ISDOTDOT) || |
(ip->de_flag & DE_RENAME)) { |
(ip->de_flag & DE_RENAME)) { |
VOP_UNLOCK(fvp, 0); |
VOP_UNLOCK(fvp); |
error = EINVAL; |
error = EINVAL; |
goto abortit; |
goto abortit; |
} |
} |
|
|
} |
} |
VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */ |
VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */ |
|
|
|
fstrans_start(fdvp->v_mount, FSTRANS_SHARED); |
/* |
/* |
* When the target exists, both the directory |
* When the target exists, both the directory |
* and target vnodes are returned locked. |
* and target vnodes are returned locked. |
|
|
* 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, p); |
error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred); |
VOP_UNLOCK(fvp, 0); |
VOP_UNLOCK(fvp); |
if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster) |
if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster) |
newparent = 1; |
newparent = 1; |
|
|
|
/* |
|
* XXX: We can do this here because rename uses SAVEFART and |
|
* therefore fdvp has at least two references (one doesn't |
|
* belong to us, though, and that's evil). We'll get |
|
* another "extra" reference when we do relookup(), so we |
|
* need to compensate. We should *NOT* be doing this, but |
|
* it works, so whatever. |
|
*/ |
vrele(fdvp); |
vrele(fdvp); |
|
|
if (doingdirectory && newparent) { |
if (doingdirectory && newparent) { |
if (error) /* write access check above */ |
if (error) /* write access check above */ |
goto bad; |
goto tdvpbad; |
if (xp != NULL) |
if (xp != NULL) |
vput(tvp); |
vput(tvp); |
|
tvp = NULL; |
/* |
/* |
* doscheckpath() vput()'s dp, |
* doscheckpath() vput()'s dp, |
* so we have to do a relookup afterwards |
* so we have to do a relookup afterwards |
|
|
goto out; |
goto out; |
if ((tcnp->cn_flags & SAVESTART) == 0) |
if ((tcnp->cn_flags & SAVESTART) == 0) |
panic("msdosfs_rename: lost to startdir"); |
panic("msdosfs_rename: lost to startdir"); |
if ((error = relookup(tdvp, &tvp, tcnp)) != 0) |
vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY); |
|
if ((error = relookup(tdvp, &tvp, tcnp)) != 0) { |
|
VOP_UNLOCK(tdvp); |
goto out; |
goto out; |
|
} |
|
/* |
|
* XXX: SAVESTART causes us to get a reference, but |
|
* that's released already above in doscheckpath() |
|
*/ |
dp = VTODE(tdvp); |
dp = VTODE(tdvp); |
xp = tvp ? VTODE(tvp) : NULL; |
xp = tvp ? VTODE(tvp) : NULL; |
} |
} |
|
|
if (xp->de_Attributes & ATTR_DIRECTORY) { |
if (xp->de_Attributes & ATTR_DIRECTORY) { |
if (!dosdirempty(xp)) { |
if (!dosdirempty(xp)) { |
error = ENOTEMPTY; |
error = ENOTEMPTY; |
goto bad; |
goto tdvpbad; |
} |
} |
if (!doingdirectory) { |
if (!doingdirectory) { |
error = ENOTDIR; |
error = ENOTDIR; |
goto bad; |
goto tdvpbad; |
} |
} |
} else if (doingdirectory) { |
} else if (doingdirectory) { |
error = EISDIR; |
error = EISDIR; |
goto bad; |
goto tdvpbad; |
} |
} |
if ((error = removede(dp, xp)) != 0) |
if ((error = removede(dp, xp)) != 0) |
goto bad; |
goto tdvpbad; |
VN_KNOTE(tdvp, NOTE_WRITE); |
VN_KNOTE(tdvp, NOTE_WRITE); |
VN_KNOTE(tvp, NOTE_DELETE); |
VN_KNOTE(tvp, NOTE_DELETE); |
cache_purge(tvp); |
cache_purge(tvp); |
vput(tvp); |
vput(tvp); |
|
tvp = NULL; |
xp = NULL; |
xp = NULL; |
} |
} |
|
|
|
|
* into the denode and directory entry for the destination |
* into the denode and directory entry for the destination |
* file/directory. |
* file/directory. |
*/ |
*/ |
if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0) |
if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0) { |
|
fstrans_done(fdvp->v_mount); |
goto abortit; |
goto abortit; |
|
} |
|
|
/* |
/* |
* Since from wasn't locked at various places above, |
* Since from wasn't locked at various places above, |
|
|
fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; |
fcnp->cn_flags |= LOCKPARENT | LOCKLEAF; |
if ((fcnp->cn_flags & SAVESTART) == 0) |
if ((fcnp->cn_flags & SAVESTART) == 0) |
panic("msdosfs_rename: lost from startdir"); |
panic("msdosfs_rename: lost from startdir"); |
if (!newparent) |
VOP_UNLOCK(tdvp); |
VOP_UNLOCK(tdvp, 0); |
vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY); |
(void) relookup(fdvp, &fvp, fcnp); |
if ((error = relookup(fdvp, &fvp, fcnp))) { |
|
VOP_UNLOCK(fdvp); |
|
vrele(ap->a_fvp); |
|
vrele(tdvp); |
|
fstrans_done(fdvp->v_mount); |
|
return (error); |
|
} |
if (fvp == NULL) { |
if (fvp == NULL) { |
/* |
/* |
* From name has disappeared. |
* From name has disappeared. |
*/ |
*/ |
if (doingdirectory) |
if (doingdirectory) |
panic("rename: lost dir entry"); |
panic("rename: lost dir entry"); |
|
vput(fdvp); |
vrele(ap->a_fvp); |
vrele(ap->a_fvp); |
if (newparent) |
|
VOP_UNLOCK(tdvp, 0); |
|
vrele(tdvp); |
vrele(tdvp); |
|
fstrans_done(fdvp->v_mount); |
return 0; |
return 0; |
} |
} |
fdvp_dorele = 1; |
fdvp_dorele = 1; |
|
VOP_UNLOCK(fdvp); |
xp = VTODE(fvp); |
xp = VTODE(fvp); |
zp = VTODE(fdvp); |
zp = VTODE(fdvp); |
from_diroffset = zp->de_fndoffset; |
from_diroffset = zp->de_fndoffset; |
|
|
if (doingdirectory) |
if (doingdirectory) |
panic("rename: lost dir entry"); |
panic("rename: lost dir entry"); |
vrele(ap->a_fvp); |
vrele(ap->a_fvp); |
VOP_UNLOCK(fvp, 0); |
|
if (newparent) |
|
VOP_UNLOCK(fdvp, 0); |
|
xp = NULL; |
xp = NULL; |
} else { |
} else { |
vrele(fvp); |
vrele(fvp); |
|
|
error = createde(ip, dp, (struct denode **)0, tcnp); |
error = createde(ip, dp, (struct denode **)0, tcnp); |
if (error) { |
if (error) { |
memcpy(ip->de_Name, oldname, 11); |
memcpy(ip->de_Name, oldname, 11); |
if (newparent) |
VOP_UNLOCK(fvp); |
VOP_UNLOCK(fdvp, 0); |
|
VOP_UNLOCK(fvp, 0); |
|
goto bad; |
goto bad; |
} |
} |
ip->de_refcnt++; |
ip->de_refcnt++; |
zp->de_fndoffset = from_diroffset; |
zp->de_fndoffset = from_diroffset; |
if ((error = removede(zp, ip)) != 0) { |
if ((error = removede(zp, ip)) != 0) { |
/* XXX should really panic here, fs is corrupt */ |
/* XXX should really panic here, fs is corrupt */ |
if (newparent) |
VOP_UNLOCK(fvp); |
VOP_UNLOCK(fdvp, 0); |
|
VOP_UNLOCK(fvp, 0); |
|
goto bad; |
goto bad; |
} |
} |
cache_purge(fvp); |
cache_purge(fvp); |
|
|
&ip->de_dirclust, 0); |
&ip->de_dirclust, 0); |
if (error) { |
if (error) { |
/* XXX should really panic here, fs is corrupt */ |
/* XXX should really panic here, fs is corrupt */ |
if (newparent) |
VOP_UNLOCK(fvp); |
VOP_UNLOCK(fdvp, 0); |
|
VOP_UNLOCK(fvp, 0); |
|
goto bad; |
goto bad; |
} |
} |
ip->de_diroffset = to_diroffset; |
ip->de_diroffset = to_diroffset; |
|
|
ip->de_diroffset &= pmp->pm_crbomask; |
ip->de_diroffset &= pmp->pm_crbomask; |
} |
} |
reinsert(ip); |
reinsert(ip); |
if (newparent) |
|
VOP_UNLOCK(fdvp, 0); |
|
} |
} |
|
|
/* |
/* |
|
|
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, de_bn2kb(pmp, bn), |
NOCRED, &bp); |
pmp->pm_bpcluster, NOCRED, B_MODIFY, &bp); |
if (error) { |
if (error) { |
/* XXX should really panic here, fs is corrupt */ |
/* XXX should really panic here, fs is corrupt */ |
brelse(bp); |
brelse(bp, 0); |
VOP_UNLOCK(fvp, 0); |
VOP_UNLOCK(fvp); |
goto bad; |
goto bad; |
} |
} |
dotdotp = (struct direntry *)bp->b_data + 1; |
dotdotp = (struct direntry *)bp->b_data + 1; |
|
|
if (FAT32(pmp)) { |
if (FAT32(pmp)) { |
putushort(dotdotp->deHighClust, |
putushort(dotdotp->deHighClust, |
dp->de_StartCluster >> 16); |
dp->de_StartCluster >> 16); |
|
} else { |
|
putushort(dotdotp->deHighClust, 0); |
} |
} |
if ((error = bwrite(bp)) != 0) { |
if ((error = bwrite(bp)) != 0) { |
/* XXX should really panic here, fs is corrupt */ |
/* XXX should really panic here, fs is corrupt */ |
VOP_UNLOCK(fvp, 0); |
VOP_UNLOCK(fvp); |
goto bad; |
goto bad; |
} |
} |
} |
} |
|
|
VN_KNOTE(fvp, NOTE_RENAME); |
VN_KNOTE(fvp, NOTE_RENAME); |
VOP_UNLOCK(fvp, 0); |
VOP_UNLOCK(fvp); |
bad: |
bad: |
if (xp) |
if (tvp) |
vput(tvp); |
vput(tvp); |
vput(tdvp); |
vrele(tdvp); |
out: |
out: |
ip->de_flag &= ~DE_RENAME; |
ip->de_flag &= ~DE_RENAME; |
if (fdvp_dorele) |
if (fdvp_dorele) |
vrele(fdvp); |
vrele(fdvp); |
vrele(fvp); |
vrele(fvp); |
|
fstrans_done(fdvp->v_mount); |
return (error); |
return (error); |
|
|
|
/* XXX: uuuh */ |
|
tdvpbad: |
|
VOP_UNLOCK(tdvp); |
|
goto bad; |
} |
} |
|
|
static const struct { |
static const struct { |
Line 1197 static const struct { |
|
Line 1186 static const struct { |
|
}; |
}; |
|
|
int |
int |
msdosfs_mkdir(v) |
msdosfs_mkdir(void *v) |
void *v; |
|
{ |
{ |
struct vop_mkdir_args /* { |
struct vop_mkdir_args /* { |
struct vnode *a_dvp; |
struct vnode *a_dvp; |
Line 1213 msdosfs_mkdir(v) |
|
Line 1201 msdosfs_mkdir(v) |
|
int error; |
int error; |
int bn; |
int bn; |
u_long newcluster, pcl; |
u_long newcluster, pcl; |
|
daddr_t lbn; |
struct direntry *denp; |
struct direntry *denp; |
struct msdosfsmount *pmp = pdep->de_pmp; |
struct msdosfsmount *pmp = pdep->de_pmp; |
struct buf *bp; |
struct buf *bp; |
struct timespec ts; |
|
int async = pdep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC; |
int async = pdep->de_pmp->pm_mountp->mnt_flag & MNT_ASYNC; |
|
|
|
fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); |
/* |
/* |
* If this is the root directory and there is no space left we |
* If this is the root directory and there is no space left we |
* can't do anything. This is because the root directory can not |
* can't do anything. This is because the root directory can not |
Line 1240 msdosfs_mkdir(v) |
|
Line 1229 msdosfs_mkdir(v) |
|
memset(&ndirent, 0, sizeof(ndirent)); |
memset(&ndirent, 0, sizeof(ndirent)); |
ndirent.de_pmp = pmp; |
ndirent.de_pmp = pmp; |
ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; |
ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; |
TIMEVAL_TO_TIMESPEC(&time, &ts); |
DETIMES(&ndirent, NULL, NULL, NULL, pmp->pm_gmtoff); |
DETIMES(&ndirent, &ts, &ts, &ts, pmp->pm_gmtoff); |
|
|
|
/* |
/* |
* Now fill the cluster with the "." and ".." entries. And write |
* Now fill the cluster with the "." and ".." entries. And write |
Line 1249 msdosfs_mkdir(v) |
|
Line 1237 msdosfs_mkdir(v) |
|
* directory to be pointing at if there were a crash. |
* directory to be pointing at if there were a crash. |
*/ |
*/ |
bn = cntobn(pmp, newcluster); |
bn = cntobn(pmp, newcluster); |
|
lbn = de_bn2kb(pmp, bn); |
/* always succeeds */ |
/* always succeeds */ |
bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0); |
bp = getblk(pmp->pm_devvp, lbn, pmp->pm_bpcluster, 0, 0); |
memset(bp->b_data, 0, pmp->pm_bpcluster); |
memset(bp->b_data, 0, pmp->pm_bpcluster); |
memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate); |
memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate); |
denp = (struct direntry *)bp->b_data; |
denp = (struct direntry *)bp->b_data; |
Line 1274 msdosfs_mkdir(v) |
|
Line 1263 msdosfs_mkdir(v) |
|
if (FAT32(pmp)) { |
if (FAT32(pmp)) { |
putushort(denp[0].deHighClust, newcluster >> 16); |
putushort(denp[0].deHighClust, newcluster >> 16); |
putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16); |
putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16); |
|
} else { |
|
putushort(denp[0].deHighClust, 0); |
|
putushort(denp[1].deHighClust, 0); |
} |
} |
|
|
if (async) |
if (async) |
Line 1305 msdosfs_mkdir(v) |
|
Line 1297 msdosfs_mkdir(v) |
|
VN_KNOTE(ap->a_dvp, NOTE_WRITE | NOTE_LINK); |
VN_KNOTE(ap->a_dvp, NOTE_WRITE | NOTE_LINK); |
vput(ap->a_dvp); |
vput(ap->a_dvp); |
*ap->a_vpp = DETOV(dep); |
*ap->a_vpp = DETOV(dep); |
|
fstrans_done(ap->a_dvp->v_mount); |
return (0); |
return (0); |
|
|
bad: |
bad: |
|
|
bad2: |
bad2: |
PNBUF_PUT(cnp->cn_pnbuf); |
PNBUF_PUT(cnp->cn_pnbuf); |
vput(ap->a_dvp); |
vput(ap->a_dvp); |
|
fstrans_done(ap->a_dvp->v_mount); |
return (error); |
return (error); |
} |
} |
|
|
int |
int |
msdosfs_rmdir(v) |
msdosfs_rmdir(void *v) |
void *v; |
|
{ |
{ |
struct vop_rmdir_args /* { |
struct vop_rmdir_args /* { |
struct vnode *a_dvp; |
struct vnode *a_dvp; |
Line 1340 msdosfs_rmdir(v) |
|
Line 1333 msdosfs_rmdir(v) |
|
vput(vp); |
vput(vp); |
return (EINVAL); |
return (EINVAL); |
} |
} |
|
fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED); |
/* |
/* |
* 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 |
Line 1374 msdosfs_rmdir(v) |
|
Line 1368 msdosfs_rmdir(v) |
|
/* |
/* |
* Truncate the directory that is being deleted. |
* Truncate the directory that is being deleted. |
*/ |
*/ |
error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred, cnp->cn_proc); |
error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred); |
cache_purge(vp); |
cache_purge(vp); |
out: |
out: |
VN_KNOTE(vp, NOTE_DELETE); |
VN_KNOTE(vp, NOTE_DELETE); |
if (dvp) |
if (dvp) |
vput(dvp); |
vput(dvp); |
vput(vp); |
vput(vp); |
|
fstrans_done(ap->a_dvp->v_mount); |
return (error); |
return (error); |
} |
} |
|
|
/* |
|
* DOS filesystems don't know what symlinks are. |
|
*/ |
|
int |
|
msdosfs_symlink(v) |
|
void *v; |
|
{ |
|
struct vop_symlink_args /* { |
|
struct vnode *a_dvp; |
|
struct vnode **a_vpp; |
|
struct componentname *a_cnp; |
|
struct vattr *a_vap; |
|
char *a_target; |
|
} */ *ap = v; |
|
|
|
VOP_ABORTOP(ap->a_dvp, ap->a_cnp); |
|
vput(ap->a_dvp); |
|
return (EOPNOTSUPP); |
|
} |
|
|
|
int |
int |
msdosfs_readdir(v) |
msdosfs_readdir(void *v) |
void *v; |
|
{ |
{ |
struct vop_readdir_args /* { |
struct vop_readdir_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
struct uio *a_uio; |
struct uio *a_uio; |
struct ucred *a_cred; |
kauth_cred_t a_cred; |
int *a_eofflag; |
int *a_eofflag; |
off_t **a_cookies; |
off_t **a_cookies; |
int *a_ncookies; |
int *a_ncookies; |
Line 1432 msdosfs_readdir(v) |
|
Line 1406 msdosfs_readdir(v) |
|
struct denode *dep = VTODE(ap->a_vp); |
struct denode *dep = VTODE(ap->a_vp); |
struct msdosfsmount *pmp = dep->de_pmp; |
struct msdosfsmount *pmp = dep->de_pmp; |
struct direntry *dentp; |
struct direntry *dentp; |
struct dirent dirbuf; |
struct dirent *dirbuf; |
struct uio *uio = ap->a_uio; |
struct uio *uio = ap->a_uio; |
off_t *cookies = NULL; |
off_t *cookies = NULL; |
int ncookies = 0, nc = 0; |
int ncookies = 0, nc = 0; |
Line 1454 msdosfs_readdir(v) |
|
Line 1428 msdosfs_readdir(v) |
|
return (ENOTDIR); |
return (ENOTDIR); |
|
|
/* |
/* |
* To be safe, initialize dirbuf |
|
*/ |
|
memset(dirbuf.d_name, 0, sizeof(dirbuf.d_name)); |
|
|
|
/* |
|
* If the user buffer is smaller than the size of one dos directory |
* If the user buffer is smaller than the size of one dos directory |
* entry or the file offset is not a multiple of the size of a |
* entry or the file offset is not a multiple of the size of a |
* directory entry, then we fail the read. |
* directory entry, then we fail the read. |
Line 1471 msdosfs_readdir(v) |
|
Line 1440 msdosfs_readdir(v) |
|
lost = uio->uio_resid - count; |
lost = uio->uio_resid - count; |
uio->uio_resid = count; |
uio->uio_resid = count; |
uio_off = uio->uio_offset; |
uio_off = uio->uio_offset; |
|
|
|
fstrans_start(ap->a_vp->v_mount, FSTRANS_SHARED); |
|
|
|
/* Allocate a temporary dirent buffer. */ |
|
dirbuf = malloc(sizeof(struct dirent), M_MSDOSFSTMP, M_WAITOK | M_ZERO); |
|
|
if (ap->a_ncookies) { |
if (ap->a_ncookies) { |
nc = uio->uio_resid / 16; |
nc = uio->uio_resid / _DIRENT_MINSIZE((struct dirent *)0); |
cookies = malloc(nc * sizeof (off_t), M_TEMP, M_WAITOK); |
cookies = malloc(nc * sizeof (off_t), M_TEMP, M_WAITOK); |
*ap->a_cookies = cookies; |
*ap->a_cookies = cookies; |
} |
} |
Line 1490 msdosfs_readdir(v) |
|
Line 1464 msdosfs_readdir(v) |
|
if (dep->de_StartCluster == MSDOSFSROOT |
if (dep->de_StartCluster == MSDOSFSROOT |
|| (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) { |
|| (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) { |
#if 0 |
#if 0 |
printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n", |
printf("msdosfs_readdir(): going after . or .. in root dir, " |
offset); |
"offset %" PRIu64 "\n", offset); |
#endif |
#endif |
bias = 2 * sizeof(struct direntry); |
bias = 2 * sizeof(struct direntry); |
if (offset < bias) { |
if (offset < bias) { |
for (n = (int)offset / sizeof(struct direntry); |
for (n = (int)offset / sizeof(struct direntry); |
n < 2; n++) { |
n < 2; n++) { |
if (FAT32(pmp)) |
if (FAT32(pmp)) |
dirbuf.d_fileno = cntobn(pmp, |
dirbuf->d_fileno = cntobn(pmp, |
(ino_t)pmp->pm_rootdirblk) |
(ino_t)pmp->pm_rootdirblk) |
* dirsperblk; |
* dirsperblk; |
else |
else |
dirbuf.d_fileno = 1; |
dirbuf->d_fileno = 1; |
dirbuf.d_type = DT_DIR; |
dirbuf->d_type = DT_DIR; |
switch (n) { |
switch (n) { |
case 0: |
case 0: |
dirbuf.d_namlen = 1; |
dirbuf->d_namlen = 1; |
strlcpy(dirbuf.d_name, ".", |
strlcpy(dirbuf->d_name, ".", |
sizeof(dirbuf.d_name)); |
sizeof(dirbuf->d_name)); |
break; |
break; |
case 1: |
case 1: |
dirbuf.d_namlen = 2; |
dirbuf->d_namlen = 2; |
strlcpy(dirbuf.d_name, "..", |
strlcpy(dirbuf->d_name, "..", |
sizeof(dirbuf.d_name)); |
sizeof(dirbuf->d_name)); |
break; |
break; |
} |
} |
dirbuf.d_reclen = _DIRENT_SIZE(&dirbuf); |
dirbuf->d_reclen = _DIRENT_SIZE(dirbuf); |
if (uio->uio_resid < dirbuf.d_reclen) |
if (uio->uio_resid < dirbuf->d_reclen) |
goto out; |
goto out; |
error = uiomove(&dirbuf, |
error = uiomove(dirbuf, dirbuf->d_reclen, uio); |
dirbuf.d_reclen, uio); |
|
if (error) |
if (error) |
goto out; |
goto out; |
offset += sizeof(struct direntry); |
offset += sizeof(struct direntry); |
Line 1545 msdosfs_readdir(v) |
|
Line 1518 msdosfs_readdir(v) |
|
n = MIN(n, diff); |
n = MIN(n, diff); |
if ((error = pcbmap(dep, lbn, &bn, &cn, &blsize)) != 0) |
if ((error = pcbmap(dep, lbn, &bn, &cn, &blsize)) != 0) |
break; |
break; |
error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); |
error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, |
|
NOCRED, 0, &bp); |
if (error) { |
if (error) { |
brelse(bp); |
brelse(bp, 0); |
return (error); |
goto bad; |
} |
} |
n = MIN(n, blsize - bp->b_resid); |
n = MIN(n, blsize - bp->b_resid); |
|
|
Line 1556 msdosfs_readdir(v) |
|
Line 1530 msdosfs_readdir(v) |
|
* Convert from dos directory entries to fs-independent |
* Convert from dos directory entries to fs-independent |
* directory entries. |
* directory entries. |
*/ |
*/ |
for (dentp = (struct direntry *)(bp->b_data + on); |
for (dentp = (struct direntry *)((char *)bp->b_data + on); |
(char *)dentp < bp->b_data + on + n; |
(char *)dentp < (char *)bp->b_data + on + n; |
dentp++, offset += sizeof(struct direntry)) { |
dentp++, offset += sizeof(struct direntry)) { |
#if 0 |
#if 0 |
|
|
Line 1568 msdosfs_readdir(v) |
|
Line 1542 msdosfs_readdir(v) |
|
* If this is an unused entry, we can stop. |
* If this is an unused entry, we can stop. |
*/ |
*/ |
if (dentp->deName[0] == SLOT_EMPTY) { |
if (dentp->deName[0] == SLOT_EMPTY) { |
brelse(bp); |
brelse(bp, 0); |
goto out; |
goto out; |
} |
} |
/* |
/* |
Line 1585 msdosfs_readdir(v) |
|
Line 1559 msdosfs_readdir(v) |
|
if (dentp->deAttributes == ATTR_WIN95) { |
if (dentp->deAttributes == ATTR_WIN95) { |
if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) |
if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) |
continue; |
continue; |
chksum = win2unixfn((struct winentry *)dentp, &dirbuf, chksum); |
chksum = win2unixfn((struct winentry *)dentp, |
|
dirbuf, chksum); |
continue; |
continue; |
} |
} |
|
|
Line 1615 msdosfs_readdir(v) |
|
Line 1590 msdosfs_readdir(v) |
|
fileno = 1; |
fileno = 1; |
else |
else |
fileno = cntobn(pmp, fileno) * dirsperblk; |
fileno = cntobn(pmp, fileno) * dirsperblk; |
dirbuf.d_fileno = fileno; |
dirbuf->d_fileno = fileno; |
dirbuf.d_type = DT_DIR; |
dirbuf->d_type = DT_DIR; |
} else { |
} else { |
dirbuf.d_fileno = offset / sizeof(struct direntry); |
dirbuf->d_fileno = |
dirbuf.d_type = DT_REG; |
offset / sizeof(struct direntry); |
|
dirbuf->d_type = DT_REG; |
} |
} |
if (chksum != winChksum(dentp->deName)) |
if (chksum != winChksum(dentp->deName)) |
dirbuf.d_namlen = dos2unixfn(dentp->deName, |
dirbuf->d_namlen = dos2unixfn(dentp->deName, |
(u_char *)dirbuf.d_name, |
(u_char *)dirbuf->d_name, |
pmp->pm_flags & MSDOSFSMNT_SHORTNAME); |
pmp->pm_flags & MSDOSFSMNT_SHORTNAME); |
else |
else |
dirbuf.d_name[dirbuf.d_namlen] = 0; |
dirbuf->d_name[dirbuf->d_namlen] = 0; |
chksum = -1; |
chksum = -1; |
dirbuf.d_reclen = _DIRENT_SIZE(&dirbuf); |
dirbuf->d_reclen = _DIRENT_SIZE(dirbuf); |
if (uio->uio_resid < dirbuf.d_reclen) { |
if (uio->uio_resid < dirbuf->d_reclen) { |
brelse(bp); |
brelse(bp, 0); |
goto out; |
goto out; |
} |
} |
error = uiomove(&dirbuf, |
error = uiomove(dirbuf, dirbuf->d_reclen, uio); |
dirbuf.d_reclen, uio); |
|
if (error) { |
if (error) { |
brelse(bp); |
brelse(bp, 0); |
goto out; |
goto out; |
} |
} |
uio_off = offset + sizeof(struct direntry); |
uio_off = offset + sizeof(struct direntry); |
Line 1644 msdosfs_readdir(v) |
|
Line 1619 msdosfs_readdir(v) |
|
*cookies++ = offset + sizeof(struct direntry); |
*cookies++ = offset + sizeof(struct direntry); |
ncookies++; |
ncookies++; |
if (ncookies >= nc) { |
if (ncookies >= nc) { |
brelse(bp); |
brelse(bp, 0); |
goto out; |
goto out; |
} |
} |
} |
} |
} |
} |
brelse(bp); |
brelse(bp, 0); |
} |
} |
|
|
out: |
out: |
|
|
} else |
} else |
*ap->a_ncookies = ncookies; |
*ap->a_ncookies = ncookies; |
} |
} |
return (error); |
|
} |
|
|
|
/* |
bad: |
* DOS filesystems don't know what symlinks are. |
free(dirbuf, M_MSDOSFSTMP); |
*/ |
fstrans_done(ap->a_vp->v_mount); |
int |
return (error); |
msdosfs_readlink(v) |
|
void *v; |
|
{ |
|
#if 0 |
|
struct vop_readlink_args /* { |
|
struct vnode *a_vp; |
|
struct uio *a_uio; |
|
struct ucred *a_cred; |
|
} */ *ap; |
|
#endif |
|
|
|
return (EINVAL); |
|
} |
} |
|
|
/* |
/* |
Line 1697 msdosfs_readlink(v) |
|
Line 1658 msdosfs_readlink(v) |
|
* bnp - address of where to return the filesystem relative block number |
* bnp - address of where to return the filesystem relative block number |
*/ |
*/ |
int |
int |
msdosfs_bmap(v) |
msdosfs_bmap(void *v) |
void *v; |
|
{ |
{ |
struct vop_bmap_args /* { |
struct vop_bmap_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
Line 1708 msdosfs_bmap(v) |
|
Line 1668 msdosfs_bmap(v) |
|
int *a_runp; |
int *a_runp; |
} */ *ap = v; |
} */ *ap = v; |
struct denode *dep = VTODE(ap->a_vp); |
struct denode *dep = VTODE(ap->a_vp); |
|
int run, maxrun; |
|
daddr_t runbn; |
|
int status; |
|
|
if (ap->a_vpp != NULL) |
if (ap->a_vpp != NULL) |
*ap->a_vpp = dep->de_devvp; |
*ap->a_vpp = dep->de_devvp; |
if (ap->a_bnp == NULL) |
if (ap->a_bnp == NULL) |
return (0); |
return (0); |
if (ap->a_runp) { |
status = pcbmap(dep, ap->a_bn, ap->a_bnp, 0, 0); |
/* |
|
* Sequential clusters should be counted here. |
|
*/ |
|
*ap->a_runp = 0; |
|
} |
|
return (pcbmap(dep, ap->a_bn, ap->a_bnp, 0, 0)); |
|
} |
|
|
|
int |
/* |
msdosfs_reallocblks(v) |
* From FreeBSD: |
void *v; |
* A little kludgy, but we loop calling pcbmap until we |
{ |
* reach the end of the contiguous piece, or reach MAXPHYS. |
#if 0 |
* Since it reduces disk I/Os, the "wasted" CPU is put to |
struct vop_reallocblks_args /* { |
* good use (4 to 5 fold sequential read I/O improvement on USB |
struct vnode *a_vp; |
* drives). |
struct cluster_save *a_buflist; |
*/ |
} */ *ap = v; |
if (ap->a_runp != NULL) { |
#endif |
/* taken from ufs_bmap */ |
|
maxrun = ulmin(MAXPHYS / dep->de_pmp->pm_bpcluster - 1, |
|
dep->de_pmp->pm_maxcluster - ap->a_bn); |
|
for (run = 1; run <= maxrun; run++) { |
|
if (pcbmap(dep, ap->a_bn + run, &runbn, NULL, NULL) |
|
!= 0 || runbn != |
|
*ap->a_bnp + de_cn2bn(dep->de_pmp, run)) |
|
break; |
|
} |
|
*ap->a_runp = run - 1; |
|
} |
|
|
/* Currently no support for clustering */ /* XXX */ |
/* |
return (ENOSPC); |
* We need to scale *ap->a_bnp by sector_size/DEV_BSIZE |
|
*/ |
|
*ap->a_bnp = de_bn2kb(dep->de_pmp, *ap->a_bnp); |
|
return status; |
} |
} |
|
|
int |
int |
msdosfs_strategy(v) |
msdosfs_strategy(void *v) |
void *v; |
|
{ |
{ |
struct vop_strategy_args /* { |
struct vop_strategy_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
Line 1765 msdosfs_strategy(v) |
|
Line 1733 msdosfs_strategy(v) |
|
bp->b_blkno = -1; |
bp->b_blkno = -1; |
if (bp->b_blkno == -1) |
if (bp->b_blkno == -1) |
clrbuf(bp); |
clrbuf(bp); |
|
else |
|
bp->b_blkno = de_bn2kb(dep->de_pmp, bp->b_blkno); |
} |
} |
if (bp->b_blkno == -1) { |
if (bp->b_blkno == -1) { |
biodone(bp); |
biodone(bp); |
Line 1781 msdosfs_strategy(v) |
|
Line 1751 msdosfs_strategy(v) |
|
} |
} |
|
|
int |
int |
msdosfs_print(v) |
msdosfs_print(void *v) |
void *v; |
|
{ |
{ |
struct vop_print_args /* { |
struct vop_print_args /* { |
struct vnode *vp; |
struct vnode *vp; |
Line 1792 msdosfs_print(v) |
|
Line 1761 msdosfs_print(v) |
|
printf( |
printf( |
"tag VT_MSDOSFS, startcluster %ld, dircluster %ld, diroffset %ld ", |
"tag VT_MSDOSFS, startcluster %ld, dircluster %ld, diroffset %ld ", |
dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset); |
dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset); |
printf(" dev %d, %d ", major(dep->de_dev), minor(dep->de_dev)); |
printf(" dev %llu, %llu ", (unsigned long long)major(dep->de_dev), |
lockmgr_printinfo(&ap->a_vp->v_lock); |
(unsigned long long)minor(dep->de_dev)); |
printf("\n"); |
printf("\n"); |
return (0); |
return (0); |
} |
} |
|
|
int |
int |
msdosfs_advlock(v) |
msdosfs_advlock(void *v) |
void *v; |
|
{ |
{ |
struct vop_advlock_args /* { |
struct vop_advlock_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
Line 1815 msdosfs_advlock(v) |
|
Line 1783 msdosfs_advlock(v) |
|
} |
} |
|
|
int |
int |
msdosfs_pathconf(v) |
msdosfs_pathconf(void *v) |
void *v; |
|
{ |
{ |
struct vop_pathconf_args /* { |
struct vop_pathconf_args /* { |
struct vnode *a_vp; |
struct vnode *a_vp; |
Line 1852 msdosfs_pathconf(v) |
|
Line 1819 msdosfs_pathconf(v) |
|
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
|
|
int |
|
msdosfs_fsync(void *v) |
|
{ |
|
struct vop_fsync_args /* { |
|
struct vnode *a_vp; |
|
kauth_cred_t a_cred; |
|
int a_flags; |
|
off_t offlo; |
|
off_t offhi; |
|
} */ *ap = v; |
|
struct vnode *vp = ap->a_vp; |
|
int wait; |
|
int error; |
|
|
|
fstrans_start(vp->v_mount, FSTRANS_LAZY); |
|
wait = (ap->a_flags & FSYNC_WAIT) != 0; |
|
vflushbuf(vp, wait); |
|
if ((ap->a_flags & FSYNC_DATAONLY) != 0) |
|
error = 0; |
|
else |
|
error = msdosfs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0); |
|
|
|
if (error == 0 && ap->a_flags & FSYNC_CACHE) { |
|
struct denode *dep = VTODE(vp); |
|
struct vnode *devvp = dep->de_devvp; |
|
|
|
int l = 0; |
|
error = VOP_IOCTL(devvp, DIOCCACHESYNC, &l, FWRITE, |
|
curlwp->l_cred); |
|
} |
|
fstrans_done(vp->v_mount); |
|
|
|
return (error); |
|
} |
|
|
|
void |
|
msdosfs_detimes(struct denode *dep, const struct timespec *acc, |
|
const struct timespec *mod, const struct timespec *cre, int gmtoff) |
|
{ |
|
struct timespec *ts = NULL, tsb; |
|
|
|
KASSERT(dep->de_flag & (DE_UPDATE | DE_CREATE | DE_ACCESS)); |
|
/* XXX just call getnanotime early and use result if needed? */ |
|
dep->de_flag |= DE_MODIFIED; |
|
if (dep->de_flag & DE_UPDATE) { |
|
if (mod == NULL) { |
|
getnanotime(&tsb); |
|
mod = ts = &tsb; |
|
} |
|
unix2dostime(mod, gmtoff, &dep->de_MDate, &dep->de_MTime, NULL); |
|
dep->de_Attributes |= ATTR_ARCHIVE; |
|
} |
|
if ((dep->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0) { |
|
if (dep->de_flag & DE_ACCESS) { |
|
if (acc == NULL) |
|
acc = ts == NULL ? |
|
(getnanotime(&tsb), ts = &tsb) : ts; |
|
unix2dostime(acc, gmtoff, &dep->de_ADate, NULL, NULL); |
|
} |
|
if (dep->de_flag & DE_CREATE) { |
|
if (cre == NULL) |
|
cre = ts == NULL ? |
|
(getnanotime(&tsb), ts = &tsb) : ts; |
|
unix2dostime(cre, gmtoff, &dep->de_CDate, |
|
&dep->de_CTime, &dep->de_CHun); |
|
} |
|
} |
|
|
|
dep->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS); |
|
} |
|
|
/* Global vfs data structures for msdosfs */ |
/* Global vfs data structures for msdosfs */ |
int (**msdosfs_vnodeop_p)(void *); |
int (**msdosfs_vnodeop_p)(void *); |
const struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = { |
const struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = { |
{ &vop_default_desc, vn_default_error }, |
{ &vop_default_desc, vn_default_error }, |
{ &vop_lookup_desc, msdosfs_lookup }, /* lookup */ |
{ &vop_lookup_desc, msdosfs_lookup }, /* lookup */ |
{ &vop_create_desc, msdosfs_create }, /* create */ |
{ &vop_create_desc, msdosfs_create }, /* create */ |
{ &vop_mknod_desc, msdosfs_mknod }, /* mknod */ |
{ &vop_mknod_desc, genfs_eopnotsupp }, /* mknod */ |
{ &vop_open_desc, msdosfs_open }, /* open */ |
{ &vop_open_desc, genfs_nullop }, /* open */ |
{ &vop_close_desc, msdosfs_close }, /* close */ |
{ &vop_close_desc, msdosfs_close }, /* close */ |
{ &vop_access_desc, msdosfs_access }, /* access */ |
{ &vop_access_desc, msdosfs_access }, /* access */ |
{ &vop_getattr_desc, msdosfs_getattr }, /* getattr */ |
{ &vop_getattr_desc, msdosfs_getattr }, /* getattr */ |
{ &vop_setattr_desc, msdosfs_setattr }, /* setattr */ |
{ &vop_setattr_desc, msdosfs_setattr }, /* setattr */ |
{ &vop_read_desc, msdosfs_read }, /* read */ |
{ &vop_read_desc, msdosfs_read }, /* read */ |
{ &vop_write_desc, msdosfs_write }, /* write */ |
{ &vop_write_desc, msdosfs_write }, /* write */ |
{ &vop_lease_desc, msdosfs_lease_check }, /* lease */ |
|
{ &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ |
{ &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ |
{ &vop_ioctl_desc, msdosfs_ioctl }, /* ioctl */ |
{ &vop_ioctl_desc, msdosfs_ioctl }, /* ioctl */ |
{ &vop_poll_desc, msdosfs_poll }, /* poll */ |
{ &vop_poll_desc, msdosfs_poll }, /* poll */ |
Line 1876 const struct vnodeopv_entry_desc msdosfs |
|
Line 1913 const struct vnodeopv_entry_desc msdosfs |
|
{ &vop_fsync_desc, msdosfs_fsync }, /* fsync */ |
{ &vop_fsync_desc, msdosfs_fsync }, /* fsync */ |
{ &vop_seek_desc, msdosfs_seek }, /* seek */ |
{ &vop_seek_desc, msdosfs_seek }, /* seek */ |
{ &vop_remove_desc, msdosfs_remove }, /* remove */ |
{ &vop_remove_desc, msdosfs_remove }, /* remove */ |
{ &vop_link_desc, msdosfs_link }, /* link */ |
{ &vop_link_desc, genfs_eopnotsupp }, /* link */ |
{ &vop_rename_desc, msdosfs_rename }, /* rename */ |
{ &vop_rename_desc, msdosfs_rename }, /* rename */ |
{ &vop_mkdir_desc, msdosfs_mkdir }, /* mkdir */ |
{ &vop_mkdir_desc, msdosfs_mkdir }, /* mkdir */ |
{ &vop_rmdir_desc, msdosfs_rmdir }, /* rmdir */ |
{ &vop_rmdir_desc, msdosfs_rmdir }, /* rmdir */ |
{ &vop_symlink_desc, msdosfs_symlink }, /* symlink */ |
{ &vop_symlink_desc, genfs_eopnotsupp }, /* symlink */ |
{ &vop_readdir_desc, msdosfs_readdir }, /* readdir */ |
{ &vop_readdir_desc, msdosfs_readdir }, /* readdir */ |
{ &vop_readlink_desc, msdosfs_readlink }, /* readlink */ |
{ &vop_readlink_desc, genfs_einval }, /* readlink */ |
{ &vop_abortop_desc, msdosfs_abortop }, /* abortop */ |
{ &vop_abortop_desc, msdosfs_abortop }, /* abortop */ |
{ &vop_inactive_desc, msdosfs_inactive }, /* inactive */ |
{ &vop_inactive_desc, msdosfs_inactive }, /* inactive */ |
{ &vop_reclaim_desc, msdosfs_reclaim }, /* reclaim */ |
{ &vop_reclaim_desc, msdosfs_reclaim }, /* reclaim */ |
Line 1894 const struct vnodeopv_entry_desc msdosfs |
|
Line 1931 const struct vnodeopv_entry_desc msdosfs |
|
{ &vop_islocked_desc, genfs_islocked }, /* islocked */ |
{ &vop_islocked_desc, genfs_islocked }, /* islocked */ |
{ &vop_pathconf_desc, msdosfs_pathconf }, /* pathconf */ |
{ &vop_pathconf_desc, msdosfs_pathconf }, /* pathconf */ |
{ &vop_advlock_desc, msdosfs_advlock }, /* advlock */ |
{ &vop_advlock_desc, msdosfs_advlock }, /* advlock */ |
{ &vop_reallocblks_desc, msdosfs_reallocblks }, /* reallocblks */ |
|
{ &vop_update_desc, msdosfs_update }, /* update */ |
|
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
{ &vop_bwrite_desc, vn_bwrite }, /* bwrite */ |
{ &vop_getpages_desc, genfs_getpages }, /* getpages */ |
{ &vop_getpages_desc, genfs_getpages }, /* getpages */ |
{ &vop_putpages_desc, genfs_putpages }, /* putpages */ |
{ &vop_putpages_desc, genfs_putpages }, /* putpages */ |