Switch to Vreixo development branch 386

This commit is contained in:
Thomas Schmitt 2008-03-09 14:42:15 +00:00
parent b3540fafb6
commit 0c8ae84e59
9 changed files with 588 additions and 18 deletions

View File

@ -53,11 +53,12 @@ int default_create_file(IsoNodeBuilder *builder, IsoImage *image,
return ret; return ret;
} }
/* take a ref to the src, as stream has taken our ref */
iso_file_source_ref(src);
name = iso_file_source_get_name(src); name = iso_file_source_get_name(src);
ret = iso_node_new_file(name, stream, &node); ret = iso_node_new_file(name, stream, &node);
if (ret < 0) { if (ret < 0) {
/* the stream has taken our ref to src, so we need to add one */
iso_file_source_ref(src);
iso_stream_unref(stream); iso_stream_unref(stream);
free(name); free(name);
return ret; return ret;

View File

@ -34,8 +34,7 @@ struct Iso_Node_Builder
* In that case, if the implementation can't do the conversion, it * In that case, if the implementation can't do the conversion, it
* should fail propertly. * should fail propertly.
* *
* On sucess, the ref. to src will be owned by file, so you musn't * Note that the src is never unref, so you need to free it.
* unref it.
* *
* @return * @return
* 1 on success, < 0 on error * 1 on success, < 0 on error

View File

@ -632,6 +632,60 @@ int ifs_read(IsoFileSource *src, void *buf, size_t count)
return read; return read;
} }
static
off_t ifs_lseek(IsoFileSource *src, off_t offset, int flag)
{
ImageFileSourceData *data;
if (src == NULL) {
return (off_t)ISO_NULL_POINTER;
}
if (offset < (off_t)0) {
return (off_t)ISO_WRONG_ARG_VALUE;
}
data = src->data;
if (!data->opened) {
return (off_t)ISO_FILE_NOT_OPENED;
} else if (data->opened != 1) {
return (off_t)ISO_FILE_IS_DIR;
}
switch (flag) {
case 0: /* SEEK_SET */
data->data.offset = offset;
break;
case 1: /* SEEK_CUR */
data->data.offset += offset;
break;
case 2: /* SEEK_END */
/* do this make sense? */
data->data.offset = data->info.st_size + offset;
break;
default:
return (off_t)ISO_WRONG_ARG_VALUE;
}
if (data->data.offset % BLOCK_SIZE != 0) {
/* we need to buffer the block */
uint32_t block;
_ImageFsData *fsdata;
if (data->data.offset < data->info.st_size) {
int ret;
fsdata = data->fs->data;
block = data->block + (data->data.offset / BLOCK_SIZE);
ret = fsdata->src->read_block(fsdata->src, block,
data->data.content);
if (ret < 0) {
return (off_t)ret;
}
}
}
return data->data.offset;
}
static static
int ifs_readdir(IsoFileSource *src, IsoFileSource **child) int ifs_readdir(IsoFileSource *src, IsoFileSource **child)
{ {
@ -774,7 +828,8 @@ IsoFileSourceIface ifs_class = {
ifs_readdir, ifs_readdir,
ifs_readlink, ifs_readlink,
ifs_get_filesystem, ifs_get_filesystem,
ifs_free ifs_free,
ifs_lseek
}; };
/** /**

View File

@ -304,6 +304,52 @@ int lfs_read(IsoFileSource *src, void *buf, size_t count)
} }
} }
static
off_t lfs_lseek(IsoFileSource *src, off_t offset, int flag)
{
_LocalFsFileSource *data;
int whence;
if (src == NULL) {
return (off_t)ISO_NULL_POINTER;
}
switch (flag) {
case 0:
whence = SEEK_SET; break;
case 1:
whence = SEEK_CUR; break;
case 2:
whence = SEEK_END; break;
default:
return (off_t)ISO_WRONG_ARG_VALUE;
}
data = src->data;
switch (data->openned) {
case 1: /* not dir */
{
off_t ret;
ret = lseek(data->info.fd, offset, whence);
if (ret < 0) {
/* error on read */
switch (errno) {
case ESPIPE:
ret = (off_t)ISO_FILE_ERROR;
break;
default:
ret = (off_t)ISO_ERROR;
break;
}
}
return ret;
}
case 2: /* directory */
return (off_t)ISO_FILE_IS_DIR;
default:
return (off_t)ISO_FILE_NOT_OPENED;
}
}
static static
int lfs_readdir(IsoFileSource *src, IsoFileSource **child) int lfs_readdir(IsoFileSource *src, IsoFileSource **child)
{ {
@ -433,7 +479,8 @@ IsoFileSourceIface lfs_class = {
lfs_readdir, lfs_readdir,
lfs_readlink, lfs_readlink,
lfs_get_filesystem, lfs_get_filesystem,
lfs_free lfs_free,
lfs_lseek
}; };
/** /**

View File

@ -92,6 +92,12 @@ int iso_file_source_read(IsoFileSource *src, void *buf, size_t count)
return src->class->read(src, buf, count); return src->class->read(src, buf, count);
} }
inline
off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag)
{
return src->class->lseek(src, offset, flag);
}
inline inline
int iso_file_source_readdir(IsoFileSource *src, IsoFileSource **child) int iso_file_source_readdir(IsoFileSource *src, IsoFileSource **child)
{ {

View File

@ -623,6 +623,26 @@ struct IsoFileSource_Iface
*/ */
void (*free)(IsoFileSource *src); void (*free)(IsoFileSource *src);
/**
* Repositions the offset of the IsoFileSource (must be opened) to the
* given offset according to the value of flag.
*
* @param offset
* in bytes
* @param flag
* 0 The offset is set to offset bytes (SEEK_SET)
* 1 The offset is set to its current location plus offset bytes
* (SEEK_CUR)
* 2 The offset is set to the size of the file plus offset bytes
* (SEEK_END).
* @return
* Absolute offset posistion on the file, or < 0 on error. Cast the
* returning value to int to get a valid libisofs error.
*
* @since 0.6.4
*/
off_t (*lseek)(IsoFileSource *src, off_t offset, int flag);
/* /*
* TODO #00004 Add a get_mime_type() function. * TODO #00004 Add a get_mime_type() function.
* This can be useful for GUI apps, to choose the icon of the file * This can be useful for GUI apps, to choose the icon of the file
@ -2131,8 +2151,8 @@ void iso_dir_iter_free(IsoDirIter *iter);
* It's like iso_node_take(), but to be used during a directory iteration. * It's like iso_node_take(), but to be used during a directory iteration.
* The node removed will be the last returned by the iteration. * The node removed will be the last returned by the iteration.
* *
* The behavior on two call to this function without calling iso_dir_iter_next * If you call this function twice without calling iso_dir_iter_next between
* between then is undefined, and should never occur. (TODO protect against this?) * them is not allowed and you will get an ISO_ERROR in second call.
* *
* @return * @return
* 1 on succes, < 0 error * 1 on succes, < 0 error
@ -2150,8 +2170,8 @@ int iso_dir_iter_take(IsoDirIter *iter);
* It's like iso_node_remove(), but to be used during a directory iteration. * It's like iso_node_remove(), but to be used during a directory iteration.
* The node removed will be the last returned by the iteration. * The node removed will be the last returned by the iteration.
* *
* The behavior on two call to this function without calling iso_tree_iter_next * If you call this function twice without calling iso_dir_iter_next between
* between then is undefined, and should never occur. (TODO protect against this?) * them is not allowed and you will get an ISO_ERROR in second call.
* *
* @return * @return
* 1 on succes, < 0 error * 1 on succes, < 0 error
@ -2469,10 +2489,36 @@ int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag);
*/ */
int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir); int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir);
/* /**
TODO #00007 expose Stream and this function: * Add a new regular file to the iso tree. Permissions are set to 0444,
int iso_tree_add_new_file(IsoDir *parent, const char *name, stream, file) * owner and hidden atts are taken from parent. You can modify any of them
* later.
*
* @param parent
* the dir where the new file will be created
* @param name
* name for the new file. If a node with same name already exists on
* parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
* @param stream
* IsoStream for the contents of the file. The reference will be taken
* by the newly created file, you will need to take an extra ref to it
* if you need it.
* @param file
* place where to store a pointer to the newly created file. No extra
* ref is addded, so you will need to call iso_node_ref() if you really
* need it. You can pass NULL in this parameter if you don't need the
* pointer
* @return
* number of nodes in parent if success, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if parent, name or dest are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
* ISO_OUT_OF_MEM
*
* @since 0.6.4
*/ */
int iso_tree_add_new_file(IsoDir *parent, const char *name, IsoStream *stream,
IsoFile **file);
/** /**
* Add a new symlink to the directory tree. Permissions are set to 0777, * Add a new symlink to the directory tree. Permissions are set to 0777,
@ -2760,6 +2806,44 @@ int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name,
const char *path, IsoNode **node); const char *path, IsoNode **node);
/**
* Add a new node to the image tree, from an existing file, and with the
* given name, that must not exist on dir. The node will be cut-out to the
* submitted size, and its contents will be read from the given offset. This
* function is thus suitable for adding only a piece of a file to the image.
*
* @param image
* The image
* @param parent
* The directory in the image tree where the node will be added.
* @param name
* The name that the node will have on image.
* @param path
* The path of the file to add in the filesystem. For now only regular
* files and symlinks to regular files are supported.
* @param offset
* Offset on the given file from where to start reading data.
* @param size
* Max size of the file.
* @param node
* place where to store a pointer to the newly added file. No
* extra ref is addded, so you will need to call iso_node_ref() if you
* really need it. You can pass NULL in this parameter if you don't need
* the pointer.
* @return
* number of nodes in parent if success, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if image, parent or path are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
* ISO_OUT_OF_MEM
*
* @since 0.6.4
*/
int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent,
const char *name, const char *path,
off_t offset, off_t size,
IsoNode **node);
/** /**
* Add the contents of a dir to a given directory of the iso tree. * Add the contents of a dir to a given directory of the iso tree.
* *
@ -3190,6 +3274,25 @@ int iso_file_source_close(IsoFileSource *src);
*/ */
int iso_file_source_read(IsoFileSource *src, void *buf, size_t count); int iso_file_source_read(IsoFileSource *src, void *buf, size_t count);
/**
* Repositions the offset of the given IsoFileSource (must be opened) to the
* given offset according to the value of flag.
*
* @param offset
* in bytes
* @param flag
* 0 The offset is set to offset bytes (SEEK_SET)
* 1 The offset is set to its current location plus offset bytes
* (SEEK_CUR)
* 2 The offset is set to the size of the file plus offset bytes
* (SEEK_END).
* @return
* Absolute offset posistion on the file, or < 0 on error. Cast the
* returning value to int to get a valid libisofs error.
* @since 0.6.4
*/
off_t iso_file_source_lseek(IsoFileSource *src, off_t offset, int flag);
/** /**
* Read a directory. * Read a directory.
* *
@ -3575,10 +3678,16 @@ void iso_stream_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
/** /**
* File path break specification constraints and will be ignored * File path break specification constraints and will be ignored
* (HINT,MEDIUM, -141) * (HINT,MEDIUM, -144)
*/ */
#define ISO_FILE_IMGPATH_WRONG 0xC020FF70 #define ISO_FILE_IMGPATH_WRONG 0xC020FF70
/**
* Offset greater than file size (FAILURE,HIGH, -145)
* @since 0.6.4
*/
#define ISO_FILE_OFFSET_TOO_BIG 0xE830FF6A
/** Charset conversion error (FAILURE,HIGH, -256) */ /** Charset conversion error (FAILURE,HIGH, -256) */
#define ISO_CHARSET_CONV_ERROR 0xE830FF00 #define ISO_CHARSET_CONV_ERROR 0xE830FF00

View File

@ -17,6 +17,7 @@
ino_t serial_id = (ino_t)1; ino_t serial_id = (ino_t)1;
ino_t mem_serial_id = (ino_t)1; ino_t mem_serial_id = (ino_t)1;
ino_t cut_out_serial_id = (ino_t)1;
typedef struct typedef struct
{ {
@ -175,7 +176,7 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
return ISO_OUT_OF_MEM; return ISO_OUT_OF_MEM;
} }
data = malloc(sizeof(FSrcStreamData)); data = malloc(sizeof(FSrcStreamData));
if (str == NULL) { if (data == NULL) {
free(str); free(str);
return ISO_OUT_OF_MEM; return ISO_OUT_OF_MEM;
} }
@ -212,6 +213,193 @@ int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream)
return ISO_SUCCESS; return ISO_SUCCESS;
} }
struct cut_out_stream
{
IsoFileSource *src;
/* key for file identification inside filesystem */
dev_t dev_id;
ino_t ino_id;
off_t offset; /**< offset where read begins */
off_t size; /**< size of this file */
off_t pos; /* position on the file for read */
};
static
int cut_out_open(IsoStream *stream)
{
int ret;
struct stat info;
IsoFileSource *src;
struct cut_out_stream *data;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
data = stream->data;
src = data->src;
ret = iso_file_source_stat(data->src, &info);
if (ret < 0) {
return ret;
}
ret = iso_file_source_open(src);
if (ret < 0) {
return ret;
}
{
off_t ret;
if (data->offset > info.st_size) {
/* file is smaller than expected */
ret = iso_file_source_lseek(src, info.st_size, 0);
} else {
ret = iso_file_source_lseek(src, data->offset, 0);
}
if (ret < 0) {
return (int) ret;
}
}
data->pos = 0;
if (data->offset + data->size > info.st_size) {
return 3; /* file smaller than expected */
} else {
return ISO_SUCCESS;
}
}
static
int cut_out_close(IsoStream *stream)
{
IsoFileSource *src;
if (stream == NULL) {
return ISO_NULL_POINTER;
}
src = ((struct cut_out_stream*)stream->data)->src;
return iso_file_source_close(src);
}
static
off_t cut_out_get_size(IsoStream *stream)
{
struct cut_out_stream *data = stream->data;
return data->size;
}
static
int cut_out_read(IsoStream *stream, void *buf, size_t count)
{
struct cut_out_stream *data = stream->data;
count = (size_t)MIN(data->size - data->pos, count);
if (count == 0) {
return 0;
}
return iso_file_source_read(data->src, buf, count);
}
static
int cut_out_is_repeatable(IsoStream *stream)
{
/* reg files are always repeatable */
return 1;
}
static
void cut_out_get_id(IsoStream *stream, unsigned int *fs_id, dev_t *dev_id,
ino_t *ino_id)
{
FSrcStreamData *data;
IsoFilesystem *fs;
data = (FSrcStreamData*)stream->data;
fs = iso_file_source_get_filesystem(data->src);
*fs_id = fs->get_id(fs);
*dev_id = data->dev_id;
*ino_id = data->ino_id;
}
static
void cut_out_free(IsoStream *stream)
{
struct cut_out_stream *data = stream->data;
iso_file_source_unref(data->src);
free(data);
}
IsoStreamIface cut_out_stream_class = {
0,
"cout",
cut_out_open,
cut_out_close,
cut_out_get_size,
cut_out_read,
cut_out_is_repeatable,
cut_out_get_id,
cut_out_free
};
int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size,
IsoStream **stream)
{
int r;
struct stat info;
IsoStream *str;
struct cut_out_stream *data;
if (src == NULL || stream == NULL) {
return ISO_NULL_POINTER;
}
if (size == 0) {
return ISO_WRONG_ARG_VALUE;
}
r = iso_file_source_stat(src, &info);
if (r < 0) {
return r;
}
if (!S_ISREG(info.st_mode)) {
return ISO_WRONG_ARG_VALUE;
}
if (offset > info.st_size) {
return ISO_FILE_OFFSET_TOO_BIG;
}
/* check for read access to contents */
r = iso_file_source_access(src);
if (r < 0) {
return r;
}
str = malloc(sizeof(IsoStream));
if (str == NULL) {
return ISO_OUT_OF_MEM;
}
data = malloc(sizeof(struct cut_out_stream));
if (data == NULL) {
free(str);
return ISO_OUT_OF_MEM;
}
/* take a new ref to IsoFileSource */
data->src = src;
iso_file_source_ref(src);
data->offset = offset;
data->size = MIN(info.st_size - offset, size);
/* get the id numbers */
data->dev_id = (dev_t) 0;
data->ino_id = cut_out_serial_id++;
str->refcount = 1;
str->data = data;
str->class = &cut_out_stream_class;
*stream = str;
return ISO_SUCCESS;
}
typedef struct typedef struct

View File

@ -33,6 +33,16 @@ void iso_stream_get_file_name(IsoStream *stream, char *name);
*/ */
int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream); int iso_file_source_stream_new(IsoFileSource *src, IsoStream **stream);
/**
* Create a new stream to read a chunk of an IsoFileSource..
* The stream will add a ref. to the IsoFileSource.
*
* @return
* 1 sucess, < 0 error
*/
int iso_cut_out_stream_new(IsoFileSource *src, off_t offset, off_t size,
IsoStream **stream);
/** /**
* Create a stream for reading from a arbitrary memory buffer. * Create a stream for reading from a arbitrary memory buffer.
* When the Stream refcount reach 0, the buffer is free(3). * When the Stream refcount reach 0, the buffer is free(3).

View File

@ -256,6 +256,81 @@ int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode,
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER); return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
} }
/**
* Add a new regular file to the iso tree. Permissions are set to 0444,
* owner and hidden atts are taken from parent. You can modify any of them
* later.
*
* @param parent
* the dir where the new file will be created
* @param name
* name for the new file. If a node with same name already exists on
* parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
* @param stream
* IsoStream for the contents of the file
* @param file
* place where to store a pointer to the newly created file. No extra
* ref is addded, so you will need to call iso_node_ref() if you really
* need it. You can pass NULL in this parameter if you don't need the
* pointer
* @return
* number of nodes in parent if success, < 0 otherwise
* Possible errors:
* ISO_NULL_POINTER, if parent, name or dest are NULL
* ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
* ISO_OUT_OF_MEM
*
* @since 0.6.4
*/
int iso_tree_add_new_file(IsoDir *parent, const char *name, IsoStream *stream,
IsoFile **file)
{
int ret;
char *n;
IsoFile *node;
IsoNode **pos;
time_t now;
if (parent == NULL || name == NULL || stream == NULL) {
return ISO_NULL_POINTER;
}
if (file) {
*file = NULL;
}
/* find place where to insert */
if (iso_dir_exists(parent, name, &pos)) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
n = strdup(name);
ret = iso_node_new_file(n, stream, &node);
if (ret < 0) {
free(n);
return ret;
}
/* permissions from parent */
iso_node_set_permissions((IsoNode*)node, 0444);
iso_node_set_uid((IsoNode*)node, parent->node.uid);
iso_node_set_gid((IsoNode*)node, parent->node.gid);
iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
/* current time */
now = time(NULL);
iso_node_set_atime((IsoNode*)node, now);
iso_node_set_ctime((IsoNode*)node, now);
iso_node_set_mtime((IsoNode*)node, now);
if (file) {
*file = node;
}
/* add to dir */
return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
}
/** /**
* Set whether to follow or not symbolic links when added a file from a source * Set whether to follow or not symbolic links when added a file from a source
* to IsoImage. * to IsoImage.
@ -507,13 +582,14 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name,
} }
result = image->builder->create_node(image->builder, image, file, &new); result = image->builder->create_node(image->builder, image, file, &new);
if (result < 0) {
return result;
}
/* free the file */ /* free the file */
iso_file_source_unref(file); iso_file_source_unref(file);
if (result < 0) {
return result;
}
result = iso_node_set_name(new, name); result = iso_node_set_name(new, name);
if (result < 0) { if (result < 0) {
iso_node_unref(new); iso_node_unref(new);
@ -528,6 +604,85 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name,
return iso_dir_insert(parent, new, pos, ISO_REPLACE_NEVER); return iso_dir_insert(parent, new, pos, ISO_REPLACE_NEVER);
} }
int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent,
const char *name, const char *path,
off_t offset, off_t size,
IsoNode **node)
{
int result;
struct stat info;
IsoFilesystem *fs;
IsoFileSource *src;
IsoFile *new;
IsoNode **pos;
IsoStream *stream;
if (image == NULL || parent == NULL || name == NULL || path == NULL) {
return ISO_NULL_POINTER;
}
if (node) {
*node = NULL;
}
/* find place where to insert */
result = iso_dir_exists(parent, name, &pos);
if (result) {
/* a node with same name already exists */
return ISO_NODE_NAME_NOT_UNIQUE;
}
fs = image->fs;
result = fs->get_by_path(fs, path, &src);
if (result < 0) {
return result;
}
result = iso_file_source_stat(src, &info);
if (result < 0) {
iso_file_source_unref(src);
return result;
}
if (!S_ISREG(info.st_mode)) {
return ISO_WRONG_ARG_VALUE;
}
if (offset >= info.st_size) {
return ISO_WRONG_ARG_VALUE;
}
/* force regular file */
result = image->builder->create_file(image->builder, image, src, &new);
/* free the file */
iso_file_source_unref(src);
if (result < 0) {
return result;
}
/* replace file iso stream with a cut-out-stream */
result = iso_cut_out_stream_new(src, offset, size, &stream);
if (result < 0) {
iso_node_unref((IsoNode*)new);
return result;
}
iso_stream_unref(new->stream);
new->stream = stream;
result = iso_node_set_name((IsoNode*)new, name);
if (result < 0) {
iso_node_unref((IsoNode*)new);
return result;
}
if (node) {
*node = (IsoNode*)new;
}
/* finally, add node to parent */
return iso_dir_insert(parent, (IsoNode*)new, pos, ISO_REPLACE_NEVER);
}
static static
int check_excludes(IsoImage *image, const char *path) int check_excludes(IsoImage *image, const char *path)
{ {