terom@30: #include terom@30: #include terom@30: terom@30: #include terom@30: terom@30: #include "dbfs.h" terom@30: #include "op_base.h" terom@30: #include "../lib/log.h" terom@30: terom@30: struct dbfs_fileop { terom@30: struct dbfs_op base; terom@30: terom@30: uint32_t lo_fd; terom@30: }; terom@30: terom@30: static void _dbfs_fileop_free (struct dbfs_op *op_base) { terom@30: struct dbfs_fileop *fop = (struct dbfs_fileop *) op_base; terom@30: terom@30: /* no-op */ terom@30: (void) fop; terom@30: } terom@30: terom@30: static void dbfs_open_res (const struct evsql_result_info *res, void *arg) { terom@30: struct dbfs_fileop *fop = arg; terom@30: int err; terom@30: terom@30: // check the results terom@30: if ((err = _dbfs_check_res(res, 1, 2))) terom@30: SERROR(err = (err == 1 ? ENOENT : EIO)); terom@30: terom@30: const char *type; terom@30: terom@30: // extract the data terom@30: if (0 terom@30: || evsql_result_string(res, 0, 0, &type, 0 ) // inodes.type terom@30: || evsql_result_uint32(res, 0, 1, &fop->lo_fd, 0 ) // fd terom@30: ) terom@30: SERROR(err = EIO); terom@30: terom@30: // is it a dir? terom@30: if (_dbfs_mode(type) != S_IFREG) terom@35: EERROR(err = EINVAL, "wrong type: %s", type); terom@30: terom@36: INFO("\t[dbfs.open %p:%p] -> ino=%lu, type=%s", fop, fop->base.req, (unsigned long int) fop->base.ino, type); terom@30: terom@30: // open_fn done, do the open_reply terom@30: if ((err = dbfs_op_open_reply(&fop->base))) terom@30: goto error; terom@30: terom@30: // success, fallthrough for evsql_result_free terom@30: err = 0; terom@30: terom@30: error: terom@30: if (err) terom@30: // fail it terom@30: dbfs_op_fail(&fop->base, err); terom@30: terom@30: // free terom@30: evsql_result_free(res); terom@30: } terom@30: terom@30: static void dbfs_fileop_open (struct dbfs_op *op_base) { terom@30: struct dbfs_fileop *fop = (struct dbfs_fileop *) op_base; terom@30: struct dbfs *ctx = fuse_req_userdata(fop->base.req); terom@30: int err; terom@30: terom@30: // make sure the file actually exists terom@30: const char *sql = terom@30: "SELECT" terom@30: " inodes.type, lo_open(inodes.data, $1::int4) AS fd" terom@30: " FROM inodes" terom@30: " WHERE inodes.ino = $2::int4"; terom@30: terom@30: static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { terom@30: EVSQL_PARAM ( UINT32 ), terom@30: EVSQL_PARAM ( UINT32 ), terom@30: terom@30: EVSQL_PARAMS_END terom@30: }; terom@30: terom@30: // build params terom@30: if (0 terom@30: || evsql_param_uint32(¶ms, 0, INV_READ | INV_WRITE) terom@30: || evsql_param_uint32(¶ms, 1, fop->base.ino) terom@30: ) terom@30: SERROR(err = EIO); terom@30: terom@30: // query terom@30: if (evsql_query_params(ctx->db, fop->base.trans, sql, ¶ms, dbfs_open_res, fop) == NULL) terom@30: SERROR(err = EIO); terom@30: terom@30: // ok, wait for the info results terom@30: return; terom@30: terom@30: error: terom@30: // fail it terom@30: dbfs_op_fail(&fop->base, err); terom@30: } terom@30: terom@30: void dbfs_open (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { terom@30: struct dbfs *ctx = fuse_req_userdata(req); terom@30: struct dbfs_fileop *fop = NULL; terom@30: int err; terom@30: terom@30: // allocate it terom@30: if ((fop = calloc(1, sizeof(*fop))) == NULL && (err = EIO)) terom@30: ERROR("calloc"); terom@30: terom@30: // do the op_open terom@30: if ((err = dbfs_op_open(ctx, &fop->base, req, ino, fi, _dbfs_fileop_free, dbfs_fileop_open))) terom@30: ERROR("dbfs_op_open"); terom@30: terom@30: // log terom@30: INFO("[dbfs.open %p:%p] ino=%lu, fi->flags=%04X", fop, req, ino, fi->flags); terom@30: terom@30: // wait terom@30: return; terom@30: terom@30: error: terom@30: if (fop) { terom@30: // we can fail normally terom@30: dbfs_op_fail(&fop->base, err); terom@30: terom@30: } else { terom@30: // must error out manually as we couldn't alloc the context terom@30: if ((err = fuse_reply_err(req, err))) terom@30: EWARNING(err, "fuse_reply_err"); terom@30: } terom@30: } terom@30: terom@30: void dbfs_read_res (const struct evsql_result_info *res, void *arg) { terom@30: struct dbfs_fileop *fop = arg; terom@30: int err; terom@30: const char *buf; terom@30: size_t size; terom@30: terom@30: // check the results terom@30: if ((err = _dbfs_check_res(res, 1, 1)) < 0) terom@30: SERROR(err = EIO); terom@30: terom@30: // get the data terom@31: if (evsql_result_binary(res, 0, 0, &buf, &size, 0)) terom@30: SERROR(err = EIO); terom@30: terom@36: INFO("\t[dbfs.read %p:%p] -> size=%zu", fop, fop->base.req, size); terom@30: terom@30: // send it terom@30: if ((err = fuse_reply_buf(fop->base.req, buf, size))) terom@30: EERROR(err, "fuse_reply_buf"); terom@30: terom@30: // ok, req handled terom@30: if ((err = dbfs_op_req_done(&fop->base))) terom@30: goto error; terom@30: terom@30: // good, fallthrough terom@30: err = 0; terom@30: terom@30: error: terom@30: if (err) terom@30: dbfs_op_fail(&fop->base, err); terom@30: terom@30: // free terom@30: evsql_result_free(res); terom@30: } terom@30: terom@30: void dbfs_read (struct fuse_req *req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { terom@30: struct dbfs *ctx = fuse_req_userdata(req); terom@30: struct dbfs_fileop *fop; terom@30: int err; terom@30: terom@30: // get the op terom@30: if ((fop = (struct dbfs_fileop *) dbfs_op_req(req, ino, fi)) == NULL) terom@30: return; terom@30: terom@30: // log terom@30: INFO("[dbfs.read %p:%p] ino=%lu, size=%zu, off=%lu, fi->flags=%04X", fop, req, ino, size, off, fi->flags); terom@30: terom@30: // query terom@30: const char *sql = terom@30: "SELECT" terom@30: " lo_pread($1::int4, $2::int4, $3::int4)"; terom@30: terom@30: static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { terom@30: EVSQL_PARAM ( UINT32 ), // fd terom@30: EVSQL_PARAM ( UINT32 ), // len terom@30: EVSQL_PARAM ( UINT32 ), // off terom@30: terom@30: EVSQL_PARAMS_END terom@30: }; terom@30: terom@30: // build params terom@30: if (0 terom@30: || evsql_param_uint32(¶ms, 0, fop->lo_fd) terom@30: || evsql_param_uint32(¶ms, 1, size) terom@30: || evsql_param_uint32(¶ms, 2, off) terom@30: ) terom@30: SERROR(err = EIO); terom@30: terom@30: // query terom@30: if (evsql_query_params(ctx->db, fop->base.trans, sql, ¶ms, dbfs_read_res, fop) == NULL) terom@30: SERROR(err = EIO); terom@30: terom@30: // ok, wait for the info results terom@30: return; terom@30: terom@30: error: terom@30: // fail it terom@30: dbfs_op_fail(&fop->base, err); terom@30: } terom@30: terom@31: void dbfs_write_res (const struct evsql_result_info *res, void *arg) { terom@31: struct dbfs_fileop *fop = arg; terom@31: int err; terom@31: uint32_t size; terom@31: terom@31: // check the results terom@31: if ((err = _dbfs_check_res(res, 1, 1)) < 0) terom@31: SERROR(err = EIO); terom@31: terom@31: // get the size terom@31: if (evsql_result_uint32(res, 0, 0, &size, 0)) terom@31: SERROR(err = EIO); terom@31: terom@36: INFO("\t[dbfs.write %p:%p] -> size=%lu", fop, fop->base.req, (long unsigned int) size); terom@31: terom@31: // send it terom@31: if ((err = fuse_reply_write(fop->base.req, size))) terom@31: EERROR(err, "fuse_reply_write"); terom@31: terom@31: // ok, req handled terom@31: if ((err = dbfs_op_req_done(&fop->base))) terom@31: goto error; terom@31: terom@31: // good, fallthrough terom@31: err = 0; terom@31: terom@31: error: terom@31: if (err) terom@31: dbfs_op_fail(&fop->base, err); terom@31: terom@31: // free terom@31: evsql_result_free(res); terom@31: } terom@31: terom@30: void dbfs_write (struct fuse_req *req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { terom@31: struct dbfs *ctx = fuse_req_userdata(req); terom@31: struct dbfs_fileop *fop; terom@31: int err; terom@31: terom@31: // get the op terom@31: if ((fop = (struct dbfs_fileop *) dbfs_op_req(req, ino, fi)) == NULL) terom@31: return; terom@30: terom@31: // log terom@31: INFO("[dbfs.write %p:%p] ino=%lu, size=%zu, off=%lu, fi->flags=%04X", fop, req, ino, size, off, fi->flags); terom@31: terom@31: // query terom@31: const char *sql = terom@31: "SELECT" terom@31: " lo_pwrite($1::int4, $2::bytea, $3::int4)"; terom@31: terom@31: static struct evsql_query_params params = EVSQL_PARAMS(EVSQL_FMT_BINARY) { terom@31: EVSQL_PARAM ( UINT32 ), // fd terom@31: EVSQL_PARAM ( BINARY ), // buf terom@31: EVSQL_PARAM ( UINT32 ), // off 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, fop->lo_fd) terom@31: || evsql_param_binary(¶ms, 1, buf, size) terom@31: || evsql_param_uint32(¶ms, 2, off) terom@31: ) terom@31: SERROR(err = EIO); terom@31: terom@31: // query terom@31: if (evsql_query_params(ctx->db, fop->base.trans, sql, ¶ms, dbfs_write_res, fop) == NULL) terom@31: SERROR(err = EIO); terom@31: terom@31: // ok, wait for the info results terom@31: return; terom@31: terom@31: error: terom@31: // fail it terom@31: dbfs_op_fail(&fop->base, err); terom@30: } terom@30: terom@30: void dbfs_flush (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { terom@30: struct dbfs_fileop *fop; terom@30: int err; terom@30: terom@30: // get the fop terom@30: if ((fop = (struct dbfs_fileop *) dbfs_op_req(req, ino, fi)) == NULL) terom@30: return; terom@30: terom@30: // log terom@30: INFO("[dbfs.flush %p:%p] ino=%lu", fop, req, ino); terom@30: terom@30: // and reply... terom@30: if ((err = fuse_reply_err(req, 0))) terom@30: EWARNING(err, "fuse_reply_err"); terom@30: terom@30: // done terom@30: if ((err = dbfs_op_req_done(&fop->base))) terom@30: goto error; terom@30: terom@30: // good terom@30: return; terom@30: terom@30: error: terom@30: dbfs_op_fail(&fop->base, err); terom@30: } terom@30: terom@30: void dbfs_release (struct fuse_req *req, fuse_ino_t ino, struct fuse_file_info *fi) { terom@30: // just passthrough to dbfs_op terom@30: // the lo_fd will be closed automatically terom@30: dbfs_op_release(req, ino, fi); terom@30: }