/* * Implementation of iso_file_src for: * * a) read from local filesystem files * b) read from previous session / image files */ #include #include #include #include #include #include #include #include #include #include "file_src.h" #include "messages.h" #include "libisofs.h" #include "util.h" #define BLOCK_SIZE 2048 void iso_file_src_free(struct iso_file_src *src) { src->free_data(src); free(src); } /* * ========================================================================== * A) FILE SRC FOR LOCAL FILESYSTEM FILES * ========================================================================== */ 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) { struct local_file_data *data; data = (struct local_file_data*) src->data; free(data->path); free(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; } /* * ========================================================================== * B) FILE SRC FOR PREVIOUS IMAGE FILES * ========================================================================== */ struct prev_img_file_data { int block; /* block where image begins */ off_t size; /* file size */ int nblocks; /* file size in blocks */ int current; /* last block read from file */ int error; struct data_source *src; /* source for reading from previous image */ }; static int pi_open(struct iso_file_src *src) { struct prev_img_file_data *data; assert(src); data = (struct prev_img_file_data*) src->data; data->current = data->block; data->error = 0; return 1; } static void pi_close(struct iso_file_src *src) { /* nothing needed */ return; } static int pi_read_block(struct iso_file_src *src, unsigned char *buffer) { int res; struct prev_img_file_data *data; assert(src); assert(buffer); data = (struct prev_img_file_data*) src->data; if (data->current >= data->block + data->nblocks) { return 0; } if (data->error) { memset(buffer, 0, BLOCK_SIZE); data->current++; return -2; } res = data->src->read_block(data->src, data->current++, buffer); if (res < 0) { iso_msg_sorry(LIBISO_CANT_READ_IMG, "Problem reading file from previous image"); /* fill buffer with 0s and return */ memset(buffer, 0, BLOCK_SIZE); return -1; } if (data->current >= data->block + data->nblocks) { return 0; } else { return 1; } } static off_t pi_get_size(struct iso_file_src *src) { struct prev_img_file_data *data; assert(src); data = (struct prev_img_file_data*) src->data; return data->size; } static void pi_free_data(struct iso_file_src *src) { free(src->data); } struct iso_file_src* iso_file_src_from_prev_img(struct data_source* data_src, int block, off_t size) { struct iso_file_src *src; struct prev_img_file_data *data; data = malloc(sizeof(struct prev_img_file_data)); if (!data) return NULL; src = malloc(sizeof(struct iso_file_src)); if (!src) { free(data); return NULL; } data->block = block; data->size = size; data->nblocks = div_up(size, BLOCK_SIZE); data->src = data_src; src->open = pi_open; src->close = pi_close; src->read_block = pi_read_block; src->get_size = pi_get_size; src->free_data = pi_free_data; src->data = data; return src; }