terom@31: terom@31: #include "dbfs.h" terom@31: #include "../lib/log.h" terom@31: #include "../lib/misc.h" terom@31: terom@31: // max. size for a setattr UPDATE query terom@31: #define DBFS_SETATTR_SQL_MAX 512 terom@31: terom@31: // for building the setattr UPDATE terom@31: #define FIELD(to_set, flag, field, value) ((to_set) & (flag)) ? (field " = " value ", ") : "" terom@31: terom@31: void _dbfs_attr_res (const struct evsql_result_info *res, void *arg) { terom@31: struct fuse_req *req = arg; terom@31: struct stat st; ZINIT(st); terom@31: int err = 0; terom@31: terom@31: uint32_t ino; terom@31: terom@31: // check the results terom@31: if ((err = _dbfs_check_res(res, 1, 5))) terom@31: SERROR(err = (err == 1 ? ENOENT : EIO)); terom@31: terom@31: // get our data terom@31: if (0 terom@31: || evsql_result_uint32(res, 0, 0, &ino, 0 ) // inodes.ino terom@31: ) terom@31: EERROR(err = EIO, "invalid db data"); terom@31: terom@31: terom@36: INFO("\t[dbfs.getattr %p] -> ino=%lu, stat follows", req, (unsigned long int) ino); terom@31: terom@32: // inode terom@32: st.st_ino = ino; terom@32: terom@31: // stat attrs terom@31: if ((err = _dbfs_stat_info(&st, res, 0, 1))) terom@31: goto error; terom@31: terom@31: // reply terom@31: if ((err = fuse_reply_attr(req, &st, st.st_nlink ? CACHE_TIMEOUT : 0))) terom@31: EERROR(err, "fuse_reply_entry"); terom@31: terom@31: error: terom@31: if (err && (err = fuse_reply_err(req, err))) terom@31: EWARNING(err, "fuse_reply_err"); terom@31: terom@31: // free terom@31: evsql_result_free(res); terom@31: } terom@31: terom@31: void dbfs_getattr (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { terom@31: struct dbfs *ctx = fuse_req_userdata(req); terom@41: struct evsql_query *query; terom@31: int err; terom@31: terom@31: (void) fi; terom@31: terom@31: INFO("[dbfs.getattr %p] ino=%lu", req, ino); terom@31: terom@31: const char *sql = terom@31: "SELECT" terom@31: " inodes.ino, " DBFS_STAT_COLS terom@31: " FROM inodes" terom@33: " WHERE inodes.ino = $1::int4"; terom@31: terom@31: static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { terom@31: EVSQL_PARAM ( UINT32 ), terom@31: terom@31: EVSQL_PARAMS_END terom@31: }; terom@31: terom@31: // build params terom@31: if (0 terom@31: || evsql_param_uint32(¶ms, 0, ino) terom@31: ) terom@31: SERROR(err = EIO); terom@31: terom@31: // query terom@41: if ((query = evsql_query_params(ctx->db, NULL, sql, ¶ms, _dbfs_attr_res, req)) == NULL) terom@31: SERROR(err = EIO); terom@31: terom@41: // handle interrupts terom@41: fuse_req_interrupt_func(req, dbfs_interrupt_query, query); terom@31: terom@31: // wait terom@31: return; terom@31: terom@31: error: terom@31: if ((err = fuse_reply_err(req, err))) terom@31: EWARNING(err, "fuse_reply_err"); terom@31: } terom@31: terom@31: terom@31: void dbfs_setattr (struct fuse_req *req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi) { terom@31: struct dbfs *ctx = fuse_req_userdata(req); terom@41: struct evsql_query *query; terom@31: int err; terom@31: int ret; terom@31: terom@31: char sql_buf[DBFS_SETATTR_SQL_MAX]; terom@31: terom@31: static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { terom@31: EVSQL_PARAM ( UINT16 ), // inodes.mode terom@31: EVSQL_PARAM ( UINT32 ), // inodes.uid terom@31: EVSQL_PARAM ( UINT32 ), // inodes.gid terom@31: EVSQL_PARAM ( UINT32 ), // data size terom@31: EVSQL_PARAM ( UINT32 ), // ino terom@31: terom@31: EVSQL_PARAMS_END terom@31: }; terom@31: terom@31: // log terom@31: INFO("[dbfs.setattr %p] ino=%lu, fileop=%p: ", req, ino, fi && fi->fh ? (void*) fi->fh : NULL); terom@31: terom@31: if (to_set & FUSE_SET_ATTR_MODE) { terom@31: // ignore the S_IFMT terom@31: attr->st_mode &= 07777; terom@31: terom@31: INFO("\tmode = %08o", attr->st_mode); terom@31: } terom@31: terom@31: if (to_set & FUSE_SET_ATTR_UID) terom@31: INFO("\tuid = %u", attr->st_uid); terom@31: terom@31: if (to_set & FUSE_SET_ATTR_GID) terom@31: INFO("\tgid = %u", attr->st_gid); terom@31: terom@31: if (to_set & FUSE_SET_ATTR_SIZE) terom@31: INFO("\tsize = %lu", attr->st_size); terom@31: terom@31: if (to_set & FUSE_SET_ATTR_ATIME) terom@31: INFO("\tatime = %lu", attr->st_atime); terom@31: terom@31: if (to_set & FUSE_SET_ATTR_MTIME) terom@31: INFO("\tmtime = %lu", attr->st_mtime); terom@31: terom@31: // the SQL terom@31: if ((ret = snprintf(sql_buf, DBFS_SETATTR_SQL_MAX, terom@31: "UPDATE inodes SET" terom@31: " %s%s%s%s ino = ino" terom@31: " WHERE inodes.ino = $5::int4" terom@33: " RETURNING inodes.ino, " DBFS_STAT_COLS, terom@31: terom@31: FIELD(to_set, FUSE_SET_ATTR_MODE, "mode", "$1::int2"), terom@31: FIELD(to_set, FUSE_SET_ATTR_UID, "uid", "$2::int4"), terom@31: FIELD(to_set, FUSE_SET_ATTR_GID, "gid", "$3::int4"), terom@31: FIELD(to_set, FUSE_SET_ATTR_SIZE, "data", "lo_otruncate(data, $4::int4)") terom@31: )) >= DBFS_SETATTR_SQL_MAX && (err = EIO)) terom@31: ERROR("sql_buf is too small: %i", ret); terom@31: terom@31: // the params... terom@31: if (0 terom@31: || ( evsql_params_clear(¶ms) ) terom@31: || ((to_set & FUSE_SET_ATTR_MODE ) && evsql_param_uint16(¶ms, 0, attr->st_mode) ) terom@31: || ((to_set & FUSE_SET_ATTR_UID ) && evsql_param_uint32(¶ms, 1, attr->st_uid) ) terom@31: || ((to_set & FUSE_SET_ATTR_GID ) && evsql_param_uint32(¶ms, 2, attr->st_gid) ) terom@31: || ((to_set & FUSE_SET_ATTR_SIZE ) && evsql_param_uint32(¶ms, 3, attr->st_size) ) terom@31: || ( evsql_param_uint32(¶ms, 4, ino) ) terom@31: ) terom@31: SERROR(err = EIO); terom@31: terom@31: // trace the query terom@31: evsql_query_debug(sql_buf, ¶ms); terom@31: terom@31: // query... we can pretend it's a getattr :) terom@41: if ((query = evsql_query_params(ctx->db, NULL, sql_buf, ¶ms, _dbfs_attr_res, req)) == NULL) terom@31: SERROR(err = EIO); terom@31: terom@41: // handle interrupts terom@41: fuse_req_interrupt_func(req, dbfs_interrupt_query, query); terom@31: terom@31: // wait terom@31: return; terom@31: terom@31: error: terom@31: if ((err = fuse_reply_err(req, err))) terom@31: EWARNING(err, "fuse_reply_err"); terom@31: }