*/
int (*poll) (const char *, struct fuse_file_info *,
struct fuse_pollhandle *ph, unsigned *reventsp);
+
+ /** Write contents of buffer to an open file
+ *
+ * Similar to the write() method, but data is supplied in a
+ * generic buffer. Use fuse_buf_copy() to transfer data to
+ * the destination.
+ *
+ * Introduced in version 2.9
+ */
+ int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off,
+ struct fuse_file_info *);
};
/** Extra context that may be needed by some filesystems
off_t off, struct fuse_file_info *fi);
int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
size_t size, off_t off, struct fuse_file_info *fi);
+int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
+ struct fuse_bufvec *buf, off_t off,
+ struct fuse_file_info *fi);
int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
struct fuse_file_info *fi);
int fuse_fs_flush(struct fuse_fs *fs, const char *path,
}
}
-int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
- size_t size, off_t off, struct fuse_file_info *fi)
+int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
+ struct fuse_bufvec *buf, off_t off,
+ struct fuse_file_info *fi)
{
fuse_get_context()->private_data = fs->user_data;
- if (fs->op.write) {
+ if (fs->op.write_buf || fs->op.write) {
int res;
+ size_t size = fuse_buf_size(buf);
+ assert(buf->idx = 0 && buf->off == 0);
if (fs->debug)
fprintf(stderr,
- "write%s[%llu] %lu bytes to %llu flags: 0x%x\n",
+ "write%s[%llu] %zu bytes to %llu flags: 0x%x\n",
fi->writepage ? "page" : "",
(unsigned long long) fi->fh,
- (unsigned long) size, (unsigned long long) off,
+ size,
+ (unsigned long long) off,
fi->flags);
- res = fs->op.write(path, buf, size, off, fi);
+ if (fs->op.write_buf) {
+ res = fs->op.write_buf(path, buf, off, fi);
+ } else {
+ void *mem = NULL;
+ struct fuse_buf *flatbuf;
+ struct fuse_bufvec tmp = FUSE_BUFVEC_INIT(size);
+
+ if (buf->count == 1 &&
+ !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
+ flatbuf = &buf->buf[0];
+ } else {
+ mem = malloc(size);
+ if (mem == NULL)
+ goto out;
+
+ tmp.buf[0].mem = mem;
+ res = fuse_buf_copy(&tmp, buf, 0);
+ if (res <= 0)
+ goto out_free;
+ tmp.buf[0].size = res;
+ flatbuf = &tmp.buf[0];
+ }
+
+ res = fs->op.write(path, flatbuf->mem, flatbuf->size,
+ off, fi);
+out_free:
+ free(mem);
+ }
+out:
if (fs->debug && res >= 0)
fprintf(stderr, " write%s[%llu] %u bytes to %llu\n",
fi->writepage ? "page" : "",
}
}
+int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *mem,
+ size_t size, off_t off, struct fuse_file_info *fi)
+{
+ struct fuse_bufvec bufv = FUSE_BUFVEC_INIT(size);
+
+ bufv.buf[0].mem = (void *) mem;
+
+ return fuse_fs_write_buf(fs, path, &bufv, off, fi);
+}
+
int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
struct fuse_file_info *fi)
{
void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn)
{
fuse_get_context()->private_data = fs->user_data;
+ if (!fs->op.write_buf)
+ conn->want &= ~FUSE_CAP_SPLICE_READ;
if (fs->op.init)
fs->user_data = fs->op.init(conn);
}
free(buf);
}
-static void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
- size_t size, off_t off, struct fuse_file_info *fi)
+static void fuse_lib_write_buf(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_bufvec *buf, off_t off,
+ struct fuse_file_info *fi)
{
struct fuse *f = req_fuse_prepare(req);
char *path;
struct fuse_intr_data d;
fuse_prepare_interrupt(f, req, &d);
- res = fuse_fs_write(f->fs, path, buf, size, off, fi);
+ res = fuse_fs_write_buf(f->fs, path, buf, off, fi);
fuse_finish_interrupt(f, req, &d);
free_path(f, ino, path);
}
.create = fuse_lib_create,
.open = fuse_lib_open,
.read = fuse_lib_read,
- .write = fuse_lib_write,
+ .write_buf = fuse_lib_write_buf,
.flush = fuse_lib_flush,
.release = fuse_lib_release,
.fsync = fuse_lib_fsync,
return err;
}
-static int iconv_write(const char *path, const char *buf, size_t size,
- off_t offset, struct fuse_file_info *fi)
+static int iconv_write_buf(const char *path, struct fuse_bufvec *buf,
+ off_t offset, struct fuse_file_info *fi)
{
struct iconv *ic = iconv_get();
char *newpath;
int err = iconv_convpath(ic, path, &newpath, 0);
if (!err) {
- err = fuse_fs_write(ic->next, newpath, buf, size, offset, fi);
+ err = fuse_fs_write_buf(ic->next, newpath, buf, offset, fi);
free(newpath);
}
return err;
.create = iconv_create,
.open = iconv_open_file,
.read = iconv_read,
- .write = iconv_write,
+ .write_buf = iconv_write_buf,
.statfs = iconv_statfs,
.flush = iconv_flush,
.release = iconv_release,
return err;
}
-static int subdir_write(const char *path, const char *buf, size_t size,
+static int subdir_write_buf(const char *path, struct fuse_bufvec *buf,
off_t offset, struct fuse_file_info *fi)
{
struct subdir *d = subdir_get();
char *newpath;
int err = subdir_addpath(d, path, &newpath);
if (!err) {
- err = fuse_fs_write(d->next, newpath, buf, size, offset, fi);
+ err = fuse_fs_write_buf(d->next, newpath, buf, offset, fi);
free(newpath);
}
return err;
.create = subdir_create,
.open = subdir_open,
.read = subdir_read,
- .write = subdir_write,
+ .write_buf = subdir_write_buf,
.statfs = subdir_statfs,
.flush = subdir_flush,
.release = subdir_release,