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.
release-1.5.4.branch
Vreixo Formoso 16 years ago
parent 449ed65fe9
commit 2f383215ff

@ -310,7 +310,6 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts,
target->ms_block = 0;
target->input_charset = strdup("UTF-8"); //TODO
/*
* 2. Based on those options, create needed writers: iso, joliet...
* 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 */
target->curblock++;
/* create writer for file contents */
ret = iso_file_src_writer_create(target);
if (ret < 0) {
goto target_cleanup;
}
/*
* 3.

@ -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;
}

@ -52,46 +52,11 @@ void iso_file_src_free(void *node);
*/
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
* TODO not implemented
*
* Read a block (2048 bytes) from the IsoFileSrc.
*
* 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.
* Create a Writer for file contents.
*
* 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)
* It takes care of written the files in the correct order.
*/
int iso_file_src_read_block(IsoFileSrc *file, void *buf);
int iso_file_src_writer_create(Ecma119Image *target);
#endif /*LIBISO_FILESRC_H_*/

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

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

@ -18,16 +18,6 @@
#include <ctype.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 result = 1;

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

Loading…
Cancel
Save