First pinch of libisofs rewrite
This commit is contained in:
parent
176e1654ff
commit
48d76e844e
33
Makefile.am
33
Makefile.am
@ -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 \
|
||||
|
@ -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)
|
||||
|
2042
libisofs/ecma119.c
2042
libisofs/ecma119.c
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
216
libisofs/susp.c
216
libisofs/susp.c
@ -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;
|
||||
|
@ -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 *);
|
||||
|
||||
|
512
libisofs/tree.c
512
libisofs/tree.c
@ -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);
|
||||
}
|
||||
|
232
libisofs/tree.h
232
libisofs/tree.h
@ -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 */
|
||||
|
632
libisofs/util.c
632
libisofs/util.c
@ -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;
|
||||
}
|
||||
|
||||
|
163
libisofs/util.h
163
libisofs/util.h
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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. */
|
||||
};
|
||||
|
||||
|
51
test/iso.c
51
test/iso.c
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user