src/dbfs.c
changeset 25 99a41f48e29b
parent 24 82cfdb6680d1
child 26 61668c57f4bb
--- a/src/dbfs.c	Sun Oct 12 14:57:06 2008 +0300
+++ b/src/dbfs.c	Sun Oct 12 20:10:47 2008 +0300
@@ -56,51 +56,98 @@
 
 }
 
+/*
+ * Check the result set.
+ *
+ * Returns;
+ *  -1  if the query failed, the columns do not match, or there are too many/few rows
+ *  0   the results match
+ *  1   there were no results
+ */
+int _dbfs_check_res (const struct evsql_result_info *res, size_t rows, size_t cols) {
+    int err = 0;
+
+    // check if it failed
+    if (res->error)
+        NERROR(evsql_result_error(res));
+        
+    // not found?
+    if (evsql_result_rows(res) == 0)
+        SERROR(err = 1);
+
+    // duplicate rows?
+    if (evsql_result_rows(res) != rows)
+        ERROR("multiple rows returned");
+    
+    // correct number of columns
+    if (evsql_result_cols(res) != 5)
+        ERROR("wrong number of columns: %zu", evsql_result_cols(res));
+
+    // good
+    return 0;
+
+error:
+    if (!err)
+        err = -1;
+
+    return err;
+}
+
+int _dbfs_stat_info (struct stat *st, const struct evsql_result_info *res, size_t row, size_t col_offset) {
+    int err = 0;
+    
+    uint16_t mode;
+    uint64_t size, nlink;
+    const char *type;
+    
+    // extract the data
+    if (0
+        ||  evsql_result_string(res, row, col_offset + 0, &type,       0 ) // inodes.type
+        ||  evsql_result_uint16(res, row, col_offset + 1, &mode,       0 ) // inodes.mode
+        ||  evsql_result_uint64(res, row, col_offset + 2, &size,       0 ) // inodes.size
+        ||  evsql_result_uint64(res, row, col_offset + 3, &nlink,      0 ) // count(*)
+    )
+        EERROR(err = EIO, "invalid db data");
+
+    INFO("\tst_mode=S_IF%s | %ho, st_nlink=%llu, st_size=%llu", type, mode, (long long unsigned int) nlink, (long long unsigned int) size);
+
+    // convert and store
+    st->st_mode = _dbfs_mode(type) | mode;
+    st->st_nlink = nlink;
+    st->st_size = size;
+    
+    // good
+    return 0;
+
+error:
+    return -1;
+}
+
 void _dbfs_lookup_result (const struct evsql_result_info *res, void *arg) {
     struct fuse_req *req = arg;
     struct fuse_entry_param e; ZINIT(e);
     int err = 0;
     
-    uint16_t mode;
     uint32_t ino;
-    uint64_t size, nlink;
-    const char *type;
     
-    // check if it failed
-    if (res->error && (err = EIO))
-        NERROR(evsql_result_error(res));
-
-    // duplicate rows?
-    if (evsql_result_rows(res) > 1)
-        EERROR(err = EIO, "multiple rows returned");
-
-    // not found?
-    if (evsql_result_rows(res) == 0)
-        SERROR(err = ENOENT);
-    
-    // correct number of columns
-    if (evsql_result_cols(res) != 5)
-        EERROR(err = EIO, "wrong number of columns: %zu", evsql_result_cols(res));
+    // check the results
+    if ((err = _dbfs_check_res(res, 1, 5)))
+        SERROR(err = (err ==  1 ? ENOENT : EIO));
     
     // get the data
     if (0
         ||  evsql_result_uint32(res, 0, 0, &ino,        0 ) // inodes.ino
-        ||  evsql_result_string(res, 0, 1, &type,       0 ) // inodes.type
-        ||  evsql_result_uint16(res, 0, 2, &mode,       0 ) // inodes.mode
-        ||  evsql_result_uint64(res, 0, 3, &size,       0 ) // inodes.size
-        ||  evsql_result_uint64(res, 0, 4, &nlink,      0 ) // count(*)
     )
         EERROR(err = EIO, "invalid db data");
+        
+    INFO("[dbfs.lookup] -> ion=%u", ino);
     
-    INFO("[dbfs.look] -> ino=%u, st_mode=S_IF%s | %ho, st_nlink=%llu, st_size=%llu", ino, type, mode, (long long unsigned int) nlink, (long long unsigned int) size);
+    // stat attrs
+    if (_dbfs_stat_info(&e.attr, res, 0, 1))
+        goto error;
 
-    // convert and store
+    // other attrs
     e.ino = e.attr.st_ino = ino;
-    e.attr.st_mode = _dbfs_mode(type) | mode;
-    e.attr.st_nlink = nlink;
-    e.attr.st_size = size;
-    
-    // XXX: timeouts
     e.attr_timeout = CACHE_TIMEOUT;
     e.entry_timeout = CACHE_TIMEOUT;
         
@@ -127,7 +174,7 @@
         "SELECT"
         " inodes.ino, inodes.type, inodes.mode, inodes.size, count(*)"
         " FROM file_tree INNER JOIN inodes ON (file_tree.inode = inodes.ino)"
-        " WHERE file_tree.parent = $1::int AND file_tree.name = $2::varchar"
+        " WHERE file_tree.parent = $1::int4 AND file_tree.name = $2::varchar"
         " GROUP BY inodes.ino, inodes.type, inodes.mode, inodes.size";
     
     static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
@@ -145,7 +192,7 @@
         EERROR(err = EIO, "evsql_param_*");
 
     // query
-    if (evsql_query_params(ctx->db, sql, &params, _dbfs_lookup_result, req) == NULL)
+    if (evsql_query_params(ctx->db, NULL, sql, &params, _dbfs_lookup_result, req) == NULL)
         EERROR(err = EIO, "evsql_query_params");
 
     // XXX: handle interrupts
@@ -158,11 +205,85 @@
         EWARNING(err, "fuse_reply_err");
 }
 
+void _dbfs_getattr_result (const struct evsql_result_info *res, void *arg) {
+    struct fuse_req *req = arg;
+    struct stat st; ZINIT(st);
+    int err = 0;
+    
+    // check the results
+    if ((err = _dbfs_check_res(res, 1, 4)))
+        SERROR(err = (err ==  1 ? ENOENT : EIO));
+        
+    INFO("[dbfs.getattr %p] -> (stat follows)", req);
+    
+    // stat attrs
+    if (_dbfs_stat_info(&st, res, 0, 0))
+        goto error;
+
+    // XXX: we don't have the ino
+    st.st_ino = 0;
+
+    // reply
+    if ((err = fuse_reply_attr(req, &st, CACHE_TIMEOUT)))
+        EERROR(err, "fuse_reply_entry");
+
+error:
+    if (err && (err = fuse_reply_err(req, err)))
+        EWARNING(err, "fuse_reply_err");
+
+    // free
+    evsql_result_free(res);
+}
+
+static void dbfs_getattr (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) {
+    struct dbfs *ctx = fuse_req_userdata(req);
+    int err;
+    
+    (void) fi;
+
+    INFO("[dbfs.getattr %p] ino=%lu", req, ino);
+
+    const char *sql =
+        "SELECT"
+        " inodes.type, inodes.mode, inodes.size, count(*)"
+        " FROM inodes"
+        " WHERE inodes.ino = ‰1::int4"
+        " GROUP BY inodes.type, inodes.mode, inodes.size";
+
+    static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) {
+        EVSQL_PARAM ( UINT32 ),
+
+        EVSQL_PARAMS_END
+    };
+
+    // build params
+    if (0
+        ||  evsql_param_uint32(&params, 0, ino)
+    )
+        SERROR(err = EIO);
+        
+    // query
+    if (evsql_query_params(ctx->db, NULL, sql, &params, _dbfs_getattr_result, req) == NULL)
+        SERROR(err = EIO);
+
+    // XXX: handle interrupts
+    
+    // wait
+    return;
+
+error:
+    if ((err = fuse_reply_err(req, err)))
+        EWARNING(err, "fuse_reply_err");
+}
+
 struct fuse_lowlevel_ops dbfs_llops = {
+
     .init           = dbfs_init,
     .destroy        = dbfs_destroy,
     
     .lookup         = dbfs_lookup,
+
+    .getattr        = dbfs_getattr,
 };
 
 void dbfs_sql_error (struct evsql *evsql, void *arg) {