*/
int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off,
struct fuse_file_info *);
+
+ /** Store data from an open file in a buffer
+ *
+ * Similar to the read() method, but data is stored and
+ * returned in a generic buffer.
+ *
+ * No actual copying of data has to take place, the source
+ * file descriptor may simply be stored in the buffer for
+ * later data transfer.
+ *
+ * The buffer must be allocated dynamically and stored at the
+ * location pointed to by bufp. If the buffer contains memory
+ * regions, they too must be allocated using malloc(). The
+ * allocated memory will be freed by the caller.
+ *
+ * Introduced in version 2.9
+ */
+ int (*read_buf) (const char *, struct fuse_bufvec **bufp,
+ size_t size, off_t off, struct fuse_file_info *);
};
/** Extra context that may be needed by some filesystems
struct fuse_file_info *fi);
int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
off_t off, struct fuse_file_info *fi);
+int fuse_fs_read_buf(struct fuse_fs *fs, const char *path,
+ struct fuse_bufvec **bufp, size_t size, 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,
}
}
-int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
- off_t off, struct fuse_file_info *fi)
+static void fuse_free_buf(struct fuse_bufvec *buf)
+{
+ if (buf != NULL) {
+ size_t i;
+
+ for (i = 0; i < buf->count; i++)
+ free(buf->buf[i].mem);
+ free(buf);
+ }
+}
+
+int fuse_fs_read_buf(struct fuse_fs *fs, const char *path,
+ struct fuse_bufvec **bufp, size_t size, off_t off,
+ struct fuse_file_info *fi)
{
fuse_get_context()->private_data = fs->user_data;
- if (fs->op.read) {
+ if (fs->op.read || fs->op.read_buf) {
int res;
if (fs->debug)
fprintf(stderr,
- "read[%llu] %lu bytes from %llu flags: 0x%x\n",
+ "read[%llu] %zu bytes from %llu flags: 0x%x\n",
(unsigned long long) fi->fh,
- (unsigned long) size, (unsigned long long) off,
- fi->flags);
+ size, (unsigned long long) off, fi->flags);
+
+ if (fs->op.read_buf) {
+ res = fs->op.read_buf(path, bufp, size, off, fi);
+ } else {
+ struct fuse_bufvec *buf;
+ void *mem;
- res = fs->op.read(path, buf, size, off, fi);
+ buf = malloc(sizeof(struct fuse_bufvec));
+ if (buf == NULL)
+ return -ENOMEM;
+
+ mem = malloc(size);
+ if (mem == NULL) {
+ free(buf);
+ return -ENOMEM;
+ }
+ *buf = FUSE_BUFVEC_INIT(size);
+ buf->buf[0].mem = mem;
+ *bufp = buf;
+
+ res = fs->op.read(path, mem, size, off, fi);
+ if (res >= 0)
+ buf->buf[0].size = res;
+ }
if (fs->debug && res >= 0)
- fprintf(stderr, " read[%llu] %u bytes from %llu\n",
- (unsigned long long) fi->fh, res,
+ fprintf(stderr, " read[%llu] %zu bytes from %llu\n",
+ (unsigned long long) fi->fh,
+ fuse_buf_size(*bufp),
(unsigned long long) off);
- if (res > (int) size)
+ if (res >= 0 && fuse_buf_size(*bufp) > (int) size)
fprintf(stderr, "fuse: read too many bytes\n");
- return res;
+ if (res < 0)
+ return res;
+
+ return 0;
} else {
return -ENOSYS;
}
}
+int fuse_fs_read(struct fuse_fs *fs, const char *path, char *mem, size_t size,
+ off_t off, struct fuse_file_info *fi)
+{
+ int res;
+ struct fuse_bufvec *buf = NULL;
+
+ res = fuse_fs_read_buf(fs, path, &buf, size, off, fi);
+ if (res == 0) {
+ struct fuse_bufvec dst = FUSE_BUFVEC_INIT(size);
+
+ dst.buf[0].mem = mem;
+ res = fuse_buf_copy(&dst, buf, 0);
+ }
+ fuse_free_buf(buf);
+
+ return res;
+}
+
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 res;
size_t size = fuse_buf_size(buf);
- assert(buf->idx = 0 && buf->off == 0);
+ assert(buf->idx == 0 && buf->off == 0);
if (fs->debug)
fprintf(stderr,
"write%s[%llu] %zu bytes to %llu flags: 0x%x\n",
!(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
flatbuf = &buf->buf[0];
} else {
+ res = -ENOMEM;
mem = malloc(size);
if (mem == NULL)
goto out;
off_t off, struct fuse_file_info *fi)
{
struct fuse *f = req_fuse_prepare(req);
+ struct fuse_bufvec *buf = NULL;
char *path;
- char *buf;
int res;
- buf = (char *) malloc(size);
- if (buf == NULL) {
- reply_err(req, -ENOMEM);
- return;
- }
-
res = get_path_nullok(f, ino, &path);
if (res == 0) {
struct fuse_intr_data d;
fuse_prepare_interrupt(f, req, &d);
- res = fuse_fs_read(f->fs, path, buf, size, off, fi);
+ res = fuse_fs_read_buf(f->fs, path, &buf, size, off, fi);
fuse_finish_interrupt(f, req, &d);
free_path(f, ino, path);
}
- if (res >= 0)
- fuse_reply_buf(req, buf, res);
+ if (res == 0)
+ fuse_reply_data(req, buf, FUSE_BUF_SPLICE_MOVE);
else
reply_err(req, res);
- free(buf);
+ fuse_free_buf(buf);
}
static void fuse_lib_write_buf(fuse_req_t req, fuse_ino_t ino,
return err;
}
-static int iconv_read(const char *path, char *buf, size_t size, off_t offset,
- struct fuse_file_info *fi)
+static int iconv_read_buf(const char *path, struct fuse_bufvec **bufp,
+ size_t size, 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_read(ic->next, newpath, buf, size, offset, fi);
+ err = fuse_fs_read_buf(ic->next, newpath, bufp, size, offset, fi);
free(newpath);
}
return err;
.utimens = iconv_utimens,
.create = iconv_create,
.open = iconv_open_file,
- .read = iconv_read,
+ .read_buf = iconv_read_buf,
.write_buf = iconv_write_buf,
.statfs = iconv_statfs,
.flush = iconv_flush,
return err;
}
-static int subdir_read(const char *path, char *buf, size_t size, off_t offset,
- struct fuse_file_info *fi)
+static int subdir_read_buf(const char *path, struct fuse_bufvec **bufp,
+ size_t size, 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_read(d->next, newpath, buf, size, offset, fi);
+ err = fuse_fs_read_buf(d->next, newpath, bufp, size, offset, fi);
free(newpath);
}
return err;
.utimens = subdir_utimens,
.create = subdir_create,
.open = subdir_open,
- .read = subdir_read,
+ .read_buf = subdir_read_buf,
.write_buf = subdir_write_buf,
.statfs = subdir_statfs,
.flush = subdir_flush,