aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2006-08-05 02:18:11 -0400
committerJeff Garzik <jeff@garzik.org>2006-08-05 02:18:11 -0400
commit2755810159041a4b7ed41f322f30b2654e1d27b5 (patch)
tree6e07ca31adb8ecb2314a5446c1301c4cce7d78ae
parentc00d2b74c5042acd8a4c2043fa9a83cc75558a8c (diff)
downloaddbfs-2755810159041a4b7ed41f322f30b2654e1d27b5.tar.gz
Implement open, read ops.
-rw-r--r--dbfs-backend.c170
-rw-r--r--dbfs.c28
-rw-r--r--dbfs.h1
3 files changed, 197 insertions, 2 deletions
diff --git a/dbfs-backend.c b/dbfs-backend.c
index 43ee6f0..36d873a 100644
--- a/dbfs-backend.c
+++ b/dbfs-backend.c
@@ -24,6 +24,12 @@ struct dbfs_dirscan_info {
void *end_ent;
};
+struct dbfs_ext_list {
+ dbfs_blk_id_t id; /* block id */
+ guint64 off; /* offset into block */
+ guint64 len; /* length of fragment */
+};
+
static int dbmeta_del(const char *key_str)
{
DBT key;
@@ -888,3 +894,167 @@ int dbfs_xattr_remove(guint64 ino_n, const char *name, gboolean update_list)
return dbmeta_del(key_str);
}
+static void ext_list_free(GList *ext_list)
+{
+ GList *tmp;
+
+ tmp = ext_list;
+ while (tmp) {
+ g_free(tmp->data);
+ tmp = tmp->next;
+ }
+ g_list_free(ext_list);
+}
+
+static int dbfs_ext_match(struct dbfs_inode *ino, guint64 off, guint64 rd_size,
+ GList **ext_list_out)
+{
+ struct dbfs_ext_list *el;
+ guint64 pos, size, ext_list_want, bytes = 0;
+ GList *ext_list = *ext_list_out;
+ gboolean in_frag;
+ unsigned int i;
+ int rc;
+
+ pos = 0;
+ in_frag = FALSE;
+ ext_list_want = rd_size;
+ for (i = 0; i < ino->n_extents; i++) {
+ size = GUINT64_FROM_LE(ino->raw_inode->blocks[i].size);
+
+ if ((!in_frag) && ((pos + size) > off)) {
+ el = g_new(struct dbfs_ext_list, 1);
+ if (!el) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ memcpy(&el->id, &ino->raw_inode->blocks[i].id,
+ sizeof(dbfs_blk_id_t));
+ el->off = off - pos;
+ el->len = MIN(size - el->off, ext_list_want);
+
+ ext_list = g_list_append(ext_list, el);
+ ext_list_want -= el->len;
+ bytes += el->len;
+ in_frag = TRUE;
+ }
+
+ else if (in_frag) {
+ el = g_new(struct dbfs_ext_list, 1);
+ if (!el) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ memcpy(&el->id, &ino->raw_inode->blocks[i].id,
+ sizeof(dbfs_blk_id_t));
+ el->off = 0;
+ el->len = MIN(size, ext_list_want);
+
+ ext_list = g_list_append(ext_list, el);
+ ext_list_want -= el->len;
+ bytes += el->len;
+
+ if (ext_list_want == 0)
+ break;
+ }
+
+ pos += size;
+ }
+
+ *ext_list_out = ext_list;
+ return (int) bytes;
+
+err_out:
+ ext_list_free(ext_list);
+ *ext_list_out = NULL;
+ return rc;
+}
+
+static int dbfs_ext_read(dbfs_blk_id_t *id, void **buf, size_t *buflen)
+{
+ DBT key, val;
+ int rc;
+
+ memset(&key, 0, sizeof(key));
+ key.data = id;
+ key.size = DBFS_BLK_ID_LEN;
+
+ memset(&val, 0, sizeof(val));
+ val.flags = DB_DBT_MALLOC;
+
+ rc = gfs->data->get(gfs->data, NULL, &key, &val, 0);
+ if (rc == DB_NOTFOUND)
+ return -ENOENT;
+ if (rc)
+ return rc;
+
+ *buf = val.data;
+ *buflen = val.size;
+ return 0;
+}
+
+int dbfs_read(guint64 ino_n, guint64 off, size_t read_req_size,
+ void **buf_out)
+{
+ struct dbfs_inode *ino;
+ GList *tmp, *ext_list = NULL;
+ void *buf = NULL;
+ size_t buflen = 0;
+ unsigned int pos = 0;
+ int rc;
+
+ rc = dbfs_inode_read(ino_n, &ino);
+ if (rc)
+ goto out;
+
+ rc = dbfs_ext_match(ino, off, read_req_size, &ext_list);
+ if (rc <= 0)
+ goto out_ino;
+ buflen = rc;
+
+ buf = malloc(buflen);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto out_list;
+ }
+
+ tmp = ext_list;
+ while (tmp) {
+ struct dbfs_ext_list *el;
+ void *frag;
+ size_t fraglen;
+
+ el = tmp->data;
+ rc = dbfs_ext_read(&el->id, &frag, &fraglen);
+ if (rc) {
+ free(buf);
+ buf = NULL;
+ goto out_list;
+ }
+ if ((el->off + el->len) > fraglen) {
+ free(frag);
+ free(buf);
+ buf = NULL;
+ rc = -EINVAL;
+ goto out_list;
+ }
+
+ memcpy(buf + pos, frag + el->off, el->len);
+ free(frag);
+
+ pos += el->len;
+
+ tmp = tmp->next;
+ }
+
+out_list:
+ ext_list_free(ext_list);
+out_ino:
+ dbfs_inode_free(ino);
+out:
+ *buf_out = buf;
+ return rc < 0 ? rc : buflen;
+}
+
diff --git a/dbfs.c b/dbfs.c
index 19f4608..a3ab8ce 100644
--- a/dbfs.c
+++ b/dbfs.c
@@ -239,6 +239,30 @@ err_out:
fuse_reply_err(req, -rc);
}
+static void dbfs_op_open(fuse_req_t req, fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ fi->direct_io = 0;
+ fi->keep_cache = 1;
+ fuse_reply_open(req, fi);
+}
+
+static void dbfs_op_read(fuse_req_t req, fuse_ino_t ino, size_t size,
+ off_t off, struct fuse_file_info *fi)
+{
+ void *buf = NULL;
+ int rc;
+
+ rc = dbfs_read(ino, off, size, &buf);
+ if (rc < 0) {
+ fuse_reply_err(req, -rc);
+ return;
+ }
+
+ fuse_reply_buf(req, buf, rc);
+ free(buf);
+}
+
static int dbfs_chk_empty(struct dbfs_dirent *de, void *userdata)
{
if ((GUINT16_FROM_LE(de->namelen) == 1) && (!memcmp(de->name, ".", 1)))
@@ -479,8 +503,8 @@ static struct fuse_lowlevel_ops dbfs_ops = {
.symlink = dbfs_op_symlink,
.rename = NULL,
.link = dbfs_op_link,
- .open = NULL,
- .read = NULL,
+ .open = dbfs_op_open,
+ .read = dbfs_op_read,
.write = NULL,
.flush = NULL,
.release = NULL,
diff --git a/dbfs.h b/dbfs.h
index 7ae42b1..ed1e925 100644
--- a/dbfs.h
+++ b/dbfs.h
@@ -124,6 +124,7 @@ extern int dbfs_xattr_set(guint64 ino_n, const char *name,
int flags);
extern int dbfs_xattr_remove(guint64, const char *, gboolean);
extern int dbfs_xattr_list(guint64 ino, void **buf_out, size_t *buflen_out);
+extern int dbfs_read(guint64, guint64, size_t, void **);
/* libdbfs.c */
extern int dbfs_open(struct dbfs *, unsigned int, unsigned int, const char *);