diff --git a/libisofs/trunk/Makefile.am b/libisofs/trunk/Makefile.am index e079dc6a..267b52ae 100644 --- a/libisofs/trunk/Makefile.am +++ b/libisofs/trunk/Makefile.am @@ -32,6 +32,8 @@ libisofs_libisofs_la_SOURCES = \ libisofs/hash.c \ libisofs/file.h \ libisofs/file.c \ + libisofs/file_src.h \ + libisofs/file_src.c \ libisofs/eltorito.h \ libisofs/eltorito.c \ libisofs/data_source.c \ diff --git a/libisofs/trunk/libisofs/file_src.c b/libisofs/trunk/libisofs/file_src.c new file mode 100644 index 00000000..f7ed4d86 --- /dev/null +++ b/libisofs/trunk/libisofs/file_src.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "file_src.h" +#include "messages.h" + +#define BLOCK_SIZE 2048 + +struct local_file_data { + int fd; /* the file descriptor, once the file is opened */ + off_t size; /* file size */ + off_t bytes_read; /* bytes already read from file */ + int error; + char *path; /* path of the file on local filesystem */ +}; + +static +int lf_open(struct iso_file_src *src) +{ + struct local_file_data *data; + assert(src); + + data = (struct local_file_data*) src->data; + + assert(data->fd == -1); + + data->fd = open(data->path, O_RDONLY); + data->bytes_read = (off_t) 0; + data->error = 0; + return (data->fd != -1 ? 1 : 0); +} + +static +void lf_close(struct iso_file_src *src) +{ + struct local_file_data *data; + assert(src); + + data = (struct local_file_data*) src->data; + assert(data->fd != -1); + + close(data->fd); + data->fd = -1; +} + +static +int lf_read_block(struct iso_file_src *src, unsigned char *buffer) +{ + ssize_t bytes; + struct local_file_data *data; + assert(src); + assert(buffer); + + data = (struct local_file_data*) src->data; + assert(data->fd != -1); + + if (data->bytes_read >= data->size) { + return 0; + } + + if (data->error) { + memset(buffer, 0, BLOCK_SIZE); + data->bytes_read += BLOCK_SIZE; + return -2; + } + + bytes = 0; + + do { + ssize_t result; + result = read(data->fd, buffer + bytes, BLOCK_SIZE - bytes); + if (result < 0) { + char msg[PATH_MAX + 32]; + sprintf(msg, "Problem reading from %s", data->path); + iso_msg_sorry(LIBISO_CANT_READ_FILE, msg); + + /* fill buffer with 0s and return */ + memset(buffer + bytes, 0, BLOCK_SIZE - bytes); + data->bytes_read += BLOCK_SIZE; + return -1; + } + if (!result) + break; + bytes += result; + } while (bytes < BLOCK_SIZE); + + if (bytes < BLOCK_SIZE) { + /* eof */ + memset(buffer + bytes, 0, BLOCK_SIZE - bytes); + } + + data->bytes_read += (off_t) bytes; + if (data->bytes_read >= data->size) { + return 0; + } else { + return 1; + } +} + +static +off_t lf_get_size(struct iso_file_src *src) +{ + struct local_file_data *data; + assert(src); + + data = (struct local_file_data*) src->data; + return data->size; +} + +static +void lf_free_data(struct iso_file_src *src) +{ + free(src->data); +} + +struct iso_file_src* +iso_file_src_from_path(const char *path) +{ + struct stat info; + struct iso_file_src *src; + struct local_file_data *data; + + assert(path); + + if (lstat(path, &info) < 0) { + iso_msg_fatal(LIBISO_FILE_DOESNT_EXIST, "File doesn't exist"); + return NULL; + } + if (access(path, R_OK) < 0) { + iso_msg_fatal(LIBISO_FILE_NO_READ_ACCESS, "No read access"); + return NULL; + } + + data = malloc(sizeof(struct local_file_data)); + if (!data) + return NULL; + + src = malloc(sizeof(struct iso_file_src)); + if (!src) { + free(data); + return NULL; + } + + data->fd = -1; + data->path = strdup(path); + data->size = info.st_size; + + src->open = lf_open; + src->close = lf_close; + src->read_block = lf_read_block; + src->get_size = lf_get_size; + src->free_data = lf_free_data; + + src->data = data; + return src; +} diff --git a/libisofs/trunk/libisofs/file_src.h b/libisofs/trunk/libisofs/file_src.h new file mode 100644 index 00000000..f0b3abfa --- /dev/null +++ b/libisofs/trunk/libisofs/file_src.h @@ -0,0 +1,82 @@ + +/* + * Class for reading data from files, with base implementations + * for reading local filesystem files and previous session files. + * + * TODO this is kept private for now, it can be useful to make that + * public later. + */ + +#ifndef FILE_SRC_H_ +#define FILE_SRC_H_ + +#include + +struct iso_file_src { + + /** + * Opens the file. + * This should be called before any call to read_block(). + * @return 1 on success, <= 0 on error + */ + int (*open)(struct iso_file_src *src); + + /** + * Close the file. + * This should be called when the iso_file_src is no more needed. + */ + void (*close)(struct iso_file_src *src); + + /** + * Read data from the file in 2048 bytes chunks. + * + * A pointer to the contents of the file will be updated, in such a way + * that each time this function is called, new data is read to the buffer. + * It behaves in the same way as usual read(2) call this way. + * + * This always reads 2048 bytes, unless an EOF is found, or we reach the + * size previously returned by get_size(). In this case, the buffer is + * completed with 0s. + * + * @param buffer Buffer where the data will be written. Its size must + * be at least 2048 bytes. + * @return + * 1 if file contains more data. If we reach EOF before the expected + * size, this keeps returning 1, and next blocks are filled with 0s. + * 0 when we reach the expected size, that in normal usage is also EOF + * on file. + * < 0 on error. If such case, next calls to read_block will keep + * returning < 0 until we reach the expected size, filling blocks with + * 0s. + */ + int (*read_block)(struct iso_file_src *src, unsigned char *buffer); + + /** + * Get the size in bytes of the file. + * + * This is set when the iso_file_src is created, and should not change. If + * the actual file size changes, it will be truncated or padding with 0s + * when the block is read + */ + off_t (*get_size)(struct iso_file_src *); + + /** Clean up the source specific data */ + void (*free_data)(struct iso_file_src *); + + /** Source specific data */ + void *data; + +}; + +/** + * Get a iso_file_src() for reading from a local filesystem file. + */ +struct iso_file_src* iso_file_src_from_path(const char *path); + +/** + * close and free a iso_file_src + */ +void iso_file_src_free(struct iso_file_src *src); + + +#endif /*FILE_SRC_H_*/ diff --git a/libisofs/trunk/libisofs/libiso_msgs.h b/libisofs/trunk/libisofs/libiso_msgs.h index 9f02ea6d..029f3cd3 100644 --- a/libisofs/trunk/libisofs/libiso_msgs.h +++ b/libisofs/trunk/libisofs/libiso_msgs.h @@ -385,6 +385,8 @@ Range "vreixo" : 0x00030000 to 0x0003ffff General: 0x00031001 (SORRY,HIGH) = Can't read file (ignored) 0x00031002 (FATAL,HIGH) = Can't read file (operation canceled) + 0x00031003 (FATAL,HIGH) = File doesn't exist + 0x00031004 (FATAL,HIGH) = Read access denied Image reading: 0x00031000 (FATAL,HIGH) = Unsupported ISO-9660 image diff --git a/libisofs/trunk/libisofs/messages.h b/libisofs/trunk/libisofs/messages.h index 4668fded..2eb7d5cf 100644 --- a/libisofs/trunk/libisofs/messages.h +++ b/libisofs/trunk/libisofs/messages.h @@ -11,6 +11,10 @@ #define LIBISO_CANT_READ_FILE 0x00031001 /** Can't read file (operation canceled) */ #define LIBISO_FILE_READ_ERROR 0x00031002 +/** File doesn't exist */ +#define LIBISO_FILE_DOESNT_EXIST 0x00031003 +/** Read access denied */ +#define LIBISO_FILE_NO_READ_ACCESS 0x00031004 /** Unsupported image feature */ #define LIBISO_IMG_UNSUPPORTED 0x00031000