Changeset View
Changeset View
Standalone View
Standalone View
sys/fs/msdosfs/msdosfs_vnops.c
| Show First 20 Lines • Show All 514 Lines • ▼ Show 20 Lines | #endif | ||||
| return (deupdat(dep, 0)); | return (deupdat(dep, 0)); | ||||
| } | } | ||||
| static int | static int | ||||
| msdosfs_read(struct vop_read_args *ap) | msdosfs_read(struct vop_read_args *ap) | ||||
| { | { | ||||
| int error = 0; | int error = 0; | ||||
| int blsize; | int blsize; | ||||
| int isadir; | |||||
| ssize_t orig_resid; | ssize_t orig_resid; | ||||
| u_int n; | u_int n; | ||||
| u_long diff; | u_long diff; | ||||
| u_long on; | u_long on; | ||||
| daddr_t lbn; | daddr_t lbn; | ||||
| daddr_t rablock; | daddr_t rablock; | ||||
| int rasize; | int rasize; | ||||
| int seqcount; | int seqcount; | ||||
| Show All 15 Lines | msdosfs_read(struct vop_read_args *ap) | ||||
| * uio->uio_offset >= 0 and uio->uio_resid >= 0. | * uio->uio_offset >= 0 and uio->uio_resid >= 0. | ||||
| * We don't need to check for large offsets as in ffs because | * We don't need to check for large offsets as in ffs because | ||||
| * dep->de_FileSize <= MSDOSFS_FILESIZE_MAX < OFF_MAX, so large | * dep->de_FileSize <= MSDOSFS_FILESIZE_MAX < OFF_MAX, so large | ||||
| * offsets cannot cause overflow even in theory. | * offsets cannot cause overflow even in theory. | ||||
| */ | */ | ||||
| seqcount = ap->a_ioflag >> IO_SEQSHIFT; | seqcount = ap->a_ioflag >> IO_SEQSHIFT; | ||||
| isadir = dep->de_Attributes & ATTR_DIRECTORY; | |||||
kib: I think it is still worth keep this check somehow, either as KASSERT, or just as `return… | |||||
kevansAuthorUnsubmitted Done Inline ActionsGood point- I'm leaning towards replacing it with return (EISDIR). If the situation is volatile enough that we end up here after having checked back up in vn_io_fault, I'm not sure panicking has much utility from a debugging perspective and we're not not necessarily in a state that otherwise warrants it. kevans: Good point- I'm leaning towards replacing it with `return (EISDIR)`. If the situation is… | |||||
| do { | do { | ||||
| if (uio->uio_offset >= dep->de_FileSize) | if (uio->uio_offset >= dep->de_FileSize) | ||||
| break; | break; | ||||
| lbn = de_cluster(pmp, uio->uio_offset); | lbn = de_cluster(pmp, uio->uio_offset); | ||||
| rablock = lbn + 1; | rablock = lbn + 1; | ||||
| blsize = pmp->pm_bpcluster; | blsize = pmp->pm_bpcluster; | ||||
| on = uio->uio_offset & pmp->pm_crbomask; | on = uio->uio_offset & pmp->pm_crbomask; | ||||
| /* | if (de_cn2off(pmp, rablock) >= dep->de_FileSize) { | ||||
| * If we are operating on a directory file then be sure to | |||||
| * do i/o with the vnode for the filesystem instead of the | |||||
| * vnode for the directory. | |||||
| */ | |||||
| if (isadir) { | |||||
| /* convert cluster # to block # */ | |||||
| error = pcbmap(dep, lbn, &lbn, 0, &blsize); | |||||
| if (error == E2BIG) { | |||||
| error = EINVAL; | |||||
| break; | |||||
| } else if (error) | |||||
| break; | |||||
| error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp); | |||||
| } else if (de_cn2off(pmp, rablock) >= dep->de_FileSize) { | |||||
| error = bread(vp, lbn, blsize, NOCRED, &bp); | error = bread(vp, lbn, blsize, NOCRED, &bp); | ||||
| } else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { | } else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { | ||||
| error = cluster_read(vp, dep->de_FileSize, lbn, blsize, | error = cluster_read(vp, dep->de_FileSize, lbn, blsize, | ||||
| NOCRED, on + uio->uio_resid, seqcount, 0, &bp); | NOCRED, on + uio->uio_resid, seqcount, 0, &bp); | ||||
| } else if (seqcount > 1) { | } else if (seqcount > 1) { | ||||
| rasize = blsize; | rasize = blsize; | ||||
| error = breadn(vp, lbn, | error = breadn(vp, lbn, | ||||
| blsize, &rablock, &rasize, 1, NOCRED, &bp); | blsize, &rablock, &rasize, 1, NOCRED, &bp); | ||||
| Show All 10 Lines | do { | ||||
| if (diff < n) | if (diff < n) | ||||
| n = diff; | n = diff; | ||||
| diff = blsize - bp->b_resid; | diff = blsize - bp->b_resid; | ||||
| if (diff < n) | if (diff < n) | ||||
| n = diff; | n = diff; | ||||
| error = vn_io_fault_uiomove(bp->b_data + on, (int) n, uio); | error = vn_io_fault_uiomove(bp->b_data + on, (int) n, uio); | ||||
| brelse(bp); | brelse(bp); | ||||
| } while (error == 0 && uio->uio_resid > 0 && n != 0); | } while (error == 0 && uio->uio_resid > 0 && n != 0); | ||||
| if (!isadir && (error == 0 || uio->uio_resid != orig_resid) && | if ((error == 0 || uio->uio_resid != orig_resid) && | ||||
| (vp->v_mount->mnt_flag & (MNT_NOATIME | MNT_RDONLY)) == 0) | (vp->v_mount->mnt_flag & (MNT_NOATIME | MNT_RDONLY)) == 0) | ||||
| dep->de_flag |= DE_ACCESS; | dep->de_flag |= DE_ACCESS; | ||||
| return (error); | return (error); | ||||
| } | } | ||||
| /* | /* | ||||
| * Write data to a file or directory. | * Write data to a file or directory. | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 1,354 Lines • Show Last 20 Lines | |||||
I think it is still worth keep this check somehow, either as KASSERT, or just as return (EISDIR). After all, msdosfs is often read from untrusted sources or even synthesized on fly.
There of course will be a redundancy with the upper-level check that in principle looked at the same data, but for msdosfs it is better to recheck.