340 lines
12 KiB
Plaintext
Executable File
340 lines
12 KiB
Plaintext
Executable File
===============================================================================
|
|
LIBISOFS DEVELOPMENT TUTORIAL
|
|
===============================================================================
|
|
|
|
Creation date: 2008-Jan-27
|
|
Author: Vreixo Formoso
|
|
_______________________________________________________________________________
|
|
|
|
This is a little tutorial of how to use libisofs library for application
|
|
development.
|
|
|
|
Contents:
|
|
---------
|
|
|
|
1. Introduction
|
|
1.1 Library initialization
|
|
1.2 Image context
|
|
1.3 Error reporting
|
|
2. Creating an image
|
|
2.1 Image tree manipulation
|
|
2.2 Set the write options
|
|
2.3 Obtaining a burn_source
|
|
3. Image growing and multisession
|
|
4. Bootable images
|
|
5. Advanced features
|
|
|
|
|
|
-------------------------------------------------------------------------------
|
|
1. Introduction
|
|
-------------------------------------------------------------------------------
|
|
|
|
[TODO some lines about refcounts]
|
|
|
|
-------------------------------------------------------------------------------
|
|
1.1. Library initialization
|
|
|
|
Before any usage of the library, you have to call
|
|
|
|
iso_init()
|
|
|
|
in the same way, when you have finished using the library, you should call
|
|
|
|
iso_finish()
|
|
|
|
to free all resources reserved by the library.
|
|
|
|
-------------------------------------------------------------------------------
|
|
1.2. Image context
|
|
|
|
Libisofs is image-oriented, the core of libisofs usage is the IsoImage object.
|
|
Thus, the first you need to do is to get your own IsoImage object:
|
|
|
|
IsoImage *my_image;
|
|
iso_image_new("NEW DISC", &my_image);
|
|
|
|
An IsoImage is a context for image creation. It holds the files that will be
|
|
added to image, other related information and several options to customize
|
|
the behavior of libisofs when working with such Image. i.e., an IsoImage is
|
|
a context for libisofs operations. As such, you can work with several image
|
|
contexts at a time.
|
|
|
|
-------------------------------------------------------------------------------
|
|
1.3. Error reporting
|
|
|
|
In libisofs error reporting is done in two ways: with the return value of
|
|
the functions and with the message queue.
|
|
|
|
Error codes are negative numbers, defined in "libisofs.h" header. An
|
|
error code is associated with a given severity, either "DEBUG", "UPDATE",
|
|
"NOTE", "HINT", "WARNING", "SORRY", "FAILURE" and "FATAL". For the meaning
|
|
of each severity take a look at private header "libiso_msgs.h". Errors
|
|
reported by function return value are always "FAILURE" or "FATAL". Other kind
|
|
of errors are only reported with the message queue. You can get the severity
|
|
of any error message with ISO_ERR_SEV() macro [TODO: we need a function to
|
|
translate error severity to string]
|
|
|
|
First of all, most libisofs functions return an integer. If such integer is
|
|
a negative number, it means the function has returned an error. The error code
|
|
and its severity is encoded in the return value (take a look at error codes in
|
|
libisofs.h header).
|
|
|
|
Additionally, libisofs reports most of its errors in a message queue. Error
|
|
messages on that queue can be printed directly to stderr or programmatically
|
|
retrieved. First of all, you should set the severity threshold over which an
|
|
error is printed or enqueued, with function:
|
|
|
|
iso_set_msgs_severities()
|
|
|
|
Errors enqueued can be retrieved with function:
|
|
|
|
iso_obtain_msgs()
|
|
|
|
Together with the code error, a text message and its severity, this function
|
|
also returns the image id. This is an identifier that uniquely identifies a
|
|
given image context. You can get the identifier of each IsoImage with the
|
|
|
|
iso_image_get_msg_id()
|
|
|
|
and that way distinguish what image has issued the message.
|
|
|
|
|
|
-------------------------------------------------------------------------------
|
|
2. Creating an Image
|
|
-------------------------------------------------------------------------------
|
|
|
|
An image is built from a set of files that you want to store together in an
|
|
ISO-9660 volume. We call the "iso tree" to the file hierarchy that will be
|
|
written to image. The image context, IsoImage, holds that tree, together with
|
|
configuration options and other properties of the image, that provide info
|
|
about the volume (such as the identifier, author, etc...).
|
|
|
|
All configuration options and volume properties are set by its corresponding
|
|
setters (iso_image_set_volset_id(), iso_image_set_publisher_id()...)
|
|
|
|
To create an image, you have to follow the following steps:
|
|
|
|
* Obtain the image context.
|
|
See "1.2 Image context" for details of how to obtain the IsoImage.
|
|
* Set the desired properties
|
|
* Prepare the iso tree with the files you want to add to image.
|
|
See "2.1 Image tree manipulation" for details
|
|
* Select the options for image generation.
|
|
See "2.2 Set the write options"
|
|
* Get the burn_source used to actually write the image.
|
|
|
|
|
|
-------------------------------------------------------------------------------
|
|
2.1 Image tree manipulation
|
|
|
|
libisofs maintains in memory a file tree (usually called the iso tree), that
|
|
represents the files and directories that will be written later to image. You
|
|
are allowed to make whatever changes you want to that tree, just like you do
|
|
to any "real" filesystem, before actually write it to image.
|
|
|
|
Unlike other ISO-9660 mastering tools, you have full control over the file
|
|
hierarchy that will be written to image, via the libisofs API. You can add
|
|
new files, create any file in image, change its name, attributes, etc The iso
|
|
tree behaves just like any other POSIX filesystem.
|
|
|
|
The root of the iso tree is created automatically when the IsoImage is
|
|
allocated, and you can't replace it. To get a reference to it you can use the
|
|
function:
|
|
|
|
iso_image_get_root()
|
|
|
|
* Iso tree objects
|
|
|
|
Each file in the image or iso tree is represented by an IsoNode instance. In
|
|
the same way a POSIX filesystem has several file types (regular files,
|
|
directories, symlinks...), the IsoNode has several subtypes:
|
|
|
|
IsoNode
|
|
|
|
|
---------------------------------
|
|
| | | |
|
|
IsoDir IsoFile IsoSymlink IsoSpecial
|
|
|
|
where
|
|
|
|
- IsoDir represents a directory
|
|
- IsoFile represents a regular file
|
|
- IsoSymlink represents a symbolic linke
|
|
- IsoSpecial represents any other POSIX file, i.e. block and character
|
|
devices, FIFOs, sockets.
|
|
|
|
You can obtain the concrete type of an IsoNode with the iso_node_get_type()
|
|
function.
|
|
|
|
Many libisofs functions take or return an IsoNode. Many others, however,
|
|
require an specific type. You can safety cast any subtype to an IsoNode
|
|
object. In the same way, after ensuring you are dealing with the correct
|
|
subtype, you can downcast a given IsoNode to the specific subtype.
|
|
|
|
IsoDir *dir;
|
|
IsoNode *node;
|
|
|
|
node = (IsoNode*) dir;
|
|
|
|
if (iso_node_get_type(node) == LIBISO_DIR) {
|
|
dir = (IsoDir*) node;
|
|
...
|
|
}
|
|
|
|
or with the provided macros:
|
|
|
|
IsoDir *dir;
|
|
IsoNode *node;
|
|
|
|
node = ISO_NODE(dir);
|
|
|
|
if (ISO_NODE_IS_DIR(node)) {
|
|
dir = ISO_DIR(node);
|
|
...
|
|
}
|
|
|
|
* Adding files to the image
|
|
|
|
Files can be added to the image or iso tree either as new files or as files
|
|
from the filesystem.
|
|
|
|
In the first case, files are created directly on the image. They do not
|
|
correspond to any file in the filesystem. Provided functions are:
|
|
|
|
- iso_tree_add_new_dir()
|
|
- iso_tree_add_new_symlink()
|
|
- iso_tree_add_new_special()
|
|
|
|
On the other side, you can add local files to the image, either with the
|
|
|
|
iso_tree_add_node()
|
|
|
|
or with
|
|
|
|
iso_tree_add_dir_rec().
|
|
|
|
The first is intended to add a single file, while the last can be used to add,
|
|
recursively, a full directory (see below for details).
|
|
|
|
It is important to note that libisofs doesn't store any kind of link between
|
|
the IsoNode and the filesystem file it was created from. The above functions
|
|
just initialize a newly created IsoNode with the attributes of a given file in
|
|
the filesystem. After that, you can move the original file, change its
|
|
attributes or even delete it. The IsoNode in the image tree remains with the
|
|
original attributes. One exception to this rule are the contents of a regular
|
|
file. Libisofs does not make any copy of those contents until they're actually
|
|
written to image. Thus, you shouldn't modify, move or delete regular files
|
|
after adding them to the IsoImage.
|
|
|
|
|
|
* Recursive directory addition.
|
|
|
|
One common use case is to add a local directory to the image. While this can
|
|
be done with iso_tree_add_node(), handling the addition of directory children
|
|
in the application, libisofs provides a function suitable for this case:
|
|
|
|
iso_tree_add_dir_rec()
|
|
|
|
that takes care of adding all files inside a directory, recursing on directory
|
|
children. By default, this function adds all children. However, it is usual
|
|
that you don't want really this. For example, you may want to exclude some
|
|
kind of files (backup files, application sockets,...). Libisofs provides
|
|
several functions to customize the behavior of that function:
|
|
|
|
- iso_tree_set_follow_symlinks()
|
|
- iso_tree_set_ignore_hidden()
|
|
- iso_tree_set_ignore_special()
|
|
- iso_tree_add_exclude()
|
|
|
|
* Operations on iso tree
|
|
|
|
[TODO briefly explain how to add node, change attributes, ...]
|
|
|
|
* Replace mode
|
|
|
|
[TODO]
|
|
|
|
-------------------------------------------------------------------------------
|
|
2.2 Set the write options
|
|
|
|
Once you have prepared the iso tree, it is time to select the options for the
|
|
image writing.
|
|
|
|
These options affect the characteristics of the filesystem to create in the
|
|
image, but also can control how libisofs generates the image.
|
|
|
|
First of all you have to get an instance of IsoWriteOpts, with the function
|
|
|
|
iso_write_opts_new()
|
|
|
|
The several options available can be classified in:
|
|
|
|
- Extensions to add to the ISO-9660 image:
|
|
|
|
iso_write_opts_set_rockridge()
|
|
iso_write_opts_set_joliet()
|
|
iso_write_opts_set_iso1999()
|
|
|
|
RockRidge is highly recommended, in fact you should use it in all image. Joliet
|
|
is needed if you want to use your images in Windows system. Nowadays,
|
|
ISO-9660:1999 is no much useful, so in most cases you don't want such
|
|
extension.
|
|
|
|
- ISO-9660 options:
|
|
|
|
iso_write_opts_set_iso_level()
|
|
iso_write_opts_set_omit_version_numbers()
|
|
iso_write_opts_set_allow_deep_paths()
|
|
iso_write_opts_set_allow_longer_paths()
|
|
iso_write_opts_set_max_37_char_filenames()
|
|
iso_write_opts_set_no_force_dots()
|
|
iso_write_opts_set_allow_lowercase()
|
|
iso_write_opts_set_allow_full_ascii()
|
|
|
|
These control the options for the ISO-9660 filesystem. In most cases you won't
|
|
care about them, as it is the RockRidge or Joliet extensions what determine the
|
|
properties of the files once the image is mounted.
|
|
|
|
- File attributes options
|
|
|
|
iso_write_opts_set_replace_mode()
|
|
iso_write_opts_set_default_dir_mode()
|
|
iso_write_opts_set_default_file_mode()
|
|
iso_write_opts_set_default_uid()
|
|
iso_write_opts_set_default_gid()
|
|
iso_write_opts_set_replace_timestamps()
|
|
iso_write_opts_set_default_timestamp()
|
|
iso_write_opts_set_always_gmt()
|
|
|
|
They allow to set default attributes for files in image, despite of the real
|
|
attributes of the file on the local filesystem.
|
|
|
|
-------------------------------------------------------------------------------
|
|
2.3 Obtaining a burn_source
|
|
|
|
Finally, you get the burn_source used to write the image with the function:
|
|
|
|
iso_image_create_burn_source()
|
|
|
|
The returned burn_source is suitable for using with libburn, to directly burn
|
|
the image to a disc. Alternatively, you can use burn_source read() to get
|
|
the image contents (for example, to write them to a file, pipe...).
|
|
|
|
Before creating the burn_source, libisofs computes the size of the image, so
|
|
the get_size() function of the burn_source always returns the final image
|
|
size. It also starts a writing thread. All the operations needed to generate
|
|
the image are done by this thread, including read the original files contents.
|
|
The image is writing to a FIFO buffer, from which the burn_source will read.
|
|
The size of the buffer can be set in advanced with a property of the
|
|
IsoWriteOpts struct:
|
|
|
|
iso_write_opts_set_fifo_size()
|
|
|
|
You can get the state of the buffer in any moment, with the function:
|
|
|
|
iso_ring_buffer_get_status()
|
|
|
|
You can also cancel the writer thread at any time, with the cancel() function
|
|
of the burn_source.
|
|
|