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 = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
libisofs_libisofs_la_SOURCES = \
libisofs/errors.h \
libisofs/errors.c \
libisofs/tree.h \
libisofs/tree.c \
libisofs/volume.h \
libisofs/volume.c \
libisofs/util.h \
libisofs/util.c \
libisofs/ecma119.c \
libisofs/ecma119.h \
libisofs/struct.h \
libisofs/struct.c \
libisofs/susp.h \
libisofs/susp.c \
libisofs/rockridge.h \
libisofs/rockridge.c \
libisofs/libisofs.h
libisofs/tree.h \
libisofs/tree.c \
libisofs/volume.h \
libisofs/volume.c \
libisofs/util.h \
libisofs/util.c \
libisofs/ecma119.c \
libisofs/ecma119.h \
libisofs/ecma119_tree.c \
libisofs/ecma119_tree.h \
libisofs/susp.h \
libisofs/susp.c \
libisofs/rockridge.h \
libisofs/rockridge.c \
libisofs/joliet.c \
libisofs/joliet.h
libinclude_HEADERS = \
libburn/libburn.h \

View File

@ -1,11 +1,11 @@
pkgconfigdir=$(libdir)/pkgconfig
libincludedir=$(includedir)/libburn
##bin_PROGRAMS = test
lib_LTLIBRARIES = libisofs.la
libisofs_la_SOURCES = \
errors.h \
errors.c \
tree.h \
tree.c \
volume.h \
@ -14,20 +14,25 @@ libisofs_la_SOURCES = \
util.c \
ecma119.c \
ecma119.h \
struct.h \
struct.c \
ecma119_tree.c \
ecma119_tree.h \
susp.h \
susp.c \
rockridge.h \
rockridge.c
rockridge.c \
joliet.c \
joliet.h
libinclude_HEADERS = libisofs.h
noinst_PROGRAMS = test
test_SOURCES = test.c
test_LDADD = $(libisofs_la_OBJECTS)
##test_SOURCES = test.c
##test_LDADD = libisofs.la
INCLUDES = -I..
##noinst_PROGRAMS = test
##test_SOURCES = test.c
##test_LDADD = $(libisofs_la_OBJECTS)
##INCLUDES = -I../burn/libburn
## ========================================================================= ##
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 : */
/**
@ -7,70 +8,17 @@
* volume.
*/
#ifndef __ISO_ECMA119
#define __ISO_ECMA119
#ifndef LIBISO_ECMA119_H
#define LIBISO_ECMA119_H
#include <stdio.h>
#include <sys/time.h>
#include <stdint.h>
#include <stdio.h> /* for FILE */
#include <sys/types.h>
#include "susp.h"
/**
* Persistent data for writing directories according to the ecma119 standard.
*/
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. */
};
struct ecma119_tree_node;
struct joliet_tree_node;
/**
* The possible states that the ecma119 writer can be in.
@ -100,11 +48,13 @@ enum ecma119_write_state
*/
struct ecma119_write_target
{
struct ecma119_tree_node *root;
struct joliet_tree_node *joliet_root;
struct iso_volset *volset;
int volnum;
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. */
uint32_t vol_space_size;
@ -120,73 +70,63 @@ struct ecma119_write_target
uint32_t m_path_table_pos;
uint32_t l_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
* out directory records).
*/
struct iso_tree_dir **pathlist; /* A breadth-first list of directories.
* This is used for writing out the path
* tables.
struct ecma119_tree_node **pathlist;
/**< A breadth-first list of
* 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.
*/
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 */
/* Joliet versions of the above lists. Since Joliet doesn't require
* directory relocation, the order of these list might be different from
* the lists above. */
struct iso_tree_dir **dirlist_joliet;
struct iso_tree_dir **pathlist_joliet;
* directory relocation, the order of these lists might be different
* from the lists above (but they will be the same length).
*/
struct joliet_tree_node **dirlist_joliet;
struct joliet_tree_node **pathlist_joliet;
enum ecma119_write_state state; /* The current state of the writer. */
/* persistent data for the various states. Each struct should not be
* touched except for the writer of the relevant stage. When the writer
* of the relevant stage is finished, it should set all fields to 0.
/* Most writers work by
* 1) making sure state_data is big enough for their data
* 2) writing _all_ their data into state_data
* 3) relying on write_data_chunk to write the data block
* by block.
*/
union
{
struct
{
int blocks;
unsigned char *data;
} path_table;
struct
{
size_t pos; /* The number of bytes we have written
* so far in the current directory.
*/
size_t data_len;/* The number of bytes in the current
* directory.
*/
unsigned char *data; /* The data (combined Directory
* Records and susp_CE areas) of the
* 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;
uint8_t *state_data;
off_t state_data_size;
off_t state_data_off;
int state_data_valid;
/* for writing out files */
struct state_files {
off_t pos; /* The number of bytes we have written
* so far in the current file.
*/
off_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 (or about to write). */
} state_files;
};
/**
@ -198,23 +138,130 @@ struct ecma119_write_target
* \post The directory heirarchy has been reorganised to be ecma119-compatible.
*/
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) )
#define FILE_INF(a) ( (struct file_write_info*) (a) )
#define NODE_INF(a) ( (struct node_write_info*) (a) )
void
ecma119_start_chunking(struct ecma119_write_target *t,
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 )
#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 */
#endif /* LIBISO_ECMA119_H */

View File

@ -9,10 +9,11 @@
* - Write the volume to a file or create a burn source for use with Libburn.
*/
#ifndef __LIBISOFS
#define __LIBISOFS
#ifndef LIBISO_LIBISOFS_H
#define LIBISO_LIBISOFS_H
#include "libburn/libburn.h"
/* #include <libburn.h> */
struct burn_source;
/**
* Data volume.
@ -27,35 +28,11 @@ struct iso_volume;
struct iso_volset;
/**
* Directory on a volume.
* @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.
* A node in the filesystem tree.
* \see tree.h
*/
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 {
ECMA119_ROCKRIDGE = (1<<0),
ECMA119_JOLIET = (1<<1)
@ -69,6 +46,11 @@ struct iso_volume *iso_volume_new(const char *volume_id,
const char *publisher_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.
*/
@ -77,7 +59,7 @@ void iso_volume_free(struct iso_volume *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.
@ -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,
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.
* @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.
*
* \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
* 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);
/**
* 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.
* 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.
*
* \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
* filesystem.
* \return a pointer to the newly created directory.
*/
struct iso_tree_dir *iso_tree_radd_dir(struct iso_tree_dir *parent,
const char *path);
struct iso_tree_node *iso_tree_radd_dir(struct iso_tree_node *parent,
const char *path);
/**
* 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.
* 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.
* \return a pointer to the newly created directory.
*/
struct iso_tree_dir *iso_tree_add_new_dir(struct iso_tree_dir *parent,
const char *name);
struct iso_tree_node *iso_tree_add_new_dir(struct iso_tree_node *parent,
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,
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);
void iso_tree_node_set_name(struct iso_tree_node *file, const char *name);
/**
* Recursively print a directory to stdout.
* \param spaces The initial number of spaces on the left. Set to 0 if you
* 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
*
@ -240,4 +162,4 @@ struct burn_source* iso_source_new_ecma119 (struct iso_volset *volumeset,
int level,
int flags);
#endif /* __LIBISOFS */
#endif /* LIBISO_LIBISOFS_H */

View File

@ -1,10 +1,10 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
#include "rockridge.h"
#include "tree.h"
#include "util.h"
#include "volume.h"
#include "ecma119.h"
#include "ecma119_tree.h"
#include "tree.h"
#include "susp.h"
#include <stdlib.h>
@ -15,53 +15,50 @@
#include <sys/stat.h>
/* create a PX field from the permissions on the current node. */
unsigned char *rrip_make_PX(struct ecma119_write_target *t,
struct iso_tree_node *node)
uint8_t *rrip_make_PX(struct ecma119_write_target *t,
struct ecma119_tree_node *node)
{
unsigned char *PX = malloc(44);
uint8_t *PX = malloc(44);
PX[0] = 'P';
PX[1] = 'X';
PX[2] = 44;
PX[3] = 1;
iso_bb(&PX[4], node->attrib.st_mode, 4);
iso_bb(&PX[12], node->attrib.st_nlink, 4);
iso_bb(&PX[20], node->attrib.st_uid, 4);
iso_bb(&PX[28], node->attrib.st_gid, 4);
iso_bb(&PX[36], node->attrib.st_ino, 4);
iso_bb(&PX[4], node->iso_self->attrib.st_mode, 4);
iso_bb(&PX[12], node->iso_self->attrib.st_nlink, 4);
iso_bb(&PX[20], node->iso_self->attrib.st_uid, 4);
iso_bb(&PX[28], node->iso_self->attrib.st_gid, 4);
iso_bb(&PX[36], node->iso_self->attrib.st_ino, 4);
return PX;
}
/** 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)));
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);
uint8_t *PN = malloc(20);
PN[0] = 'P';
PN[1] = 'N';
PN[2] = 20;
PN[3] = 1;
iso_bb(&PN[4], node->attrib.st_dev >> 32, 4);
iso_bb(&PN[12], node->attrib.st_dev & 0xffffffff, 4);
susp_append(t, node, PN);
iso_bb(&PN[4], node->iso_self->attrib.st_dev >> 32, 4);
iso_bb(&PN[12], node->iso_self->attrib.st_dev & 0xffffffff, 4);
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)
{
unsigned char *comp = malloc(size + 2);
uint8_t *comp = malloc(size + 2);
(*n)++;
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,
unsigned char ***comps)
uint8_t ***comps)
{
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);
}
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;
char *path = NULL, *cur, *prev;
struct iso_tree_file *file = (struct iso_tree_file *)node;
int i, j;
unsigned char **comp = NULL;
uint8_t **comp = NULL;
int n_comp = 0;
int total_comp_len = 0;
int written = 0, pos;
unsigned char *SL;
uint8_t *SL;
do {
pathsize += 128;
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);
if (ret == -1) {
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]);
pos += comp[j][2];
}
susp_append(t, node, SL);
susp_append(t, &node->susp, SL);
written = 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);
pos += comp[j][1] + 2;
}
susp_append(t, node, SL);
susp_append(t, &node->susp, SL);
free(path);
/* 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,
struct iso_tree_node *node,
struct susp_info *susp,
char *name, int size, int flags)
{
unsigned char *NM = malloc(size + 5);
uint8_t *NM = malloc(size + 5);
NM[0] = 'N';
NM[1] = 'M';
@ -197,103 +194,107 @@ static void rrip_add_NM_single(struct ecma119_write_target *t,
if (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;
int len = strlen(file->name.rockridge);
char *pos = file->name.rockridge;
char *name = iso_p_fileid(node->iso_self->name);
int len = name ? strlen(name) : 0;
char *pos = name;
if (len == 1 && pos[0] == '.') {
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);
if (!len)
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) {
rrip_add_NM_single(t, node, pos, 250, 1);
rrip_add_NM_single(t, &node->susp, pos, 250, 1);
len -= 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[1] = 'L';
CL[2] = 12;
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[1] = 'L';
PL[2] = 12;
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[1] = 'E';
RE[2] = 4;
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[1] = 'F';
TF[2] = 5 + 3 * 17;
TF[2] = 5 + 3 * 7;
TF[3] = 1;
TF[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7);
iso_datetime_17(&TF[5], node->attrib.st_mtime);
iso_datetime_17(&TF[22], node->attrib.st_atime);
iso_datetime_17(&TF[39], node->attrib.st_ctime);
susp_append(t, node, TF);
iso_datetime_7(&TF[5], node->iso_self->attrib.st_mtime);
iso_datetime_7(&TF[12], node->iso_self->attrib.st_atime);
iso_datetime_7(&TF[19], node->iso_self->attrib.st_ctime);
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;
inf = dir->writer_data;
if (dir->parent != inf->real_parent) {
unsigned char *PL = susp_find(&inf->parent_susp, "PL");
assert(dir->type == ECMA119_DIR);
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++) {
finf = dir->files[i]->writer_data;
if (finf->real_me) {
unsigned char *CL = susp_find(&finf->susp, "CL");
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
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. */
#ifndef __ISO_ROCKRIDGE
#define __ISO_ROCKRIDGE
#ifndef ISO_ROCKRIDGE_H
#define ISO_ROCKRIDGE_H
struct ecma119_write_target;
struct iso_tree_node;
struct iso_tree_dir;
struct ecma119_tree_node;
void rrip_add_PX(struct ecma119_write_target *, struct iso_tree_node *);
void rrip_add_PN(struct ecma119_write_target *, struct iso_tree_node *);
void rrip_add_SL(struct ecma119_write_target *, struct iso_tree_node *);
void rrip_add_NM(struct ecma119_write_target *, struct iso_tree_node *);
void rrip_add_CL(struct ecma119_write_target *, struct iso_tree_node *);
void rrip_add_RE(struct ecma119_write_target *, struct iso_tree_node *);
void rrip_add_TF(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 ecma119_tree_node *);
void rrip_add_SL(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_NM(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_CL(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_add_RE(struct ecma119_write_target *, struct ecma119_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
* that gets passed to it; it modifies the susp fields of the ".." entry in
* 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_add_PX_dir(struct ecma119_write_target *, struct iso_tree_dir *);
void rrip_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
void rrip_finalize(struct ecma119_write_target *, struct iso_tree_dir *);
#endif /* __ISO_ROCKRIDGE */
#endif /* ISO_ROCKRIDGE_H */

View File

@ -1,20 +1,25 @@
/* vim: set noet ts=8 sts=8 sw=8 : */
#include "susp.h"
#include "tree.h"
#include "util.h"
#include "ecma119.h"
#include "ecma119_tree.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>
static void susp_insert_direct(struct ecma119_write_target *t,
struct susp_info *susp, unsigned char *data,
int pos)
void susp_insert(struct ecma119_write_target *t,
struct susp_info *susp,
uint8_t *data,
int pos)
{
int i;
if (pos < 0) {
pos = susp->n_susp_fields;
}
assert(pos <= susp->n_susp_fields);
susp->n_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,
struct iso_tree_node *node, unsigned char *data)
struct susp_info *susp,
uint8_t *data)
{
struct dir_write_info *inf = node->writer_data;
struct susp_info *susp = &inf->susp;
susp_insert_direct(t, susp, data, susp->n_susp_fields);
susp_insert(t, susp, data, susp->n_susp_fields);
}
void susp_append_self(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->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)
uint8_t *susp_find(struct susp_info *susp, const char *name)
{
int i;
@ -92,11 +50,15 @@ unsigned char *susp_find(struct susp_info *susp, const char *name)
return NULL;
}
/* utility function for susp_add_CE because susp_add_CE needs to act 3 times
* on directories (for the "." and ".." entries. */
/** Utility function for susp_add_CE because susp_add_CE needs to act 3 times
* on directories (for the "." and ".." entries.
*
* \param len The amount of space available for the System Use area.
*/
#define CE_LEN 28
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 i;
@ -138,33 +100,36 @@ static unsigned char *susp_add_single_CE(struct ecma119_write_target *t,
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
* 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;
unsigned char *CE;
CE = susp_add_single_CE(t, &inf->susp, 255 - node->dirent_len);
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);
try_add_CE(t, &node->susp, node->dirent_len);
if (node->type == ECMA119_DIR) {
try_add_CE(t, &node->dir.self_susp, 34);
try_add_CE(t, &node->dir.parent_susp, 34);
}
}
/** 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);
assert(dir->type == ECMA119_DIR);
SP[0] = 'S';
SP[1] = 'P';
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[5] = 0xef;
SP[6] = 0;
susp_append_self(t, dir, SP);
susp_append(t, &dir->dir.self_susp, SP);
}
#if 0
@ -190,11 +155,14 @@ static void susp_add_ST(struct ecma119_write_target *t,
}
#endif
/** See IEEE P1281 Draft Version 1.12/5.5 */
void susp_add_ER(struct ecma119_write_target *t, struct iso_tree_dir *dir)
/** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */
void
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
{
unsigned char *ER = malloc(182);
assert(dir->type == ECMA119_DIR);
ER[0] = 'E';
ER[1] = 'R';
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);
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
"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,
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 CE_offset = inf->len;
size_t CE_offset = dir->dir.len;
if (inf->self_susp.CE_len) {
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;
}
assert(dir->type == ECMA119_DIR);
for (i = 0; i < dir->nchildren; i++) {
cinf = dir->children[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;
susp_fin_1_CE(t, &dir->dir.self_susp, dir->block, &CE_offset);
susp_fin_1_CE(t, &dir->dir.parent_susp, dir->block, &CE_offset);
for (i = 0; i < dir->dir.nchildren; i++) {
struct ecma119_tree_node *ch = dir->dir.children[i];
susp_fin_1_CE(t, &ch->susp, dir->block, &CE_offset);
}
for (i = 0; i < dir->nfiles; i++) {
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);
assert(CE_offset == dir->dir.len + dir->dir.CE_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;
if (dir->depth != 1) {
assert(dir->type = ECMA119_DIR);
if (dir->dir.depth != 1) {
susp_fin_CE(t, dir);
}
for (i = 0; i < dir->nchildren; i++) {
susp_finalize(t, dir->children[i]);
for (i = 0; i < dir->dir.nchildren; 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)
{
int i;

View File

@ -6,17 +6,18 @@
#ifndef __ISO_SUSP
#define __ISO_SUSP
#include <stdint.h>
/* SUSP is only present in standard ecma119 */
struct ecma119_write_target;
struct iso_tree_node;
struct iso_tree_dir;
struct ecma119_tree_node;
/** This contains the information that needs to go in the SUSP area of a file.
*/
struct susp_info
{
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. */
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. */
};
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
* 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. */
void susp_add_SP(struct ecma119_write_target *, struct iso_tree_dir *);
void susp_add_ER(struct ecma119_write_target *, struct iso_tree_dir *);
void susp_add_SP(struct ecma119_write_target *, struct ecma119_tree_node *);
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
* 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 *,
struct iso_tree_node *,
unsigned char *);
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 *);
struct susp_info *,
uint8_t *);
void susp_insert(struct ecma119_write_target *,
struct iso_tree_node *,
unsigned char *,
struct susp_info *,
uint8_t *,
int pos);
void susp_insert_self(struct ecma119_write_target *,
struct iso_tree_dir *,
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 *);
uint8_t *susp_find(struct susp_info *,
const char *);
void susp_write(struct ecma119_write_target *,
struct susp_info *,
unsigned char *);
uint8_t *);
void susp_write_CE(struct ecma119_write_target *,
struct susp_info *,
unsigned char *);
uint8_t *);
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 : */
#include <dirent.h>
#include <stdio.h>
/**
* \file tree.c
*
* Implement filesystem trees.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.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 <err.h>
#include <stdio.h>
#include "libisofs.h"
#include "tree.h"
#include "util.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);
dir = calloc(1, sizeof(struct iso_tree_dir));
dir->attrib.st_mode = S_IFDIR;
dir->volume = volume;
return dir;
memset(s, 0, sizeof(struct stat));
s->st_mode = 0777 | S_IFREG;
s->st_atime = s->st_mtime = s->st_ctime = now;
}
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;
int statret;
const char *name;
assert( parent != NULL && path != NULL );
statret = lstat(path, &st);
if (statret == -1) {
fprintf(stderr, "couldn't stat file %s: %s\n",
path, strerror(errno));
return NULL;
if (node) {
return node->attrib;
}
/* Set up path, parent and volume. */
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;
set_default_stat(&st);
return st;
}
struct iso_tree_dir *iso_tree_add_dir(struct iso_tree_dir *parent,
const char *path)
static void
append_node(struct iso_tree_node *parent,
struct iso_tree_node *child)
{
struct iso_tree_dir *dir;
struct stat st;
int statret;
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);
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && child);
if (!parent)
return;
parent->nchildren++;
parent->children = realloc(parent->children,
parent->nchildren * sizeof(void*));
parent->children[parent->nchildren - 1] = dir;
return dir;
parent->children =
realloc(parent->children, parent->nchildren * sizeof(void*));
parent->children[parent->nchildren-1] = child;
}
struct iso_tree_dir *iso_tree_radd_dir(struct iso_tree_dir *parent,
const char *path)
struct iso_tree_node*
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;
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;
struct dirent *ent;
assert( parent && path );
statret = stat(path, &st);
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
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);
if (!dir) {
fprintf(stderr, "couldn't open directory %s: %s\n",
path, strerror(errno));
return NULL;
warn("couldn't open directory %s: %s\n", path, strerror(errno));
return new;
}
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 ||
strcmp(ent->d_name, "..") == 0)
strcmp(ent->d_name, "..") == 0)
continue;
/* Build the child's full pathname. */
child = iso_pathname(path, ent->d_name);
/* 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);
sprintf(child, "%s/%s", path, ent->d_name);
iso_tree_radd_dir(new, child);
}
closedir(dir);
return nparent;
return new;
}
struct iso_tree_dir *iso_tree_add_new_dir(struct iso_tree_dir *parent,
const char *name)
void
iso_tree_free(struct iso_tree_node *root)
{
struct iso_tree_dir *dir;
size_t i;
assert( parent && name );
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;
}
for (i=0; i < root->nchildren; i++) {
iso_tree_free(root->children[i]);
}
switch (ver) {
case ISO_NAME_FULL:
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 */
free(root->name);
free(root->children);
free(root);
}
const char *iso_tree_node_get_name(const struct iso_tree_node *node,
enum iso_name_version ver)
void
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)
{
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);
}
memset(sp, ' ', spaces);
sp[spaces] = '\0';
/* Compares file names for use with qsort. */
int iso_node_cmp(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_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);
printf("%s%ls\n", sp, root->name);
for (i=0; i < root->nchildren; i++) {
iso_tree_print(root->children[i], spaces+2);
}
}
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 : */
/**
* \file tree.h
*
* Extra declarations for use with the iso_tree_dir and iso_tree_file
* structures.
* Declare the structure of a libisofs filesystem tree. The files in this
* 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
#define __ISO_TREE
#ifndef LIBISO_TREE_H
#define LIBISO_TREE_H
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdint.h>
#include <wchar.h>
#include "libisofs.h"
/**
* File or directory names or identifiers.
*/
struct iso_names
{
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. */
enum file_location {
LIBISO_FILESYS,
LIBISO_PREVSESSION,
LIBISO_NONE /**< for files/dirs that were added with
* iso_tree_add_new_XXX. */
};
/**
* 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 */
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 */
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. */
enum file_location type;
/* union {*/
char *path; /* in the current locale */
uint32_t block;
/* };*/
};
/**
* File on a volume.
*/
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.
* A node in the filesystem tree.
*/
struct iso_tree_node
{
struct iso_tree_dir *parent; /**< The parent of this node. Must be
* non-NULL unless we are the
* root directory on a volume.
*/
struct iso_volume *volume; /**< The volume to which this node
* belongs.
*/
struct iso_names name; /**< The name of this node in its parent
* directory. Must be non-NULL unless
* 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.
*/
struct iso_volume *volume;
struct iso_tree_node *parent;
wchar_t *name;
struct stat attrib; /**< The POSIX attributes of this node as
* documented in "man 2 stat". */
struct iso_file_location loc;
/**< Only used for regular files and symbolic
* links (ie. files for which we might have to
* copy data). */
/* information used for writing */
off_t block; /**< The block at which this node's
* data will be written.
*/
uint8_t dirent_len; /**< The size of this node's
* Directory Record in its parent.
* This does not include System Use
* fields, if present.
*/
void *writer_data; /**< This is writer-specific data. It
* must be set to NULL when a node
* is created and it should be NULL
* again when the node is freed.
*/
size_t nchildren; /**< The number of children of this
* directory (if this is a directory). */
struct iso_tree_node **children;
size_t block; /**< The block at which this file will
* reside on disk. We store this here as
* well as in the various mangled trees
* because many different trees might point
* to the same file and they need to share the
* block location. */
};
/** 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.
*
* \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.
* \post \p volume has a non-NULL, empty root directory.
* \return \p volume's new non-NULL, empty root directory.
* \pre \p vol is non-NULL.
* \post \p vol has a non-NULL, empty root directory with permissions 777.
* \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.
*
* \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.
*
* \pre \p parent is non-NULL.
* \pre \p name is non-NULL and it does not match any other file or directory
* name in \p parent.
* \post \p parent contains a file with the following properties:
* - the file's (full) name is \p name
* - the file's POSIX permissions are the same as \p parent's
* - the file is a regular file
* - the file is empty
* name in \p parent.
* \post \p parent (if non-NULL) contains a file with the following properties:
* - 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 is a regular file
* - the file is empty
*
* \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);
/**
@ -173,37 +108,7 @@ struct iso_tree_file *iso_tree_add_new_file(struct iso_tree_dir *parent,
*
* \pre \p root is non-NULL.
*/
void iso_tree_free(struct iso_tree_dir *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);
void iso_tree_free(struct iso_tree_node *root);
/**
* 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
*/
typedef void (*print_dir_callback) (const struct iso_tree_dir *dir,
typedef void (*print_dir_callback) (const struct iso_tree_node *dir,
void *data,
int spaces);
/**
@ -226,7 +131,7 @@ typedef void (*print_dir_callback) (const struct iso_tree_dir *dir,
*
* \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,
int spaces);
@ -243,17 +148,12 @@ typedef void (*print_file_callback) (const struct iso_tree_file *file,
* \pre \p root is not NULL.
* \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_file_callback file,
void *callback_data,
int spaces);
/**
* 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
* 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 */
#define ISO_ISDIR(n) S_ISDIR(n->attrib.st_mode)
#endif /* LIBISO_TREE_H */

View File

@ -1,136 +1,190 @@
/* -*- 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 <stdlib.h>
#include <stdint.h>
#include <langinfo.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <stdio.h>
#include <errno.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 == '_');
}
int valid_a_char(char c)
static int valid_a_char(char c)
{
return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?') || (c >= 'A' &&
c <= 'Z')
|| (c == '_');
return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?')
|| (c >= 'A' && c <= 'Z')
|| (c == '_');
}
int valid_j_char(char msb, char lsb)
static int valid_j_char(uint16_t c)
{
return !(msb == '\0' &&
(lsb < ' ' || lsb == '*' || lsb == '/' || lsb == ':' ||
lsb == ';' || lsb == '?' || lsb == '\\'));
return !(c < (uint16_t)' ' || c == (uint16_t)'*' || c == (uint16_t)'/'
|| c == (uint16_t)':' || c == (uint16_t)';'
|| 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' &&
c <= 'z')
|| (c == '.') || (c == '_') || (c == '-');
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (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 ||
pad ? malloc(size + 1) : malloc(strlen(src) + 1);
int i;
char *ret = wcstoascii(src);
size_t len, i;
/* Try converting to upper-case before validating. */
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);
if (!ret)
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
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;
return ret;
}
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
(;1) + 1 (\0) */
char *dot = strrchr(src, '.'); /* Position of the last dot in the
return iso_dirid(src, 8);
}
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
lname and lext. */
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;
lname = strlen(src) - lext - (dot ? 1 : 0);
/* If we can't build a filename, return NULL. */
if (lname == 0 && lext == 0) {
free(src);
free(dest);
return NULL;
}
@ -156,16 +210,24 @@ char *iso_1_fileid(const char *src)
dest[pos] = '\0';
dest = (char *)realloc(dest, pos + 1);
free(src);
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
(;1) + 1 (\0) */
char *dot = strrchr(src, '.');
char *src = wcstoascii(wsrc);
char *dest;
char *dot;
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
extension, we need to calculate their new lengths (lnname and
lnext). If the original filename is too long, we start by trimming
@ -177,12 +239,13 @@ char *iso_2_fileid(const char *src)
} else {
lext = strlen(dot + 1);
lname = strlen(src) - lext - 1;
lnext = (strlen(src) > 31 &&
lext > 3) ? (lname < 27 ? 30 - lname : 3) : lext;
lnext = (strlen(src) > 31 && lext > 3)
? (lname < 27 ? 30 - lname : 3) : lext;
lnname = (strlen(src) > 31) ? 30 - lnext : lname;
}
if (lnname == 0 && lnext == 0) {
free(src);
free(dest);
return NULL;
}
@ -206,276 +269,43 @@ char *iso_2_fileid(const char *src)
dest[pos] = '\0';
dest = (char *)realloc(dest, pos + 1);
free(src);
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 .) +
4 (\0 ; \0 1) + 2 (\0 \0) */
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;
char *ret = wcstoascii(src);
size_t i, len;
if (dot == NULL || dot == src || *(dot + 1) == '\0') {
lname = strlen(src);
lext = 0;
} else {
lext = strlen(dot + 1);
lname = strlen(src) - lext - 1;
}
if (lname == 0 && lext == 0) {
free(dest);
if (!ret)
return NULL;
}
cd = iconv_open("UCS-2BE", nl_langinfo(CODESET));
if (cd == (iconv_t) - 1) {
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;
len = strlen(ret);
for (i = 0; i < len; i++) {
if (!valid_p_char(ret[i])) {
ret[i] = (uint16_t)'_';
}
cext = malloc(lext * 2);
in = dot + 1;
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;
}
return ret;
}
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
a Rock Ridge name entry. */
char *dot = strrchr(src, '.');
int lname, lext, lnname, lnext, pos, i;
uint16_t *j_str = wcstoucs(src);
size_t len = ucslen(j_str);
size_t n;
if (dot == NULL || dot == src || *(dot + 1) == '\0') {
lname = strlen(src);
lnname = (lname > 250) ? 250 : lname;
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 (len > 128) {
j_str[128] = '\0';
len = 128;
}
if (lnname == 0 && lnext == 0) {
free(dest);
return NULL;
}
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;
for (n = 0; n < len; n++)
if (!valid_j_char(j_str[n]))
j_str[n] = '_';
return j_str;
}
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 tzoffset;
struct tm tm;
char c[5];
if (t == (time_t) - 1) {
/* unspecified time */
@ -570,27 +399,13 @@ void iso_datetime_17(unsigned char *buf, time_t t)
localtime_r(&t, &tm);
/* year */
sprintf(c, "%04d", tm.tm_year + 1900);
memcpy(&buf[0], c, 4);
/* month */
sprintf(c, "%02d", tm.tm_mon + 1);
memcpy(&buf[4], c, 2);
/* 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 */
sprintf((char*)&buf[0], "%04d", tm.tm_year + 1900);
sprintf((char*)&buf[4], "%02d", tm.tm_mon + 1);
sprintf((char*)&buf[6], "%02d", tm.tm_mday);
sprintf((char*)&buf[8], "%02d", tm.tm_hour);
sprintf((char*)&buf[10], "%02d", tm.tm_min);
sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec));
memcpy(&buf[14], "00", 2);
/* timezone */
buf[16] = tzoffset;
}
}
@ -611,47 +426,6 @@ time_t iso_datetime_read_17(const uint8_t *buf)
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)
{
int i;
@ -661,20 +435,30 @@ size_t ucslen(const uint16_t *str)
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 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++) {
if (s1[i] < s2[i]) {
for (i=0; i < len; i++) {
if (s[i] < t[i]) {
return -1;
} else if (s1[i] > s2[i]) {
} else if (s[i] > t[i]) {
return 1;
} else if (s1[i] == 0 && s2[i] == 0) {
break;
}
}
if (len1 < len2)
return -1;
else if (len1 > len2)
return 1;
return 0;
}

View File

@ -1,122 +1,95 @@
/* -*- 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.
*/
#ifndef __ISO_UTIL
#define __ISO_UTIL
#ifndef LIBISO_UTIL_H
#define LIBISO_UTIL_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.
*/
int valid_j_char(char msb, char lsb);
/**
* 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).
* 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.
*/
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.
* The combined file name and extension length will not exceed 30, the name and extension will be separated (.),
* and the extension will be followed by a separator (;) and a version number (digit 1).
* Create a level 2 file identifier that consists of a name, extension and
* version number. The combined file name and extension length will not exceed
* 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.
*/
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.
* The combined name and extension length will not exceed 128 bytes, the name and extension will be separated (.),
* and the extension will be followed by a separator (;) and a version number (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.
* Create a Joliet file or directory identifier that consists of a name,
* extension and version number. The combined name and extension length will
* not exceed 128 bytes, the name and extension will be separated (.),
* and the extension will be followed by a separator (;) and a version number
* (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.
* @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.
* The resulting file name will not exceed 250 characters.
* @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.
* The resulting directory name will not exceed 250 characters.
* @return NULL if the original name is of length 0.
*/
char *iso_p_dirname(const char *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);
char *iso_p_dirid(const wchar_t *src);
void iso_lsb(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);
/** 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) */
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_17(const uint8_t *buf);
/** Removes the extension from the name, and returns the extension. The
returned extension should _not_ be freed! */
void iso_split_filename(char *name, char **ext);
/**
* Like strlen, but for Joliet strings.
*/
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);
/* 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 */
#endif /* LIBISO_UTIL_H */

View File

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

View File

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

View File

@ -3,8 +3,8 @@
#define _GNU_SOURCE
#include "libisofs/libisofs.h"
#include "libburn/libburn.h"
#include "libisofs.h"
#include "libburn.h"
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
@ -16,7 +16,7 @@
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
#include <errno.h>
#include <err.h>
#define SECSIZE 2048
@ -44,13 +44,12 @@ int main(int argc, char **argv)
{
struct iso_volset *volset;
struct iso_volume *volume;
struct iso_tree_node *root;
struct burn_source *src;
unsigned char buf[2048];
FILE *fd;
int c;
int level=1, flags=0;
DIR *dir;
struct dirent *ent;
while ((c = getopt(argc, argv, optstring)) != -1) {
switch(c) {
@ -87,45 +86,15 @@ int main(int argc, char **argv)
}
fd = fopen(argv[optind+1], "w");
if (!fd) {
perror("error opening output file");
exit(1);
err(1, "error opening output file");
}
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" );
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);