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

@ -310,7 +310,6 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts,
target->ms_block = 0; target->ms_block = 0;
target->input_charset = strdup("UTF-8"); //TODO target->input_charset = strdup("UTF-8"); //TODO
/* /*
* 2. Based on those options, create needed writers: iso, joliet... * 2. Based on those options, create needed writers: iso, joliet...
* Each writer inits its structures and stores needed info into * Each writer inits its structures and stores needed info into
@ -338,6 +337,11 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts,
/* Volume Descriptor Set Terminator */ /* Volume Descriptor Set Terminator */
target->curblock++; target->curblock++;
/* create writer for file contents */
ret = iso_file_src_writer_create(target);
if (ret < 0) {
goto target_cleanup;
}
/* /*
* 3. * 3.

View File

@ -10,8 +10,11 @@
#include "error.h" #include "error.h"
#include "node.h" #include "node.h"
#include "util.h" #include "util.h"
#include "writer.h"
#include "messages.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
int iso_file_src_cmp(const void *n1, const void *n2) 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); 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;
}

View File

@ -52,46 +52,11 @@ void iso_file_src_free(void *node);
*/ */
off_t iso_file_src_get_size(IsoFileSrc *file); off_t iso_file_src_get_size(IsoFileSrc *file);
// TODO not implemented
int iso_file_src_open(IsoFileSrc *file);
// TODO not implemented
int iso_file_src_close(IsoFileSrc *file);
/** /**
* TODO define propertly this comment * Create a Writer for file contents.
* TODO not implemented
* *
* Read a block (2048 bytes) from the IsoFileSrc. * It takes care of written the files in the correct order.
*
* This function should always read the full 2048 bytes, blocking if
* needed. When it reaches EOF, the buf is filled with 0's, if needed.
* Note that the EOF is not reported in that call, but in the next call.
* I.e., when the EOF is reported you can be sure that the function
* has not written anything to the buffer. If the file size is a multiple
* of block size, i.e N*2048, the read_block reports the EOF just when
* reading the N+1 block.
*
* Note that EOF refers to the original size as reported by get_size.
* If the underlying source size has changed, this function should take
* care of this, truncating the file, or filling the buffer with 0s. I.e.
* this function return 0 (EOF) only when get_size() bytes have been
* readed.
*
* On an I/O error, or a file smaller than the expected size, this
* function returns a [specific error code], and the buffer is filled
* with 0s. Subsequent calls will still return an error code and fill
* buffer with 0's, until EOF (as defined above) is reached, and then
* the function will return 0.
*
* Note that if the current size is larger than expected, you don't get
* any error on reading.
*
* @param buf
* Buffer where data fill be copied, with at least 2048 bytes.
* @return
* 1 sucess, 0 EOF, < 0 error (buf is filled with 0's)
*/ */
int iso_file_src_read_block(IsoFileSrc *file, void *buf); int iso_file_src_writer_create(Ecma119Image *target);
#endif /*LIBISO_FILESRC_H_*/ #endif /*LIBISO_FILESRC_H_*/

View File

@ -384,6 +384,7 @@ Range "vreixo" : 0x00030000 to 0x0003ffff
Image creation: Image creation:
0x00030100 (NOTE,MEDIUM) = File cannot be added to image (ignored) 0x00030100 (NOTE,MEDIUM) = File cannot be added to image (ignored)
0x00030101 (NOTE,MEDIUM) = File cannot be writing to image (ignored)
General: General:
0x00031001 (SORRY,HIGH) = Cannot read file (ignored) 0x00031001 (SORRY,HIGH) = Cannot read file (ignored)

View File

@ -17,6 +17,8 @@
/** File cannot be added to image (ignored) */ /** File cannot be added to image (ignored) */
#define LIBISO_FILE_IGNORED 0x00030100 #define LIBISO_FILE_IGNORED 0x00030100
/** File cannot be writing to image (ignored) */
#define LIBISO_FILE_CANT_WRITE 0x00030101
/** Can't read file (ignored) */ /** Can't read file (ignored) */
#define LIBISO_CANT_READ_FILE 0x00031001 #define LIBISO_CANT_READ_FILE 0x00031001

View File

@ -18,16 +18,6 @@
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
int div_up(int n, int div)
{
return (n + div - 1) / div;
}
int round_up(int n, int mul)
{
return div_up(n, mul) * mul;
}
int int_pow(int base, int power) int int_pow(int base, int power)
{ {
int result = 1; int result = 1;

View File

@ -20,9 +20,15 @@
# define MIN(a, b) (((a) < (b)) ? (a) : (b)) # define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif #endif
extern inline int div_up(int n, int div); extern inline int div_up(unsigned int n, unsigned int div)
{
return (n + div - 1) / div;
}
extern inline int round_up(int n, int mul); extern inline int round_up(unsigned int n, unsigned int mul)
{
return div_up(n, mul) * mul;
}
int int_pow(int base, int power); int int_pow(int base, int power);