aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2006-08-04 10:30:19 -0400
committerJeff Garzik <jeff@garzik.org>2006-08-04 10:30:19 -0400
commitedfeb83763d87b31ab8f2359e4c826edb64d6be2 (patch)
tree355796e8847dbc0d470dc5c2dd62546ff2156300
parentc8f869f43eda037b0e6c7be24a2fdb5dec4bab1b (diff)
downloaddbfs-edfeb83763d87b31ab8f2359e4c826edb64d6be2.tar.gz
Implement listxattr op.
Also, prefer 'void *' to 'char *' when referring to anonymous blobs of RAM.
-rw-r--r--dbfs-backend.c222
-rw-r--r--dbfs.c30
-rw-r--r--dbfs.h19
3 files changed, 254 insertions, 17 deletions
diff --git a/dbfs-backend.c b/dbfs-backend.c
index 14eeb2b..0f1b2e9 100644
--- a/dbfs-backend.c
+++ b/dbfs-backend.c
@@ -581,6 +581,192 @@ err_out:
return rc;
}
+static int dbfs_xattr_list_read(DBT *key, DBT *val, char *keystr, guint64 ino)
+{
+ snprintf(keystr, 32, "/xattr/%Lu", (unsigned long long) ino);
+
+ memset(key, 0, sizeof(*key));
+ key->data = keystr;
+ key->size = strlen(keystr);
+
+ memset(val, 0, sizeof(*val));
+ val->flags = DB_DBT_MALLOC;
+
+ return gfs->meta->get(gfs->meta, NULL, key, val, 0);
+}
+
+static int dbfs_xattr_list_add(guint64 ino, const char *name)
+{
+ struct dbfs_xlist *ent;
+ char keystr[32];
+ DBT key, val;
+ size_t alloc_len;
+ size_t name_len = strlen(name);
+ int rc;
+
+ /* get list from db */
+ rc = dbfs_xattr_list_read(&key, &val, keystr, ino);
+ if (rc && (rc != DB_NOTFOUND))
+ return -EIO;
+
+ alloc_len = dbfs_xlist_next(name_len);
+
+ /* if list not found, create new one */
+ if (rc == DB_NOTFOUND) {
+ ent = malloc(alloc_len);
+ if (!ent)
+ return -ENOMEM;
+
+ val.data = ent;
+ val.size = alloc_len;
+ }
+
+ /* otherwise, append to existing list */
+ else {
+ void *mem;
+ size_t old_size;
+
+ alloc_len += val.size;
+ mem = realloc(val.data, alloc_len);
+ if (!mem) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ old_size = val.size;
+ val.data = mem;
+ val.size = alloc_len;
+
+ mem += old_size;
+ ent = mem;
+ }
+
+ /* fill in list entry at tail of list */
+ ent->namelen = GUINT32_TO_LE(name_len);
+ memcpy(ent->name, name, name_len);
+
+ /* store new list in db */
+ rc = gfs->meta->put(gfs->meta, NULL, &key, &val, 0) ? -EIO : 0;
+
+out:
+ free(val.data);
+ return rc;
+}
+
+static int dbfs_xattr_list_del(guint64 ino, const char *name)
+{
+ size_t name_len = strlen(name);
+ struct dbfs_xlist *ent;
+ char keystr[32];
+ DBT key, val;
+ int rc;
+ long bytes;
+ void *mem;
+ size_t ssize = 0;
+
+ /* get list from db */
+ rc = dbfs_xattr_list_read(&key, &val, keystr, ino);
+ if (rc == DB_NOTFOUND)
+ return -ENOENT;
+ if (rc)
+ return -EIO;
+
+ /* find entry in list */
+ mem = val.data;
+ bytes = val.size;
+ while (bytes > 0) {
+ ent = mem;
+ ssize = dbfs_xlist_next(GUINT32_FROM_LE(ent->namelen));
+ if (ssize > bytes) { /* data corrupt */
+ rc = -EIO;
+ goto out;
+ }
+
+ if (!memcmp(ent->name, name, name_len))
+ break;
+
+ bytes -= ssize;
+ }
+
+ /* if not found, exit */
+ if (bytes <= 0) {
+ rc = -ENOENT;
+ goto out;
+ }
+
+ /* swallow entry */
+ memmove(mem, mem + ssize, bytes - ssize);
+ val.size -= ssize;
+
+ /* store new list in db */
+ rc = gfs->meta->put(gfs->meta, NULL, &key, &val, 0) ? -EIO : 0;
+
+out:
+ free(val.data);
+ return rc;
+}
+
+int dbfs_xattr_list(guint64 ino, void **buf_out, size_t *buflen_out)
+{
+ struct dbfs_xlist *ent;
+ char keystr[32];
+ DBT key, val;
+ void *mem, *name_list;
+ size_t name_list_len, ssize, name_len;
+ long bytes;
+ char null = 0;
+ int rc;
+
+ *buf_out = NULL;
+ *buflen_out = 0;
+
+ /* get list from db */
+ rc = dbfs_xattr_list_read(&key, &val, keystr, ino);
+ if (rc == DB_NOTFOUND)
+ return 0;
+ if (rc)
+ return -EIO;
+ if (val.size == 0)
+ return 0;
+
+ /* allocate output buffer */
+ name_list = malloc(val.size);
+ if (!name_list) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ name_list_len = 0;
+
+ /* fill output buffer */
+ mem = val.data;
+ bytes = val.size;
+ while (bytes > 0) {
+ ent = mem;
+ name_len = GUINT32_FROM_LE(ent->namelen);
+ ssize = dbfs_xlist_next(name_len);
+
+ if (ssize > bytes) { /* data corrupt */
+ rc = -EIO;
+ goto out;
+ }
+
+ memcpy(name_list + name_list_len, ent->name, name_len);
+ name_list_len += name_len;
+
+ memcpy(name_list + name_list_len, &null, 1);
+ name_list_len++;
+
+ bytes -= ssize;
+ }
+
+ *buf_out = name_list;
+ *buflen_out = name_list_len;
+
+out:
+ free(val.data);
+ return rc;
+}
+
static int dbfs_xattr_read(guint64 ino, const char *name, DBT *val)
{
char key_str[DBFS_XATTR_NAME_LEN + 32];
@@ -604,7 +790,7 @@ static int dbfs_xattr_read(guint64 ino, const char *name, DBT *val)
}
static int dbfs_xattr_write(guint64 ino, const char *name,
- const char *buf, size_t buflen)
+ const void *buf, size_t buflen)
{
char key_str[DBFS_XATTR_NAME_LEN + 32];
DBT key, val;
@@ -624,7 +810,7 @@ static int dbfs_xattr_write(guint64 ino, const char *name,
}
int dbfs_xattr_get(guint64 ino_n, const char *name,
- char **buf_out, size_t *buflen_out)
+ void **buf_out, size_t *buflen_out)
{
int rc;
DBT val;
@@ -639,13 +825,19 @@ int dbfs_xattr_get(guint64 ino_n, const char *name,
return 0;
}
-int dbfs_xattr_set(guint64 ino_n, const char *name, const char *buf,
+int dbfs_xattr_set(guint64 ino_n, const char *name, const void *buf,
size_t buflen, int flags)
{
- char *current = NULL;
+ void *current = NULL;
size_t current_len = 0;
+ size_t name_len = strlen(name);
int rc, exists;
+ if ((!name) || (!*name) || (name_len > DBFS_XATTR_NAME_LEN) ||
+ (!g_utf8_validate(name, name_len, NULL)) ||
+ (buflen > DBFS_XATTR_MAX_LEN))
+ return -EINVAL;
+
rc = dbfs_xattr_get(ino_n, name, &current, &current_len);
if (rc && (rc != -EINVAL))
return rc;
@@ -657,15 +849,21 @@ int dbfs_xattr_set(guint64 ino_n, const char *name, const char *buf,
return -EEXIST;
if (!exists && (flags & XATTR_REPLACE))
return -ENOATTR;
- if (buflen > DBFS_XATTR_MAX_LEN)
- return -ENOSPC; /* TODO: return value sane? */
- /* FIXME: update list of xattrs for this inode */
+ rc = dbfs_xattr_write(ino_n, name, buf, buflen);
+ if (rc)
+ return rc;
- return dbfs_xattr_write(ino_n, name, buf, buflen);
+ rc = dbfs_xattr_list_add(ino_n, name);
+ if (rc) {
+ dbfs_xattr_remove(ino_n, name, FALSE);
+ return rc;
+ }
+
+ return 0;
}
-int dbfs_xattr_remove(guint64 ino_n, const char *name)
+int dbfs_xattr_remove(guint64 ino_n, const char *name, gboolean update_list)
{
char key_str[DBFS_XATTR_NAME_LEN + 32];
DBT key;
@@ -678,7 +876,11 @@ int dbfs_xattr_remove(guint64 ino_n, const char *name)
key.data = key_str;
key.size = strlen(key_str);
- /* FIXME: update list of xattrs for this inode */
+ if (update_list) {
+ rc = dbfs_xattr_list_del(ino_n, name);
+ if (rc)
+ return rc;
+ }
rc = gfs->meta->del(gfs->meta, NULL, &key, 0);
if (rc == DB_NOTFOUND)
diff --git a/dbfs.c b/dbfs.c
index d665cf0..b0fe751 100644
--- a/dbfs.c
+++ b/dbfs.c
@@ -362,7 +362,7 @@ static void dirbuf_add(struct dirbuf *b, const char *name, fuse_ino_t ino)
#endif
/* stock function copied from FUSE template */
-static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
+static int reply_buf_limited(fuse_req_t req, const void *buf, size_t bufsize,
off_t off, size_t maxsize)
{
if (off < bufsize)
@@ -413,7 +413,7 @@ static void dbfs_op_setxattr(fuse_req_t req, fuse_ino_t ino,
static void dbfs_op_getxattr(fuse_req_t req, fuse_ino_t ino,
const char *name, size_t size)
{
- char *buf = NULL;
+ void *buf = NULL;
size_t buflen = 0;
int rc;
@@ -437,10 +437,32 @@ err_out:
fuse_reply_err(req, -rc);
}
+static void dbfs_op_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
+{
+ int rc;
+ void *buf;
+ size_t buflen;
+
+ rc = dbfs_xattr_list(ino, &buf, &buflen);
+ if (rc < 0) {
+ fuse_reply_err(req, -rc);
+ return;
+ }
+
+ if (size == 0)
+ fuse_reply_xattr(req, buflen);
+ else if (size < buflen)
+ fuse_reply_err(req, ERANGE);
+ else
+ fuse_reply_buf(req, buf, buflen);
+
+ free(buf);
+}
+
static void dbfs_op_removexattr(fuse_req_t req, fuse_ino_t ino,
const char *name)
{
- int rc = dbfs_xattr_remove(ino, name);
+ int rc = dbfs_xattr_remove(ino, name, TRUE);
fuse_reply_err(req, -rc);
}
@@ -472,7 +494,7 @@ static struct fuse_lowlevel_ops dbfs_ops = {
.statfs = NULL,
.setxattr = dbfs_op_setxattr,
.getxattr = dbfs_op_getxattr,
- .listxattr = NULL,
+ .listxattr = dbfs_op_listxattr,
.removexattr = dbfs_op_removexattr,
.access = NULL,
.create = NULL,
diff --git a/dbfs.h b/dbfs.h
index 5e22788..5ef86fd 100644
--- a/dbfs.h
+++ b/dbfs.h
@@ -16,6 +16,8 @@ enum {
DBFS_XATTR_NAME_LEN = 256,
DBFS_XATTR_MAX_LEN = (1024 * 1024),
+
+ DBFS_XLIST_ALIGN = 8,
};
enum {
@@ -43,6 +45,11 @@ struct dbfs_dirent {
char name[0];
} __attribute__ ((packed));
+struct dbfs_xlist {
+ guint32 namelen;
+ char name[0];
+} __attribute__ ((packed));
+
struct dbfs_extent {
dbfs_blk_id_t id;
guint64 size;
@@ -99,11 +106,12 @@ extern int dbfs_mknod(guint64 parent, const char *name,
extern int dbfs_symlink_write(guint64 ino, const char *link);
extern int dbfs_inode_del(struct dbfs_inode *ino);
extern int dbfs_xattr_get(guint64 ino_n, const char *name,
- char **buf_out, size_t *buflen_out);
+ void **buf_out, size_t *buflen_out);
extern int dbfs_xattr_set(guint64 ino_n, const char *name,
- const char *buf, size_t buflen,
+ const void *buf, size_t buflen,
int flags);
-extern int dbfs_xattr_remove(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);
/* libdbfs.c */
extern int dbfs_open(struct dbfs *fs);
@@ -121,4 +129,9 @@ static inline size_t dbfs_dirent_next(guint16 namelen)
return ALIGN(sizeof(struct dbfs_dirent) + namelen, DBFS_DIRENT_ALIGN);
}
+static inline size_t dbfs_xlist_next(guint16 namelen)
+{
+ return ALIGN(sizeof(struct dbfs_xlist) + namelen, DBFS_XLIST_ALIGN);
+}
+
#endif /* __DBFS_H__ */