block_store_t *block_store_create() { // While assembly-wise it shouldn't change, it looks cleaner, // even if we have extra free/destruct calls on the error path // (but then again, who cares about the length of the error path?) // This will probably have to be encapsulated eventually, like bitmap's creations // (also because import is a MEEEESSSSSSSSS) // (Actually, with bitmap_overlay now, we may just be able to call create whenever) // (Although file-backed stuff will throw a wrench in it, but it's VERY different (just an fd?)) // (file-backing is a headache for some other day) block_store_t *bs = calloc(sizeof(block_store_t), 1); if (bs) { if ((bs->data_blocks = calloc(BLOCK_SIZE, BLOCK_COUNT)) && // Eh, calloc, why not (technically a security risk if we don't) (bs->fbm = bitmap_overlay(BLOCK_COUNT, bs->data_blocks)) && (bs->dbm = bitmap_create(BLOCK_COUNT))) { for (size_t idx = 0; idx < FBM_BLOCK_COUNT; ++idx) { bitmap_set(bs->fbm, idx); } bitmap_format(bs->dbm, 0xFF); // we have never synced, mark all as changed bs->flags = DIRTY; bs->fd = -1; bs_errno = BS_OK; return bs; } free(bs->data_blocks); bitmap_destroy(bs->dbm); bitmap_destroy(bs->fbm); free(bs); } bs_errno = BS_MEMORY; return NULL; }
void block_store_flush(block_store_t *const bs) { if (bs) { if (FLAG_CHECK(bs, FILE_LINKED)) { if (FLAG_CHECK(bs, DIRTY)) { // actual work to do // size_t blocks_to_write = bitmap_total_set(bs->dbm); /* typedef struct { int disaster_errno; block_store_t *const bs; size_t byte_counter; bs_status status; } bs_sync_obj; */ bs_sync_obj sync_results = {0, bs, 0, BS_OK}; bitmap_for_each(bs->dbm, &block_sync, &sync_results); if (sync_results.status == BS_OK) { // Well it worked, hopefully // Sipe the DBM and clear the dirty bit bitmap_format(bs->dbm, 0x00); FLAG_CLEAR(bs, DIRTY); } bs_errno = sync_results.status; return; } bs_errno = BS_OK; return; } bs_errno = BS_NO_LINK; return; } bs_errno = BS_PARAM; return; }
void block_store_link(block_store_t *const bs, const char *const filename) { if (bs && filename) { if (! FLAG_CHECK(bs, FILE_LINKED)) { // Ok, I can make a giant complicated hunk of logic to: // Create if it doesn't exist // Increase size if smaller // Decrease size if larger // and It'll be a giant headache for various reasons (error checking, portability) // OR, I can just do it in two commands and call it a day. bs->fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP); if (bs->fd != -1) { if (utility_write_file(bs->fd, bs->data_blocks, BLOCK_COUNT * BLOCK_SIZE) == BLOCK_COUNT * BLOCK_SIZE) { // Kill the DBM and dirty flag, set link state bitmap_format(bs->dbm, 0x00); FLAG_CLEAR(bs, DIRTY); FLAG_SET(bs, FILE_LINKED); bs_errno = BS_OK; return; } bs_errno = BS_FILE_IO; return; } bs_errno = BS_FILE_ACCESS; return; } bs_errno = BS_LINK_EXISTS; return; } bs_errno = BS_PARAM; }
/* * PURPOSE: imports block store * INPUTS: char, filename * RETURN: block_store_t **/ block_store_t *block_store_import(const char *const filename) { block_store_t *bs = block_store_create(); //create blockstore bs if(bs){ bitmap_destroy(bs -> fbm); //destroy fbm in bs bitmap_format(bs -> dbm, 0); //format dbm in bs struct stat file_info; // size_t urf = 0; if(stat(filename, &file_info) != -1){ if(file_info.st_size == BLOCK_SIZE * BLOCK_COUNT){ int fd; fd = open(filename, O_RDONLY); if(fd != -1){ size_t ct = FBM_SIZE * BLOCK_SIZE; urf = utility_read_file(fd, bs -> data_blocks, ct); if (urf) { bs -> fbm = bitmap_import(BLOCK_COUNT, bs -> data_blocks); if (bs -> fbm) { ct = (BLOCK_COUNT - FBM_SIZE) * BLOCK_SIZE; urf = utility_read_file(fd, bs -> data_blocks, ct); if (urf) { block_store_errno = BS_OK; close(fd); }return 0; } } } } } } // struct stat { // dev_t st_dev; /* ID of device containing file */ // ino_t st_ino; /* inode number */ // mode_t st_mode; /* protection */ // nlink_t st_nlink; /* number of hard links */ // uid_t st_uid; /* user ID of owner */ // gid_t st_gid; /* group ID of owner */ // dev_t st_rdev; /* device ID (if special file) */ // off_t st_size; /* total size, in bytes */ // blksize_t st_blksize; /* blocksize for filesystem I/O */ // blkcnt_t st_blocks; /* number of 512B blocks allocated */ block_store_errno = BS_FATAL; return NULL; }
block_store_t *block_store_import(const char *const filename) { block_store_t *bs = NULL; int fd = 0; if (filename) { struct stat file_stat; // macro count * size ? if (!stat(filename, &file_stat) && file_stat.st_size == (BLOCK_COUNT * BLOCK_SIZE)) { fd = open(filename, O_RDONLY); if (fd != -1) { bs = block_store_create(); if (bs) { if (utility_read_file(fd, bs->data_blocks, BLOCK_COUNT * BLOCK_SIZE) == BLOCK_COUNT * BLOCK_SIZE) { // We're good to go, attempt to link. close(fd); // manual override because I'm not going to call link // and just have it write what we just read back out bs->fd = open(filename, O_WRONLY); if (bs->fd != -1) { // Wipe it, we have a link to something we JUST read // So it SHOULD be in sync with us unless something else is using the file FLAG_SET(bs, FILE_LINKED); FLAG_CLEAR(bs, DIRTY); bitmap_format(bs->dbm, 0x00); } bs_errno = ((bs->fd == -1) ? BS_NO_LINK : BS_OK); return bs; } // WAY less branching and resource management // no real need for the dreaded goto for maintainability bs_errno = BS_FILE_IO; block_store_destroy(bs, BS_NO_FLUSH); close(fd); return NULL; } close(fd); } } bs_errno = BS_FILE_ACCESS; return NULL; } bs_errno = BS_PARAM; return NULL; }