mirror of
https://github.com/libfuse/libfuse.git
synced 2024-12-04 01:24:18 +08:00
add ftruncate() method
This commit is contained in:
parent
d9079a75b1
commit
11509ce3fc
11
ChangeLog
11
ChangeLog
@ -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.
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
34
kernel/dir.c
34
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;
|
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;
|
||||||
|
@ -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 {
|
||||||
|
11
lib/fuse.c
11
lib/fuse.c
@ -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)
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user