add ftruncate() method

This commit is contained in:
Miklos Szeredi 2005-10-26 16:04:04 +00:00
parent d9079a75b1
commit 11509ce3fc
8 changed files with 103 additions and 36 deletions

View File

@ -1,15 +1,20 @@
2005-10-26 Miklos Szeredi <miklos@szeredi.hu> 2005-10-26 Miklos Szeredi <miklos@szeredi.hu>
* Change kernel ABI version to 7.3
* Add ACCESS operation. This is called from the access() system * Add ACCESS operation. This is called from the access() system
call if 'default_permissions' mount option is not given, and is call if 'default_permissions' mount option is not given, and is
not called on kernels 2.4.* not called on kernels 2.4.*
* Fix kernel module compile if kernel source and build directories
differ. Report and initial patch by John Eastman
* Add atomic CREATE+OPEN operation. This will only work with * Add atomic CREATE+OPEN operation. This will only work with
2.6.15 (presumably) or later Linux kernels. 2.6.15 (presumably) or later Linux kernels.
* Add ftruncate() method. This will only work with 2.6.15
(presumably) or later Linux kernels.
* Fix kernel module compile if kernel source and build directories
differ. Report and initial patch by John Eastman
2005-10-18 Miklos Szeredi <miklos@szeredi.hu> 2005-10-18 Miklos Szeredi <miklos@szeredi.hu>
* lib: optimize buffer reallocation in fill_dir. * lib: optimize buffer reallocation in fill_dir.

View File

@ -204,6 +204,20 @@ static int xmp_truncate(const char *path, off_t size)
return 0; return 0;
} }
static int xmp_ftruncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
int res;
(void) path;
res = ftruncate(fi->fh, size);
if(res == -1)
return -errno;
return 0;
}
static int xmp_utime(const char *path, struct utimbuf *buf) static int xmp_utime(const char *path, struct utimbuf *buf)
{ {
int res; int res;
@ -354,6 +368,7 @@ static struct fuse_operations xmp_oper = {
.chmod = xmp_chmod, .chmod = xmp_chmod,
.chown = xmp_chown, .chown = xmp_chown,
.truncate = xmp_truncate, .truncate = xmp_truncate,
.ftruncate = xmp_ftruncate,
.utime = xmp_utime, .utime = xmp_utime,
.create = xmp_create, .create = xmp_create,
.open = xmp_open, .open = xmp_open,

View File

@ -63,9 +63,9 @@ typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type,
* *
* All methods are optional, but some are essential for a useful * All methods are optional, but some are essential for a useful
* filesystem (e.g. getattr). Open, flush, release, fsync, opendir, * filesystem (e.g. getattr). Open, flush, release, fsync, opendir,
* releasedir, fsyncdir, access, create, init and destroy are special * releasedir, fsyncdir, access, create, ftruncate, init and destroy
* purpose methods, without which a full featured filesystem can still * are special purpose methods, without which a full featured
* be implemented. * filesystem can still be implemented.
*/ */
struct fuse_operations { struct fuse_operations {
/** Get file attributes. /** Get file attributes.
@ -324,6 +324,20 @@ struct fuse_operations {
* Introduced in version 2.5 * Introduced in version 2.5
*/ */
int (*create) (const char *, mode_t, struct fuse_file_info *); int (*create) (const char *, mode_t, struct fuse_file_info *);
/**
* Change the size of an open file
*
* This method is called instead of the truncate() method if the
* truncation was invoked from an ftruncate() system call.
*
* If this method is not implemented or under Linux kernel
* versions earlier than 2.6.15, the truncate() method will be
* called instead.
*
* Introduced in version 2.5
*/
int (*ftruncate) (const char *, off_t, struct fuse_file_info *);
}; };
/** Extra context that may be needed by some filesystems /** Extra context that may be needed by some filesystems

View File

@ -198,6 +198,13 @@ struct fuse_lowlevel_ops {
* bitmask contain valid values. Other members contain undefined * bitmask contain valid values. Other members contain undefined
* values. * values.
* *
* If the setattr was invoked from the ftruncate() system call
* under Linux kernel versions 2.6.15 or later, the fi->fh will
* contain the value set by the open method or will be undefined
* if the open method didn't set any value. Otherwise (not
* ftruncate call, or kernel version earlier than 2.6.15) the fi
* parameter will be NULL.
*
* Valid replies: * Valid replies:
* fuse_reply_attr() * fuse_reply_attr()
* fuse_reply_err() * fuse_reply_err()
@ -206,7 +213,10 @@ struct fuse_lowlevel_ops {
* @param ino the inode number * @param ino the inode number
* @param attr the attributes * @param attr the attributes
* @param to_set bit mask of attributes which should be set * @param to_set bit mask of attributes which should be set
* @param fi for future use, currently always NULL * @param fi file information, or NULL
*
* Changed in version 2.5:
* file information filled in for ftruncate
*/ */
void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info *fi); int to_set, struct fuse_file_info *fi);

View File

@ -838,34 +838,36 @@ static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
return file ? fuse_fsync_common(file, de, datasync, 1) : 0; return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
} }
static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr) static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
{ {
unsigned ivalid = iattr->ia_valid; unsigned ivalid = iattr->ia_valid;
unsigned fvalid = 0;
memset(fattr, 0, sizeof(*fattr));
if (ivalid & ATTR_MODE) if (ivalid & ATTR_MODE)
fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode; arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
if (ivalid & ATTR_UID) if (ivalid & ATTR_UID)
fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid; arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
if (ivalid & ATTR_GID) if (ivalid & ATTR_GID)
fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid; arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
if (ivalid & ATTR_SIZE) if (ivalid & ATTR_SIZE)
fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size; arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
/* You can only _set_ these together (they may change by themselves) */ /* You can only _set_ these together (they may change by themselves) */
if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) { if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
fvalid |= FATTR_ATIME | FATTR_MTIME; arg->valid |= FATTR_ATIME | FATTR_MTIME;
#ifdef KERNEL_2_6 #ifdef KERNEL_2_6
fattr->atime = iattr->ia_atime.tv_sec; arg->atime = iattr->ia_atime.tv_sec;
fattr->mtime = iattr->ia_mtime.tv_sec; arg->mtime = iattr->ia_mtime.tv_sec;
#else #else
fattr->atime = iattr->ia_atime; arg->atime = iattr->ia_atime;
fattr->mtime = iattr->ia_mtime; arg->mtime = iattr->ia_mtime;
#endif #endif
} }
#ifdef ATTR_FILE
return fvalid; if (ivalid & ATTR_FILE) {
struct fuse_file *ff = iattr->ia_file->private_data;
arg->valid |= FATTR_FH;
arg->fh = ff->fh;
}
#endif
} }
static int fuse_setattr(struct dentry *entry, struct iattr *attr) static int fuse_setattr(struct dentry *entry, struct iattr *attr)
@ -904,7 +906,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
return -EINTR; return -EINTR;
memset(&inarg, 0, sizeof(inarg)); memset(&inarg, 0, sizeof(inarg));
inarg.valid = iattr_to_fattr(attr, &inarg.attr); iattr_to_fattr(attr, &inarg);
req->in.h.opcode = FUSE_SETATTR; req->in.h.opcode = FUSE_SETATTR;
req->in.h.nodeid = get_node_id(inode); req->in.h.nodeid = get_node_id(inode);
req->inode = inode; req->inode = inode;

View File

@ -42,7 +42,7 @@
#define FUSE_KERNEL_VERSION 7 #define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */ /** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 2 #define FUSE_KERNEL_MINOR_VERSION 3
/** The node ID of the root inode */ /** The node ID of the root inode */
#define FUSE_ROOT_ID 1 #define FUSE_ROOT_ID 1
@ -89,6 +89,7 @@ struct fuse_kstatfs {
#define FATTR_SIZE (1 << 3) #define FATTR_SIZE (1 << 3)
#define FATTR_ATIME (1 << 4) #define FATTR_ATIME (1 << 4)
#define FATTR_MTIME (1 << 5) #define FATTR_MTIME (1 << 5)
#define FATTR_FH (1 << 6)
/** /**
* Flags returned by the OPEN request * Flags returned by the OPEN request
@ -182,7 +183,20 @@ struct fuse_link_in {
struct fuse_setattr_in { struct fuse_setattr_in {
__u32 valid; __u32 valid;
__u32 padding; __u32 padding;
struct fuse_attr attr; __u64 fh;
__u64 size;
__u64 unused1;
__u64 atime;
__u64 mtime;
__u64 unused2;
__u32 atimensec;
__u32 mtimensec;
__u32 unused3;
__u32 mode;
__u32 unused4;
__u32 uid;
__u32 gid;
__u32 unused5;
}; };
struct fuse_open_in { struct fuse_open_in {

View File

@ -674,12 +674,15 @@ static int do_chown(struct fuse *f, const char *path, struct stat *attr,
return err; return err;
} }
static int do_truncate(struct fuse *f, const char *path, struct stat *attr) static int do_truncate(struct fuse *f, const char *path, struct stat *attr,
struct fuse_file_info *fi)
{ {
int err; int err;
err = -ENOSYS; err = -ENOSYS;
if (f->op.truncate) if (fi && f->op.ftruncate)
err = f->op.ftruncate(path, attr->st_size, fi);
else if (f->op.truncate)
err = f->op.truncate(path, attr->st_size); err = f->op.truncate(path, attr->st_size);
return err; return err;
@ -706,8 +709,6 @@ static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
char *path; char *path;
int err; int err;
(void) fi;
err = -ENOENT; err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock); pthread_rwlock_rdlock(&f->tree_lock);
path = get_path(f, ino); path = get_path(f, ino);
@ -720,7 +721,7 @@ static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)))
err = do_chown(f, path, attr, valid); err = do_chown(f, path, attr, valid);
if (!err && (valid & FUSE_SET_ATTR_SIZE)) if (!err && (valid & FUSE_SET_ATTR_SIZE))
err = do_truncate(f, path, attr); err = do_truncate(f, path, attr, fi);
if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))
err = do_utime(f, path, attr); err = do_utime(f, path, attr);
if (!err) if (!err)

View File

@ -95,7 +95,7 @@ static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
#endif #endif
} }
static void convert_attr(const struct fuse_attr *attr, struct stat *stbuf) static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
{ {
stbuf->st_mode = attr->mode; stbuf->st_mode = attr->mode;
stbuf->st_uid = attr->uid; stbuf->st_uid = attr->uid;
@ -103,11 +103,9 @@ static void convert_attr(const struct fuse_attr *attr, struct stat *stbuf)
stbuf->st_size = attr->size; stbuf->st_size = attr->size;
stbuf->st_atime = attr->atime; stbuf->st_atime = attr->atime;
stbuf->st_mtime = attr->mtime; stbuf->st_mtime = attr->mtime;
stbuf->st_ctime = attr->ctime;
#ifdef HAVE_STRUCT_STAT_ST_ATIM #ifdef HAVE_STRUCT_STAT_ST_ATIM
stbuf->st_atim.tv_nsec = attr->atimensec; stbuf->st_atim.tv_nsec = attr->atimensec;
stbuf->st_mtim.tv_nsec = attr->mtimensec; stbuf->st_mtim.tv_nsec = attr->mtimensec;
stbuf->st_ctim.tv_nsec = attr->ctimensec;
#endif #endif
} }
@ -366,12 +364,20 @@ static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
} }
static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
struct fuse_setattr_in *arg, struct fuse_file_info *fi) struct fuse_setattr_in *arg)
{ {
if (req->f->op.setattr) { if (req->f->op.setattr) {
struct fuse_file_info *fi = NULL;
struct fuse_file_info fi_store;
struct stat stbuf; struct stat stbuf;
memset(&stbuf, 0, sizeof(stbuf)); memset(&stbuf, 0, sizeof(stbuf));
convert_attr(&arg->attr, &stbuf); convert_attr(arg, &stbuf);
if (arg->valid & FATTR_FH) {
arg->valid &= ~FATTR_FH;
memset(&fi_store, 0, sizeof(fi_store));
fi = &fi_store;
fi->fh = arg->fh;
}
req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi); req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
} else } else
fuse_reply_err(req, ENOSYS); fuse_reply_err(req, ENOSYS);
@ -754,7 +760,7 @@ static void fuse_ll_process(void *data, const char *buf, size_t len,
break; break;
case FUSE_SETATTR: case FUSE_SETATTR:
do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg, NULL); do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
break; break;
case FUSE_READLINK: case FUSE_READLINK: