267 lines
6.1 KiB
C
267 lines
6.1 KiB
C
#include <bh/internal/file.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
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
|
|
};
|
|
|
|
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;
|
|
}
|
|
|
|
void bh_file_free(bh_file_t *file)
|
|
{
|
|
bh_file_destroy(file);
|
|
free(file);
|
|
}
|
|
|
|
int bh_file_init(bh_file_t *file,
|
|
const char *path)
|
|
{
|
|
/* Ensure that path is not empty */
|
|
if (!path)
|
|
return BH_INVALID;
|
|
|
|
/* Initialize base io object */
|
|
bh_io_init(&file->base, &bh_file_table);
|
|
|
|
/* Initialize file io object */
|
|
file->handle = -1;
|
|
file->mode = 0;
|
|
file->path = strdup(path);
|
|
|
|
return BH_OK;
|
|
}
|
|
|
|
void bh_file_destroy(bh_file_t *file)
|
|
{
|
|
/* Close the file */
|
|
bh_file_close(file);
|
|
free(file->path);
|
|
}
|
|
|
|
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;
|
|
}
|