aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2006-08-06 04:32:15 -0400
committerJeff Garzik <jeff@garzik.org>2006-08-06 04:32:15 -0400
commit590d1454714cd8c1395b0d94ba83268b420e6f57 (patch)
tree1faa86b1653c363d23423a1080290b14edc0d928
parent89419915ba7b438d6631e086cdf95fee9b23060f (diff)
downloaddbfs-590d1454714cd8c1395b0d94ba83268b420e6f57.tar.gz
Implement write op (well, most of it).
-rw-r--r--dbfs-backend.c149
-rw-r--r--dbfs.c12
-rw-r--r--dbfs.h3
3 files changed, 159 insertions, 5 deletions
diff --git a/dbfs-backend.c b/dbfs-backend.c
index ae575a6..d233170 100644
--- a/dbfs-backend.c
+++ b/dbfs-backend.c
@@ -797,7 +797,6 @@ out:
return rc < 0 ? rc : buflen;
}
-#if 0
static int dbfs_write_unique_buf(DBT *key, const void *buf, size_t buflen)
{
struct dbfs_hashref ref;
@@ -827,6 +826,8 @@ static int dbfs_write_unique_buf(DBT *key, const void *buf, size_t buflen)
return -EIO;
}
+
+ return 0;
}
static int dbfs_write_buf(const void *buf, size_t buflen,
@@ -840,7 +841,7 @@ static int dbfs_write_buf(const void *buf, size_t buflen,
return -EINVAL;
memset(ext, 0, sizeof(*ext));
- ext->len = buflen;
+ ext->len = GUINT32_TO_LE(buflen);
if (is_zero_buf(buf, buflen))
return 0;
@@ -917,4 +918,146 @@ static int dbfs_data_unref(dbfs_blk_id_t *id)
return (rc || rc2) ? -EIO : 0;
}
-#endif
+static int dbfs_inode_realloc(struct dbfs_inode *ino,
+ unsigned int new_n_extents)
+{
+ struct dbfs_raw_inode *new_raw;
+ size_t new_size = sizeof(struct dbfs_inode) +
+ (sizeof(struct dbfs_extent) * new_n_extents);
+
+ new_raw = g_malloc0(new_size);
+ if (!new_raw)
+ return -ENOMEM;
+
+ memcpy(new_raw, ino->raw_inode, MIN(new_size, ino->raw_ino_size));
+
+ free(ino->raw_inode);
+ ino->raw_inode = new_raw;
+ ino->raw_ino_size = new_size;
+ ino->n_extents = new_n_extents;
+
+ return 0;
+}
+
+static int dbfs_inode_resize(struct dbfs_inode *ino, guint64 new_size)
+{
+ guint64 old_size, diff, diff_ext;
+ unsigned int grow, i, new_n_extents, tmp;
+ int rc;
+
+ old_size = GUINT64_FROM_LE(ino->raw_inode->size);
+ grow = (old_size < new_size);
+ diff = grow ? new_size - old_size : old_size - new_size;
+
+ diff_ext = (diff / DBFS_MAX_EXT_LEN);
+ if (diff % DBFS_MAX_EXT_LEN)
+ diff_ext++;
+
+ if (grow) {
+ new_n_extents = ino->n_extents + diff_ext;
+ rc = dbfs_inode_realloc(ino, new_n_extents);
+ if (rc)
+ return rc;
+
+ for (i = ino->n_extents; i < new_n_extents; i++) {
+ g_assert(diff > 0);
+ tmp = MIN(diff, DBFS_MAX_EXT_LEN);
+ ino->raw_inode->blocks[i].len =
+ GUINT32_TO_LE(tmp);
+ diff -= tmp;
+ }
+
+ g_assert(diff == 0);
+ }
+
+ else {
+ struct dbfs_extent *ext;
+ guint32 ext_len;
+
+ new_n_extents = ino->n_extents;
+ while (new_n_extents > 0) {
+ ext = &ino->raw_inode->blocks[new_n_extents - 1];
+ ext_len = GUINT32_FROM_LE(ext->len);
+ if (ext_len > diff)
+ break;
+
+ rc = dbfs_data_unref(&ext->id);
+ if (rc)
+ return rc;
+
+ memset(ext, 0, sizeof(*ext));
+ ino->n_extents--;
+
+ new_n_extents--;
+ diff -= ext_len;
+ }
+
+ if (diff > 0) {
+ ext = &ino->raw_inode->blocks[new_n_extents - 1];
+ ext_len = GUINT32_FROM_LE(ext->len);
+ ext_len -= diff;
+ ext->len = GUINT32_TO_LE(ext_len);
+
+ g_assert(ext_len > 0);
+ }
+
+ rc = dbfs_inode_realloc(ino, new_n_extents);
+ if (rc)
+ return rc;
+ }
+
+ ino->raw_inode->size = GUINT64_TO_LE(new_size);
+ return 0;
+}
+
+int dbfs_write(guint64 ino_n, guint64 off, const void *buf, size_t buflen)
+{
+ struct dbfs_extent ext;
+ struct dbfs_inode *ino;
+ int rc;
+ guint64 i_size;
+
+ rc = dbfs_inode_read(ino_n, &ino);
+ if (rc)
+ return rc;
+
+ rc = dbfs_write_buf(buf, buflen, &ext);
+ if (rc)
+ goto out;
+
+ i_size = GUINT64_FROM_LE(ino->raw_inode->size);
+
+ if ((off != i_size) && ((off + buflen) > i_size)) {
+ rc = dbfs_inode_resize(ino, off + 1);
+ if (rc)
+ goto err_out;
+ }
+
+ i_size = GUINT64_FROM_LE(ino->raw_inode->size);
+
+ /* append */
+ if (off == i_size) {
+ unsigned int idx;
+
+ rc = dbfs_inode_resize(ino, i_size + buflen);
+ if (rc)
+ goto err_out;
+
+ idx = ino->n_extents - 1;
+
+ g_assert(is_null_id(&ino->raw_inode->blocks[idx].id));
+ memcpy(&ino->raw_inode->blocks[idx], &ext, sizeof(ext));
+
+ goto out;
+ }
+
+ /* FIXME: update data in middle of file */
+
+ goto out;
+
+err_out:
+ dbfs_data_unref(&ext.id);
+out:
+ dbfs_inode_free(ino);
+ return rc;
+}
diff --git a/dbfs.c b/dbfs.c
index 380d777..4370faa 100644
--- a/dbfs.c
+++ b/dbfs.c
@@ -281,6 +281,16 @@ static void dbfs_op_read(fuse_req_t req, fuse_ino_t ino, size_t size,
free(buf);
}
+static void dbfs_op_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
+ size_t size, off_t off, struct fuse_file_info *fi)
+{
+ int rc = dbfs_write(ino, off, buf, size);
+ if (rc < 0)
+ fuse_reply_err(req, -rc);
+ else
+ fuse_reply_write(req, rc);
+}
+
static int dbfs_chk_empty(struct dbfs_dirent *de, void *userdata)
{
if ((GUINT16_FROM_LE(de->namelen) == 1) && (!memcmp(de->name, ".", 1)))
@@ -560,7 +570,7 @@ static struct fuse_lowlevel_ops dbfs_ops = {
.link = dbfs_op_link,
.open = dbfs_op_open,
.read = dbfs_op_read,
- .write = NULL,
+ .write = dbfs_op_write,
.flush = NULL,
.release = NULL,
.fsync = NULL,
diff --git a/dbfs.h b/dbfs.h
index f95f444..2c541bb 100644
--- a/dbfs.h
+++ b/dbfs.h
@@ -110,9 +110,9 @@ struct dbfs_raw_inode {
} __attribute__ ((packed));
struct dbfs_inode {
+ enum dbfs_inode_type type;
unsigned int n_extents;
unsigned int raw_ino_size;
- enum dbfs_inode_type type;
struct dbfs_raw_inode *raw_inode;
};
@@ -155,6 +155,7 @@ extern int dbfs_xattr_set(guint64 ino_n, const char *name,
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 **);
+extern int dbfs_write(guint64, guint64, const void *, size_t);
/* libdbfs.c */
extern int dbfs_open(struct dbfs *, unsigned int, unsigned int, const char *);