=============================================================================== 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.