aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--example/fusexmp_fh.c15
-rw-r--r--include/fuse.h20
-rw-r--r--include/fuse_lowlevel.h12
-rw-r--r--kernel/dir.c34
-rw-r--r--kernel/fuse_kernel.h18
-rw-r--r--lib/fuse.c11
-rw-r--r--lib/fuse_lowlevel.c18
8 files changed, 103 insertions, 36 deletions
diff --git a/ChangeLog b/ChangeLog
index a92cf6f..c6dfda4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,15 +1,20 @@
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
call if 'default_permissions' mount option is not given, and is
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
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>
* lib: optimize buffer reallocation in fill_dir.
diff --git a/example/fusexmp_fh.c b/example/fusexmp_fh.c
index 262a868..2f4b187 100644
--- a/example/fusexmp_fh.c
+++ b/example/fusexmp_fh.c
@@ -204,6 +204,20 @@ static int xmp_truncate(const char *path, off_t size)
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)
{
int res;
@@ -354,6 +368,7 @@ static struct fuse_operations xmp_oper = {
.chmod = xmp_chmod,
.chown = xmp_chown,
.truncate = xmp_truncate,
+ .ftruncate = xmp_ftruncate,
.utime = xmp_utime,
.create = xmp_create,
.open = xmp_open,
diff --git a/include/fuse.h b/include/fuse.h
index 290e9d3..6d7e54b 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -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
* filesystem (e.g. getattr). Open, flush, release, fsync, opendir,
- * releasedir, fsyncdir, access, create, init and destroy are special
- * purpose methods, without which a full featured filesystem can still
- * be implemented.
+ * releasedir, fsyncdir, access, create, ftruncate, init and destroy
+ * are special purpose methods, without which a full featured
+ * filesystem can still be implemented.
*/
struct fuse_operations {
/** Get file attributes.
@@ -324,6 +324,20 @@ struct fuse_operations {
* Introduced in version 2.5
*/
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
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index e9c64ce..a027163 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -198,6 +198,13 @@ struct fuse_lowlevel_ops {
* bitmask contain valid values. Other members contain undefined
* 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:
* fuse_reply_attr()
* fuse_reply_err()
@@ -206,7 +213,10 @@ struct fuse_lowlevel_ops {
* @param ino the inode number
* @param attr the attributes
* @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,
int to_set, struct fuse_file_info *fi);
diff --git a/kernel/dir.c b/kernel/dir.c
index bc792cb..48df469 100644
--- a/kernel/dir.c
+++ b/kernel/dir.c
@@ -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;
}
-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 fvalid = 0;
-
- memset(fattr, 0, sizeof(*fattr));
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)
- fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
+ arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
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)
- 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) */
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
- fattr->atime = iattr->ia_atime.tv_sec;
- fattr->mtime = iattr->ia_mtime.tv_sec;
+ arg->atime = iattr->ia_atime.tv_sec;
+ arg->mtime = iattr->ia_mtime.tv_sec;
#else
- fattr->atime = iattr->ia_atime;
- fattr->mtime = iattr->ia_mtime;
+ arg->atime = iattr->ia_atime;
+ arg->mtime = iattr->ia_mtime;
#endif
}
-
- return fvalid;
+#ifdef ATTR_FILE
+ 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)
@@ -904,7 +906,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
return -EINTR;
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.nodeid = get_node_id(inode);
req->inode = inode;
diff --git a/kernel/fuse_kernel.h b/kernel/fuse_kernel.h
index 23f8315..48b60fc 100644
--- a/kernel/fuse_kernel.h
+++ b/kernel/fuse_kernel.h
@@ -42,7 +42,7 @@
#define FUSE_KERNEL_VERSION 7
/** 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 */
#define FUSE_ROOT_ID 1
@@ -89,6 +89,7 @@ struct fuse_kstatfs {
#define FATTR_SIZE (1 << 3)
#define FATTR_ATIME (1 << 4)
#define FATTR_MTIME (1 << 5)
+#define FATTR_FH (1 << 6)
/**
* Flags returned by the OPEN request
@@ -182,7 +183,20 @@ struct fuse_link_in {
struct fuse_setattr_in {
__u32 valid;
__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 {
diff --git a/lib/fuse.c b/lib/fuse.c
index 5dad478..1399dfd 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -674,12 +674,15 @@ static int do_chown(struct fuse *f, const char *path, struct stat *attr,
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;
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);
return err;
@@ -706,8 +709,6 @@ static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
char *path;
int err;
- (void) fi;
-
err = -ENOENT;
pthread_rwlock_rdlock(&f->tree_lock);
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)))
err = do_chown(f, path, attr, valid);
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))
err = do_utime(f, path, attr);
if (!err)
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index 9379968..b546312 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -95,7 +95,7 @@ static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
#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_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_atime = attr->atime;
stbuf->st_mtime = attr->mtime;
- stbuf->st_ctime = attr->ctime;
#ifdef HAVE_STRUCT_STAT_ST_ATIM
stbuf->st_atim.tv_nsec = attr->atimensec;
stbuf->st_mtim.tv_nsec = attr->mtimensec;
- stbuf->st_ctim.tv_nsec = attr->ctimensec;
#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,
- struct fuse_setattr_in *arg, struct fuse_file_info *fi)
+ struct fuse_setattr_in *arg)
{
if (req->f->op.setattr) {
+ struct fuse_file_info *fi = NULL;
+ struct fuse_file_info fi_store;
struct stat 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);
} else
fuse_reply_err(req, ENOSYS);
@@ -754,7 +760,7 @@ static void fuse_ll_process(void *data, const char *buf, size_t len,
break;
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;
case FUSE_READLINK: