Implement Writer for file contents.

Some aspects, such as better reporting of file bigger or smaller than 
expected is needed, but all situations are handled propertly.
This commit is contained in:
Vreixo Formoso
2007-12-20 22:17:18 +01:00
parent 449ed65fe9
commit 2f383215ff
7 changed files with 238 additions and 51 deletions

View File

@@ -10,8 +10,11 @@
#include "error.h"
#include "node.h"
#include "util.h"
#include "writer.h"
#include "messages.h"
#include <stdlib.h>
#include <string.h>
int iso_file_src_cmp(const void *n1, const void *n2)
{
@@ -101,3 +104,219 @@ off_t iso_file_src_get_size(IsoFileSrc *file)
{
return iso_stream_get_size(file->stream);
}
static int
cmp_by_weight(const void *f1, const void *f2)
{
IsoFileSrc *f = *((IsoFileSrc**)f1);
IsoFileSrc *g = *((IsoFileSrc**)f2);
/* higher weighted first */
return g->sort_weight - f->sort_weight;
}
static
int filesrc_writer_compute_data_blocks(IsoImageWriter *writer)
{
size_t i, size;
Ecma119Image *t;
IsoFileSrc **filelist;
if (writer == NULL) {
return ISO_MEM_ERROR;
}
t = writer->target;
/* store the filesrcs in a array */
filelist = (IsoFileSrc**)iso_rbtree_to_array(t->files);
if (filelist == NULL) {
return ISO_MEM_ERROR;
}
size = iso_rbtree_get_size(t->files);
/* sort files by weight, if needed */
if (t->sort_files) {
qsort(t->files, size, sizeof(void*), cmp_by_weight);
}
/* fill block value */
for (i = 0; i < size; ++i) {
IsoFileSrc *file = filelist[i];
file->block = t->curblock;
t->curblock += div_up(iso_file_src_get_size(file), BLOCK_SIZE);
}
/* the list is only needed by this writer, store locally */
writer->data = filelist;
return ISO_SUCCESS;
}
static
int filesrc_writer_write_vol_desc(IsoImageWriter *writer)
{
/* nothing needed */
return ISO_SUCCESS;
}
/* open a file, i.e., its Stream */
static inline
int filesrc_open(IsoFileSrc *file)
{
return iso_stream_open(file->stream);
}
static inline
int filesrc_close(IsoFileSrc *file)
{
return iso_stream_close(file->stream);
}
/**
* @return
* 1 ok, 0 EOF, < 0 error
*/
static
int filesrc_read(IsoFileSrc *file, char *buf, size_t count)
{
size_t bytes = 0;
/* loop to ensure the full buffer is filled */
do {
ssize_t result;
result = iso_stream_read(file->stream, buf + bytes, count - bytes);
if (result < 0) {
/* fill buffer with 0s and return */
memset(buf + bytes, 0, count - bytes);
return result;
}
if (result == 0)
break;
bytes += result;
} while (bytes < count);
if (bytes < count) {
/* eof */
memset(buf + bytes, 0, count - bytes);
return 0;
} else {
return 1;
}
}
static
int filesrc_writer_write_data(IsoImageWriter *writer)
{
int res;
size_t i, b, nfiles;
Ecma119Image *t;
IsoFileSrc **filelist;
char buffer[BLOCK_SIZE];
if (writer == NULL) {
return ISO_MEM_ERROR;
}
t = writer->target;
filelist = writer->data;
nfiles = iso_rbtree_get_size(t->files);
for (i = 0; i < nfiles; ++i) {
IsoFileSrc *file = filelist[i];
/*
* TODO WARNING
* when we allow files greater than 4GB, current div_up implementation
* can overflow!!
*/
uint32_t nblocks = div_up(iso_file_src_get_size(file), BLOCK_SIZE);
res = filesrc_open(file);
if (res < 0) {
/*
* UPS, very ugly error, the best we can do is just to write
* 0's to image
*/
// TODO Stream needs a get_path function
iso_msg_sorry(t->image, LIBISO_FILE_CANT_WRITE,
"File XXX can't be openned. Filling with 0s.");
memset(buffer, 0, BLOCK_SIZE);
for (b = 0; b < nblocks; ++b) {
res = iso_write(t, buffer, BLOCK_SIZE);
if (res < 0) {
/* ko, writer error, we need to go out! */
return res;
}
}
continue;
}
/* write file contents to image */
for (b = 0; b < nblocks; ++b) {
int wres;
res = filesrc_read(file, buffer, BLOCK_SIZE);
wres = iso_write(t, buffer, BLOCK_SIZE);
if (wres < 0) {
/* ko, writer error, we need to go out! */
return wres;
}
}
if (b < nblocks) {
/* premature end of file, due to error or eof */
if (res < 0) {
/* error */
iso_msg_sorry(t->image, LIBISO_FILE_CANT_WRITE,
"Read error in file XXXXX.");
} else {
/* eof */
iso_msg_sorry(t->image, LIBISO_FILE_CANT_WRITE,
"Premature end of file XXXXX.");
}
/* fill with 0s */
iso_msg_sorry(t->image, LIBISO_FILE_CANT_WRITE, "Filling with 0");
memset(buffer, 0, BLOCK_SIZE);
while (b++ < nblocks) {
res = iso_write(t, buffer, BLOCK_SIZE);
if (res < 0) {
/* ko, writer error, we need to go out! */
return res;
}
}
}
filesrc_close(file);
}
return ISO_SUCCESS;
}
static
int filesrc_writer_free_data(IsoImageWriter *writer)
{
/* free the list of files (contents are free together with the tree) */
free(writer->data);
return ISO_SUCCESS;
}
int iso_file_src_writer_create(Ecma119Image *target)
{
IsoImageWriter *writer;
writer = malloc(sizeof(IsoImageWriter));
if (writer == NULL) {
return ISO_MEM_ERROR;
}
writer->compute_data_blocks = filesrc_writer_compute_data_blocks;
writer->write_vol_desc = filesrc_writer_write_vol_desc;
writer->write_data = filesrc_writer_write_data;
writer->free_data = filesrc_writer_free_data;
writer->data = NULL;
writer->target = target;
/* add this writer to image */
target->writers[target->nwriters++] = writer;
return ISO_SUCCESS;
}