// Recursively copies a directory. // // src - The path of the file or directory to copy. // dest - The path where the copy should be placed. // // Returns 0 if successful, otherwise returns -1. int sky_file_cp_r(bstring src, bstring dest) { int rc; bstring ent_src = NULL; bstring ent_dest = NULL; check(src != NULL, "Source path required"); check(dest != NULL, "Destination path required"); check(sky_file_exists(src), "Source file does not exist"); // If this is a directory then create a new dest directory and copy the // contents. if(sky_file_is_dir(src)) { // Create destination directory if it doesn't exist. if(!sky_file_exists(dest)) { struct stat st; rc = stat(bdata(src), &st); check(rc == 0, "Unable to stat source directory: %s", bdata(src)); rc = mkdir(bdata(dest), st.st_mode); check(rc == 0, "Unable to create directory: %s", bdata(dest)); } // Open directory. DIR *dir = opendir(bdata(src)); check(dir != NULL, "Unable to open directory: %s", bdata(src)); // Copy over contents of directory. struct dirent *ent; while((ent = readdir(dir))) { if(strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) { ent_src = bformat("%s/%s", bdata(src), ent->d_name); check_mem(ent_src); ent_dest = bformat("%s/%s", bdata(dest), ent->d_name); check_mem(ent_dest); rc = sky_file_cp_r(ent_src, ent_dest); check(rc == 0, "Unable to copy: %s", bdata(ent_src)); bdestroy(ent_src); bdestroy(ent_dest); } } // Close directory. closedir(dir); } // If this is a file then copy its contents. else { rc = sky_file_cp(src, dest); check(rc == 0, "Unable to copy file: %s", bdata(src)); } return 0; error: bdestroy(ent_src); bdestroy(ent_dest); return -1; }
// Deletes a table to the server. This function is synchronous and does not use // a worker. // // server - The server. // header - The message header. // table - The table the message is working against // input - The input file stream. // output - The output file stream. // // Returns 0 if successful, otherwise returns -1. int sky_delete_table_message_process(sky_server *server, sky_message_header *header, sky_table *_table, FILE *input, FILE *output) { int rc = 0; size_t sz; sky_delete_table_message *message = NULL; sky_table *table = NULL; bstring path = NULL; check(server != NULL, "Server required"); check(header != NULL, "Message header required"); check(input != NULL, "Input stream required"); check(output != NULL, "Output stream required"); (void)_table; struct tagbstring status_str = bsStatic("status"); struct tagbstring ok_str = bsStatic("ok"); // Parse message. message = sky_delete_table_message_create(); check_mem(message); rc = sky_delete_table_message_unpack(message, input); check(rc == 0, "Unable to parse 'delete_table' message"); // Retrieve table reference from server. rc = sky_server_get_table(server, message->name, &table); check(rc == 0, "Unable to find table: %s", bdata(message->name)); check(table != NULL, "Table does not exist: %s", bdata(message->name)); // Detach table first. path = bstrcpy(table->path); check_mem(path); rc = sky_server_close_table(server, table); check(rc == 0, "Unable to close table before deletion"); // If the table exists then delete it. if(sky_file_exists(path)) { rc = sky_file_rm_r(path); check(rc == 0, "Unable to delete table: %s", bdata(path)); } // Return. // {status:"OK"} minipack_fwrite_map(output, 1, &sz); check(sz > 0, "Unable to write output"); check(sky_minipack_fwrite_bstring(output, &status_str) == 0, "Unable to write status key"); check(sky_minipack_fwrite_bstring(output, &ok_str) == 0, "Unable to write status value"); fclose(input); fclose(output); bdestroy(path); sky_delete_table_message_free(message); return 0; error: if(input) fclose(input); if(output) fclose(output); bdestroy(path); sky_delete_table_message_free(message); return -1; }
int test_sky_table_open() { struct tagbstring lock_file_path = bsStatic("tmp/.skylock"); struct tagbstring data_file_path = bsStatic("tmp/0/data"); struct tagbstring header_file_path = bsStatic("tmp/0/header"); cleantmp(); int rc; sky_table *table = sky_table_create(); table->path = bfromcstr("tmp"); // Open table. rc = sky_table_open(table); mu_assert_int_equals(rc, 0); mu_assert(sky_file_exists(&lock_file_path), ""); mu_assert(sky_file_exists(&data_file_path), ""); mu_assert(sky_file_exists(&header_file_path), ""); // Close table. rc = sky_table_close(table); mu_assert_int_equals(rc, 0); mu_assert(!sky_file_exists(&lock_file_path), ""); mu_assert(sky_file_exists(&data_file_path), ""); mu_assert(sky_file_exists(&header_file_path), ""); sky_table_free(table); return 0; }
int test_sky_create_table_message_process() { cleantmp(); sky_server *server = sky_server_create(NULL); server->path = bfromcstr("tmp"); sky_message_header *header = sky_message_header_create(); FILE *input = fopen("tests/fixtures/create_table_message/1/input", "r"); FILE *output = fopen("tmp/output", "w"); int rc = sky_create_table_message_process(server, header, NULL, input, output); mu_assert_int_equals(rc, 0); struct tagbstring foo_db_path = bsStatic("tmp/foo"); struct tagbstring foo_db_0_path = bsStatic("tmp/foo/0"); struct tagbstring foo_db_9_path = bsStatic("tmp/foo/9"); mu_assert_bool(sky_file_exists(&foo_db_path)); mu_assert_bool(sky_file_exists(&foo_db_0_path)); mu_assert_bool(sky_file_exists(&foo_db_9_path)); mu_assert_file("tmp/output", "tests/fixtures/create_table_message/1/output"); sky_message_header_free(header); sky_server_free(server); return 0; }
// Deletes a single file. // // path - The path of the file to delete. // // Returns 0 if successful, otherwise returns -1. int sky_file_rm(bstring path) { int rc; check(path != NULL, "Path required"); check(!sky_file_is_dir(path), "File cannot be a directory"); if(sky_file_exists(path)) { rc = remove(bdata(path)); check(rc == 0, "Unable to delete file"); } return 0; error: return -1; }
// Recursively deletes a file or directory. // // path - The path of the file or directory to delete. // // Returns 0 if successful, otherwise returns -1. int sky_file_rm_r(bstring path) { int rc; bstring ent_path = NULL; check(path != NULL, "Path required"); // If path doesn't exist then just ignore it. if(sky_file_exists(path)) { // If the file is a directory then delete its contents first and then // delete it. if(sky_file_is_dir(path)) { // Open directory. DIR *dir = opendir(bdata(path)); check(dir != NULL, "Unable to open directory: %s", bdata(path)); // Remove each file inside directory. struct dirent *ent; while((ent = readdir(dir))) { if(strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) { ent_path = bformat("%s/%s", bdata(path), ent->d_name); check_mem(ent_path); rc = sky_file_rm_r(ent_path); check(rc == 0, "Unable to delete: %s", bdata(ent_path)); bdestroy(ent_path); } } // Close directory. closedir(dir); // Remove directory. remove(bdata(path)); } // If this is a file then delete it. else { rc = sky_file_rm(path); check(rc == 0, "Unable to delete file: %s", bdata(path)); } } return 0; error: bdestroy(ent_path); return -1; }
// Opens a table and attaches it to the server. // // server - The server. // name - The table name. // path - The table path. // ret - A pointer to where the table reference should be returned. // // Returns 0 if successful, otherwise returns -1. int sky_server_open_table(sky_server *server, bstring name, bstring path, sky_table **ret) { int rc; sky_table *table = NULL; assert(server != NULL); assert(ret != NULL); check(blength(path) > 0, "Table path required"); // Initialize return values. *ret = NULL; // Only open the table if it exists already. if(sky_file_exists(path)) { // Create the table. table = sky_table_create(); check_mem(table); table->name = bstrcpy(name); check_mem(table->name); rc = sky_table_set_path(table, path); check(rc == 0, "Unable to set table path"); // Open the table. rc = sky_table_open(table); check(rc == 0, "Unable to open table"); // Append the table to the list of open tables. server->table_count++; server->tables = realloc(server->tables, server->table_count * sizeof(*server->tables)); check_mem(server->tables); server->tables[server->table_count-1] = table; // Open servlets for the table's tablets. rc = sky_server_create_servlets(server, table); check(rc == 0, "Unable to create servlets for table"); // Return table. *ret = table; } return 0; error: sky_table_free(table); if(ret) *ret = NULL; return -1; }
// Copies a single file from the source path to the destination path. // // src - The path of the file to copy. // dest - The path where the copy should be placed. // // Returns 0 if successful, otherwise returns -1. int sky_file_cp(bstring src, bstring dest) { int rc; check(src != NULL, "Source path required"); check(dest != NULL, "Destination path required"); check(sky_file_exists(src), "Source file does not exist"); check(!sky_file_is_dir(src), "Source file cannot be a directory"); // Open source files. FILE *src_file = fopen(bdata(src), "r"); check(src_file != NULL, "Unable to open source file for reading"); // Open destination file. FILE *dest_file = fopen(bdata(dest), "w"); check(dest_file != NULL, "Unable to open destination file for writing"); // Read from source and write to destination until done. while(!feof(src_file)) { int buffer_size = 1024; char *buffer[buffer_size]; size_t sz = fread(buffer, sizeof(char), buffer_size, src_file); fwrite(buffer, sizeof(char), sz, dest_file); } // Close files. fclose(src_file); fclose(dest_file); // Copy permissions to destination file. struct stat st; stat(bdata(src), &st); rc = chmod(bdata(dest), st.st_mode); check(rc == 0, "Unable to copy permissions"); return 0; error: return -1; }
// Initializes and opens the data file on the table. // // table - The table to initialize the data file for. // // Returns 0 if successful, otherwise returns -1. int sky_table_load_data_file(sky_table *table) { int rc; check(table != NULL, "Table required"); check(table->path != NULL, "Table path required"); // Unload any existing data file. sky_table_unload_data_file(table); // Initialize table space (0). bstring tablespace_path = bformat("%s/0", bdata(table->path)); if(!sky_file_exists(tablespace_path)) { rc = mkdir(bdata(tablespace_path), S_IRWXU); check(rc == 0, "Unable to create tablespace directory: %s", bdata(tablespace_path)); } bdestroy(tablespace_path); // Initialize data file. table->data_file = sky_data_file_create(); check_mem(table->data_file); table->data_file->path = bformat("%s/0/data", bdata(table->path)); check_mem(table->data_file->path); table->data_file->header_path = bformat("%s/0/header", bdata(table->path)); check_mem(table->data_file->header_path); // Initialize settings on the block. if(table->default_block_size > 0) { table->data_file->block_size = table->default_block_size; } // Load data rc = sky_data_file_load(table->data_file); check(rc == 0, "Unable to load data file"); return 0; error: bdestroy(tablespace_path); sky_table_unload_data_file(table); return -1; }
// Opens the table for reading and writing events. // // table - The table to open. // // Returns 0 if successful, otherwise returns -1. int sky_table_open(sky_table *table) { int rc; check(table != NULL, "Table required"); check(table->path != NULL, "Table path is required"); check(!table->opened, "Table is already open"); // Create directory if it doesn't exist. if(!sky_file_exists(table->path)) { rc = mkdir(bdata(table->path), S_IRWXU); check(rc == 0, "Unable to create table directory: %s", bdata(table->path)); } // Obtain a lock. rc = sky_table_lock(table); check(rc == 0, "Unable to obtain lock"); // Load data file. rc = sky_table_load_data_file(table); check(rc == 0, "Unable to load data file"); // Load action file. rc = sky_table_load_action_file(table); check(rc == 0, "Unable to load action file"); // Load property file. rc = sky_table_load_property_file(table); check(rc == 0, "Unable to load property file"); // Flag the table as open. table->opened = true; return 0; error: sky_table_close(table); return -1; }
// Loads actions from file. // // action_file - The action file to load. // // Returns 0 if successful, otherwise returns -1. int sky_action_file_load(sky_action_file *action_file) { int rc; size_t sz; uint32_t count = 0; FILE *file = NULL; sky_action **actions = NULL; assert(action_file != NULL); check(action_file->path != NULL, "Action file path required"); // Unload any actions currently in memory. rc = sky_action_file_unload(action_file); check(rc == 0, "Unable to unload action file"); // Read in actions file if it exists. if(sky_file_exists(action_file->path)) { file = fopen(bdata(action_file->path), "r"); check(file, "Failed to open action file: %s", bdata(action_file->path)); // Read action count. count = minipack_fread_array(file, &sz); check(sz != 0, "Unable to read actions array at byte: %ld", ftell(file)); // Allocate actions. if(count > 0) { actions = malloc(sizeof(sky_action*) * count); check_mem(actions); } // Read actions. uint32_t i; for(i=0; i<count; i++) { sky_action *action = sky_action_create(); check_mem(action); // Read action id. action->id = (sky_action_id_t)minipack_fread_uint(file, &sz); check(sz != 0, "Unable to read action identifier at byte: %ld", ftell(file)); // Read action name. rc = sky_minipack_fread_bstring(file, &action->name); check(rc == 0, "Unable to read action name at byte: %ld", ftell(file)); // Append to array. action->action_file = action_file; actions[i] = action; } // Close the file. fclose(file); } // Store action list on action file. action_file->actions = actions; action_file->action_count = count; return 0; error: if(file) fclose(file); if(actions) free(actions); return -1; }