First pinch of libisofs rewrite

This commit is contained in:
Mario Danic 2006-08-24 19:23:37 +00:00
parent 176e1654ff
commit 48d76e844e
16 changed files with 1610 additions and 3065 deletions

View File

@ -59,23 +59,22 @@ libburn_libburn_la_SOURCES = \
libisofs_libisofs_la_LDFLAGS = \ libisofs_libisofs_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
libisofs_libisofs_la_SOURCES = \ libisofs_libisofs_la_SOURCES = \
libisofs/errors.h \ libisofs/tree.h \
libisofs/errors.c \ libisofs/tree.c \
libisofs/tree.h \ libisofs/volume.h \
libisofs/tree.c \ libisofs/volume.c \
libisofs/volume.h \ libisofs/util.h \
libisofs/volume.c \ libisofs/util.c \
libisofs/util.h \ libisofs/ecma119.c \
libisofs/util.c \ libisofs/ecma119.h \
libisofs/ecma119.c \ libisofs/ecma119_tree.c \
libisofs/ecma119.h \ libisofs/ecma119_tree.h \
libisofs/struct.h \ libisofs/susp.h \
libisofs/struct.c \ libisofs/susp.c \
libisofs/susp.h \ libisofs/rockridge.h \
libisofs/susp.c \ libisofs/rockridge.c \
libisofs/rockridge.h \ libisofs/joliet.c \
libisofs/rockridge.c \ libisofs/joliet.h
libisofs/libisofs.h
libinclude_HEADERS = \ libinclude_HEADERS = \
libburn/libburn.h \ libburn/libburn.h \

View File

@ -1,11 +1,11 @@
pkgconfigdir=$(libdir)/pkgconfig pkgconfigdir=$(libdir)/pkgconfig
libincludedir=$(includedir)/libburn libincludedir=$(includedir)/libburn
##bin_PROGRAMS = test
lib_LTLIBRARIES = libisofs.la lib_LTLIBRARIES = libisofs.la
libisofs_la_SOURCES = \ libisofs_la_SOURCES = \
errors.h \
errors.c \
tree.h \ tree.h \
tree.c \ tree.c \
volume.h \ volume.h \
@ -14,20 +14,25 @@ libisofs_la_SOURCES = \
util.c \ util.c \
ecma119.c \ ecma119.c \
ecma119.h \ ecma119.h \
struct.h \ ecma119_tree.c \
struct.c \ ecma119_tree.h \
susp.h \ susp.h \
susp.c \ susp.c \
rockridge.h \ rockridge.h \
rockridge.c rockridge.c \
joliet.c \
joliet.h
libinclude_HEADERS = libisofs.h libinclude_HEADERS = libisofs.h
noinst_PROGRAMS = test ##test_SOURCES = test.c
test_SOURCES = test.c ##test_LDADD = libisofs.la
test_LDADD = $(libisofs_la_OBJECTS)
INCLUDES = -I.. ##noinst_PROGRAMS = test
##test_SOURCES = test.c
##test_LDADD = $(libisofs_la_OBJECTS)
##INCLUDES = -I../burn/libburn
## ========================================================================= ## ## ========================================================================= ##
indent_files = $(libisofs_la_SOURCES) indent_files = $(libisofs_la_SOURCES)

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */ /* vim: set noet ts=8 sts=8 sw=8 : */
/** /**
@ -7,70 +8,17 @@
* volume. * volume.
*/ */
#ifndef __ISO_ECMA119 #ifndef LIBISO_ECMA119_H
#define __ISO_ECMA119 #define LIBISO_ECMA119_H
#include <stdio.h>
#include <sys/time.h> #include <sys/time.h>
#include <stdint.h>
#include <stdio.h> /* for FILE */
#include <sys/types.h>
#include "susp.h" #include "susp.h"
/** struct ecma119_tree_node;
* Persistent data for writing directories according to the ecma119 standard. struct joliet_tree_node;
*/
struct dir_write_info
{
struct susp_info susp; /**< \see node_write_info */
struct susp_info self_susp; /**< SUSP data for this directory's
* "." entry.
*/
struct susp_info parent_susp; /**< SUSP data for this directory's
* ".." entry.
*/
int len; /**< The combined length of all children's
* Directory Record lengths. This includes
* the System Use areas.
*/
int susp_len; /**< The combined length of all children's
* SUSP Continuation Areas.
*/
/* the parent/child information prior to relocation */
struct iso_tree_dir *real_parent;
int real_nchildren;
struct iso_tree_dir **real_children;
int real_depth;
/* joliet information */
int joliet_block; /**< The block at which the Joliet version of
* this directory will be written.
*/
int joliet_len; /**< The combined length of all children's
* Joliet Directory Record lengths.
*/
};
/**
* Persistent data for writing files according to the ecma119 standard.
*/
struct file_write_info
{
struct susp_info susp; /**< \see node_write_info */
struct iso_tree_dir *real_me; /**< If this is non-NULL, the file is
* a placeholder for a relocated
* directory and this field points to
* that relocated directory.
*/
};
/**
* The fields in common between file_write_info and dir_write_info.
*/
struct node_write_info
{
struct susp_info susp; /**< The SUSP data for this file. */
};
/** /**
* The possible states that the ecma119 writer can be in. * The possible states that the ecma119 writer can be in.
@ -100,11 +48,13 @@ enum ecma119_write_state
*/ */
struct ecma119_write_target struct ecma119_write_target
{ {
struct ecma119_tree_node *root;
struct joliet_tree_node *joliet_root;
struct iso_volset *volset; struct iso_volset *volset;
int volnum; int volnum;
time_t now; /**< Time at which writing began. */ time_t now; /**< Time at which writing began. */
int total_size; /**< Total size of the output. This only off_t total_size; /**< Total size of the output. This only
* includes the current volume. */ * includes the current volume. */
uint32_t vol_space_size; uint32_t vol_space_size;
@ -120,73 +70,63 @@ struct ecma119_write_target
uint32_t m_path_table_pos; uint32_t m_path_table_pos;
uint32_t l_path_table_pos_joliet; uint32_t l_path_table_pos_joliet;
uint32_t m_path_table_pos_joliet; uint32_t m_path_table_pos_joliet;
uint32_t total_dir_size;
uint32_t total_dir_size_joliet;
struct iso_tree_dir **dirlist; /* A pre-order list of directories struct ecma119_tree_node **dirlist;
/**< A pre-order list of directories
* (this is the order in which we write * (this is the order in which we write
* out directory records). * out directory records).
*/ */
struct iso_tree_dir **pathlist; /* A breadth-first list of directories. struct ecma119_tree_node **pathlist;
* This is used for writing out the path /**< A breadth-first list of
* tables. * directories. This is used for
* writing out the path tables.
*/ */
int dirlist_len; /* The length of the previous 2 lists. size_t dirlist_len; /**< The length of the previous 2 lists.
*/ */
struct iso_tree_file **filelist;/* A pre-order list of files with struct ecma119_tree_node **filelist;
/**< A pre-order list of files with
* non-NULL paths and non-zero sizes. * non-NULL paths and non-zero sizes.
*/ */
int filelist_len; /* Length of the previous list. */ size_t filelist_len; /* Length of the previous list. */
int curfile; /* Used as a helper field for writing int curfile; /**< Used as a helper field for writing
out filelist and dirlist */ out filelist and dirlist */
/* Joliet versions of the above lists. Since Joliet doesn't require /* Joliet versions of the above lists. Since Joliet doesn't require
* directory relocation, the order of these list might be different from * directory relocation, the order of these lists might be different
* the lists above. */ * from the lists above (but they will be the same length).
struct iso_tree_dir **dirlist_joliet; */
struct iso_tree_dir **pathlist_joliet; struct joliet_tree_node **dirlist_joliet;
struct joliet_tree_node **pathlist_joliet;
enum ecma119_write_state state; /* The current state of the writer. */ enum ecma119_write_state state; /* The current state of the writer. */
/* persistent data for the various states. Each struct should not be /* Most writers work by
* touched except for the writer of the relevant stage. When the writer * 1) making sure state_data is big enough for their data
* of the relevant stage is finished, it should set all fields to 0. * 2) writing _all_ their data into state_data
* 3) relying on write_data_chunk to write the data block
* by block.
*/ */
union uint8_t *state_data;
{ off_t state_data_size;
struct off_t state_data_off;
{ int state_data_valid;
int blocks;
unsigned char *data; /* for writing out files */
} path_table; struct state_files {
struct off_t pos; /* The number of bytes we have written
{ * so far in the current file.
size_t pos; /* The number of bytes we have written */
* so far in the current directory. off_t data_len;/* The number of bytes in the currently
*/ * open file.
size_t data_len;/* The number of bytes in the current */
* directory. FILE *fd; /* The currently open file. */
*/ int file; /* The index in filelist that we are
unsigned char *data; /* The data (combined Directory * currently writing (or about to write). */
* Records and susp_CE areas) of the } state_files;
* current directory.
*/
int dir; /* The index in dirlist that we are
* currently writing. */
} dir_records;
struct
{
size_t pos; /* The number of bytes we have written
* so far in the current file.
*/
size_t data_len;/* The number of bytes in the currently
* open file.
*/
FILE *fd; /* The currently open file. */
int file; /* The index in filelist that we are
* currently writing. */
} files;
} state_data;
}; };
/** /**
@ -198,23 +138,130 @@ struct ecma119_write_target
* \post The directory heirarchy has been reorganised to be ecma119-compatible. * \post The directory heirarchy has been reorganised to be ecma119-compatible.
*/ */
struct ecma119_write_target *ecma119_target_new(struct iso_volset *volset, struct ecma119_write_target *ecma119_target_new(struct iso_volset *volset,
int volnum); int volnum,
int level,
int flags);
/** Macros to help with casting between node_write_info and dir/file_write_info. #define BP(a,b) [(b) - (a) + 1]
struct ecma119_pri_vol_desc
{
uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7);
uint8_t unused1 BP(8, 8);
uint8_t system_id BP(9, 40);
uint8_t volume_id BP(41, 72);
uint8_t unused2 BP(73, 80);
uint8_t vol_space_size BP(81, 88);
uint8_t unused3 BP(89, 120);
uint8_t vol_set_size BP(121, 124);
uint8_t vol_seq_number BP(125, 128);
uint8_t block_size BP(129, 132);
uint8_t path_table_size BP(133, 140);
uint8_t l_path_table_pos BP(141, 144);
uint8_t opt_l_path_table_pos BP(145, 148);
uint8_t m_path_table_pos BP(149, 152);
uint8_t opt_m_path_table_pos BP(153, 156);
uint8_t root_dir_record BP(157, 190);
uint8_t vol_set_id BP(191, 318);
uint8_t publisher_id BP(319, 446);
uint8_t data_prep_id BP(447, 574);
uint8_t application_id BP(575, 702);
uint8_t copyright_file_id BP(703, 739);
uint8_t abstract_file_id BP(740, 776);
uint8_t bibliographic_file_id BP(777, 813);
uint8_t vol_creation_time BP(814, 830);
uint8_t vol_modification_time BP(831, 847);
uint8_t vol_expiration_time BP(848, 864);
uint8_t vol_effective_time BP(865, 881);
uint8_t file_structure_version BP(882, 882);
uint8_t reserved1 BP(883, 883);
uint8_t app_use BP(884, 1395);
uint8_t reserved2 BP(1396, 2048);
};
struct ecma119_sup_vol_desc
{
uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7);
uint8_t vol_flags BP(8, 8);
uint8_t system_id BP(9, 40);
uint8_t volume_id BP(41, 72);
uint8_t unused2 BP(73, 80);
uint8_t vol_space_size BP(81, 88);
uint8_t esc_sequences BP(89, 120);
uint8_t vol_set_size BP(121, 124);
uint8_t vol_seq_number BP(125, 128);
uint8_t block_size BP(129, 132);
uint8_t path_table_size BP(133, 140);
uint8_t l_path_table_pos BP(141, 144);
uint8_t opt_l_path_table_pos BP(145, 148);
uint8_t m_path_table_pos BP(149, 152);
uint8_t opt_m_path_table_pos BP(153, 156);
uint8_t root_dir_record BP(157, 190);
uint8_t vol_set_id BP(191, 318);
uint8_t publisher_id BP(319, 446);
uint8_t data_prep_id BP(447, 574);
uint8_t application_id BP(575, 702);
uint8_t copyright_file_id BP(703, 739);
uint8_t abstract_file_id BP(740, 776);
uint8_t bibliographic_file_id BP(777, 813);
uint8_t vol_creation_time BP(814, 830);
uint8_t vol_modification_time BP(831, 847);
uint8_t vol_expiration_time BP(848, 864);
uint8_t vol_effective_time BP(865, 881);
uint8_t file_structure_version BP(882, 882);
uint8_t reserved1 BP(883, 883);
uint8_t app_use BP(884, 1395);
uint8_t reserved2 BP(1396, 2048);
};
struct ecma119_vol_desc_terminator
{
uint8_t vol_desc_type BP(1, 1);
uint8_t std_identifier BP(2, 6);
uint8_t vol_desc_version BP(7, 7);
uint8_t reserved BP(8, 2048);
};
struct ecma119_dir_record
{
uint8_t len_dr BP(1, 1);
uint8_t len_xa BP(2, 2);
uint8_t block BP(3, 10);
uint8_t length BP(11, 18);
uint8_t recording_time BP(19, 25);
uint8_t flags BP(26, 26);
uint8_t file_unit_size BP(27, 27);
uint8_t interleave_gap_size BP(28, 28);
uint8_t vol_seq_number BP(29, 32);
uint8_t len_fi BP(33, 33);
uint8_t file_id BP(34, 34); /* 34 to 33+len_fi */
/* padding field (if len_fi is even) */
/* system use (len_dr - len_su + 1 to len_dr) */
};
struct ecma119_path_table_record
{
uint8_t len_di BP(1, 1);
uint8_t len_xa BP(2, 2);
uint8_t block BP(3, 6);
uint8_t parent BP(7, 8);
uint8_t dir_id BP(9, 9); /* 9 to 8+len_di */
/* padding field (if len_di is odd) */
};
/**
* A utility function for writers that want to write their data all at once
* rather than block-by-block. This creates a buffer of size \p size, passes
* it to the given writer, then hands out block-sized chunks.
*/ */
#define DIR_INF(a) ( (struct dir_write_info*) (a) ) void
#define FILE_INF(a) ( (struct file_write_info*) (a) ) ecma119_start_chunking(struct ecma119_write_target *t,
#define NODE_INF(a) ( (struct node_write_info*) (a) ) void (*)(struct ecma119_write_target*, uint8_t*),
off_t size,
uint8_t *buf);
#define GET_DIR_INF(a) ( (struct dir_write_info*) (a)->writer_data ) #endif /* LIBISO_ECMA119_H */
#define GET_FILE_INF(a) ( (struct file_write_info*) (a)->writer_data )
#define GET_NODE_INF(a) ( (struct node_write_info*) (a)->writer_data )
#define TARGET_ROOT(t) ( (t)->volset->volume[(t)->volnum]->root )
#define NODE_NAMELEN(n,i) strlen(iso_tree_node_get_name(ISO_NODE(n), i))
#define NODE_JOLLEN(n) ucslen(iso_tree_node_get_name(ISO_NODE(n), \
ISO_NAME_JOLIET))
#endif /* __ISO_ECMA119 */

View File

@ -9,10 +9,11 @@
* - Write the volume to a file or create a burn source for use with Libburn. * - Write the volume to a file or create a burn source for use with Libburn.
*/ */
#ifndef __LIBISOFS #ifndef LIBISO_LIBISOFS_H
#define __LIBISOFS #define LIBISO_LIBISOFS_H
#include "libburn/libburn.h" /* #include <libburn.h> */
struct burn_source;
/** /**
* Data volume. * Data volume.
@ -27,35 +28,11 @@ struct iso_volume;
struct iso_volset; struct iso_volset;
/** /**
* Directory on a volume. * A node in the filesystem tree.
* @see tree.h for details.
*/
struct iso_tree_dir;
/**
* File on a volume.
* @see tree.h for details.
*/
struct iso_tree_file;
/**
* Either a file or a directory.
* \see tree.h * \see tree.h
*/ */
struct iso_tree_node; struct iso_tree_node;
/**
* Possible versions of a file or directory name or identifier.
*/
enum iso_name_version {
ISO_NAME_FULL, /**< In the current locale. */
ISO_NAME_ISO, /**< Current ISO level identifier. */
ISO_NAME_ISO_L1, /**< ISO level 1 identifier. */
ISO_NAME_ISO_L2, /**< ISO level 2 identifier. */
ISO_NAME_ROCKRIDGE, /**< Rock Ridge file or directory name. */
ISO_NAME_JOLIET /**< Joliet identifier. */
};
enum ecma119_extension_flag { enum ecma119_extension_flag {
ECMA119_ROCKRIDGE = (1<<0), ECMA119_ROCKRIDGE = (1<<0),
ECMA119_JOLIET = (1<<1) ECMA119_JOLIET = (1<<1)
@ -69,6 +46,11 @@ struct iso_volume *iso_volume_new(const char *volume_id,
const char *publisher_id, const char *publisher_id,
const char *data_preparer_id); const char *data_preparer_id);
struct iso_volume *iso_volume_new_with_root(const char *volume_id,
const char *publisher_id,
const char *data_preparer_id,
struct iso_tree_node *root);
/** /**
* Free a volume. * Free a volume.
*/ */
@ -77,7 +59,7 @@ void iso_volume_free(struct iso_volume *volume);
/** /**
* Get the root directory for a volume. * Get the root directory for a volume.
*/ */
struct iso_tree_dir *iso_volume_get_root(const struct iso_volume *volume); struct iso_tree_node *iso_volume_get_root(const struct iso_volume *volume);
/** /**
* Fill in the volume identifier for a volume. * Fill in the volume identifier for a volume.
@ -97,37 +79,6 @@ void iso_volume_set_publisher_id(struct iso_volume *volume,
void iso_volume_set_data_preparer_id(struct iso_volume *volume, void iso_volume_set_data_preparer_id(struct iso_volume *volume,
const char *data_preparer_id); const char *data_preparer_id);
/**
* Get the current ISO level for a volume.
*/
int iso_volume_get_iso_level(const struct iso_volume *volume);
/**
* Set the current ISO level for a volume.
* ISO level must be 1 or 2.
*/
void iso_volume_set_iso_level(struct iso_volume *volume, int level);
/**
* See if Rock Ridge (POSIX) is enabled for a volume.
*/
int iso_volume_get_rockridge(const struct iso_volume *volume);
/**
* Enable or disable Rock Ridge (POSIX) for a volume.
*/
void iso_volume_set_rockridge(struct iso_volume *volume, int rockridge);
/**
* See if Joliet (Unicode) is enabled for a volume.
*/
int iso_volume_get_joliet(const struct iso_volume *volume);
/**
* Enable or disable Joliet (Unicode) for a volume.
*/
void iso_volume_set_joliet(struct iso_volume *volume, int joliet);
/** /**
* Create a new Volume Set consisting of only one volume. * Create a new Volume Set consisting of only one volume.
* @param volume The first and only volume for the volset to contain. * @param volume The first and only volume for the volset to contain.
@ -142,28 +93,14 @@ struct iso_volset *iso_volset_new(struct iso_volume *volume,
* *
* \param path The path, on the local filesystem, of the file. * \param path The path, on the local filesystem, of the file.
* *
* \pre \p parent is non-NULL * \pre \p parent is NULL or is a directory.
* \pre \p path is non-NULL and is a valid path to a non-directory on the local * \pre \p path is non-NULL and is a valid path to a non-directory on the local
* filesystem. * filesystem.
* \return An iso_tree_file whose path is \p path and whose parent is \p parent. * \return An iso_tree_node whose path is \p path and whose parent is \p parent.
*/ */
struct iso_tree_file *iso_tree_add_file(struct iso_tree_dir *parent, struct iso_tree_node *iso_tree_add_node(struct iso_tree_node *parent,
const char *path); const char *path);
/**
* Add a directory from the local filesystem to the tree.
* Warning: this only adds the directory itself, no files or subdirectories.
*
* \param path The path, on the local filesystem, of the directory.
*
* \pre \p parent is non-NULL
* \pre \p path is non-NULL and is a valid path to a directory on the local
* filesystem.
* \return a pointer to the newly created directory.
*/
struct iso_tree_dir *iso_tree_add_dir(struct iso_tree_dir *parent,
const char *path);
/** /**
* Recursively add an existing directory to the tree. * Recursively add an existing directory to the tree.
* Warning: when using this, you'll lose pointers to files or subdirectories. * Warning: when using this, you'll lose pointers to files or subdirectories.
@ -172,18 +109,18 @@ struct iso_tree_dir *iso_tree_add_dir(struct iso_tree_dir *parent,
* *
* \param path The path, on the local filesystem, of the directory to add. * \param path The path, on the local filesystem, of the directory to add.
* *
* \pre \p parent is non-NULL * \pre \p parent is NULL or is a directory.
* \pre \p path is non-NULL and is a valid path to a directory on the local * \pre \p path is non-NULL and is a valid path to a directory on the local
* filesystem. * filesystem.
* \return a pointer to the newly created directory. * \return a pointer to the newly created directory.
*/ */
struct iso_tree_dir *iso_tree_radd_dir(struct iso_tree_dir *parent, struct iso_tree_node *iso_tree_radd_dir(struct iso_tree_node *parent,
const char *path); const char *path);
/** /**
* Creates a new, empty directory on the volume. * Creates a new, empty directory on the volume.
* *
* \pre \p parent is non-NULL * \pre \p parent is NULL or is a directory.
* \pre \p name is unique among the children and files belonging to \p parent. * \pre \p name is unique among the children and files belonging to \p parent.
* Also, it doesn't contain '/' characters. * Also, it doesn't contain '/' characters.
* *
@ -191,35 +128,20 @@ struct iso_tree_dir *iso_tree_radd_dir(struct iso_tree_dir *parent,
* POSIX attributes are the same as \p parent's. * POSIX attributes are the same as \p parent's.
* \return a pointer to the newly created directory. * \return a pointer to the newly created directory.
*/ */
struct iso_tree_dir *iso_tree_add_new_dir(struct iso_tree_dir *parent, struct iso_tree_node *iso_tree_add_new_dir(struct iso_tree_node *parent,
const char *name); const char *name);
/** /**
* Get the name of a node. * Set the name of a file (using the current locale).
*/ */
const char *iso_tree_node_get_name(const struct iso_tree_node *node, void iso_tree_node_set_name(struct iso_tree_node *file, const char *name);
enum iso_name_version ver);
/**
* Set the name of a file.
* The name you input here will be the full name and will be used to derive the
* ISO, RockRidge and Joliet names.
*/
void iso_tree_file_set_name(struct iso_tree_file *file, const char *name);
/**
* Set the name of a directory.
* The name you input here will be the full name and will be used to derive the
* ISO, RockRidge and Joliet names.
*/
void iso_tree_dir_set_name(struct iso_tree_dir *dir, const char *name);
/** /**
* Recursively print a directory to stdout. * Recursively print a directory to stdout.
* \param spaces The initial number of spaces on the left. Set to 0 if you * \param spaces The initial number of spaces on the left. Set to 0 if you
* supply a root directory. * supply a root directory.
*/ */
void iso_tree_print(const struct iso_tree_dir *root, int spaces); void iso_tree_print(const struct iso_tree_node *root, int spaces);
/** Create a burn_source which can be used as a data source for a track /** Create a burn_source which can be used as a data source for a track
* *
@ -240,4 +162,4 @@ struct burn_source* iso_source_new_ecma119 (struct iso_volset *volumeset,
int level, int level,
int flags); int flags);
#endif /* __LIBISOFS */ #endif /* LIBISO_LIBISOFS_H */

View File

@ -1,10 +1,10 @@
/* vim: set noet ts=8 sts=8 sw=8 : */ /* vim: set noet ts=8 sts=8 sw=8 : */
#include "rockridge.h" #include "rockridge.h"
#include "tree.h"
#include "util.h" #include "util.h"
#include "volume.h"
#include "ecma119.h" #include "ecma119.h"
#include "ecma119_tree.h"
#include "tree.h"
#include "susp.h" #include "susp.h"
#include <stdlib.h> #include <stdlib.h>
@ -15,53 +15,50 @@
#include <sys/stat.h> #include <sys/stat.h>
/* create a PX field from the permissions on the current node. */ /* create a PX field from the permissions on the current node. */
unsigned char *rrip_make_PX(struct ecma119_write_target *t, uint8_t *rrip_make_PX(struct ecma119_write_target *t,
struct iso_tree_node *node) struct ecma119_tree_node *node)
{ {
unsigned char *PX = malloc(44); uint8_t *PX = malloc(44);
PX[0] = 'P'; PX[0] = 'P';
PX[1] = 'X'; PX[1] = 'X';
PX[2] = 44; PX[2] = 44;
PX[3] = 1; PX[3] = 1;
iso_bb(&PX[4], node->attrib.st_mode, 4); iso_bb(&PX[4], node->iso_self->attrib.st_mode, 4);
iso_bb(&PX[12], node->attrib.st_nlink, 4); iso_bb(&PX[12], node->iso_self->attrib.st_nlink, 4);
iso_bb(&PX[20], node->attrib.st_uid, 4); iso_bb(&PX[20], node->iso_self->attrib.st_uid, 4);
iso_bb(&PX[28], node->attrib.st_gid, 4); iso_bb(&PX[28], node->iso_self->attrib.st_gid, 4);
iso_bb(&PX[36], node->attrib.st_ino, 4); iso_bb(&PX[36], node->iso_self->attrib.st_ino, 4);
return PX; return PX;
} }
/** See IEEE 1282 4.1.1 */ /** See IEEE 1282 4.1.1 */
void rrip_add_PX(struct ecma119_write_target *t, struct iso_tree_node *node) void rrip_add_PX(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{ {
susp_append(t, node, rrip_make_PX(t, node)); susp_append(t, &node->susp, rrip_make_PX(t, node));
if (node->type == ECMA119_DIR) {
susp_append(t, &node->dir.self_susp, rrip_make_PX(t, node));
susp_append(t, &node->dir.parent_susp, rrip_make_PX(t, node));
}
} }
void rrip_add_PX_dir(struct ecma119_write_target *t, struct iso_tree_dir *dir) void rrip_add_PN(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{ {
susp_append(t, ISO_NODE(dir), rrip_make_PX(t, ISO_NODE(dir))); uint8_t *PN = malloc(20);
susp_append_self(t, dir, rrip_make_PX(t, ISO_NODE(dir)));
susp_append_parent(t, dir, rrip_make_PX(t, ISO_NODE(dir)));
}
void rrip_add_PN(struct ecma119_write_target *t, struct iso_tree_node *node)
{
unsigned char *PN = malloc(20);
PN[0] = 'P'; PN[0] = 'P';
PN[1] = 'N'; PN[1] = 'N';
PN[2] = 20; PN[2] = 20;
PN[3] = 1; PN[3] = 1;
iso_bb(&PN[4], node->attrib.st_dev >> 32, 4); iso_bb(&PN[4], node->iso_self->attrib.st_dev >> 32, 4);
iso_bb(&PN[12], node->attrib.st_dev & 0xffffffff, 4); iso_bb(&PN[12], node->iso_self->attrib.st_dev & 0xffffffff, 4);
susp_append(t, node, PN); susp_append(t, &node->susp, PN);
} }
static void rrip_SL_append_comp(int *n, unsigned char ***comps, static void rrip_SL_append_comp(int *n, uint8_t ***comps,
char *s, int size, char fl) char *s, int size, char fl)
{ {
unsigned char *comp = malloc(size + 2); uint8_t *comp = malloc(size + 2);
(*n)++; (*n)++;
comp[0] = fl; comp[0] = fl;
@ -75,7 +72,7 @@ static void rrip_SL_append_comp(int *n, unsigned char ***comps,
} }
static void rrip_SL_add_component(char *prev, char *cur, int *n_comp, static void rrip_SL_add_component(char *prev, char *cur, int *n_comp,
unsigned char ***comps) uint8_t ***comps)
{ {
int size = cur - prev; int size = cur - prev;
@ -103,24 +100,24 @@ static void rrip_SL_add_component(char *prev, char *cur, int *n_comp,
rrip_SL_append_comp(n_comp, comps, prev, size, 0); rrip_SL_append_comp(n_comp, comps, prev, size, 0);
} }
void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node) void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{ {
int ret, pathsize = 0; int ret, pathsize = 0;
char *path = NULL, *cur, *prev; char *path = NULL, *cur, *prev;
struct iso_tree_file *file = (struct iso_tree_file *)node;
int i, j; int i, j;
unsigned char **comp = NULL; uint8_t **comp = NULL;
int n_comp = 0; int n_comp = 0;
int total_comp_len = 0; int total_comp_len = 0;
int written = 0, pos; int written = 0, pos;
unsigned char *SL; uint8_t *SL;
do { do {
pathsize += 128; pathsize += 128;
path = realloc(path, pathsize); path = realloc(path, pathsize);
ret = readlink(file->path, path, pathsize); /* FIXME: what if the file is not on the local fs? */
ret = readlink(node->iso_self->loc.path, path, pathsize);
} while (ret == pathsize); } while (ret == pathsize);
if (ret == -1) { if (ret == -1) {
fprintf(stderr, "Error: couldn't read symlink: %s\n", fprintf(stderr, "Error: couldn't read symlink: %s\n",
@ -156,7 +153,7 @@ void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node)
memcpy(&SL[pos], comp[j], comp[j][2]); memcpy(&SL[pos], comp[j], comp[j][2]);
pos += comp[j][2]; pos += comp[j][2];
} }
susp_append(t, node, SL); susp_append(t, &node->susp, SL);
written = i - 1; written = i - 1;
total_comp_len = comp[i][1]; total_comp_len = comp[i][1];
} }
@ -173,7 +170,7 @@ void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node)
memcpy(&SL[pos], comp[j], comp[j][1] + 2); memcpy(&SL[pos], comp[j], comp[j][1] + 2);
pos += comp[j][1] + 2; pos += comp[j][1] + 2;
} }
susp_append(t, node, SL); susp_append(t, &node->susp, SL);
free(path); free(path);
/* free the components */ /* free the components */
@ -184,10 +181,10 @@ void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node)
} }
static void rrip_add_NM_single(struct ecma119_write_target *t, static void rrip_add_NM_single(struct ecma119_write_target *t,
struct iso_tree_node *node, struct susp_info *susp,
char *name, int size, int flags) char *name, int size, int flags)
{ {
unsigned char *NM = malloc(size + 5); uint8_t *NM = malloc(size + 5);
NM[0] = 'N'; NM[0] = 'N';
NM[1] = 'M'; NM[1] = 'M';
@ -197,103 +194,107 @@ static void rrip_add_NM_single(struct ecma119_write_target *t,
if (size) { if (size) {
memcpy(&NM[5], name, size); memcpy(&NM[5], name, size);
} }
susp_append(t, node, NM); susp_append(t, susp, NM);
} }
void rrip_add_NM(struct ecma119_write_target *t, struct iso_tree_node *node) void
rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{ {
struct iso_tree_file *file = (struct iso_tree_file *)node; char *name = iso_p_fileid(node->iso_self->name);
int len = strlen(file->name.rockridge); int len = name ? strlen(name) : 0;
char *pos = file->name.rockridge; char *pos = name;
if (len == 1 && pos[0] == '.') { if (!len)
rrip_add_NM_single(t, node, pos, 0, 1 << 1);
return;
}
if (len == 2 && !strncmp(pos, "..", 2)) {
rrip_add_NM_single(t, node, pos, 0, 1 << 2);
return; return;
if (node->type == ECMA119_DIR) {
rrip_add_NM_single(t, &node->dir.self_susp, pos, 0, 1 << 1);
rrip_add_NM_single(t, &node->dir.parent_susp, pos, 0, 1 << 2);
} }
while (len > 250) { while (len > 250) {
rrip_add_NM_single(t, node, pos, 250, 1); rrip_add_NM_single(t, &node->susp, pos, 250, 1);
len -= 250; len -= 250;
pos += 250; pos += 250;
} }
rrip_add_NM_single(t, node, pos, len, 0); rrip_add_NM_single(t, &node->susp, pos, len, 0);
} }
void rrip_add_CL(struct ecma119_write_target *t, struct iso_tree_node *node) void rrip_add_CL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{ {
unsigned char *CL = calloc(1, 12); uint8_t *CL = calloc(1, 12);
CL[0] = 'C'; CL[0] = 'C';
CL[1] = 'L'; CL[1] = 'L';
CL[2] = 12; CL[2] = 12;
CL[3] = 1; CL[3] = 1;
susp_append(t, node, CL); susp_append(t, &node->susp, CL);
} }
void rrip_add_PL(struct ecma119_write_target *t, struct iso_tree_dir *node) void
rrip_add_PL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{ {
unsigned char *PL = calloc(1, 12); uint8_t *PL = calloc(1, 12);
PL[0] = 'P'; PL[0] = 'P';
PL[1] = 'L'; PL[1] = 'L';
PL[2] = 12; PL[2] = 12;
PL[3] = 1; PL[3] = 1;
susp_append_parent(t, node, PL); susp_append(t, &node->dir.parent_susp, PL);
} }
void rrip_add_RE(struct ecma119_write_target *t, struct iso_tree_node *node) void
rrip_add_RE(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{ {
unsigned char *RE = malloc(4); uint8_t *RE = malloc(4);
RE[0] = 'R'; RE[0] = 'R';
RE[1] = 'E'; RE[1] = 'E';
RE[2] = 4; RE[2] = 4;
RE[3] = 1; RE[3] = 1;
susp_append(t, node, RE); susp_append(t, &node->susp, RE);
} }
void rrip_add_TF(struct ecma119_write_target *t, struct iso_tree_node *node) void
rrip_add_TF(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{ {
unsigned char *TF = malloc(5 + 3 * 17); uint8_t *TF = malloc(5 + 3 * 7);
TF[0] = 'T'; TF[0] = 'T';
TF[1] = 'F'; TF[1] = 'F';
TF[2] = 5 + 3 * 17; TF[2] = 5 + 3 * 7;
TF[3] = 1; TF[3] = 1;
TF[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7); TF[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7);
iso_datetime_17(&TF[5], node->attrib.st_mtime); iso_datetime_7(&TF[5], node->iso_self->attrib.st_mtime);
iso_datetime_17(&TF[22], node->attrib.st_atime); iso_datetime_7(&TF[12], node->iso_self->attrib.st_atime);
iso_datetime_17(&TF[39], node->attrib.st_ctime); iso_datetime_7(&TF[19], node->iso_self->attrib.st_ctime);
susp_append(t, node, TF); susp_append(t, &node->susp, TF);
} }
void rrip_finalize(struct ecma119_write_target *t, struct iso_tree_dir *dir) void
rrip_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
{ {
struct dir_write_info *inf;
struct file_write_info *finf;
int i; int i;
inf = dir->writer_data; assert(dir->type == ECMA119_DIR);
if (dir->parent != inf->real_parent) {
unsigned char *PL = susp_find(&inf->parent_susp, "PL");
iso_bb(&PL[4], inf->real_parent->block, 4); if (dir->parent != dir->dir.real_parent) {
uint8_t *PL = susp_find(&dir->dir.parent_susp, "PL");
assert(PL);
iso_bb(&PL[4], dir->dir.real_parent->block, 4);
} }
for (i = 0; i < dir->nfiles; i++) { for (i = 0; i < dir->dir.nchildren; i++) {
finf = dir->files[i]->writer_data; struct ecma119_tree_node *ch = dir->dir.children[i];
if (finf->real_me) {
unsigned char *CL = susp_find(&finf->susp, "CL");
iso_bb(&CL[4], finf->real_me->block, 4); if (ch->type == ECMA119_FILE && ch->file.real_me) {
uint8_t *CL = susp_find(&ch->susp, "CL");
assert(CL);
iso_bb(&CL[4], ch->file.real_me->block, 4);
} else if (ch->type == ECMA119_DIR) {
rrip_finalize(t, ch);
} }
} }
for (i = 0; i < dir->nchildren; i++) {
rrip_finalize(t, dir->children[i]);
}
} }

View File

@ -2,29 +2,25 @@
/** Functions and structures used for Rock Ridge support. */ /** Functions and structures used for Rock Ridge support. */
#ifndef __ISO_ROCKRIDGE #ifndef ISO_ROCKRIDGE_H
#define __ISO_ROCKRIDGE #define ISO_ROCKRIDGE_H
struct ecma119_write_target; struct ecma119_write_target;
struct iso_tree_node; struct ecma119_tree_node;
struct iso_tree_dir;
void rrip_add_PX(struct ecma119_write_target *, struct iso_tree_node *); void rrip_add_PX(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_PN(struct ecma119_write_target *, struct iso_tree_node *); void rrip_add_PN(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_SL(struct ecma119_write_target *, struct iso_tree_node *); void rrip_add_SL(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_NM(struct ecma119_write_target *, struct iso_tree_node *); void rrip_add_NM(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_CL(struct ecma119_write_target *, struct iso_tree_node *); void rrip_add_CL(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_RE(struct ecma119_write_target *, struct iso_tree_node *); void rrip_add_RE(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_TF(struct ecma119_write_target *, struct iso_tree_node *); void rrip_add_TF(struct ecma119_write_target *, struct ecma119_tree_node *);
/* This is special because it doesn't modify the susp fields of the directory /* This is special because it doesn't modify the susp fields of the directory
* that gets passed to it; it modifies the susp fields of the ".." entry in * that gets passed to it; it modifies the susp fields of the ".." entry in
* that directory. */ * that directory. */
void rrip_add_PL(struct ecma119_write_target *, struct iso_tree_dir *); void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *);
/* Add a PX field to the susp, self_susp and parent_susp entries */ void rrip_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_PX_dir(struct ecma119_write_target *, struct iso_tree_dir *);
void rrip_finalize(struct ecma119_write_target *, struct iso_tree_dir *); #endif /* ISO_ROCKRIDGE_H */
#endif /* __ISO_ROCKRIDGE */

View File

@ -1,20 +1,25 @@
/* vim: set noet ts=8 sts=8 sw=8 : */ /* vim: set noet ts=8 sts=8 sw=8 : */
#include "susp.h" #include "susp.h"
#include "tree.h"
#include "util.h" #include "util.h"
#include "ecma119.h" #include "ecma119.h"
#include "ecma119_tree.h"
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
static void susp_insert_direct(struct ecma119_write_target *t, void susp_insert(struct ecma119_write_target *t,
struct susp_info *susp, unsigned char *data, struct susp_info *susp,
int pos) uint8_t *data,
int pos)
{ {
int i; int i;
if (pos < 0) {
pos = susp->n_susp_fields;
}
assert(pos <= susp->n_susp_fields); assert(pos <= susp->n_susp_fields);
susp->n_susp_fields++; susp->n_susp_fields++;
susp->susp_fields = realloc(susp->susp_fields, susp->susp_fields = realloc(susp->susp_fields,
@ -27,60 +32,13 @@ static void susp_insert_direct(struct ecma119_write_target *t,
} }
void susp_append(struct ecma119_write_target *t, void susp_append(struct ecma119_write_target *t,
struct iso_tree_node *node, unsigned char *data) struct susp_info *susp,
uint8_t *data)
{ {
struct dir_write_info *inf = node->writer_data; susp_insert(t, susp, data, susp->n_susp_fields);
struct susp_info *susp = &inf->susp;
susp_insert_direct(t, susp, data, susp->n_susp_fields);
} }
void susp_append_self(struct ecma119_write_target *t, uint8_t *susp_find(struct susp_info *susp, const char *name)
struct iso_tree_dir *dir, unsigned char *data)
{
struct dir_write_info *inf = dir->writer_data;
struct susp_info *susp = &inf->self_susp;
susp_insert_direct(t, susp, data, susp->n_susp_fields);
}
void susp_append_parent(struct ecma119_write_target *t,
struct iso_tree_dir *dir, unsigned char *data)
{
struct dir_write_info *inf = dir->writer_data;
struct susp_info *susp = &inf->parent_susp;
susp_insert_direct(t, susp, data, susp->n_susp_fields);
}
void susp_insert(struct ecma119_write_target *t,
struct iso_tree_node *node, unsigned char *data, int pos)
{
struct dir_write_info *inf = node->writer_data;
struct susp_info *susp = &inf->susp;
susp_insert_direct(t, susp, data, pos);
}
void susp_insert_self(struct ecma119_write_target *t,
struct iso_tree_dir *dir, unsigned char *data, int pos)
{
struct dir_write_info *inf = dir->writer_data;
struct susp_info *susp = &inf->self_susp;
susp_insert_direct(t, susp, data, pos);
}
void susp_insert_parent(struct ecma119_write_target *t,
struct iso_tree_dir *dir, unsigned char *data, int pos)
{
struct dir_write_info *inf = dir->writer_data;
struct susp_info *susp = &inf->parent_susp;
susp_insert_direct(t, susp, data, pos);
}
unsigned char *susp_find(struct susp_info *susp, const char *name)
{ {
int i; int i;
@ -92,11 +50,15 @@ unsigned char *susp_find(struct susp_info *susp, const char *name)
return NULL; return NULL;
} }
/* utility function for susp_add_CE because susp_add_CE needs to act 3 times /** Utility function for susp_add_CE because susp_add_CE needs to act 3 times
* on directories (for the "." and ".." entries. */ * on directories (for the "." and ".." entries.
*
* \param len The amount of space available for the System Use area.
*/
#define CE_LEN 28 #define CE_LEN 28
static unsigned char *susp_add_single_CE(struct ecma119_write_target *t, static unsigned char *susp_add_single_CE(struct ecma119_write_target *t,
struct susp_info *susp, int len) struct susp_info *susp,
int len)
{ {
int susp_length = 0, tmp_len; int susp_length = 0, tmp_len;
int i; int i;
@ -138,33 +100,36 @@ static unsigned char *susp_add_single_CE(struct ecma119_write_target *t,
return NULL; return NULL;
} }
static void
try_add_CE(struct ecma119_write_target *t,
struct susp_info *susp,
size_t dirent_len)
{
uint8_t *CE = susp_add_single_CE(t, susp, 255 - dirent_len);
if (CE)
susp_insert(t, susp, CE, susp->n_fields_fit - 1);
}
/** See IEEE P1281 Draft Version 1.12/5.2. Because this function depends on the /** See IEEE P1281 Draft Version 1.12/5.2. Because this function depends on the
* length of the other SUSP fields, it should always be calculated last. */ * length of the other SUSP fields, it should always be calculated last. */
void susp_add_CE(struct ecma119_write_target *t, struct iso_tree_node *node) void
susp_add_CE(struct ecma119_write_target *t, struct ecma119_tree_node *node)
{ {
struct dir_write_info *inf = node->writer_data; try_add_CE(t, &node->susp, node->dirent_len);
unsigned char *CE; if (node->type == ECMA119_DIR) {
try_add_CE(t, &node->dir.self_susp, 34);
CE = susp_add_single_CE(t, &inf->susp, 255 - node->dirent_len); try_add_CE(t, &node->dir.parent_susp, 34);
if (CE)
susp_insert(t, node, CE, inf->susp.n_fields_fit - 1);
if (S_ISDIR(node->attrib.st_mode)) {
CE = susp_add_single_CE(t, &inf->self_susp, 255 - 34);
if (CE)
susp_insert_self(t, (struct iso_tree_dir *)node, CE,
inf->self_susp.n_fields_fit - 1);
CE = susp_add_single_CE(t, &inf->parent_susp, 255 - 34);
if (CE)
susp_insert_parent(t, (struct iso_tree_dir *)node, CE,
inf->parent_susp.n_fields_fit - 1);
} }
} }
/** See IEEE P1281 Draft Version 1.12/5.3 */ /** See IEEE P1281 Draft Version 1.12/5.3 */
void susp_add_SP(struct ecma119_write_target *t, struct iso_tree_dir *dir) void
susp_add_SP(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
{ {
unsigned char *SP = malloc(7); unsigned char *SP = malloc(7);
assert(dir->type == ECMA119_DIR);
SP[0] = 'S'; SP[0] = 'S';
SP[1] = 'P'; SP[1] = 'P';
SP[2] = (char)7; SP[2] = (char)7;
@ -172,7 +137,7 @@ void susp_add_SP(struct ecma119_write_target *t, struct iso_tree_dir *dir)
SP[4] = 0xbe; SP[4] = 0xbe;
SP[5] = 0xef; SP[5] = 0xef;
SP[6] = 0; SP[6] = 0;
susp_append_self(t, dir, SP); susp_append(t, &dir->dir.self_susp, SP);
} }
#if 0 #if 0
@ -190,11 +155,14 @@ static void susp_add_ST(struct ecma119_write_target *t,
} }
#endif #endif
/** See IEEE P1281 Draft Version 1.12/5.5 */ /** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */
void susp_add_ER(struct ecma119_write_target *t, struct iso_tree_dir *dir) void
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
{ {
unsigned char *ER = malloc(182); unsigned char *ER = malloc(182);
assert(dir->type == ECMA119_DIR);
ER[0] = 'E'; ER[0] = 'E';
ER[1] = 'R'; ER[1] = 'R';
ER[2] = 182; ER[2] = 182;
@ -208,71 +176,71 @@ void susp_add_ER(struct ecma119_write_target *t, struct iso_tree_dir *dir)
"FILE SYSTEM SEMANTICS.", 72); "FILE SYSTEM SEMANTICS.", 72);
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, " memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
"PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93); "PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
susp_append_self(t, dir, ER); susp_append(t, &dir->dir.self_susp, ER);
}
/* calculate the location of the CE areas. Since CE areas don't need to be
* aligned to a block boundary, we contatenate all CE areas from a single
* directory and dump them immediately after all the directory records.
*
* Requires that the following be known:
* - position of the current directory (dir->block)
* - length of the current directory (dir->dir.len)
* - sum of the children's CE lengths (dir->dir.CE_len)
*/
static void
susp_fin_1_CE(struct ecma119_write_target *t,
struct susp_info *susp,
size_t block,
size_t *offset)
{
uint8_t *CE = susp->susp_fields[susp->n_fields_fit - 1];
if (!susp->CE_len) {
return;
}
iso_bb(&CE[4], block + (*offset) / t->block_size, 4);
iso_bb(&CE[12], (*offset) % t->block_size, 4);
*offset += susp->CE_len;
} }
static void susp_fin_CE(struct ecma119_write_target *t, static void susp_fin_CE(struct ecma119_write_target *t,
struct iso_tree_dir *dir) struct ecma119_tree_node *dir)
{ {
struct dir_write_info *inf = (struct dir_write_info *)
dir->writer_data;
struct node_write_info *cinf;
unsigned char *CE;
int i; int i;
int CE_offset = inf->len; size_t CE_offset = dir->dir.len;
if (inf->self_susp.CE_len) { assert(dir->type == ECMA119_DIR);
CE = inf->self_susp.susp_fields[inf->self_susp.n_fields_fit -
1];
iso_bb(&CE[4], dir->block + CE_offset / 2048, 4);
iso_bb(&CE[12], CE_offset % 2048, 4);
CE_offset += inf->self_susp.CE_len;
}
if (inf->parent_susp.CE_len) {
CE = inf->parent_susp.susp_fields[inf->parent_susp.
n_fields_fit - 1];
iso_bb(&CE[4], dir->block + CE_offset / 2048, 4);
iso_bb(&CE[12], CE_offset % 2048, 4);
CE_offset += inf->parent_susp.CE_len;
}
for (i = 0; i < dir->nchildren; i++) { susp_fin_1_CE(t, &dir->dir.self_susp, dir->block, &CE_offset);
cinf = dir->children[i]->writer_data; susp_fin_1_CE(t, &dir->dir.parent_susp, dir->block, &CE_offset);
if (!cinf->susp.CE_len) {
continue; for (i = 0; i < dir->dir.nchildren; i++) {
} struct ecma119_tree_node *ch = dir->dir.children[i];
CE = cinf->susp.susp_fields[cinf->susp.n_fields_fit - 1]; susp_fin_1_CE(t, &ch->susp, dir->block, &CE_offset);
iso_bb(&CE[4], dir->block + CE_offset / 2048, 4);
iso_bb(&CE[12], CE_offset % 2048, 4);
CE_offset += cinf->susp.CE_len;
} }
for (i = 0; i < dir->nfiles; i++) { assert(CE_offset == dir->dir.len + dir->dir.CE_len);
cinf = dir->files[i]->writer_data;
if (!cinf->susp.CE_len) {
continue;
}
CE = cinf->susp.susp_fields[cinf->susp.n_fields_fit - 1];
iso_bb(&CE[4], dir->block + CE_offset / 2048, 4);
iso_bb(&CE[12], CE_offset % 2048, 4);
CE_offset += cinf->susp.CE_len;
}
assert(CE_offset == inf->len + inf->susp_len);
} }
void susp_finalize(struct ecma119_write_target *t, struct iso_tree_dir *dir) void
susp_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
{ {
int i; int i;
if (dir->depth != 1) { assert(dir->type = ECMA119_DIR);
if (dir->dir.depth != 1) {
susp_fin_CE(t, dir); susp_fin_CE(t, dir);
} }
for (i = 0; i < dir->nchildren; i++) { for (i = 0; i < dir->dir.nchildren; i++) {
susp_finalize(t, dir->children[i]); if (dir->dir.children[i]->type == ECMA119_DIR)
susp_finalize(t, dir->dir.children[i]);
} }
} }
void susp_write(struct ecma119_write_target *t, struct susp_info *susp, void susp_write(struct ecma119_write_target *t,
struct susp_info *susp,
unsigned char *buf) unsigned char *buf)
{ {
int i; int i;

View File

@ -6,17 +6,18 @@
#ifndef __ISO_SUSP #ifndef __ISO_SUSP
#define __ISO_SUSP #define __ISO_SUSP
#include <stdint.h>
/* SUSP is only present in standard ecma119 */ /* SUSP is only present in standard ecma119 */
struct ecma119_write_target; struct ecma119_write_target;
struct iso_tree_node; struct ecma119_tree_node;
struct iso_tree_dir;
/** This contains the information that needs to go in the SUSP area of a file. /** This contains the information that needs to go in the SUSP area of a file.
*/ */
struct susp_info struct susp_info
{ {
int n_susp_fields; /**< Number of SUSP fields */ int n_susp_fields; /**< Number of SUSP fields */
unsigned char **susp_fields; /**< Data for each SUSP field */ uint8_t **susp_fields; /**< Data for each SUSP field */
/* the next 3 relate to CE and are filled out by susp_add_CE. */ /* the next 3 relate to CE and are filled out by susp_add_CE. */
int n_fields_fit; /**< How many of the above SUSP fields fit int n_fields_fit; /**< How many of the above SUSP fields fit
@ -27,48 +28,34 @@ struct susp_info
* will go in a CE area. */ * will go in a CE area. */
}; };
void susp_add_CE(struct ecma119_write_target *, struct iso_tree_node *); void susp_add_CE(struct ecma119_write_target *, struct ecma119_tree_node *);
/* these next 2 are special because they don't modify the susp fields of the /* these next 2 are special because they don't modify the susp fields of the
* directory that gets passed to them; they modify the susp fields of the * directory; they modify the susp fields of the
* "." entry in the directory. */ * "." entry in the directory. */
void susp_add_SP(struct ecma119_write_target *, struct iso_tree_dir *); void susp_add_SP(struct ecma119_write_target *, struct ecma119_tree_node *);
void susp_add_ER(struct ecma119_write_target *, struct iso_tree_dir *); void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *);
/** Once all the directories and files are laid out, recurse through the tree /** Once all the directories and files are laid out, recurse through the tree
* and finalize all SUSP CE entries. */ * and finalize all SUSP CE entries. */
void susp_finalize(struct ecma119_write_target *, struct iso_tree_dir *); void susp_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
void susp_append(struct ecma119_write_target *, void susp_append(struct ecma119_write_target *,
struct iso_tree_node *, struct susp_info *,
unsigned char *); uint8_t *);
void susp_append_self(struct ecma119_write_target *,
struct iso_tree_dir *,
unsigned char *);
void susp_append_parent(struct ecma119_write_target *,
struct iso_tree_dir *,
unsigned char *);
void susp_insert(struct ecma119_write_target *, void susp_insert(struct ecma119_write_target *,
struct iso_tree_node *, struct susp_info *,
unsigned char *, uint8_t *,
int pos); int pos);
void susp_insert_self(struct ecma119_write_target *, uint8_t *susp_find(struct susp_info *,
struct iso_tree_dir *, const char *);
unsigned char *,
int pos);
void susp_insert_parent(struct ecma119_write_target *,
struct iso_tree_dir *,
unsigned char *,
int pos);
unsigned char *susp_find(struct susp_info *,
const char *);
void susp_write(struct ecma119_write_target *, void susp_write(struct ecma119_write_target *,
struct susp_info *, struct susp_info *,
unsigned char *); uint8_t *);
void susp_write_CE(struct ecma119_write_target *, void susp_write_CE(struct ecma119_write_target *,
struct susp_info *, struct susp_info *,
unsigned char *); uint8_t *);
void susp_free_fields(struct susp_info *); void susp_free_fields(struct susp_info *);

View File

@ -1,409 +1,217 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */ /* vim: set noet ts=8 sts=8 sw=8 : */
#include <dirent.h> /**
#include <stdio.h> * \file tree.c
*
* Implement filesystem trees.
*/
#include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h> #include <time.h>
#include <assert.h> #include <dirent.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h> #include <errno.h>
#include <err.h>
#include <stdio.h>
#include "libisofs.h"
#include "tree.h" #include "tree.h"
#include "util.h" #include "util.h"
#include "volume.h" #include "volume.h"
struct iso_tree_dir *iso_tree_new_root(struct iso_volume *volume) static void
set_default_stat(struct stat *s)
{ {
struct iso_tree_dir *dir; time_t now = time(NULL);
assert(volume); memset(s, 0, sizeof(struct stat));
s->st_mode = 0777 | S_IFREG;
dir = calloc(1, sizeof(struct iso_tree_dir)); s->st_atime = s->st_mtime = s->st_ctime = now;
dir->attrib.st_mode = S_IFDIR;
dir->volume = volume;
return dir;
} }
void iso_tree_free(struct iso_tree_dir *root) static struct stat
get_attrib(const struct iso_tree_node *node)
{ {
int i;
assert(root);
/* Free names. */
free(root->name.full);
free(root->name.iso1);
free(root->name.iso2);
free(root->name.rockridge);
free(root->name.joliet);
/* Free the children. */
for (i = 0; i < root->nchildren; i++)
iso_tree_free(root->children[i]);
free(root->children);
/* Free all files. */
for (i = 0; i < root->nfiles; i++) {
struct iso_tree_file *file = root->files[i];
free(file->path);
free(file->name.full);
free(file->name.iso1);
free(file->name.iso2);
free(file->name.rockridge);
free(file->name.joliet);
free(file);
}
free(root->files);
if (root->writer_data) {
fprintf(stderr, "Warning: freeing a directory with non-NULL "
"writer_data\n");
}
/* Free ourself. */
free(root);
}
struct iso_tree_file *iso_tree_add_new_file(struct iso_tree_dir *parent,
const char *name)
{
struct iso_tree_file *file;
assert(parent && name);
file = calloc(1, sizeof(struct iso_tree_file));
file->path = calloc(1, 1);
file->parent = parent;
file->volume = parent->volume;
file->attrib = parent->attrib;
file->attrib.st_mode &= ~S_IFMT;
file->attrib.st_mode |= S_IFREG;
file->attrib.st_size = 0;
iso_tree_file_set_name(file, name);
/* Add the new file to the parent directory */
parent->nfiles++;
parent->files = realloc(parent->files, sizeof(void *) * parent->nfiles);
parent->files[parent->nfiles - 1] = file;
return file;
}
struct iso_tree_file *iso_tree_add_file(struct iso_tree_dir *parent,
const char *path)
{
struct iso_tree_file *file;
struct stat st; struct stat st;
int statret;
const char *name;
assert( parent != NULL && path != NULL ); if (node) {
statret = lstat(path, &st); return node->attrib;
if (statret == -1) {
fprintf(stderr, "couldn't stat file %s: %s\n",
path, strerror(errno));
return NULL;
} }
set_default_stat(&st);
/* Set up path, parent and volume. */ return st;
file = calloc(1, sizeof(struct iso_tree_file));
file->path = strdup(path);
file->parent = parent;
file->volume = parent->volume;
file->attrib = st;
/* find the last component in the path */
name = strrchr(path, '/');
if (name == NULL) {
name = path;
} else {
name++;
}
iso_tree_file_set_name(file, name);
if (!S_ISREG(st.st_mode)) {
file->attrib.st_size = 0;
}
/* Add the new file to the parent directory */
parent->nfiles++;
parent->files = realloc(parent->files, sizeof(void *) * parent->nfiles);
parent->files[parent->nfiles - 1] = file;
return file;
} }
struct iso_tree_dir *iso_tree_add_dir(struct iso_tree_dir *parent, static void
const char *path) append_node(struct iso_tree_node *parent,
struct iso_tree_node *child)
{ {
struct iso_tree_dir *dir; assert((!parent || S_ISDIR(parent->attrib.st_mode)) && child);
struct stat st; if (!parent)
int statret; return;
char *pathcpy;
char *name;
assert( parent && path );
statret = stat(path, &st);
if (statret == -1) {
fprintf(stderr, "couldn't stat directory %s: %s\n",
path, strerror(errno));
return NULL;
}
dir = calloc(1, sizeof(struct iso_tree_dir));
dir->parent = parent;
dir->volume = parent->volume;
dir->attrib = st;
/* find the last component in the path. We need to copy the path because
* we modify it if there is a trailing slash. */
pathcpy = strdup(path);
name = strrchr(pathcpy, '/');
if (name == &pathcpy[strlen(pathcpy) - 1]) {
/* get rid of the trailing slash */
*name = '\0';
name = strrchr(pathcpy, '/');
}
if (name == NULL) {
name = pathcpy;
} else {
name++;
}
iso_tree_dir_set_name(dir, name);
free(pathcpy);
parent->nchildren++; parent->nchildren++;
parent->children = realloc(parent->children, parent->children =
parent->nchildren * sizeof(void*)); realloc(parent->children, parent->nchildren * sizeof(void*));
parent->children[parent->nchildren - 1] = dir; parent->children[parent->nchildren-1] = child;
return dir;
} }
struct iso_tree_dir *iso_tree_radd_dir(struct iso_tree_dir *parent, struct iso_tree_node*
const char *path) iso_tree_new_root(struct iso_volume *vol)
{ {
struct iso_tree_dir *nparent; assert(vol);
if (vol->root) {
iso_tree_free(vol->root);
}
vol->root = calloc(1, sizeof(struct iso_tree_node));
vol->root->volume = vol;
set_default_stat(&vol->root->attrib);
vol->root->attrib.st_mode = S_IFDIR | 0777;
vol->root->loc.type = LIBISO_NONE;
return vol->root;
}
struct iso_tree_node*
iso_tree_add_new_file(struct iso_tree_node *parent, const char *name)
{
struct iso_tree_node *f = calloc(1, sizeof(struct iso_tree_node));
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
f->volume = parent ? parent->volume : NULL;
f->parent = parent;
f->name = parent ? towcs(name) : NULL;
f->attrib = get_attrib(parent);
f->attrib.st_mode = 0777 | S_IFREG;
f->loc.type = LIBISO_NONE;
append_node(parent, f);
return f;
}
struct iso_tree_node*
iso_tree_add_new_dir(struct iso_tree_node *parent, const char *name)
{
struct iso_tree_node *d = iso_tree_add_new_file(parent, name);
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
d->attrib.st_mode = (d->attrib.st_mode & ~S_IFMT) | S_IFDIR;
return d;
}
struct iso_tree_node*
iso_tree_add_node(struct iso_tree_node *parent, const char *path)
{
char *p;
struct stat st; struct stat st;
int statret; struct iso_tree_node *ret;
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
if (lstat(path, &st) == -1)
return NULL;
p = strdup(path); /* because basename() might modify its arg */
/* it doesn't matter if we add a file or directory since we modify
* attrib anyway. */
ret = iso_tree_add_new_file(parent, basename(p));
ret->attrib = st;
ret->loc.type = LIBISO_FILESYS;
ret->loc.path = strdup(path);
free(p);
return ret;
}
struct iso_tree_node*
iso_tree_radd_dir (struct iso_tree_node *parent, const char *path)
{
struct iso_tree_node *new;
DIR *dir; DIR *dir;
struct dirent *ent; struct dirent *ent;
assert( parent && path ); assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
statret = stat(path, &st);
nparent = iso_tree_add_dir(parent, path); new = iso_tree_add_node(parent, path);
if (!new || !S_ISDIR(new->attrib.st_mode)) {
return new;
}
/* Open the directory for reading and iterate over the directory
entries. */
dir = opendir(path); dir = opendir(path);
if (!dir) { if (!dir) {
fprintf(stderr, "couldn't open directory %s: %s\n", warn("couldn't open directory %s: %s\n", path, strerror(errno));
path, strerror(errno)); return new;
return NULL;
} }
while ((ent = readdir(dir))) { while ((ent = readdir(dir))) {
char *child; char child[strlen(ent->d_name) + strlen(path) + 2];
/* Skip current and parent directory entries. */
if (strcmp(ent->d_name, ".") == 0 || if (strcmp(ent->d_name, ".") == 0 ||
strcmp(ent->d_name, "..") == 0) strcmp(ent->d_name, "..") == 0)
continue; continue;
/* Build the child's full pathname. */ sprintf(child, "%s/%s", path, ent->d_name);
child = iso_pathname(path, ent->d_name); iso_tree_radd_dir(new, child);
/* Skip to the next entry on errors. */
if (stat(child, &st) != 0)
continue;
if (S_ISDIR(st.st_mode)) {
iso_tree_radd_dir(nparent, child);
} else {
iso_tree_add_file(nparent, child);
}
free(child);
} }
closedir(dir); closedir(dir);
return nparent; return new;
} }
struct iso_tree_dir *iso_tree_add_new_dir(struct iso_tree_dir *parent, void
const char *name) iso_tree_free(struct iso_tree_node *root)
{ {
struct iso_tree_dir *dir; size_t i;
assert( parent && name ); for (i=0; i < root->nchildren; i++) {
iso_tree_free(root->children[i]);
dir = calloc(1, sizeof(struct iso_tree_dir));
dir->parent = parent;
dir->volume = parent->volume;
iso_tree_dir_set_name(dir, name);
dir->attrib = parent->attrib;
dir->attrib.st_mtime = time(NULL);
dir->attrib.st_atime = time(NULL);
dir->attrib.st_ctime = time(NULL);
/* add the new directory to parent */
parent->nchildren++;
parent->children = realloc(parent->children,
parent->nchildren * sizeof(void*));
parent->children[parent->nchildren - 1] = dir;
return dir;
}
void iso_tree_file_set_name(struct iso_tree_file *file, const char *name)
{
file->name.full = strdup(name);
file->name.iso1 = iso_1_fileid(name);
file->name.iso2 = iso_2_fileid(name);
file->name.rockridge = iso_p_filename(name);
file->name.joliet = iso_j_id(file->name.full);
}
char *iso_tree_node_get_name_nconst(const struct iso_tree_node *node,
enum iso_name_version ver)
{
if (ver == ISO_NAME_ISO) {
if (node->volume->iso_level == 1) {
return node->name.iso1;
} else {
return node->name.iso2;
}
} }
free(root->name);
switch (ver) { free(root->children);
case ISO_NAME_FULL: free(root);
return node->name.full;
case ISO_NAME_ISO:
if (node->volume->iso_level == 1) {
return node->name.iso1;
} else {
return node->name.iso2;
}
case ISO_NAME_ISO_L1:
return node->name.iso1;
case ISO_NAME_ISO_L2:
return node->name.iso2;
case ISO_NAME_ROCKRIDGE:
return node->name.rockridge;
case ISO_NAME_JOLIET:
return (char*) node->name.joliet;
}
assert(0);
return NULL; /* just to shut up warnings */
} }
const char *iso_tree_node_get_name(const struct iso_tree_node *node, void
enum iso_name_version ver) iso_tree_print(const struct iso_tree_node *root, int spaces)
{ {
return iso_tree_node_get_name_nconst(node, ver); size_t i;
} char sp[spaces+1];
void iso_tree_dir_set_name(struct iso_tree_dir *dir, const char *name) memset(sp, ' ', spaces);
{ sp[spaces] = '\0';
dir->name.full = strdup(name);
/* Level 1 directory is a string of d-characters of maximum size 8. */
dir->name.iso1 = iso_d_str(name, 8, 0);
/* Level 2 directory is a string of d-characters of maximum size 31. */
dir->name.iso2 = iso_d_str(name, 31, 0);
dir->name.rockridge = iso_p_dirname(name);
dir->name.joliet = iso_j_id(dir->name.full);
}
/* Compares file names for use with qsort. */ printf("%s%ls\n", sp, root->name);
int iso_node_cmp(const void *v1, const void *v2) for (i=0; i < root->nchildren; i++) {
{ iso_tree_print(root->children[i], spaces+2);
struct iso_tree_node **f1 = (struct iso_tree_node **)v1;
struct iso_tree_node **f2 = (struct iso_tree_node **)v2;
return strcmp(iso_tree_node_get_name(*f1, ISO_NAME_FULL),
iso_tree_node_get_name(*f2, ISO_NAME_FULL));
}
int iso_node_cmp_iso(const void *v1, const void *v2)
{
struct iso_tree_node **f1 = (struct iso_tree_node **)v1;
struct iso_tree_node **f2 = (struct iso_tree_node **)v2;
return strcmp(iso_tree_node_get_name(*f1, ISO_NAME_ISO),
iso_tree_node_get_name(*f2, ISO_NAME_ISO));
}
int iso_node_cmp_joliet(const void *v1, const void *v2)
{
struct iso_tree_node **f1 = (struct iso_tree_node **)v1;
struct iso_tree_node **f2 = (struct iso_tree_node **)v2;
return ucscmp((uint16_t*)iso_tree_node_get_name(*f1, ISO_NAME_JOLIET),
(uint16_t*)iso_tree_node_get_name(*f2, ISO_NAME_JOLIET));
}
void iso_tree_sort(struct iso_tree_dir *root)
{
int i;
qsort(root->files, root->nfiles, sizeof(struct iso_tree_file *),
iso_node_cmp);
qsort(root->children, root->nchildren, sizeof(struct iso_tree_dir *),
iso_node_cmp);
for (i = 0; i < root->nchildren; i++)
iso_tree_sort(root->children[i]);
}
void iso_tree_print(const struct iso_tree_dir *root, int spaces)
{
iso_tree_print_verbose(root, NULL, NULL, NULL, spaces);
}
void iso_tree_print_verbose(const struct iso_tree_dir *root,
print_dir_callback dc, print_file_callback fc,
void *data, int spaces)
{
int i, j;
for (i = 0; i < spaces; i++)
printf(" ");
/* Root directory doesn't have a name. */
if (root->name.full != NULL)
printf("%s", iso_tree_node_get_name(ISO_NODE(root),
ISO_NAME_ISO));
printf("/\n");
if (dc) dc(root, data, spaces);
spaces += 2;
for (j = 0; j < root->nchildren; j++) {
iso_tree_print_verbose(root->children[j], dc, fc, data,
spaces);
}
for (j = 0; j < root->nfiles; j++) {
for (i = 0; i < spaces; i++)
printf(" ");
printf("%s\n",
iso_tree_node_get_name(ISO_NODE(root->files[j]),
ISO_NAME_ISO));
if (fc) fc(root->files[j], data, spaces);
} }
} }
void
iso_tree_print_verbose(const struct iso_tree_node *root,
print_dir_callback dir,
print_file_callback file,
void *callback_data,
int spaces)
{
size_t i;
(S_ISDIR(root->attrib.st_mode) ? dir : file)
(root, callback_data, spaces);
for (i=0; i < root->nchildren; i++) {
iso_tree_print_verbose(root->children[i], dir,
file, callback_data, spaces+2);
}
}
void
iso_tree_node_set_name(struct iso_tree_node *file, const char *name)
{
free(file->name);
file->name = towcs(name);
}

View File

@ -1,169 +1,104 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */ /* vim: set noet ts=8 sts=8 sw=8 : */
/** /**
* \file tree.h * \file tree.h
* *
* Extra declarations for use with the iso_tree_dir and iso_tree_file * Declare the structure of a libisofs filesystem tree. The files in this
* structures. * tree can come from either the local filesystem or from another .iso image
* (for multisession).
*
* This tree preserves as much information as it can about the files; names
* are stored in wchar_t and we preserve POSIX attributes. This tree does
* *not* include information that is necessary for writing out, for example,
* an ISO level 1 tree. That information will go in a different tree because
* the structure is sufficiently different.
*/ */
#ifndef __ISO_TREE #ifndef LIBISO_TREE_H
#define __ISO_TREE #define LIBISO_TREE_H
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <time.h>
#include <stdint.h> #include <stdint.h>
#include <wchar.h>
#include "libisofs.h" #include "libisofs.h"
/** enum file_location {
* File or directory names or identifiers. LIBISO_FILESYS,
*/ LIBISO_PREVSESSION,
struct iso_names LIBISO_NONE /**< for files/dirs that were added with
{ * iso_tree_add_new_XXX. */
char *full; /**< Full version: either part of the path or
user input. */
char *iso1; /**< ISO level 1 identifier. */
char *iso2; /**< ISO level 2 identifier. */
char *rockridge; /**< Rock Ridge file or directory name. */
uint16_t *joliet; /**< Joliet identifier. */
}; };
/** /**
* Directory on a volume. * This tells us where to read the data from a file. Either we read from the
* local filesystem or we just point to the block on a previous session.
*/ */
struct iso_tree_dir struct iso_file_location
{ {
struct iso_tree_dir *parent; /**< \see iso_tree_node */ enum file_location type;
struct iso_volume *volume; /**< \see iso_tree_node */ /* union {*/
struct iso_names name; /**< \see iso_tree_node */ char *path; /* in the current locale */
struct stat attrib; /**< \see iso_tree_node */ uint32_t block;
off_t block; /**< \see iso_tree_node */ /* };*/
uint8_t dirent_len; /**< \see iso_tree_node */
void *writer_data; /**< \see iso_tree_node */
int depth; /**< The depth of this directory in the
* Directory Heirarchy. This is 1 for
* the root directory.
*/
int nchildren; /**< Number of child directories. */
int nfiles; /**< Number of files in this directory.
*/
struct iso_tree_dir **children; /**< Child directories. */
struct iso_tree_file **files; /**< Files in this directory. */
}; };
/** /**
* File on a volume. * A node in the filesystem tree.
*/
struct iso_tree_file
{
struct iso_tree_dir *parent; /**< \see iso_tree_node */
struct iso_volume *volume; /**< \see iso_tree_node */
struct iso_names name; /**< \see iso_tree_node */
struct stat attrib; /**< \see iso_tree_node */
off_t block; /**< \see iso_tree_node */
uint8_t dirent_len; /**< \see iso_tree_node */
void *writer_data; /**< \see iso_tree_node */
char *path; /**< Location of the file in the
* local filesystem. This can be a
* full or relative path. If this is
* NULL, then the file doesn't exist
* in the local filesystem and its
* size must be zero.
*
* FIXME: Allow references to files
* on other volumes belonging to the
* same volset as this file.
*/
};
/**
* Fields in common between iso_tree_file and iso_tree_dir.
*/ */
struct iso_tree_node struct iso_tree_node
{ {
struct iso_tree_dir *parent; /**< The parent of this node. Must be struct iso_volume *volume;
* non-NULL unless we are the struct iso_tree_node *parent;
* root directory on a volume. wchar_t *name;
*/ struct stat attrib; /**< The POSIX attributes of this node as
struct iso_volume *volume; /**< The volume to which this node * documented in "man 2 stat". */
* belongs. struct iso_file_location loc;
*/ /**< Only used for regular files and symbolic
struct iso_names name; /**< The name of this node in its parent * links (ie. files for which we might have to
* directory. Must be non-NULL unless * copy data). */
* we are the root directory on a
* volume.
*/
struct stat attrib; /**< The POSIX attributes of this
* node as documented in "man 2 stat".
*
* Any node that is not a regular
* file or a directory must have
* \p attrib.st_size set to zero. Any
* node that is a directory will have
* \p attrib.st_size filled out by the
* writer.
*/
/* information used for writing */ size_t nchildren; /**< The number of children of this
off_t block; /**< The block at which this node's * directory (if this is a directory). */
* data will be written. struct iso_tree_node **children;
*/
uint8_t dirent_len; /**< The size of this node's size_t block; /**< The block at which this file will
* Directory Record in its parent. * reside on disk. We store this here as
* This does not include System Use * well as in the various mangled trees
* fields, if present. * because many different trees might point
*/ * to the same file and they need to share the
void *writer_data; /**< This is writer-specific data. It * block location. */
* must be set to NULL when a node
* is created and it should be NULL
* again when the node is freed.
*/
}; };
/** A macro to simplify casting between nodes and files/directories. */
#define ISO_NODE(a) ( (struct iso_tree_node*) (a) )
/** A macro to simplify casting between nodes and directories. */
#define ISO_DIR(a) ( (struct iso_tree_dir*) (a) )
/** A macro to simplify casting between nodes and files. */
#define ISO_FILE(a) ( (struct iso_tree_file*) (a) )
/** /**
* Create a new root directory for a volume. * Create a new root directory for a volume.
* *
* \param volume The volume for which to create a new root directory. * \param vol The volume for which to create a new root directory.
* *
* \pre \p volume is non-NULL. * \pre \p vol is non-NULL.
* \post \p volume has a non-NULL, empty root directory. * \post \p vol has a non-NULL, empty root directory with permissions 777.
* \return \p volume's new non-NULL, empty root directory. * \return \p vol's new non-NULL, empty root directory.
*/ */
struct iso_tree_dir *iso_tree_new_root(struct iso_volume *volume); struct iso_tree_node *iso_tree_new_root(struct iso_volume *vol);
/** /**
* Create a new, empty, file. * Create a new, empty, file.
* *
* \param parent The parent of the new file. * \param parent The parent directory of the new file. If this is null, create
* and return a new file node without adding it to any tree.
* \param name The name of the new file, encoded in the current locale. * \param name The name of the new file, encoded in the current locale.
*
* \pre \p parent is non-NULL.
* \pre \p name is non-NULL and it does not match any other file or directory * \pre \p name is non-NULL and it does not match any other file or directory
* name in \p parent. * name in \p parent.
* \post \p parent contains a file with the following properties: * \post \p parent (if non-NULL) contains a file with the following properties:
* - the file's (full) name is \p name * - the file's name is \p name (converted to wchar_t)
* - the file's POSIX permissions are the same as \p parent's * - the file's POSIX permissions are the same as \p parent's
* - the file is a regular file * - the file is a regular file
* - the file is empty * - the file is empty
* *
* \return \p parent's newly created file. * \return \p parent's newly created file.
*/ */
struct iso_tree_file *iso_tree_add_new_file(struct iso_tree_dir *parent, struct iso_tree_node *iso_tree_add_new_file(struct iso_tree_node *parent,
const char *name); const char *name);
/** /**
@ -173,37 +108,7 @@ struct iso_tree_file *iso_tree_add_new_file(struct iso_tree_dir *parent,
* *
* \pre \p root is non-NULL. * \pre \p root is non-NULL.
*/ */
void iso_tree_free(struct iso_tree_dir *root); void iso_tree_free(struct iso_tree_node *root);
/**
* Recursively sort all the files and child directories in a directory.
*
* \param root The root of the directory heirarchy to sort.
*
* \pre \p root is non-NULL.
* \post For each directory \p dir in the directory heirarchy descended fro
* root, the fields in \p dir.children and \p dir.files are alphabetically
* sorted according to \p name.full.
*
* \see iso_names
*/
void iso_tree_sort(struct iso_tree_dir *root);
/**
* Compare the names of 2 nodes, \p *v1 and \p *v2. This is compatible with
* qsort.
*/
int iso_node_cmp(const void *v1, const void *v2);
/**
* Compare the joliet names of 2 nodes, compatible with qsort.
*/
int iso_node_cmp_joliet(const void *v1, const void *v2);
/**
* Compare the iso names of 2 nodes, compatible with qsort.
*/
int iso_node_cmp_iso(const void *v1, const void *v2);
/** /**
* A function that prints verbose information about a directory. * A function that prints verbose information about a directory.
@ -214,7 +119,7 @@ int iso_node_cmp_iso(const void *v1, const void *v2);
* *
* \see iso_tree_print_verbose * \see iso_tree_print_verbose
*/ */
typedef void (*print_dir_callback) (const struct iso_tree_dir *dir, typedef void (*print_dir_callback) (const struct iso_tree_node *dir,
void *data, void *data,
int spaces); int spaces);
/** /**
@ -226,7 +131,7 @@ typedef void (*print_dir_callback) (const struct iso_tree_dir *dir,
* *
* \see iso_tree_print_verbose * \see iso_tree_print_verbose
*/ */
typedef void (*print_file_callback) (const struct iso_tree_file *file, typedef void (*print_file_callback) (const struct iso_tree_node *file,
void *data, void *data,
int spaces); int spaces);
@ -243,17 +148,12 @@ typedef void (*print_file_callback) (const struct iso_tree_file *file,
* \pre \p root is not NULL. * \pre \p root is not NULL.
* \pre Neither of the callback functions modifies the directory heirarchy. * \pre Neither of the callback functions modifies the directory heirarchy.
*/ */
void iso_tree_print_verbose(const struct iso_tree_dir *root, void iso_tree_print_verbose(const struct iso_tree_node *root,
print_dir_callback dir, print_dir_callback dir,
print_file_callback file, print_file_callback file,
void *callback_data, void *callback_data,
int spaces); int spaces);
/** #define ISO_ISDIR(n) S_ISDIR(n->attrib.st_mode)
* Get a non-const version of the node name. This is used for name-mangling
* iso names. It should only be used internally in libisofs; all other users #endif /* LIBISO_TREE_H */
* should only access the const name.
*/
char *iso_tree_node_get_name_nconst(const struct iso_tree_node *node,
enum iso_name_version ver);
#endif /* __ISO_TREE */

View File

@ -1,136 +1,190 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set ts=8 sts=8 sw=8 noet : */ /* vim: set noet ts=8 sts=8 sw=8 : */
#include <ctype.h> /**
* Utility functions for the Libisofs library.
*/
#include <wchar.h>
#include <iconv.h> #include <iconv.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdio.h>
#include <langinfo.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <errno.h>
#include "util.h" #include "util.h"
int valid_d_char(char c) 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;
}
wchar_t *towcs(const char *str)
{
size_t len = strlen(str);
wchar_t *ret = malloc(sizeof(wchar_t) * (len + 1));
mbstate_t ps;
size_t n;
memset(&ps, 0, sizeof(ps));
n = mbsrtowcs(ret, &str, len, &ps);
ret[len] = '\0';
if (n != len) {
free(ret);
return NULL;
}
return ret;
}
char *wcstoascii(const wchar_t *wsrc)
{
if (!wsrc)
return NULL;
iconv_t conv = iconv_open("ASCII", "WCHAR_T");
size_t outbytes = wcslen(wsrc);
size_t inbytes = outbytes * sizeof(wchar_t);
char src_[inbytes + sizeof(wchar_t)];
char *src = src_;
char *ret_, *ret;
size_t n;
if (conv == (iconv_t)-1)
return NULL;
memcpy(src, wsrc, inbytes + sizeof(wchar_t));
ret = malloc(outbytes+1);
ret[outbytes] = '\0';
ret_ = ret;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
if (n == -1) {
free(ret_);
return NULL;
}
return ret_;
}
/* FIXME: C&P */
uint16_t *wcstoucs(const wchar_t *wsrc)
{
if (!wsrc)
return calloc(2, 1); /* empty UCS string */
iconv_t conv = iconv_open("UCS-2BE", "WCHAR_T");
size_t outbytes = wcslen(wsrc) * 2;
size_t inbytes = outbytes * sizeof(wchar_t) / 2;
char src_[inbytes + sizeof(wchar_t)];
char *src = src_;
char *ret_, *ret;
size_t n;
if (conv == (iconv_t)-1)
return calloc(2, 1);
memcpy(src, wsrc, inbytes + sizeof(wchar_t));
ret = malloc(outbytes + sizeof(wchar_t));
ret[outbytes] = 0;
ret[outbytes+1] = 0;
ret_ = ret;
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
if (n == -1) {
perror ("error in iconv conversion");
free(ret_);
return calloc(2, 1);
}
return (uint16_t*)ret_;
}
static int valid_d_char(char c)
{ {
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_'); return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
} }
int valid_a_char(char c) static int valid_a_char(char c)
{ {
return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?') || (c >= 'A' && return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?')
c <= 'Z') || (c >= 'A' && c <= 'Z')
|| (c == '_'); || (c == '_');
} }
int valid_j_char(char msb, char lsb) static int valid_j_char(uint16_t c)
{ {
return !(msb == '\0' && return !(c < (uint16_t)' ' || c == (uint16_t)'*' || c == (uint16_t)'/'
(lsb < ' ' || lsb == '*' || lsb == '/' || lsb == ':' || || c == (uint16_t)':' || c == (uint16_t)';'
lsb == ';' || lsb == '?' || lsb == '\\')); || c == (uint16_t)'?' || c == (uint16_t)'\\');
} }
int valid_p_char(char c) /* FIXME: where are these documented? */
static int valid_p_char(char c)
{ {
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
c <= 'z') || (c >= 'a' && c <= 'z')
|| (c == '.') || (c == '_') || (c == '-'); || (c == '.') || (c == '_') || (c == '-');
} }
char *iso_d_str(const char *src, int size, int pad) static char *iso_dirid(const wchar_t *src, int size)
{ {
char *dest = strlen(src) > size || char *ret = wcstoascii(src);
pad ? malloc(size + 1) : malloc(strlen(src) + 1); size_t len, i;
int i;
/* Try converting to upper-case before validating. */ if (!ret)
for (i = 0; i < size && src[i]; i++) {
char c = toupper(src[i]);
dest[i] = valid_d_char(c) ? c : '_';
}
/* Optionally pad with spaces and terminate with NULL. */
if (pad)
while (i < size)
dest[i++] = ' ';
dest[i] = '\0';
return dest;
}
char *iso_a_str(const char *src, int size)
{
char *dest = malloc(size + 1);
int i;
for (i = 0; i < size && src[i]; i++) {
char c = toupper(src[i]);
dest[i] = valid_a_char(c) ? c : '_';
}
while (i < size)
dest[i++] = ' ';
dest[i] = '\0';
return dest;
}
uint16_t *iso_j_str(const char *src)
{
int size = strlen(src) * 2;
uint16_t *dest = malloc(size + 2);
char *cpy, *in, *out;
size_t inleft, outleft;
iconv_t cd;
/* If the conversion is unavailable, return NULL. Obviously,
nl_langinfo(..) requires the locale to be set correctly. */
cd = iconv_open("UCS-2BE", nl_langinfo(CODESET));
if (cd == (iconv_t) - 1) {
free(dest);
return NULL; return NULL;
len = strlen(ret);
if (len > size) {
ret[size] = '\0';
len = size;
}
for (i = 0; i < len; i++) {
char c = toupper(ret[i]);
ret[i] = valid_d_char(c) ? c : '_';
} }
/* In, out, inleft and outleft will be updated by iconv, that's why we return ret;
need separate variables. */
cpy = strdup(src); /* iconv doesn't take const * chars, so we need our
* own copy. */
in = cpy;
out = (char*)dest;
inleft = strlen(cpy);
outleft = size;
iconv(cd, &in, &inleft, &out, &outleft);
/* Since we need to pad with NULLs, we can pad up to and including the
terminating NULLs. */
outleft += 2;
while (outleft) {
*out++ = '\0';
outleft--;
}
iconv_close(cd);
free(cpy);
return dest;
} }
char *iso_1_fileid(const char *src) char *iso_1_dirid(const wchar_t *src)
{ {
char *dest = malloc(15); /* 15 = 8 (name) + 1 (.) + 3 (ext) + 2 return iso_dirid(src, 8);
(;1) + 1 (\0) */ }
char *dot = strrchr(src, '.'); /* Position of the last dot in the
char *iso_2_dirid(const wchar_t *src)
{
return iso_dirid(src, 31);
}
char *iso_1_fileid(const wchar_t *wsrc)
{
char *src = wcstoascii(wsrc);
char *dest;
char *dot; /* Position of the last dot in the
filename, will be used to calculate filename, will be used to calculate
lname and lext. */ lname and lext. */
int lname, lext, pos, i; int lname, lext, pos, i;
if (!src)
return NULL;
dest = malloc(15); /* 15 = 8 (name) + 1 (.) + 3 (ext) + 2
(;1) + 1 (\0) */
dot = strrchr(src, '.');
lext = dot ? strlen(dot + 1) : 0; lext = dot ? strlen(dot + 1) : 0;
lname = strlen(src) - lext - (dot ? 1 : 0); lname = strlen(src) - lext - (dot ? 1 : 0);
/* If we can't build a filename, return NULL. */ /* If we can't build a filename, return NULL. */
if (lname == 0 && lext == 0) { if (lname == 0 && lext == 0) {
free(src);
free(dest); free(dest);
return NULL; return NULL;
} }
@ -156,16 +210,24 @@ char *iso_1_fileid(const char *src)
dest[pos] = '\0'; dest[pos] = '\0';
dest = (char *)realloc(dest, pos + 1); dest = (char *)realloc(dest, pos + 1);
free(src);
return dest; return dest;
} }
char *iso_2_fileid(const char *src) char *iso_2_fileid(const wchar_t *wsrc)
{ {
char *dest = malloc(34); /* 34 = 30 (name + ext) + 1 (.) + 2 char *src = wcstoascii(wsrc);
(;1) + 1 (\0) */ char *dest;
char *dot = strrchr(src, '.'); char *dot;
int lname, lext, lnname, lnext, pos, i; int lname, lext, lnname, lnext, pos, i;
if (!src)
return NULL;
dest = malloc(34); /* 34 = 30 (name + ext) + 1 (.) + 2
(;1) + 1 (\0) */
dot = strrchr(src, '.');
/* Since the maximum length can be divided freely over the name and /* Since the maximum length can be divided freely over the name and
extension, we need to calculate their new lengths (lnname and extension, we need to calculate their new lengths (lnname and
lnext). If the original filename is too long, we start by trimming lnext). If the original filename is too long, we start by trimming
@ -177,12 +239,13 @@ char *iso_2_fileid(const char *src)
} else { } else {
lext = strlen(dot + 1); lext = strlen(dot + 1);
lname = strlen(src) - lext - 1; lname = strlen(src) - lext - 1;
lnext = (strlen(src) > 31 && lnext = (strlen(src) > 31 && lext > 3)
lext > 3) ? (lname < 27 ? 30 - lname : 3) : lext; ? (lname < 27 ? 30 - lname : 3) : lext;
lnname = (strlen(src) > 31) ? 30 - lnext : lname; lnname = (strlen(src) > 31) ? 30 - lnext : lname;
} }
if (lnname == 0 && lnext == 0) { if (lnname == 0 && lnext == 0) {
free(src);
free(dest); free(dest);
return NULL; return NULL;
} }
@ -206,276 +269,43 @@ char *iso_2_fileid(const char *src)
dest[pos] = '\0'; dest[pos] = '\0';
dest = (char *)realloc(dest, pos + 1); dest = (char *)realloc(dest, pos + 1);
free(src);
return dest; return dest;
} }
uint16_t *iso_j_id(char *src) char *
iso_p_fileid(const wchar_t *src)
{ {
char *dest = malloc(136); /* 136 = 128 (name + ext) + 2 (\0 .) + char *ret = wcstoascii(src);
4 (\0 ; \0 1) + 2 (\0 \0) */ size_t i, len;
char *dot = strrchr(src, '.');
int lname, lext, lcname, lcext, lnname, lnext, pos, i;
size_t inleft, outleft;
char *cname, *cext, *in, *out;
iconv_t cd;
if (dot == NULL || dot == src || *(dot + 1) == '\0') { if (!ret)
lname = strlen(src);
lext = 0;
} else {
lext = strlen(dot + 1);
lname = strlen(src) - lext - 1;
}
if (lname == 0 && lext == 0) {
free(dest);
return NULL; return NULL;
} len = strlen(ret);
for (i = 0; i < len; i++) {
cd = iconv_open("UCS-2BE", nl_langinfo(CODESET)); if (!valid_p_char(ret[i])) {
if (cd == (iconv_t) - 1) { ret[i] = (uint16_t)'_';
free(dest);
return NULL;
}
/* We need to convert the name and extension first, in order to
calculate the number of characters they have. */
cname = malloc(lname * 2);
in = src;
out = cname;
inleft = lname;
outleft = lname * 2;
iconv(cd, &in, &inleft, &out, &outleft);
lcname = (lname * 2) - outleft;
iconv_close(cd);
if (lext) {
cd = iconv_open("UCS-2BE", nl_langinfo(CODESET));
if (cd == (iconv_t) - 1) {
free(dest);
free(cname);
return NULL;
} }
cext = malloc(lext * 2); }
in = dot + 1; return ret;
out = cext;
inleft = lext;
outleft = lext * 2;
iconv(cd, &in, &inleft, &out, &outleft);
lcext = (lext * 2) - outleft;
iconv_close(cd);
} else
lcext = 0;
/* Again, divide the available characters over name and extension, but
keep a minimum of three characters for the new extension. */
lnext = (lcname + lcext > 128 &&
lcext > 6) ? (lcname < 122 ? 128 - lcname : 6) : lcext;
lnname = (lcname + lcext > 128) ? 128 - lnext : lcname;
pos = 0;
/* Copy up to lnname bytes from the converted filename. */
for (i = 0; i < lnname; i = i + 2)
if (valid_j_char(cname[i], cname[i + 1])) {
dest[pos++] = cname[i];
dest[pos++] = cname[i + 1];
} else {
dest[pos++] = '\0';
dest[pos++] = '_';
}
/* Dot is now a 16 bit separator. */
dest[pos++] = '\0';
dest[pos++] = '.';
/* Copy up to lnext bytes from the converted extension, if any. */
for (i = 0; i < lnext; i = i + 2)
if (valid_j_char(cext[i], cext[i + 1])) {
dest[pos++] = cext[i];
dest[pos++] = cext[i + 1];
} else {
dest[pos++] = '\0';
dest[pos++] = '_';
}
/* Again, 2 bytes per character. */
dest[pos++] = '\0';
dest[pos++] = ';';
dest[pos++] = '\0';
dest[pos++] = '1';
dest[pos++] = '\0';
dest[pos] = '\0';
dest = (char *)realloc(dest, pos + 1);
free(cname);
if (lext)
free(cext);
/* Fill in the size in bytes (including the terminating NULLs) of the
destination string. */
return (uint16_t *) dest;
} }
char *iso_p_filename(const char *src) uint16_t *
iso_j_id(const wchar_t *src)
{ {
char *dest = malloc(251); /* We can fit up to 250 characters in uint16_t *j_str = wcstoucs(src);
a Rock Ridge name entry. */ size_t len = ucslen(j_str);
char *dot = strrchr(src, '.'); size_t n;
int lname, lext, lnname, lnext, pos, i;
if (dot == NULL || dot == src || *(dot + 1) == '\0') { if (len > 128) {
lname = strlen(src); j_str[128] = '\0';
lnname = (lname > 250) ? 250 : lname; len = 128;
lext = lnext = 0;
} else {
lext = strlen(dot + 1);
lname = strlen(src) - lext - 1;
lnext = (strlen(src) > 250 &&
lext > 3) ? (lname < 246 ? 249 - lname : 3) : lext;
lnname = (strlen(src) > 250) ? 249 - lnext : lname;
} }
if (lnname == 0 && lnext == 0) { for (n = 0; n < len; n++)
free(dest); if (!valid_j_char(j_str[n]))
return NULL; j_str[n] = '_';
} return j_str;
pos = 0;
for (i = 0; i < lnname; i++)
dest[pos++] = valid_p_char(src[i]) ? src[i] : '_';
if (lnext) {
dest[pos++] = '.';
for (i = 0; i < lnext; i++)
dest[pos++] =
valid_p_char(src[lname + 1 + i]) ?
src[lname + 1 + i] : '_';
}
dest[pos] = '\0';
dest = (char *)realloc(dest, pos + 1);
return dest;
}
char *iso_p_dirname(const char *src)
{
char *dest = strlen(src) > 250 ? malloc(251) : malloc(strlen(src) + 1);
int i;
if (strlen(src) == 0) {
free(dest);
return NULL;
}
for (i = 0; i < 250 && src[i]; i++)
dest[i] = valid_p_char(src[i]) ? src[i] : '_';
dest[i] = '\0';
return dest;
}
char *iso_pathname(const char *dir, const char *file)
{
char *path = malloc(strlen(dir) + strlen(file) + 2);
strcpy(path, dir);
path[strlen(dir)] = '/';
strcpy(path + strlen(dir) + 1, file);
return path;
}
void iso_a_strcpy(unsigned char *dest, int size, const char *src)
{
int i = 0, d = 0;
if (src)
for (; i < size && *src; ++i, ++src) {
char s = toupper(*src);
if (valid_a_char(s))
dest[d++] = s;
else
dest[d++] = '_';
}
for (; i < size; ++i) {
/* pad with spaces */
dest[d++] = ' ';
}
}
void iso_d_strcpy(unsigned char *dest, int size, const char *src)
{
int i = 0, d = 0;
if (src)
for (; i < size && *src; ++i, ++src) {
char s = toupper(*src);
if (valid_d_char(s))
dest[d++] = s;
else
dest[d++] = '_';
}
for (; i < size; ++i) {
/* pad with spaces */
dest[d++] = ' ';
}
}
char *iso_a_strndup(const char *src, int size)
{
int i, d;
char *out;
out = malloc(size + 1);
for (i = d = 0; i < size && *src; ++i, ++src) {
char s = toupper(*src);
if (valid_a_char(s))
out[d++] = s;
else
out[d++] = '_';
}
out[d++] = '\0';
out = realloc(out, d); /* shrink the buffer to what we used */
return out;
}
char *iso_d_strndup(const char *src, int size)
{
int i, d;
char *out;
out = malloc(size + 1);
for (i = d = 0; i < size && *src; ++i, ++src) {
char s = toupper(*src);
if (valid_d_char(s))
out[d++] = s;
else
out[d++] = '_';
}
out[d++] = '\0';
out = realloc(out, d); /* shrink the buffer to what we used */
return out;
}
char *iso_strconcat(char sep, const char *a, const char *b)
{
char *out;
int la, lb;
la = strlen(a);
lb = strlen(b);
out = malloc(la + lb + 1 + (sep ? 1 : 0));
memcpy(out, a, la);
memcpy(out + la + (sep ? 1 : 0), b, lb);
if (sep)
out[la] = sep;
out[la + lb + (sep ? 1 : 0)] = '\0';
return out;
}
char *iso_strdup(const char *src)
{
return src ? strdup(src) : NULL;
} }
void iso_lsb(uint8_t *buf, uint32_t num, int bytes) void iso_lsb(uint8_t *buf, uint32_t num, int bytes)
@ -551,7 +381,6 @@ void iso_datetime_17(unsigned char *buf, time_t t)
static int tzsetup = 0; static int tzsetup = 0;
static int tzoffset; static int tzoffset;
struct tm tm; struct tm tm;
char c[5];
if (t == (time_t) - 1) { if (t == (time_t) - 1) {
/* unspecified time */ /* unspecified time */
@ -570,27 +399,13 @@ void iso_datetime_17(unsigned char *buf, time_t t)
localtime_r(&t, &tm); localtime_r(&t, &tm);
/* year */ sprintf((char*)&buf[0], "%04d", tm.tm_year + 1900);
sprintf(c, "%04d", tm.tm_year + 1900); sprintf((char*)&buf[4], "%02d", tm.tm_mon + 1);
memcpy(&buf[0], c, 4); sprintf((char*)&buf[6], "%02d", tm.tm_mday);
/* month */ sprintf((char*)&buf[8], "%02d", tm.tm_hour);
sprintf(c, "%02d", tm.tm_mon + 1); sprintf((char*)&buf[10], "%02d", tm.tm_min);
memcpy(&buf[4], c, 2); sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec));
/* day */
sprintf(c, "%02d", tm.tm_mday);
memcpy(&buf[6], c, 2);
/* hour */
sprintf(c, "%02d", tm.tm_hour);
memcpy(&buf[8], c, 2);
/* minute */
sprintf(c, "%02d", tm.tm_min);
memcpy(&buf[10], c, 2);
/* second */
sprintf(c, "%02d", MIN(59, tm.tm_sec));
memcpy(&buf[12], c, 2);
/* hundreths */
memcpy(&buf[14], "00", 2); memcpy(&buf[14], "00", 2);
/* timezone */
buf[16] = tzoffset; buf[16] = tzoffset;
} }
} }
@ -611,47 +426,6 @@ time_t iso_datetime_read_17(const uint8_t *buf)
return mktime(&tm) - buf[16] * 60 * 60; return mktime(&tm) - buf[16] * 60 * 60;
} }
void iso_split_filename(char *name, char **ext)
{
char *r;
r = strrchr(name, '.');
if (r) {
*r = '\0';
*ext = r + 1;
} else
*ext = "";
}
void iso_filecpy(unsigned char *buf, int size, const char *name, int version)
{
char v[6];
int nl, vl;
assert(version >= 0);
assert(version < 0x8000);
nl = strlen(name);
memcpy(buf, name, nl);
if (!version)
assert(size >= strlen(name));
else {
sprintf(v, "%d", version);
vl = strlen(v);
assert(size >= nl + vl + 1);
buf[nl] = ';';
memcpy(&buf[nl + 1], v, vl);
nl += vl + 1;
}
/* pad with spaces */
if (nl < size)
memset(&buf[nl], ' ', size - nl);
}
size_t ucslen(const uint16_t *str) size_t ucslen(const uint16_t *str)
{ {
int i; int i;
@ -661,20 +435,30 @@ size_t ucslen(const uint16_t *str)
return i; return i;
} }
/**
* Although each character is 2 bytes, we actually compare byte-by-byte
* (thats what the spec says).
*/
int ucscmp(const uint16_t *s1, const uint16_t *s2) int ucscmp(const uint16_t *s1, const uint16_t *s2)
{ {
int i; const char *s = (const char*)s1;
const char *t = (const char*)s2;
size_t len1 = ucslen(s1);
size_t len2 = ucslen(s2);
size_t i, len = MIN(len1, len2) * 2;
for (i=0; 1; i++) { for (i=0; i < len; i++) {
if (s1[i] < s2[i]) { if (s[i] < t[i]) {
return -1; return -1;
} else if (s1[i] > s2[i]) { } else if (s[i] > t[i]) {
return 1; return 1;
} else if (s1[i] == 0 && s2[i] == 0) {
break;
} }
} }
if (len1 < len2)
return -1;
else if (len1 > len2)
return 1;
return 0; return 0;
} }

View File

@ -1,122 +1,95 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* vim: set noet ts=8 sts=8 sw=8 : */
/** /**
* Utility functions for the Libisofs library. * Utility functions for the Libisofs library.
*/ */
#ifndef __ISO_UTIL #ifndef LIBISO_UTIL_H
#define __ISO_UTIL #define LIBISO_UTIL_H
#include <stdint.h> #include <stdint.h>
#include <time.h>
#include <wchar.h>
#ifndef MAX
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef MIN
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
extern inline int div_up(int n, int div)
{
return (n + div - 1) / div;
}
extern inline int round_up(int n, int mul)
{
return div_up(n, mul) * mul;
}
wchar_t *towcs(const char *);
char *wcstoascii(const wchar_t *);
uint16_t *wcstoucs(const wchar_t*);
/** /**
* Checks if the given character is a valid d-character. * Create a level 1 directory identifier.
*/ */
int valid_d_char(char c); char *iso_1_dirid(const wchar_t *src);
/** /**
* Checks if the given character is a valid a-character. * Create a level 2 directory identifier.
*/ */
int valid_a_char(char c); char *iso_2_dirid(const wchar_t *src);
/** /**
* Checks if the given character is part of the Joliet Allowed Character Set. * Create a level 1 file identifier that consists of a name, extension and
*/ * version number. The resulting string will have a file name of maximum
int valid_j_char(char msb, char lsb); * length 8, followed by a separator (.), an optional extension of maximum
* length 3, followed by a separator (;) and a version number (digit 1).
/**
* Checks if the given character is part of the POSIX Portable Filename Character Set.
*/
int valid_p_char(char c);
/**
* Build a string of d-characters of maximum size 'size', optionally padded with spaces if necessary.
* Can be used to create directory identifiers if padding is turned off.
*/
char *iso_d_str(const char *src, int size, int pad);
/**
* Build a string of a-characters of maximum size 'size', padded with spaces if necessary.
*/
char *iso_a_str(const char *src, int size);
/**
* Build a string of j-characters of maximum size 'size', padded with NULLs if necessary.
* Requires the locale to be set correctly.
* @return NULL if the conversion from the current codeset to UCS-2BE is not available.
*/
uint16_t *iso_j_str(const char *src);
/**
* Create a level 1 file identifier that consists of a name, extension and version number.
* The resulting string will have a file name of maximum length 8, followed by a separator (.),
* an optional extension of maximum length 3, followed by a separator (;) and a version number (digit 1).
* @return NULL if the original name and extension both are of length 0. * @return NULL if the original name and extension both are of length 0.
*/ */
char *iso_1_fileid(const char *src); char *iso_1_fileid(const wchar_t *src);
/** /**
* Create a level 2 file identifier that consists of a name, extension and version number. * Create a level 2 file identifier that consists of a name, extension and
* The combined file name and extension length will not exceed 30, the name and extension will be separated (.), * version number. The combined file name and extension length will not exceed
* and the extension will be followed by a separator (;) and a version number (digit 1). * 30, the name and extension will be separated (.), and the extension will be
* followed by a separator (;) and a version number (digit 1).
* @return NULL if the original name and extension both are of length 0. * @return NULL if the original name and extension both are of length 0.
*/ */
char *iso_2_fileid(const char *src); char *iso_2_fileid(const wchar_t *src);
/** /**
* Create a Joliet file or directory identifier that consists of a name, extension and version number. * Create a Joliet file or directory identifier that consists of a name,
* The combined name and extension length will not exceed 128 bytes, the name and extension will be separated (.), * extension and version number. The combined name and extension length will
* and the extension will be followed by a separator (;) and a version number (digit 1). * not exceed 128 bytes, the name and extension will be separated (.),
* All characters consist of 2 bytes and the resulting string is NULL-terminated by a 2-byte NULL. * and the extension will be followed by a separator (;) and a version number
* Requires the locale to be set correctly. * (digit 1). All characters consist of 2 bytes and the resulting string is
* NULL-terminated by a 2-byte NULL. Requires the locale to be set correctly.
*
* @param size will be set to the size (in bytes) of the identifier. * @param size will be set to the size (in bytes) of the identifier.
* @return NULL if the original name and extension both are of length 0 or the conversion from the current codeset to UCS-2BE is not available. * @return NULL if the original name and extension both are of length 0 or the conversion from the current codeset to UCS-2BE is not available.
*/ */
uint16_t *iso_j_id(char *src); uint16_t *iso_j_id(const wchar_t *src);
/** /**
* FIXME: what are the requirements for these next two? Is this for RR?
*
* Create a POSIX portable file name that consists of a name and extension. * Create a POSIX portable file name that consists of a name and extension.
* The resulting file name will not exceed 250 characters. * The resulting file name will not exceed 250 characters.
* @return NULL if the original name and extension both are of length 0. * @return NULL if the original name and extension both are of length 0.
*/ */
char *iso_p_filename(const char *src); char *iso_p_fileid(const wchar_t *src);
/** /**
* Create a POSIX portable directory name. * Create a POSIX portable directory name.
* The resulting directory name will not exceed 250 characters. * The resulting directory name will not exceed 250 characters.
* @return NULL if the original name is of length 0. * @return NULL if the original name is of length 0.
*/ */
char *iso_p_dirname(const char *src); char *iso_p_dirid(const wchar_t *src);
/**
* Build a pathname out of a directory and file name.
*/
char *iso_pathname(const char *dir, const char *file);
#include <time.h>
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
/** Copy a string of a-characters, padding the unused part of the
destination buffer */
void iso_a_strcpy(unsigned char *dest, int size, const char *src);
/** Copy a string of d-characters, padding the unused part of the
destination buffer */
void iso_d_strcpy(unsigned char *dest, int size, const char *src);
/** Returns a null terminated string containing the first 'size' a-characters
from the source */
char *iso_a_strndup(const char *src, int size);
/** Returns a null terminated string containing the first 'size' d-characters
from the source */
char *iso_d_strndup(const char *src, int size);
char *iso_strconcat(char sep, const char *a, const char *b);
char *iso_strdup(const char *src);
void iso_lsb(uint8_t *buf, uint32_t num, int bytes); void iso_lsb(uint8_t *buf, uint32_t num, int bytes);
void iso_msb(uint8_t *buf, uint32_t num, int bytes); void iso_msb(uint8_t *buf, uint32_t num, int bytes);
@ -127,30 +100,22 @@ uint32_t iso_read_msb(const uint8_t *buf, int bytes);
uint32_t iso_read_bb(const uint8_t *buf, int bytes); uint32_t iso_read_bb(const uint8_t *buf, int bytes);
/** Records the date/time into a 7 byte buffer (9.1.5) */ /** Records the date/time into a 7 byte buffer (9.1.5) */
void iso_datetime_7(unsigned char *buf, time_t t); void iso_datetime_7(uint8_t *buf, time_t t);
/** Records the date/time into a 17 byte buffer (8.4.26.1) */ /** Records the date/time into a 17 byte buffer (8.4.26.1) */
void iso_datetime_17(unsigned char *buf, time_t t); void iso_datetime_17(uint8_t *buf, time_t t);
time_t iso_datetime_read_7(const uint8_t *buf); time_t iso_datetime_read_7(const uint8_t *buf);
time_t iso_datetime_read_17(const uint8_t *buf); time_t iso_datetime_read_17(const uint8_t *buf);
/** Removes the extension from the name, and returns the extension. The /**
returned extension should _not_ be freed! */ * Like strlen, but for Joliet strings.
void iso_split_filename(char *name, char **ext); */
size_t ucslen(const uint16_t *str);
void iso_filecpy(unsigned char *buf, int size, const char *name, int version); /**
* Like strcmp, but for Joliet strings.
*/
int ucscmp(const uint16_t *s1, const uint16_t *s2);
int iso_filename_len(const char *name, int iso_level); #endif /* LIBISO_UTIL_H */
/* replacement for strlen for joliet names (wcslen doesn't work on machines
* with 32-bit wchar_t */
size_t ucslen(const uint16_t *);
/* replacement for strcmp for joliet names */
int ucscmp(const uint16_t*, const uint16_t*);
#define DIV_UP(n,div) ( ((n)+(div)-1) / (div) )
#define ROUND_UP(n,mul) ( DIV_UP(n,mul) * (mul) )
#endif /* __ISO_UTIL */

View File

@ -2,50 +2,71 @@
/* vim: set ts=8 sts=8 sw=8 noet : */ /* vim: set ts=8 sts=8 sw=8 noet : */
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "libisofs.h" #include "libisofs.h"
#include "tree.h" #include "tree.h"
#include "util.h" #include "util.h"
#include "volume.h" #include "volume.h"
#include <string.h>
struct iso_volset *iso_volset_new(struct iso_volume *vol, const char *id) struct iso_volset*
iso_volset_new(struct iso_volume *vol, const char *id)
{ {
struct iso_volset *volset = calloc(1, sizeof(struct iso_volset)); struct iso_volset *volset = calloc(1, sizeof(struct iso_volset));
volset->volset_size = 1; volset->volset_size = 1;
volset->refcount = 1;
volset->volume = malloc(sizeof(void *)); volset->volume = malloc(sizeof(void *));
volset->volume[0] = vol; volset->volume[0] = vol;
volset->volset_id.cstr = strdup(id); volset->volset_id = towcs(id);
volset->volset_id.jstr = iso_j_str(id);
vol->refcount++;
return volset; return volset;
} }
struct iso_volume *iso_volume_new(const char *volume_id, void
const char *publisher_id, iso_volset_free(struct iso_volset *volset)
const char *data_preparer_id) {
if (--volset->refcount < 1) {
int i;
for (i = 0; i < volset->volset_size; i++) {
iso_volume_free(volset->volume[i]);
}
free(volset->volume);
free(volset->volset_id);
}
}
struct iso_volume*
iso_volume_new(const char *volume_id,
const char *publisher_id,
const char *data_preparer_id)
{
return iso_volume_new_with_root(volume_id,
publisher_id,
data_preparer_id,
NULL);
}
struct iso_volume*
iso_volume_new_with_root(const char *volume_id,
const char *publisher_id,
const char *data_preparer_id,
struct iso_tree_node *root)
{ {
struct iso_volume *volume; struct iso_volume *volume;
volume = calloc(1, sizeof(struct iso_volume)); volume = calloc(1, sizeof(struct iso_volume));
volume->refcount = 1; volume->refcount = 1;
/* Get a new root directory. */ volume->root = root ? root : iso_tree_new_root(volume);
volume->root = iso_tree_new_root(volume);
/* Set these fields, if given. */ if (volume_id != NULL)
if (volume_id != NULL) { volume->volume_id = towcs(volume_id);
volume->volume_id.cstr = strdup(volume_id); if (publisher_id != NULL)
volume->volume_id.jstr = iso_j_str(volume_id); volume->publisher_id = towcs(publisher_id);
} if (data_preparer_id != NULL)
if (publisher_id != NULL) { volume->data_preparer_id = towcs(data_preparer_id);
volume->publisher_id.cstr = strdup(publisher_id);
volume->publisher_id.jstr = iso_j_str(publisher_id);
}
if (data_preparer_id != NULL) {
volume->data_preparer_id.cstr = strdup(data_preparer_id);
volume->data_preparer_id.jstr = iso_j_str(data_preparer_id);
}
return volume; return volume;
} }
@ -55,18 +76,15 @@ void iso_volume_free(struct iso_volume *volume)
if (--volume->refcount < 1) { if (--volume->refcount < 1) {
iso_tree_free(volume->root); iso_tree_free(volume->root);
free(volume->volume_id.cstr); free(volume->volume_id);
free(volume->volume_id.jstr); free(volume->publisher_id);
free(volume->publisher_id.cstr); free(volume->data_preparer_id);
free(volume->publisher_id.jstr);
free(volume->data_preparer_id.cstr);
free(volume->data_preparer_id.jstr);
free(volume); free(volume);
} }
} }
struct iso_tree_dir *iso_volume_get_root(const struct iso_volume *volume) struct iso_tree_node *iso_volume_get_root(const struct iso_volume *volume)
{ {
return volume->root; return volume->root;
} }

View File

@ -5,35 +5,25 @@
* Extra declarations for use with the iso_volume structure. * Extra declarations for use with the iso_volume structure.
*/ */
#ifndef __ISO_VOLUME #ifndef LIBISO_VOLUME_H
#define __ISO_VOLUME #define LIBISO_VOLUME_H
#include "libisofs.h" #include "libisofs.h"
struct iso_string
{
char *cstr;
uint16_t *jstr;
};
/** /**
* Data volume. * Data volume.
*/ */
struct iso_volume struct iso_volume
{ {
int refcount; /**< Number of used references to th int refcount; /**< Number of used references to this
volume. */ volume. */
struct iso_tree_dir *root; /**< Root of the directory tree for the struct iso_tree_node *root; /**< Root of the directory tree for the
volume. */ volume. */
unsigned rockridge:1; wchar_t *volume_id; /**< Volume identifier. */
unsigned joliet:1; wchar_t *publisher_id; /**< Volume publisher. */
unsigned iso_level:2; wchar_t *data_preparer_id; /**< Volume data preparer. */
struct iso_string volume_id; /**< Volume identifier. */
struct iso_string publisher_id; /**< Volume publisher. */
struct iso_string data_preparer_id; /**< Volume data preparer. */
}; };
/** /**
@ -48,7 +38,7 @@ struct iso_volset
int volset_size; /**< The number of volumes in this int volset_size; /**< The number of volumes in this
volume set. */ volume set. */
struct iso_string volset_id; /**< The id of this volume set, encoded wchar_t *volset_id; /**< The id of this volume set, encoded
in the current locale. */ in the current locale. */
}; };

View File

@ -3,8 +3,8 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#include "libisofs/libisofs.h" #include "libisofs.h"
#include "libburn/libburn.h" #include "libburn.h"
#include <getopt.h> #include <getopt.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -16,7 +16,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <dirent.h> #include <dirent.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <err.h>
#define SECSIZE 2048 #define SECSIZE 2048
@ -44,13 +44,12 @@ int main(int argc, char **argv)
{ {
struct iso_volset *volset; struct iso_volset *volset;
struct iso_volume *volume; struct iso_volume *volume;
struct iso_tree_node *root;
struct burn_source *src; struct burn_source *src;
unsigned char buf[2048]; unsigned char buf[2048];
FILE *fd; FILE *fd;
int c; int c;
int level=1, flags=0; int level=1, flags=0;
DIR *dir;
struct dirent *ent;
while ((c = getopt(argc, argv, optstring)) != -1) { while ((c = getopt(argc, argv, optstring)) != -1) {
switch(c) { switch(c) {
@ -87,45 +86,15 @@ int main(int argc, char **argv)
} }
fd = fopen(argv[optind+1], "w"); fd = fopen(argv[optind+1], "w");
if (!fd) { if (!fd) {
perror("error opening output file"); err(1, "error opening output file");
exit(1);
} }
volume = iso_volume_new( "VOLID", "PUBID", "PREPID" ); root = iso_tree_radd_dir(NULL, argv[optind]);
if (!root) {
err(1, "error opening input directory");
}
volume = iso_volume_new_with_root( "VOLID", "PUBID", "PREPID", root );
volset = iso_volset_new( volume, "VOLSETID" ); volset = iso_volset_new( volume, "VOLSETID" );
dir = opendir(argv[optind]);
if (!dir) {
perror("error opening input directory");
exit(1);
}
while ( (ent = readdir(dir)) ) {
struct stat st;
char *name;
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
continue;
}
name = malloc(strlen(argv[optind]) + strlen(ent->d_name) + 2);
strcpy(name, argv[optind]);
strcat(name, "/");
strcat(name, ent->d_name);
if (lstat(name, &st) == -1) {
fprintf(stderr, "error opening file %s: %s\n",
name, strerror(errno));
exit(1);
}
if (S_ISDIR(st.st_mode)) {
iso_tree_radd_dir(iso_volume_get_root(volume), name);
} else {
iso_tree_add_file(iso_volume_get_root(volume), name);
}
free(name);
}
iso_tree_print(iso_volume_get_root(volume), 0);
src = iso_source_new_ecma119(volset, 0, level, flags); src = iso_source_new_ecma119(volset, 0, level, flags);