Marked libisofs SVN copy as outdated (use bzr on lp)
This commit is contained in:
387
libisofs_outdated/branches/thomas/libisofs/filesrc.c
Normal file
387
libisofs_outdated/branches/thomas/libisofs/filesrc.c
Normal file
@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Vreixo Formoso
|
||||
*
|
||||
* This file is part of the libisofs project; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation. See COPYING file for details.
|
||||
*/
|
||||
|
||||
#include "filesrc.h"
|
||||
#include "node.h"
|
||||
#include "util.h"
|
||||
#include "writer.h"
|
||||
#include "messages.h"
|
||||
#include "image.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
int iso_file_src_cmp(const void *n1, const void *n2)
|
||||
{
|
||||
const IsoFileSrc *f1, *f2;
|
||||
unsigned int fs_id1, fs_id2;
|
||||
dev_t dev_id1, dev_id2;
|
||||
ino_t ino_id1, ino_id2;
|
||||
|
||||
f1 = (const IsoFileSrc *)n1;
|
||||
f2 = (const IsoFileSrc *)n2;
|
||||
|
||||
iso_stream_get_id(f1->stream, &fs_id1, &dev_id1, &ino_id1);
|
||||
iso_stream_get_id(f2->stream, &fs_id2, &dev_id2, &ino_id2);
|
||||
|
||||
if (fs_id1 < fs_id2) {
|
||||
return -1;
|
||||
} else if (fs_id1 > fs_id2) {
|
||||
return 1;
|
||||
} else {
|
||||
/* files belong to the same fs */
|
||||
if (dev_id1 > dev_id2) {
|
||||
return -1;
|
||||
} else if (dev_id1 < dev_id2) {
|
||||
return 1;
|
||||
} else {
|
||||
/* files belong to same device in same fs */
|
||||
return (ino_id1 < ino_id2) ? -1 : (ino_id1 > ino_id2) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
|
||||
{
|
||||
int ret;
|
||||
IsoFileSrc *fsrc;
|
||||
unsigned int fs_id;
|
||||
dev_t dev_id;
|
||||
ino_t ino_id;
|
||||
|
||||
if (img == NULL || file == NULL || src == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
iso_stream_get_id(file->stream, &fs_id, &dev_id, &ino_id);
|
||||
|
||||
fsrc = malloc(sizeof(IsoFileSrc));
|
||||
if (fsrc == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
/* fill key and other atts */
|
||||
fsrc->prev_img = file->msblock ? 1 : 0;
|
||||
fsrc->block = file->msblock;
|
||||
fsrc->sort_weight = file->sort_weight;
|
||||
fsrc->stream = file->stream;
|
||||
|
||||
/* insert the filesrc in the tree */
|
||||
ret = iso_rbtree_insert(img->files, fsrc, (void**)src);
|
||||
if (ret <= 0) {
|
||||
free(fsrc);
|
||||
return ret;
|
||||
}
|
||||
iso_stream_ref(fsrc->stream);
|
||||
return ISO_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a given IsoFileSrc to the given image target.
|
||||
*
|
||||
* The IsoFileSrc will be cached in a tree to prevent the same file for
|
||||
* being written several times to image. If you call again this function
|
||||
* with a node that refers to the same source file, the previously
|
||||
* created one will be returned.
|
||||
*
|
||||
* @param img
|
||||
* The image where this file is to be written
|
||||
* @param new
|
||||
* The IsoFileSrc to add
|
||||
* @param src
|
||||
* Will be filled with a pointer to the IsoFileSrc really present in
|
||||
* the tree. It could be different than new if the same file already
|
||||
* exists in the tree.
|
||||
* @return
|
||||
* 1 on success, 0 if file already exists on tree, < 0 error
|
||||
*/
|
||||
int iso_file_src_add(Ecma119Image *img, IsoFileSrc *new, IsoFileSrc **src)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (img == NULL || new == NULL || src == NULL) {
|
||||
return ISO_NULL_POINTER;
|
||||
}
|
||||
|
||||
/* insert the filesrc in the tree */
|
||||
ret = iso_rbtree_insert(img->files, new, (void**)src);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iso_file_src_free(void *node)
|
||||
{
|
||||
iso_stream_unref(((IsoFileSrc*)node)->stream);
|
||||
free(node);
|
||||
}
|
||||
|
||||
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 is_ms_file(void *arg)
|
||||
{
|
||||
IsoFileSrc *f = (IsoFileSrc *)arg;
|
||||
return f->prev_img ? 0 : 1;
|
||||
}
|
||||
|
||||
static
|
||||
int filesrc_writer_compute_data_blocks(IsoImageWriter *writer)
|
||||
{
|
||||
size_t i, size;
|
||||
Ecma119Image *t;
|
||||
IsoFileSrc **filelist;
|
||||
int (*inc_item)(void *);
|
||||
|
||||
if (writer == NULL) {
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
|
||||
t = writer->target;
|
||||
|
||||
/* on appendable images, ms files shouldn't be included */
|
||||
if (t->appendable) {
|
||||
inc_item = is_ms_file;
|
||||
} else {
|
||||
inc_item = NULL;
|
||||
}
|
||||
|
||||
/* store the filesrcs in a array */
|
||||
filelist = (IsoFileSrc**)iso_rbtree_to_array(t->files, inc_item, &size);
|
||||
if (filelist == NULL) {
|
||||
return ISO_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
/* sort files by weight, if needed */
|
||||
if (t->sort_files) {
|
||||
qsort(filelist, 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;
|
||||
Ecma119Image *t;
|
||||
IsoFileSrc *file;
|
||||
IsoFileSrc **filelist;
|
||||
char name[PATH_MAX];
|
||||
char buffer[BLOCK_SIZE];
|
||||
|
||||
if (writer == NULL) {
|
||||
return ISO_ASSERT_FAILURE;
|
||||
}
|
||||
|
||||
t = writer->target;
|
||||
filelist = writer->data;
|
||||
|
||||
iso_msg_debug(t->image->id, "Writing Files...");
|
||||
|
||||
i = 0;
|
||||
while ((file = filelist[i++]) != NULL) {
|
||||
|
||||
/*
|
||||
* 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);
|
||||
iso_stream_get_file_name(file->stream, name);
|
||||
if (res < 0) {
|
||||
/*
|
||||
* UPS, very ugly error, the best we can do is just to write
|
||||
* 0's to image
|
||||
*/
|
||||
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
|
||||
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res,
|
||||
"File \"%s\" can't be opened. Filling with 0s.", name);
|
||||
if (res < 0) {
|
||||
return res; /* aborted due to error severity */
|
||||
}
|
||||
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;
|
||||
} else if (res > 1) {
|
||||
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
|
||||
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
|
||||
"Size of file \"%s\" has changed. It will be %s", name,
|
||||
(res == 2 ? "truncated" : "padded with 0's"));
|
||||
if (res < 0) {
|
||||
filesrc_close(file);
|
||||
return res; /* aborted due to error severity */
|
||||
}
|
||||
}
|
||||
#ifdef LIBISOFS_VERBOSE_DEBUG
|
||||
else {
|
||||
iso_msg_debug(t->image->id, "Writing file %s", name);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* write file contents to image */
|
||||
for (b = 0; b < nblocks; ++b) {
|
||||
int wres;
|
||||
res = filesrc_read(file, buffer, BLOCK_SIZE);
|
||||
if (res < 0) {
|
||||
/* read error */
|
||||
break;
|
||||
}
|
||||
wres = iso_write(t, buffer, BLOCK_SIZE);
|
||||
if (wres < 0) {
|
||||
/* ko, writer error, we need to go out! */
|
||||
filesrc_close(file);
|
||||
return wres;
|
||||
}
|
||||
}
|
||||
|
||||
filesrc_close(file);
|
||||
|
||||
if (b < nblocks) {
|
||||
/* premature end of file, due to error or eof */
|
||||
iso_report_errfile(name, ISO_FILE_CANT_WRITE, 0, 0);
|
||||
if (res < 0) {
|
||||
/* error */
|
||||
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, res,
|
||||
"Read error in file %s.", name);
|
||||
} else {
|
||||
/* eof */
|
||||
res = iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
|
||||
"Premature end of file %s.", name);
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
return res; /* aborted due error severity */
|
||||
}
|
||||
|
||||
/* fill with 0s */
|
||||
iso_msg_submit(t->image->id, ISO_FILE_CANT_WRITE, 0,
|
||||
"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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_ASSERT_FAILURE;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
Reference in New Issue
Block a user