summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ufs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/ufs/ufs')
-rw-r--r--sys/ufs/ufs/dinode.h4
-rw-r--r--sys/ufs/ufs/inode.h2
-rw-r--r--sys/ufs/ufs/ufs_extattr.c18
-rw-r--r--sys/ufs/ufs/ufs_vnops.c200
4 files changed, 113 insertions, 111 deletions
diff --git a/sys/ufs/ufs/dinode.h b/sys/ufs/ufs/dinode.h
index 8aa1fe0..6d06bde 100644
--- a/sys/ufs/ufs/dinode.h
+++ b/sys/ufs/ufs/dinode.h
@@ -138,7 +138,7 @@ struct ufs2_dinode {
int32_t di_atimensec; /* 68: Last access time. */
int32_t di_ctimensec; /* 72: Last inode change time. */
int32_t di_birthnsec; /* 76: Inode creation time. */
- int32_t di_gen; /* 80: Generation number. */
+ u_int32_t di_gen; /* 80: Generation number. */
u_int32_t di_kernflags; /* 84: Kernel flags. */
u_int32_t di_flags; /* 88: Status flags (chflags). */
int32_t di_extsize; /* 92: External attributes block. */
@@ -180,7 +180,7 @@ struct ufs1_dinode {
ufs1_daddr_t di_ib[NIADDR]; /* 88: Indirect disk blocks. */
u_int32_t di_flags; /* 100: Status flags (chflags). */
int32_t di_blocks; /* 104: Blocks actually held. */
- int32_t di_gen; /* 108: Generation number. */
+ u_int32_t di_gen; /* 108: Generation number. */
u_int32_t di_uid; /* 112: File owner. */
u_int32_t di_gid; /* 116: File group. */
u_int64_t di_modrev; /* 120: i_modrev for NFSv4 */
diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h
index 6416632..97ec63f 100644
--- a/sys/ufs/ufs/inode.h
+++ b/sys/ufs/ufs/inode.h
@@ -102,7 +102,7 @@ struct inode {
int16_t i_nlink; /* File link count. */
u_int64_t i_size; /* File byte count. */
u_int32_t i_flags; /* Status flags (chflags). */
- int64_t i_gen; /* Generation number. */
+ u_int64_t i_gen; /* Generation number. */
u_int32_t i_uid; /* File owner. */
u_int32_t i_gid; /* File group. */
/*
diff --git a/sys/ufs/ufs/ufs_extattr.c b/sys/ufs/ufs/ufs_extattr.c
index d52f650..209d93e 100644
--- a/sys/ufs/ufs/ufs_extattr.c
+++ b/sys/ufs/ufs/ufs_extattr.c
@@ -399,20 +399,8 @@ ufs_extattr_iterate_directory(struct ufsmount *ump, struct vnode *dvp,
return (error);
}
- /*
- * XXXRW: While in UFS, we always get DIRBLKSIZ returns from
- * the directory code on success, on other file systems this
- * may not be the case. For portability, we should check the
- * read length on return from ufs_readdir().
- */
- edp = (struct dirent *)&dirbuf[DIRBLKSIZ];
+ edp = (struct dirent *)&dirbuf[DIRBLKSIZ - auio.uio_resid];
for (dp = (struct dirent *)dirbuf; dp < edp; ) {
-#if (BYTE_ORDER == LITTLE_ENDIAN)
- dp->d_type = dp->d_namlen;
- dp->d_namlen = 0;
-#else
- dp->d_type = 0;
-#endif
if (dp->d_reclen == 0)
break;
error = ufs_extattr_lookup(dvp, UE_GETDIR_LOCKPARENT,
@@ -934,8 +922,8 @@ ufs_extattr_get(struct vnode *vp, int attrnamespace, const char *name,
* is to coerce this to undefined, and let it get cleaned
* up by the next write or extattrctl clean.
*/
- printf("ufs_extattr_get (%s): inode number inconsistency (%d, %jd)\n",
- mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen);
+ printf("ufs_extattr_get (%s): inode number inconsistency (%d, %ju)\n",
+ mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (uintmax_t)ip->i_gen);
error = ENOATTR;
goto vopunlock_exit;
}
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index 574c59c..14df1f3 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -2161,12 +2161,6 @@ ufs_symlink(ap)
/*
* Vnode op for reading directories.
- *
- * The routine below assumes that the on-disk format of a directory
- * is the same as that defined by <sys/dirent.h>. If the on-disk
- * format changes, then it will be necessary to do a conversion
- * from the on-disk format that read returns to the format defined
- * by <sys/dirent.h>.
*/
int
ufs_readdir(ap)
@@ -2179,103 +2173,123 @@ ufs_readdir(ap)
u_long **a_cookies;
} */ *ap;
{
+ struct vnode *vp = ap->a_vp;
struct uio *uio = ap->a_uio;
+ struct buf *bp;
struct inode *ip;
+ struct direct *dp, *edp;
+ u_long *cookies;
+ struct dirent dstdp;
+ off_t offset, startoffset;
+ size_t readcnt, skipcnt;
+ ssize_t startresid;
+ int ncookies;
int error;
- size_t count, lost;
- off_t off;
- if (ap->a_ncookies != NULL)
- /*
- * Ensure that the block is aligned. The caller can use
- * the cookies to determine where in the block to start.
- */
- uio->uio_offset &= ~(DIRBLKSIZ - 1);
- ip = VTOI(ap->a_vp);
+ if (uio->uio_offset < 0)
+ return (EINVAL);
+ ip = VTOI(vp);
if (ip->i_effnlink == 0)
return (0);
- off = uio->uio_offset;
- count = uio->uio_resid;
- /* Make sure we don't return partial entries. */
- if (count <= ((uio->uio_offset + count) & (DIRBLKSIZ -1)))
- return (EINVAL);
- count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
- lost = uio->uio_resid - count;
- uio->uio_resid = count;
- uio->uio_iov->iov_len = count;
-# if (BYTE_ORDER == LITTLE_ENDIAN)
- if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) {
- error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
- } else {
- struct dirent *dp, *edp;
- struct uio auio;
- struct iovec aiov;
- caddr_t dirbuf;
- int readcnt;
- u_char tmp;
-
- auio = *uio;
- auio.uio_iov = &aiov;
- auio.uio_iovcnt = 1;
- auio.uio_segflg = UIO_SYSSPACE;
- aiov.iov_len = count;
- dirbuf = malloc(count, M_TEMP, M_WAITOK);
- aiov.iov_base = dirbuf;
- error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
- if (error == 0) {
- readcnt = count - auio.uio_resid;
- edp = (struct dirent *)&dirbuf[readcnt];
- for (dp = (struct dirent *)dirbuf; dp < edp; ) {
- tmp = dp->d_namlen;
- dp->d_namlen = dp->d_type;
- dp->d_type = tmp;
- if (dp->d_reclen > 0) {
- dp = (struct dirent *)
- ((char *)dp + dp->d_reclen);
- } else {
- error = EIO;
- break;
- }
- }
- if (dp >= edp)
- error = uiomove(dirbuf, readcnt, uio);
+ if (ap->a_ncookies != NULL) {
+ ncookies = uio->uio_resid;
+ if (uio->uio_offset >= ip->i_size)
+ ncookies = 0;
+ else if (ip->i_size - uio->uio_offset < ncookies)
+ ncookies = ip->i_size - uio->uio_offset;
+ ncookies = ncookies / (offsetof(struct direct, d_name) + 4) + 1;
+ cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK);
+ *ap->a_ncookies = ncookies;
+ *ap->a_cookies = cookies;
+ } else {
+ ncookies = 0;
+ cookies = NULL;
+ }
+ offset = startoffset = uio->uio_offset;
+ startresid = uio->uio_resid;
+ error = 0;
+ while (error == 0 && uio->uio_resid > 0 &&
+ uio->uio_offset < ip->i_size) {
+ error = ffs_blkatoff(vp, uio->uio_offset, NULL, &bp);
+ if (error)
+ break;
+ if (bp->b_offset + bp->b_bcount > ip->i_size)
+ readcnt = ip->i_size - bp->b_offset;
+ else
+ readcnt = bp->b_bcount;
+ skipcnt = (size_t)(uio->uio_offset - bp->b_offset) &
+ ~(size_t)(DIRBLKSIZ - 1);
+ offset = bp->b_offset + skipcnt;
+ dp = (struct direct *)&bp->b_data[skipcnt];
+ edp = (struct direct *)&bp->b_data[readcnt];
+ while (error == 0 && uio->uio_resid > 0 && dp < edp) {
+ if (dp->d_reclen <= offsetof(struct direct, d_name) ||
+ (caddr_t)dp + dp->d_reclen > (caddr_t)edp) {
+ error = EIO;
+ break;
+ }
+#if BYTE_ORDER == LITTLE_ENDIAN
+ /* Old filesystem format. */
+ if (vp->v_mount->mnt_maxsymlinklen <= 0) {
+ dstdp.d_namlen = dp->d_type;
+ dstdp.d_type = dp->d_namlen;
+ } else
+#endif
+ {
+ dstdp.d_namlen = dp->d_namlen;
+ dstdp.d_type = dp->d_type;
+ }
+ if (offsetof(struct direct, d_name) + dstdp.d_namlen >
+ dp->d_reclen) {
+ error = EIO;
+ break;
+ }
+ if (offset < startoffset || dp->d_ino == 0)
+ goto nextentry;
+ dstdp.d_fileno = dp->d_ino;
+ dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp);
+ bcopy(dp->d_name, dstdp.d_name, dstdp.d_namlen);
+ dstdp.d_name[dstdp.d_namlen] = '\0';
+ if (dstdp.d_reclen > uio->uio_resid) {
+ if (uio->uio_resid == startresid)
+ error = EINVAL;
+ else
+ error = EJUSTRETURN;
+ break;
}
- free(dirbuf, M_TEMP);
+ /* Advance dp. */
+ error = uiomove((caddr_t)&dstdp, dstdp.d_reclen, uio);
+ if (error)
+ break;
+ if (cookies != NULL) {
+ KASSERT(ncookies > 0,
+ ("ufs_readdir: cookies buffer too small"));
+ *cookies = offset + dp->d_reclen;
+ cookies++;
+ ncookies--;
+ }
+nextentry:
+ offset += dp->d_reclen;
+ dp = (struct direct *)((caddr_t)dp + dp->d_reclen);
}
-# else
- error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
-# endif
- if (!error && ap->a_ncookies != NULL) {
- struct dirent* dpStart;
- struct dirent* dpEnd;
- struct dirent* dp;
- int ncookies;
- u_long *cookies;
- u_long *cookiep;
-
- if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
- panic("ufs_readdir: unexpected uio from NFS server");
- dpStart = (struct dirent *)
- ((char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
- dpEnd = (struct dirent *) uio->uio_iov->iov_base;
- for (dp = dpStart, ncookies = 0;
- dp < dpEnd;
- dp = (struct dirent *)((caddr_t) dp + dp->d_reclen))
- ncookies++;
- cookies = malloc(ncookies * sizeof(u_long), M_TEMP,
- M_WAITOK);
- for (dp = dpStart, cookiep = cookies;
- dp < dpEnd;
- dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
- off += dp->d_reclen;
- *cookiep++ = (u_long) off;
+ bqrelse(bp);
+ uio->uio_offset = offset;
+ }
+ /* We need to correct uio_offset. */
+ uio->uio_offset = offset;
+ if (error == EJUSTRETURN)
+ error = 0;
+ if (ap->a_ncookies != NULL) {
+ if (error == 0) {
+ ap->a_ncookies -= ncookies;
+ } else {
+ free(*ap->a_cookies, M_TEMP);
+ *ap->a_ncookies = 0;
+ *ap->a_cookies = NULL;
}
- *ap->a_ncookies = ncookies;
- *ap->a_cookies = cookies;
}
- uio->uio_resid += lost;
- if (ap->a_eofflag)
- *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
+ if (error == 0 && ap->a_eofflag)
+ *ap->a_eofflag = ip->i_size <= uio->uio_offset;
return (error);
}
OpenPOWER on IntegriCloud