// add new file entry to directory, return new inode void dir_tree_file_create (DirTree *dtree, fuse_ino_t parent_ino, const char *name, mode_t mode, DirTree_file_create_cb file_create_cb, fuse_req_t req, struct fuse_file_info *fi) { DirEntry *dir_en, *en; DirTreeFileOpData *op_data; LOG_debug (DIR_TREE_LOG, "Adding new entry '%s' to directory ino: %"INO_FMT, name, parent_ino); dir_en = g_hash_table_lookup (dtree->h_inodes, GUINT_TO_POINTER (parent_ino)); // entry not found if (!dir_en || dir_en->type != DET_dir) { LOG_msg (DIR_TREE_LOG, "Directory (%"INO_FMT") not found !", parent_ino); file_create_cb (req, FALSE, 0, 0, 0, fi); return; } // create a new entry en = dir_tree_add_entry (dtree, name, mode, DET_file, parent_ino, 0, time (NULL)); if (!en) { LOG_msg (DIR_TREE_LOG, "Failed to create file: %s !", name); file_create_cb (req, FALSE, 0, 0, 0, fi); return; } //XXX: set as new en->is_modified = TRUE; op_data = file_op_data_create (dtree, en->ino); op_data->en = en; op_data->ino = en->ino; en->op_data = (gpointer) op_data; file_create_cb (req, TRUE, en->ino, en->mode, en->size, fi); }
void dir_tree_dir_create (DirTree *dtree, fuse_ino_t parent_ino, const char *name, mode_t mode, dir_tree_mkdir_cb mkdir_cb, fuse_req_t req) { DirEntry *dir_en, *en; DirTreeFileOpData *op_data; LOG_debug (DIR_TREE_LOG, "Creating dir: %s", name); dir_en = g_hash_table_lookup (dtree->h_inodes, GUINT_TO_POINTER (parent_ino)); // entry not found if (!dir_en || dir_en->type != DET_dir) { LOG_msg (DIR_TREE_LOG, "Directory (%"INO_FMT") not found !", parent_ino); mkdir_cb (req, FALSE, 0, 0, 0, 0); return; } // create a new entry en = dir_tree_add_entry (dtree, name, mode, DET_dir, parent_ino, 10, time (NULL)); if (!en) { LOG_msg (DIR_TREE_LOG, "Failed to create dir: %s !", name); mkdir_cb (req, FALSE, 0, 0, 0, 0); return; } //XXX: set as new en->is_modified = FALSE; // do not delete it en->age = G_MAXUINT32; en->mode = DIR_DEFAULT_MODE; mkdir_cb (req, TRUE, en->ino, en->mode, en->size, en->ctime); }
// existing file is opened, create context data gboolean dir_tree_file_open (DirTree *dtree, fuse_ino_t ino, struct fuse_file_info *fi, DirTree_file_open_cb file_open_cb, fuse_req_t req) { DirTreeFileOpData *op_data; DirEntry *en; op_data = file_op_data_create (dtree, ino); op_data->c_fi = fi; op_data->c_req = req; op_data->file_open_cb = file_open_cb; en = g_hash_table_lookup (dtree->h_inodes, GUINT_TO_POINTER (ino)); // if entry does not exist // or it's not a directory type ? if (!en) { LOG_msg (DIR_TREE_LOG, "Entry (ino = %"INO_FMT") not found !", ino); file_open_cb (op_data->c_req, FALSE, op_data->c_fi); return FALSE; } op_data->en = en; op_data->en->op_data = (gpointer) op_data; LOG_debug (DIR_TREE_LOG, "[%p %p] dir_tree_open inode %"INO_FMT, op_data, fi, ino); if (!s3client_pool_get_client (application_get_read_client_pool (dtree->app), dir_tree_file_open_on_http_ready, op_data)) { LOG_err (DIR_TREE_LOG, "Failed to get S3HttpConnection from the pool !"); } return TRUE; }
// file is closed, free context data void dir_tree_file_release (DirTree *dtree, fuse_ino_t ino, struct fuse_file_info *fi) { DirEntry *en; DirTreeFileOpData *op_data; LOG_debug (DIR_TREE_LOG, "dir_tree_file_release inode %d", ino); en = g_hash_table_lookup (dtree->h_inodes, GUINT_TO_POINTER (ino)); // if entry does not exist // or it's not a directory type ? if (!en) { LOG_msg (DIR_TREE_LOG, "Entry (ino = %"INO_FMT") not found !", ino); //XXX return; } op_data = (DirTreeFileOpData *) en->op_data; // op_data->en = en; // op_data->ino = ino; if (op_data->http) s3http_client_release (op_data->http); // releasing written file if (op_data->tmp_write_fd) { if (!s3client_pool_get_client (application_get_write_client_pool (dtree->app), dir_tree_file_release_on_http_ready, op_data)) { LOG_err (DIR_TREE_LOG, "Failed to get S3HttpConnection from the pool !"); } } else { file_op_data_destroy (op_data); } }
// USR2 signal: reopen log file static void sigusr2_cb (G_GNUC_UNUSED evutil_socket_t sig, G_GNUC_UNUSED short events, G_GNUC_UNUSED void *user_data) { Application *app = _app; // just flush, if log file name is not specified if (!app->log_file_name || !app->f_log) { fflush (app->f_log); return; } LOG_msg (APP_LOG, "Reopening log file: %s !", app->log_file_name); fflush (app->f_log); fclose (app->f_log); app->f_log = fopen (app->log_file_name, "a+"); if (!app->f_log) { LOG_err (APP_LOG, "Failed to open log file: %s, output goes to stdout. Error: %s", app->log_file_name, strerror (errno)); // XXX: set output to stdout logger_set_file (stdout); return; } logger_set_file (app->f_log); }
// add new chunk range to the chunks pending queue void dir_tree_file_read (DirTree *dtree, fuse_ino_t ino, size_t size, off_t off, DirTree_file_read_cb file_read_cb, fuse_req_t req, struct fuse_file_info *fi) { DirEntry *en; char full_name[1024]; DirTreeFileOpData *op_data; DirTreeFileRange *range; en = g_hash_table_lookup (dtree->h_inodes, GUINT_TO_POINTER (ino)); // if entry does not exist // or it's not a directory type ? if (!en) { LOG_msg (DIR_TREE_LOG, "Entry (ino = %"INO_FMT") not found !", ino); file_read_cb (req, FALSE, NULL, 0); return; } op_data = (DirTreeFileOpData *) en->op_data; LOG_debug (DIR_TREE_LOG, "[%p %p] Read Object inode %"INO_FMT", size: %zd, off: %"OFF_FMT, req, op_data, ino, size, off); op_data->file_read_cb = file_read_cb; op_data->en = en; op_data->dtree = dtree; range = g_new0 (DirTreeFileRange, 1); range->off = off; range->size = size; range->c_req = req; g_queue_push_tail (op_data->q_ranges_requested, range); LOG_debug (DIR_TREE_LOG, "[%p] more data b: %zd", range->c_req, range->size); // already reading data if (op_data->op_in_progress) { return; } if (op_data->http) { LOG_debug (DIR_TREE_LOG, "Adding from main"); range = g_queue_pop_head (op_data->q_ranges_requested); if (range) { op_data->c_size = range->size; op_data->c_off = range->off; op_data->c_req = range->c_req; g_free (range); // perform the next chunk request op_data->op_in_progress = TRUE; dir_tree_file_read_prepare_request (op_data, op_data->http, op_data->c_off, op_data->c_size); } return; } }
void THROW_NoSuchMethod(CTX ctx, ksfp_t *sfp, kclass_t cid, kmethodn_t mn) { CWB_t cwbbuf, *cwb = CWB_open(ctx, &cwbbuf); char msg[256], mname[256]; knh_printf(ctx, cwb->w, "Script!!: No Such Method: %T.%M", cid, mn); knh_snprintf(msg, sizeof(msg), "%s", CWB_totext(ctx, cwb)); CWB_close(ctx, cwb); knh_printf(ctx, cwb->w, "%C.%M", cid, mn); knh_snprintf(mname, sizeof(mname), "%s", CWB_totext(ctx, cwb)); CWB_close(ctx, cwb); KNH_NTHROW2(ctx, sfp, msg, "konoha:type", K_FAILED, KNH_LDATA(LOG_msg(msg), LOG_s("method", mname))); }
void THROW_ParamTypeError(CTX ctx, ksfp_t *sfp, size_t n, kmethodn_t mn, kclass_t reqt, kclass_t cid) { CWB_t cwbbuf, *cwb = CWB_open(ctx, &cwbbuf); char msg[256], mname[256]; knh_printf(ctx, cwb->w, "Script!!: Type Error: %T.%M(#%d)", cid, mn, (int)n); knh_snprintf(msg, sizeof(msg), "%s", CWB_totext(ctx, cwb)); CWB_close(ctx, cwb); knh_printf(ctx, cwb->w, "%C.%M", cid, mn); knh_snprintf(mname, sizeof(mname), "%s", CWB_totext(ctx, cwb)); CWB_close(ctx, cwb); KNH_NTHROW2(ctx, sfp, msg, "konoha:type", K_FAILED, KNH_LDATA(LOG_msg(msg), LOG_s("method", mname), LOG_i("argument", n), LOG_t("requested_type", reqt), LOG_t("given_type", cid))); }
// return directory buffer from the cache // or regenerate directory cache void dir_tree_fill_dir_buf (DirTree *dtree, fuse_ino_t ino, size_t size, off_t off, dir_tree_readdir_cb readdir_cb, fuse_req_t req) { DirEntry *en; DirTreeFillDirData *dir_fill_data; time_t t; LOG_debug (DIR_TREE_LOG, "Requesting directory buffer for dir ino %"INO_FMT", size: %zd, off: %"OFF_FMT, ino, size, off); en = g_hash_table_lookup (dtree->h_inodes, GUINT_TO_POINTER (ino)); // if directory does not exist // or it's not a directory type ? if (!en || en->type != DET_dir) { LOG_msg (DIR_TREE_LOG, "Directory (ino = %"INO_FMT") not found !", ino); readdir_cb (req, FALSE, size, off, NULL, 0); return; } t = time (NULL); // already have directory buffer in the cache if (en->dir_cache_size && t >= en->dir_cache_created && t - en->dir_cache_created <= dtree->dir_cache_max_time) { LOG_debug (DIR_TREE_LOG, "Sending directory buffer (ino = %"INO_FMT") from cache !", ino); readdir_cb (req, TRUE, size, off, en->dir_cache, en->dir_cache_size); return; } LOG_debug (DIR_TREE_LOG, "cache time: %ld now: %ld", en->dir_cache_created, t); // reset dir cache if (en->dir_cache) g_free (en->dir_cache); en->dir_cache_size = 0; en->dir_cache_created = 0; dir_fill_data = g_new0 (DirTreeFillDirData, 1); dir_fill_data->dtree = dtree; dir_fill_data->ino = ino; dir_fill_data->size = size; dir_fill_data->off = off; dir_fill_data->readdir_cb = readdir_cb; dir_fill_data->req = req; dir_fill_data->en = en; if (!s3client_pool_get_client (application_get_ops_client_pool (dtree->app), dir_tree_fill_dir_on_http_ready, dir_fill_data)) { LOG_err (DIR_TREE_LOG, "Failed to get HTTP client !"); readdir_cb (req, FALSE, size, off, NULL, 0); g_free (dir_fill_data); } }
// send data via HTTP client void dir_tree_file_write (DirTree *dtree, fuse_ino_t ino, const char *buf, size_t size, off_t off, DirTree_file_write_cb file_write_cb, fuse_req_t req, struct fuse_file_info *fi) { DirEntry *en; DirTreeFileOpData *op_data; ssize_t out_size; en = g_hash_table_lookup (dtree->h_inodes, GUINT_TO_POINTER (ino)); // if entry does not exist // or it's not a directory type ? if (!en) { LOG_msg (DIR_TREE_LOG, "Entry (ino = %"INO_FMT") not found !", ino); file_write_cb (req, FALSE, 0); return; } op_data = (DirTreeFileOpData *) en->op_data; LOG_debug (DIR_TREE_LOG, "[%p] Writing Object inode %"INO_FMT", size: %zd, off: %"OFF_FMT, op_data, ino, size, off); // if tmp file is not opened if (!op_data->tmp_write_fd) { char filename[1024]; op_data->en = en; op_data->op_in_progress = TRUE; snprintf (filename, sizeof (filename), "%s/s3ffs.XXXXXX", application_get_tmp_dir (dtree->app)); op_data->tmp_write_fd = mkstemp (filename); if (op_data->tmp_write_fd < 0) { LOG_err (DIR_TREE_LOG, "Failed to create tmp file !"); file_write_cb (req, FALSE, 0); return; } } // if http client is not acquired yet //if (!op_data->con_http) { //} //XXX: here decide if switch to multi part upload out_size = pwrite (op_data->tmp_write_fd, buf, size, off); if (out_size < 0) { file_write_cb (req, FALSE, 0); return; } else file_write_cb (req, TRUE, out_size); }
// return entry attributes void dir_tree_getattr (DirTree *dtree, fuse_ino_t ino, dir_tree_getattr_cb getattr_cb, fuse_req_t req) { DirEntry *en; LOG_debug (DIR_TREE_LOG, "Getting attributes for %d", ino); en = g_hash_table_lookup (dtree->h_inodes, GUINT_TO_POINTER (ino)); // entry not found if (!en) { LOG_msg (DIR_TREE_LOG, "Entry (%d) not found !", ino); getattr_cb (req, FALSE, 0, 0, 0, 0); return; } getattr_cb (req, TRUE, en->ino, en->mode, en->size, en->ctime); }
// set entry's attributes // update directory cache void dir_tree_setattr (DirTree *dtree, fuse_ino_t ino, struct stat *attr, int to_set, dir_tree_setattr_cb setattr_cb, fuse_req_t req, void *fi) { DirEntry *en; LOG_debug (DIR_TREE_LOG, "Setting attributes for %d", ino); en = g_hash_table_lookup (dtree->h_inodes, GUINT_TO_POINTER (ino)); // entry not found if (!en) { LOG_msg (DIR_TREE_LOG, "Entry (%d) not found !", ino); setattr_cb (req, FALSE, 0, 0, 0); return; } //XXX: en->mode setattr_cb (req, TRUE, en->ino, en->mode, en->size); }
// lookup entry and return attributes void dir_tree_lookup (DirTree *dtree, fuse_ino_t parent_ino, const char *name, dir_tree_lookup_cb lookup_cb, fuse_req_t req) { DirEntry *dir_en, *en; LOG_debug (DIR_TREE_LOG, "Looking up for '%s' in directory ino: %d", name, parent_ino); dir_en = g_hash_table_lookup (dtree->h_inodes, GUINT_TO_POINTER (parent_ino)); // entry not found if (!dir_en || dir_en->type != DET_dir) { LOG_msg (DIR_TREE_LOG, "Directory (%d) not found !", parent_ino); lookup_cb (req, FALSE, 0, 0, 0, 0); return; } en = g_hash_table_lookup (dir_en->h_dir_tree, name); if (!en) { LOG_debug (DIR_TREE_LOG, "Entry '%s' not found !", name); lookup_cb (req, FALSE, 0, 0, 0, 0); return; } // file is removed if (en->age == 0) { LOG_debug (DIR_TREE_LOG, "Entry '%s' is removed !", name); lookup_cb (req, FALSE, 0, 0, 0, 0); return; } // hide it if (en->is_modified) { LOG_debug (DIR_TREE_LOG, "Entry '%s' is modified !", name); lookup_cb (req, TRUE, en->ino, en->mode, 0, en->ctime); return; } lookup_cb (req, TRUE, en->ino, en->mode, en->size, en->ctime); }
// socket event during connection static void s3http_client_connection_event_cb (struct bufferevent *bev, short what, void *ctx) { S3HttpClient *http = (S3HttpClient *) ctx; if (!(what & BEV_EVENT_CONNECTED)) { // XXX: reset http->connection_state = S3C_disconnected; LOG_msg (HTTP_LOG, "Failed to establish connection !"); // inform client that we are disconnected if (http->on_close_cb) http->on_close_cb (http, http->cb_ctx); s3http_client_release (http); return; } LOG_debug (HTTP_LOG, "Connected to the server ! %p", http); http->connection_state = S3C_connected; evbuffer_drain (bufferevent_get_input (bev), -1); evbuffer_drain (bufferevent_get_output (bev), -1); http->response_state = S3R_expected_first_line; bufferevent_enable (http->bev, EV_READ); bufferevent_setcb (http->bev, s3http_client_read_cb, s3http_client_write_cb, s3http_client_event_cb, http ); // inform client that we are connected if (http->on_connection_cb) http->on_connection_cb (http, http->cb_ctx); // send initial request as soon as we are connected s3http_client_send_initial_request (http); }
// ignore SIGPIPE static void sigpipe_cb (G_GNUC_UNUSED evutil_socket_t sig, G_GNUC_UNUSED short events, G_GNUC_UNUSED void *user_data) { LOG_msg (APP_LOG, "Got SIGPIPE"); }
KNHAPI2(void) THROW_OutOfRange(CTX ctx, ksfp_t *sfp, kint_t n, size_t max) { KNH_NTHROW2(ctx, sfp, "Script!!", "array_indexing", K_FAILED, KNH_LDATA(LOG_msg("out of array range"), LOG_i("index", n), LOG_i("arraysize", max))); }
void THROW_Arithmetic(CTX ctx, ksfp_t *sfp, const char *msg) { KNH_NTHROW2(ctx, sfp, "Script!!", "arithmetic_operator", K_FAILED, KNH_LDATA(LOG_msg(msg))); }
void THROW_StackOverflow(CTX ctx, ksfp_t *sfp) { KNH_NTHROW2(ctx, sfp, "Script!!", "konoha:stack", K_FAILED, KNH_LDATA(LOG_msg("stack overflow"), LOG_u("stacksize", (ctx->esp - ctx->stack)))); }
void THROW_Halt(CTX ctx, ksfp_t *sfp, const char *msg) { KNH_NTHROW2(ctx, sfp, "Panic!!", "konoha", K_FAILED, KNH_LDATA(LOG_msg(msg))); }