#include #include #include #include #include #include #include #include static const bh_io_table_t bh_file_table = { (int (*)(struct bh_io_s *, int)) bh_file_open_base, (void (*)(struct bh_io_s *)) bh_file_close_base, (int (*)(struct bh_io_s *)) bh_file_is_open_base, (size_t (*)(struct bh_io_s *, char *, size_t)) bh_file_read_base, (size_t (*)(struct bh_io_s *, const char *, size_t)) bh_file_write_base, (void (*)(struct bh_io_s *)) bh_file_flush_base, (int (*)(struct bh_io_s *, bh_off_t, int)) bh_file_seek_base, (bh_off_t (*)(struct bh_io_s *)) bh_file_size_base, (bh_off_t (*)(struct bh_io_s *)) bh_file_tell_base, (bh_off_t (*)(struct bh_io_s *)) bh_file_available_base, (void (*)(struct bh_io_s *)) bh_file_clear_base, (void (*)(struct bh_io_s *)) bh_file_destroy_base }; bh_file_t *bh_file_new(const char *path) { bh_file_t *result; /* Allocate and initialize file structure */ result = malloc(sizeof(*result)); if (result && bh_file_init(result, path)) { /* Something went wrong - free allocated memory */ free(result); result = NULL; } return result; } int bh_file_init(bh_file_t *file, const char *path) { /* Ensure that path is not empty */ if (!path) return BH_INVALID; /* Initialize underlying io object */ bh_io_init(&file->base, &bh_file_table, 1); /* Initialize file io object */ file->handle = -1; file->mode = 0; file->path = strdup(path); return BH_OK; } void bh_file_destroy_base(bh_file_t *file) { /* Close the file */ bh_file_close(file); free(file->path); bh_io_destroy_base(&file->base); } int bh_file_open_base(bh_file_t *file, int mode) { /* Set open mode for 0666 permisions */ mode_t open_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); int open_flags = 0; /* Check if file is already opened */ if (file->handle != -1) return BH_OK; /* Determine read/write flags */ if (mode & BH_IO_READ_WRITE) open_flags |= O_RDWR; else if (mode & BH_IO_READ) open_flags |= O_RDONLY; else if (mode & BH_IO_WRITE) open_flags |= O_WRONLY; else return BH_INVALID; /* Determine open mode */ switch (mode & (BH_IO_CREATE | BH_IO_OPEN)) { default: case 0: open_flags |= O_CREAT; break; case BH_IO_CREATE: open_flags |= O_CREAT | O_EXCL; break; case BH_IO_OPEN: /* Do nothing */ break; } if (mode & BH_IO_APPEND) open_flags |= O_APPEND; if (mode & BH_IO_TRUNCATE) open_flags |= O_TRUNC; /* Open file */ file->handle = open(file->path, open_flags, open_mode); /* Check for errors */ if (file->handle == -1) { switch (errno) { case EEXIST: return BH_FOUND; case ENOENT: return BH_NOT_FOUND; default: return BH_ERROR; } } return BH_OK; } void bh_file_close_base(bh_file_t *file) { /* Close file if it's open */ if (file->handle != -1) close(file->handle); /* Set handle to invalid value */ file->handle = -1; } int bh_file_is_open_base(bh_file_t *file) { /* If handle is not -1 - then file is open */ return file->handle != -1; } size_t bh_file_read_base(bh_file_t *file, char *data, size_t size) { ssize_t readed; /* Check if file is open */ if (file->handle == -1) { /* Error occured - set error bit */ file->base.flags |= BH_IO_ERROR; return 0; } /* Read data from file */ readed = read(file->handle, data, size); if (readed < 0) { /* Error occured - set error bit */ file->base.flags |= BH_IO_ERROR; return 0; } /* Check for end of file */ if (!readed) file->base.flags |= BH_IO_EOF; else file->base.flags &= ~BH_IO_EOF; /* Return number of readed bytes */ return readed; } size_t bh_file_write_base(bh_file_t *file, const char *data, size_t size) { ssize_t written; /* Check if file is open */ if (file->handle == -1) { /* Error occured - set error bit */ file->base.flags |= BH_IO_ERROR; return 0; } /* Write data to file */ written = write(file->handle, data, size); if (written < 0) { /* Error occured - set error bit */ file->base.flags |= BH_IO_ERROR; return 0; } /* Check for end of file */ if (!written) file->base.flags |= BH_IO_EOF; else file->base.flags &= ~BH_IO_EOF; /* Return number of written bytes */ return written; } void bh_file_flush_base(bh_file_t *file) { /* Check if file is open */ if (file->handle == -1) return; /* Signal OS to flush data from the internal buffers */ fsync(file->handle); } int bh_file_seek_base(bh_file_t *file, bh_off_t pos, int dir) { /* Check if file is open */ if (file->handle == -1) return BH_ERROR; /* Seek to desired location */ if (lseek(file->handle, pos, dir) == -1) return BH_ERROR; return BH_OK; } bh_off_t bh_file_size_base(bh_file_t *file) { struct stat sb; /* Check if file is open */ if (file->handle == -1) return -1; /* Get file size from the OS */ if (fstat(file->handle, &sb)) return -1; return sb.st_size; } bh_off_t bh_file_tell_base(bh_file_t *file) { /* Check if file is open */ if (file->handle == -1) return -1; /* Get current file position */ return lseek(file->handle, 0, SEEK_CUR); } bh_off_t bh_file_available_base(bh_file_t *file) { /* Get available bytes for reading */ return bh_file_size_base(file) - bh_file_tell_base(file); } void bh_file_clear_base(bh_file_t *file) { file->base.flags &= ~BH_IO_ERROR; }