mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-02 19:22:47 +00:00
Make the seek a method of the struct fileops.
Tested by: pho Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
41cf41fdfd
commit
c0a46535c4
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=254602
@ -1697,6 +1697,7 @@ static struct fileops devfs_ops_f = {
|
||||
.fo_chmod = vn_chmod,
|
||||
.fo_chown = vn_chown,
|
||||
.fo_sendfile = vn_sendfile,
|
||||
.fo_seek = vn_seek,
|
||||
.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
|
||||
};
|
||||
|
||||
|
@ -1879,77 +1879,15 @@ sys_lseek(td, uap)
|
||||
int whence;
|
||||
} */ *uap;
|
||||
{
|
||||
struct ucred *cred = td->td_ucred;
|
||||
struct file *fp;
|
||||
struct vnode *vp;
|
||||
struct vattr vattr;
|
||||
off_t foffset, offset, size;
|
||||
int error, noneg;
|
||||
int error;
|
||||
|
||||
AUDIT_ARG_FD(uap->fd);
|
||||
if ((error = fget(td, uap->fd, CAP_SEEK, &fp)) != 0)
|
||||
return (error);
|
||||
if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) {
|
||||
fdrop(fp, td);
|
||||
return (ESPIPE);
|
||||
}
|
||||
vp = fp->f_vnode;
|
||||
foffset = foffset_lock(fp, 0);
|
||||
noneg = (vp->v_type != VCHR);
|
||||
offset = uap->offset;
|
||||
switch (uap->whence) {
|
||||
case L_INCR:
|
||||
if (noneg &&
|
||||
(foffset < 0 ||
|
||||
(offset > 0 && foffset > OFF_MAX - offset))) {
|
||||
error = EOVERFLOW;
|
||||
break;
|
||||
}
|
||||
offset += foffset;
|
||||
break;
|
||||
case L_XTND:
|
||||
vn_lock(vp, LK_SHARED | LK_RETRY);
|
||||
error = VOP_GETATTR(vp, &vattr, cred);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
if (error)
|
||||
break;
|
||||
|
||||
/*
|
||||
* If the file references a disk device, then fetch
|
||||
* the media size and use that to determine the ending
|
||||
* offset.
|
||||
*/
|
||||
if (vattr.va_size == 0 && vp->v_type == VCHR &&
|
||||
fo_ioctl(fp, DIOCGMEDIASIZE, &size, cred, td) == 0)
|
||||
vattr.va_size = size;
|
||||
if (noneg &&
|
||||
(vattr.va_size > OFF_MAX ||
|
||||
(offset > 0 && vattr.va_size > OFF_MAX - offset))) {
|
||||
error = EOVERFLOW;
|
||||
break;
|
||||
}
|
||||
offset += vattr.va_size;
|
||||
break;
|
||||
case L_SET:
|
||||
break;
|
||||
case SEEK_DATA:
|
||||
error = fo_ioctl(fp, FIOSEEKDATA, &offset, cred, td);
|
||||
break;
|
||||
case SEEK_HOLE:
|
||||
error = fo_ioctl(fp, FIOSEEKHOLE, &offset, cred, td);
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
}
|
||||
if (error == 0 && noneg && offset < 0)
|
||||
error = EINVAL;
|
||||
if (error != 0)
|
||||
goto drop;
|
||||
VFS_KNOTE_UNLOCKED(vp, 0);
|
||||
*(off_t *)(td->td_retval) = offset;
|
||||
drop:
|
||||
error = (fp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ?
|
||||
fo_seek(fp, uap->offset, uap->whence, td) : ESPIPE;
|
||||
fdrop(fp, td);
|
||||
foffset_unlock(fp, offset, error != 0 ? FOF_NOUPDATE : 0);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/disk.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/kdb.h>
|
||||
@ -101,6 +102,7 @@ struct fileops vnops = {
|
||||
.fo_chmod = vn_chmod,
|
||||
.fo_chown = vn_chown,
|
||||
.fo_sendfile = vn_sendfile,
|
||||
.fo_seek = vn_seek,
|
||||
.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
|
||||
};
|
||||
|
||||
@ -2010,3 +2012,72 @@ unlock:
|
||||
*off = noff;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
vn_seek(struct file *fp, off_t offset, int whence, struct thread *td)
|
||||
{
|
||||
struct ucred *cred;
|
||||
struct vnode *vp;
|
||||
struct vattr vattr;
|
||||
off_t foffset, size;
|
||||
int error, noneg;
|
||||
|
||||
cred = td->td_ucred;
|
||||
vp = fp->f_vnode;
|
||||
foffset = foffset_lock(fp, 0);
|
||||
noneg = (vp->v_type != VCHR);
|
||||
error = 0;
|
||||
switch (whence) {
|
||||
case L_INCR:
|
||||
if (noneg &&
|
||||
(foffset < 0 ||
|
||||
(offset > 0 && foffset > OFF_MAX - offset))) {
|
||||
error = EOVERFLOW;
|
||||
break;
|
||||
}
|
||||
offset += foffset;
|
||||
break;
|
||||
case L_XTND:
|
||||
vn_lock(vp, LK_SHARED | LK_RETRY);
|
||||
error = VOP_GETATTR(vp, &vattr, cred);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
if (error)
|
||||
break;
|
||||
|
||||
/*
|
||||
* If the file references a disk device, then fetch
|
||||
* the media size and use that to determine the ending
|
||||
* offset.
|
||||
*/
|
||||
if (vattr.va_size == 0 && vp->v_type == VCHR &&
|
||||
fo_ioctl(fp, DIOCGMEDIASIZE, &size, cred, td) == 0)
|
||||
vattr.va_size = size;
|
||||
if (noneg &&
|
||||
(vattr.va_size > OFF_MAX ||
|
||||
(offset > 0 && vattr.va_size > OFF_MAX - offset))) {
|
||||
error = EOVERFLOW;
|
||||
break;
|
||||
}
|
||||
offset += vattr.va_size;
|
||||
break;
|
||||
case L_SET:
|
||||
break;
|
||||
case SEEK_DATA:
|
||||
error = fo_ioctl(fp, FIOSEEKDATA, &offset, cred, td);
|
||||
break;
|
||||
case SEEK_HOLE:
|
||||
error = fo_ioctl(fp, FIOSEEKHOLE, &offset, cred, td);
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
}
|
||||
if (error == 0 && noneg && offset < 0)
|
||||
error = EINVAL;
|
||||
if (error != 0)
|
||||
goto drop;
|
||||
VFS_KNOTE_UNLOCKED(vp, 0);
|
||||
*(off_t *)(td->td_retval) = offset;
|
||||
drop:
|
||||
foffset_unlock(fp, offset, error != 0 ? FOF_NOUPDATE : 0);
|
||||
return (error);
|
||||
}
|
||||
|
@ -108,6 +108,8 @@ typedef int fo_chown_t(struct file *fp, uid_t uid, gid_t gid,
|
||||
typedef int fo_sendfile_t(struct file *fp, int sockfd, struct uio *hdr_uio,
|
||||
struct uio *trl_uio, off_t offset, size_t nbytes,
|
||||
off_t *sent, int flags, int kflags, struct thread *td);
|
||||
typedef int fo_seek_t(struct file *fp, off_t offset, int whence,
|
||||
struct thread *td);
|
||||
typedef int fo_flags_t;
|
||||
|
||||
struct fileops {
|
||||
@ -122,6 +124,7 @@ struct fileops {
|
||||
fo_chmod_t *fo_chmod;
|
||||
fo_chown_t *fo_chown;
|
||||
fo_sendfile_t *fo_sendfile;
|
||||
fo_seek_t *fo_seek;
|
||||
fo_flags_t fo_flags; /* DFLAG_* below */
|
||||
};
|
||||
|
||||
@ -242,6 +245,7 @@ fo_chown_t invfo_chown;
|
||||
fo_sendfile_t invfo_sendfile;
|
||||
|
||||
fo_sendfile_t vn_sendfile;
|
||||
fo_seek_t vn_seek;
|
||||
|
||||
void finit(struct file *, u_int, short, void *, struct fileops *);
|
||||
int fgetvp(struct thread *td, int fd, cap_rights_t rights, struct vnode **vpp);
|
||||
@ -370,6 +374,13 @@ fo_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
|
||||
nbytes, sent, flags, kflags, td));
|
||||
}
|
||||
|
||||
static __inline int
|
||||
fo_seek(struct file *fp, off_t offset, int whence, struct thread *td)
|
||||
{
|
||||
|
||||
return ((*fp->f_ops->fo_seek)(fp, offset, whence, td));
|
||||
}
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* !SYS_FILE_H */
|
||||
|
Loading…
Reference in New Issue
Block a user