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 = \
|
libisofs_libisofs_la_LDFLAGS = \
|
||||||
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
|
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
|
||||||
libisofs_libisofs_la_SOURCES = \
|
libisofs_libisofs_la_SOURCES = \
|
||||||
libisofs/errors.h \
|
libisofs/tree.h \
|
||||||
libisofs/errors.c \
|
libisofs/tree.c \
|
||||||
libisofs/tree.h \
|
libisofs/volume.h \
|
||||||
libisofs/tree.c \
|
libisofs/volume.c \
|
||||||
libisofs/volume.h \
|
libisofs/util.h \
|
||||||
libisofs/volume.c \
|
libisofs/util.c \
|
||||||
libisofs/util.h \
|
libisofs/ecma119.c \
|
||||||
libisofs/util.c \
|
libisofs/ecma119.h \
|
||||||
libisofs/ecma119.c \
|
libisofs/ecma119_tree.c \
|
||||||
libisofs/ecma119.h \
|
libisofs/ecma119_tree.h \
|
||||||
libisofs/struct.h \
|
libisofs/susp.h \
|
||||||
libisofs/struct.c \
|
libisofs/susp.c \
|
||||||
libisofs/susp.h \
|
libisofs/rockridge.h \
|
||||||
libisofs/susp.c \
|
libisofs/rockridge.c \
|
||||||
libisofs/rockridge.h \
|
libisofs/joliet.c \
|
||||||
libisofs/rockridge.c \
|
libisofs/joliet.h
|
||||||
libisofs/libisofs.h
|
|
||||||
|
|
||||||
libinclude_HEADERS = \
|
libinclude_HEADERS = \
|
||||||
libburn/libburn.h \
|
libburn/libburn.h \
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
pkgconfigdir=$(libdir)/pkgconfig
|
pkgconfigdir=$(libdir)/pkgconfig
|
||||||
libincludedir=$(includedir)/libburn
|
libincludedir=$(includedir)/libburn
|
||||||
|
|
||||||
|
##bin_PROGRAMS = test
|
||||||
|
|
||||||
lib_LTLIBRARIES = libisofs.la
|
lib_LTLIBRARIES = libisofs.la
|
||||||
|
|
||||||
libisofs_la_SOURCES = \
|
libisofs_la_SOURCES = \
|
||||||
errors.h \
|
|
||||||
errors.c \
|
|
||||||
tree.h \
|
tree.h \
|
||||||
tree.c \
|
tree.c \
|
||||||
volume.h \
|
volume.h \
|
||||||
@ -14,20 +14,25 @@ libisofs_la_SOURCES = \
|
|||||||
util.c \
|
util.c \
|
||||||
ecma119.c \
|
ecma119.c \
|
||||||
ecma119.h \
|
ecma119.h \
|
||||||
struct.h \
|
ecma119_tree.c \
|
||||||
struct.c \
|
ecma119_tree.h \
|
||||||
susp.h \
|
susp.h \
|
||||||
susp.c \
|
susp.c \
|
||||||
rockridge.h \
|
rockridge.h \
|
||||||
rockridge.c
|
rockridge.c \
|
||||||
|
joliet.c \
|
||||||
|
joliet.h
|
||||||
|
|
||||||
libinclude_HEADERS = libisofs.h
|
libinclude_HEADERS = libisofs.h
|
||||||
|
|
||||||
noinst_PROGRAMS = test
|
##test_SOURCES = test.c
|
||||||
test_SOURCES = test.c
|
##test_LDADD = libisofs.la
|
||||||
test_LDADD = $(libisofs_la_OBJECTS)
|
|
||||||
|
|
||||||
INCLUDES = -I..
|
##noinst_PROGRAMS = test
|
||||||
|
##test_SOURCES = test.c
|
||||||
|
##test_LDADD = $(libisofs_la_OBJECTS)
|
||||||
|
|
||||||
|
##INCLUDES = -I../burn/libburn
|
||||||
|
|
||||||
## ========================================================================= ##
|
## ========================================================================= ##
|
||||||
indent_files = $(libisofs_la_SOURCES)
|
indent_files = $(libisofs_la_SOURCES)
|
||||||
|
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 : */
|
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -7,70 +8,17 @@
|
|||||||
* volume.
|
* volume.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ISO_ECMA119
|
#ifndef LIBISO_ECMA119_H
|
||||||
#define __ISO_ECMA119
|
#define LIBISO_ECMA119_H
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h> /* for FILE */
|
||||||
|
#include <sys/types.h>
|
||||||
#include "susp.h"
|
#include "susp.h"
|
||||||
|
|
||||||
/**
|
struct ecma119_tree_node;
|
||||||
* Persistent data for writing directories according to the ecma119 standard.
|
struct joliet_tree_node;
|
||||||
*/
|
|
||||||
struct dir_write_info
|
|
||||||
{
|
|
||||||
struct susp_info susp; /**< \see node_write_info */
|
|
||||||
struct susp_info self_susp; /**< SUSP data for this directory's
|
|
||||||
* "." entry.
|
|
||||||
*/
|
|
||||||
struct susp_info parent_susp; /**< SUSP data for this directory's
|
|
||||||
* ".." entry.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int len; /**< The combined length of all children's
|
|
||||||
* Directory Record lengths. This includes
|
|
||||||
* the System Use areas.
|
|
||||||
*/
|
|
||||||
int susp_len; /**< The combined length of all children's
|
|
||||||
* SUSP Continuation Areas.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* the parent/child information prior to relocation */
|
|
||||||
struct iso_tree_dir *real_parent;
|
|
||||||
int real_nchildren;
|
|
||||||
struct iso_tree_dir **real_children;
|
|
||||||
int real_depth;
|
|
||||||
|
|
||||||
/* joliet information */
|
|
||||||
int joliet_block; /**< The block at which the Joliet version of
|
|
||||||
* this directory will be written.
|
|
||||||
*/
|
|
||||||
int joliet_len; /**< The combined length of all children's
|
|
||||||
* Joliet Directory Record lengths.
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persistent data for writing files according to the ecma119 standard.
|
|
||||||
*/
|
|
||||||
struct file_write_info
|
|
||||||
{
|
|
||||||
struct susp_info susp; /**< \see node_write_info */
|
|
||||||
|
|
||||||
struct iso_tree_dir *real_me; /**< If this is non-NULL, the file is
|
|
||||||
* a placeholder for a relocated
|
|
||||||
* directory and this field points to
|
|
||||||
* that relocated directory.
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The fields in common between file_write_info and dir_write_info.
|
|
||||||
*/
|
|
||||||
struct node_write_info
|
|
||||||
{
|
|
||||||
struct susp_info susp; /**< The SUSP data for this file. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The possible states that the ecma119 writer can be in.
|
* The possible states that the ecma119 writer can be in.
|
||||||
@ -100,11 +48,13 @@ enum ecma119_write_state
|
|||||||
*/
|
*/
|
||||||
struct ecma119_write_target
|
struct ecma119_write_target
|
||||||
{
|
{
|
||||||
|
struct ecma119_tree_node *root;
|
||||||
|
struct joliet_tree_node *joliet_root;
|
||||||
struct iso_volset *volset;
|
struct iso_volset *volset;
|
||||||
int volnum;
|
int volnum;
|
||||||
|
|
||||||
time_t now; /**< Time at which writing began. */
|
time_t now; /**< Time at which writing began. */
|
||||||
int total_size; /**< Total size of the output. This only
|
off_t total_size; /**< Total size of the output. This only
|
||||||
* includes the current volume. */
|
* includes the current volume. */
|
||||||
uint32_t vol_space_size;
|
uint32_t vol_space_size;
|
||||||
|
|
||||||
@ -120,73 +70,63 @@ struct ecma119_write_target
|
|||||||
uint32_t m_path_table_pos;
|
uint32_t m_path_table_pos;
|
||||||
uint32_t l_path_table_pos_joliet;
|
uint32_t l_path_table_pos_joliet;
|
||||||
uint32_t m_path_table_pos_joliet;
|
uint32_t m_path_table_pos_joliet;
|
||||||
|
uint32_t total_dir_size;
|
||||||
|
uint32_t total_dir_size_joliet;
|
||||||
|
|
||||||
struct iso_tree_dir **dirlist; /* A pre-order list of directories
|
struct ecma119_tree_node **dirlist;
|
||||||
|
/**< A pre-order list of directories
|
||||||
* (this is the order in which we write
|
* (this is the order in which we write
|
||||||
* out directory records).
|
* out directory records).
|
||||||
*/
|
*/
|
||||||
struct iso_tree_dir **pathlist; /* A breadth-first list of directories.
|
struct ecma119_tree_node **pathlist;
|
||||||
* This is used for writing out the path
|
/**< A breadth-first list of
|
||||||
* tables.
|
* directories. This is used for
|
||||||
|
* writing out the path tables.
|
||||||
*/
|
*/
|
||||||
int dirlist_len; /* The length of the previous 2 lists.
|
size_t dirlist_len; /**< The length of the previous 2 lists.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct iso_tree_file **filelist;/* A pre-order list of files with
|
struct ecma119_tree_node **filelist;
|
||||||
|
/**< A pre-order list of files with
|
||||||
* non-NULL paths and non-zero sizes.
|
* non-NULL paths and non-zero sizes.
|
||||||
*/
|
*/
|
||||||
int filelist_len; /* Length of the previous list. */
|
size_t filelist_len; /* Length of the previous list. */
|
||||||
|
|
||||||
int curfile; /* Used as a helper field for writing
|
int curfile; /**< Used as a helper field for writing
|
||||||
out filelist and dirlist */
|
out filelist and dirlist */
|
||||||
|
|
||||||
/* Joliet versions of the above lists. Since Joliet doesn't require
|
/* Joliet versions of the above lists. Since Joliet doesn't require
|
||||||
* directory relocation, the order of these list might be different from
|
* directory relocation, the order of these lists might be different
|
||||||
* the lists above. */
|
* from the lists above (but they will be the same length).
|
||||||
struct iso_tree_dir **dirlist_joliet;
|
*/
|
||||||
struct iso_tree_dir **pathlist_joliet;
|
struct joliet_tree_node **dirlist_joliet;
|
||||||
|
struct joliet_tree_node **pathlist_joliet;
|
||||||
|
|
||||||
enum ecma119_write_state state; /* The current state of the writer. */
|
enum ecma119_write_state state; /* The current state of the writer. */
|
||||||
|
|
||||||
/* persistent data for the various states. Each struct should not be
|
/* Most writers work by
|
||||||
* touched except for the writer of the relevant stage. When the writer
|
* 1) making sure state_data is big enough for their data
|
||||||
* of the relevant stage is finished, it should set all fields to 0.
|
* 2) writing _all_ their data into state_data
|
||||||
|
* 3) relying on write_data_chunk to write the data block
|
||||||
|
* by block.
|
||||||
*/
|
*/
|
||||||
union
|
uint8_t *state_data;
|
||||||
{
|
off_t state_data_size;
|
||||||
struct
|
off_t state_data_off;
|
||||||
{
|
int state_data_valid;
|
||||||
int blocks;
|
|
||||||
unsigned char *data;
|
/* for writing out files */
|
||||||
} path_table;
|
struct state_files {
|
||||||
struct
|
off_t pos; /* The number of bytes we have written
|
||||||
{
|
* so far in the current file.
|
||||||
size_t pos; /* The number of bytes we have written
|
*/
|
||||||
* so far in the current directory.
|
off_t data_len;/* The number of bytes in the currently
|
||||||
*/
|
* open file.
|
||||||
size_t data_len;/* The number of bytes in the current
|
*/
|
||||||
* directory.
|
FILE *fd; /* The currently open file. */
|
||||||
*/
|
int file; /* The index in filelist that we are
|
||||||
unsigned char *data; /* The data (combined Directory
|
* currently writing (or about to write). */
|
||||||
* Records and susp_CE areas) of the
|
} state_files;
|
||||||
* current directory.
|
|
||||||
*/
|
|
||||||
int dir; /* The index in dirlist that we are
|
|
||||||
* currently writing. */
|
|
||||||
} dir_records;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
size_t pos; /* The number of bytes we have written
|
|
||||||
* so far in the current file.
|
|
||||||
*/
|
|
||||||
size_t data_len;/* The number of bytes in the currently
|
|
||||||
* open file.
|
|
||||||
*/
|
|
||||||
FILE *fd; /* The currently open file. */
|
|
||||||
int file; /* The index in filelist that we are
|
|
||||||
* currently writing. */
|
|
||||||
} files;
|
|
||||||
} state_data;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -198,23 +138,130 @@ struct ecma119_write_target
|
|||||||
* \post The directory heirarchy has been reorganised to be ecma119-compatible.
|
* \post The directory heirarchy has been reorganised to be ecma119-compatible.
|
||||||
*/
|
*/
|
||||||
struct ecma119_write_target *ecma119_target_new(struct iso_volset *volset,
|
struct ecma119_write_target *ecma119_target_new(struct iso_volset *volset,
|
||||||
int volnum);
|
int volnum,
|
||||||
|
int level,
|
||||||
|
int flags);
|
||||||
|
|
||||||
/** Macros to help with casting between node_write_info and dir/file_write_info.
|
#define BP(a,b) [(b) - (a) + 1]
|
||||||
|
|
||||||
|
struct ecma119_pri_vol_desc
|
||||||
|
{
|
||||||
|
uint8_t vol_desc_type BP(1, 1);
|
||||||
|
uint8_t std_identifier BP(2, 6);
|
||||||
|
uint8_t vol_desc_version BP(7, 7);
|
||||||
|
uint8_t unused1 BP(8, 8);
|
||||||
|
uint8_t system_id BP(9, 40);
|
||||||
|
uint8_t volume_id BP(41, 72);
|
||||||
|
uint8_t unused2 BP(73, 80);
|
||||||
|
uint8_t vol_space_size BP(81, 88);
|
||||||
|
uint8_t unused3 BP(89, 120);
|
||||||
|
uint8_t vol_set_size BP(121, 124);
|
||||||
|
uint8_t vol_seq_number BP(125, 128);
|
||||||
|
uint8_t block_size BP(129, 132);
|
||||||
|
uint8_t path_table_size BP(133, 140);
|
||||||
|
uint8_t l_path_table_pos BP(141, 144);
|
||||||
|
uint8_t opt_l_path_table_pos BP(145, 148);
|
||||||
|
uint8_t m_path_table_pos BP(149, 152);
|
||||||
|
uint8_t opt_m_path_table_pos BP(153, 156);
|
||||||
|
uint8_t root_dir_record BP(157, 190);
|
||||||
|
uint8_t vol_set_id BP(191, 318);
|
||||||
|
uint8_t publisher_id BP(319, 446);
|
||||||
|
uint8_t data_prep_id BP(447, 574);
|
||||||
|
uint8_t application_id BP(575, 702);
|
||||||
|
uint8_t copyright_file_id BP(703, 739);
|
||||||
|
uint8_t abstract_file_id BP(740, 776);
|
||||||
|
uint8_t bibliographic_file_id BP(777, 813);
|
||||||
|
uint8_t vol_creation_time BP(814, 830);
|
||||||
|
uint8_t vol_modification_time BP(831, 847);
|
||||||
|
uint8_t vol_expiration_time BP(848, 864);
|
||||||
|
uint8_t vol_effective_time BP(865, 881);
|
||||||
|
uint8_t file_structure_version BP(882, 882);
|
||||||
|
uint8_t reserved1 BP(883, 883);
|
||||||
|
uint8_t app_use BP(884, 1395);
|
||||||
|
uint8_t reserved2 BP(1396, 2048);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ecma119_sup_vol_desc
|
||||||
|
{
|
||||||
|
uint8_t vol_desc_type BP(1, 1);
|
||||||
|
uint8_t std_identifier BP(2, 6);
|
||||||
|
uint8_t vol_desc_version BP(7, 7);
|
||||||
|
uint8_t vol_flags BP(8, 8);
|
||||||
|
uint8_t system_id BP(9, 40);
|
||||||
|
uint8_t volume_id BP(41, 72);
|
||||||
|
uint8_t unused2 BP(73, 80);
|
||||||
|
uint8_t vol_space_size BP(81, 88);
|
||||||
|
uint8_t esc_sequences BP(89, 120);
|
||||||
|
uint8_t vol_set_size BP(121, 124);
|
||||||
|
uint8_t vol_seq_number BP(125, 128);
|
||||||
|
uint8_t block_size BP(129, 132);
|
||||||
|
uint8_t path_table_size BP(133, 140);
|
||||||
|
uint8_t l_path_table_pos BP(141, 144);
|
||||||
|
uint8_t opt_l_path_table_pos BP(145, 148);
|
||||||
|
uint8_t m_path_table_pos BP(149, 152);
|
||||||
|
uint8_t opt_m_path_table_pos BP(153, 156);
|
||||||
|
uint8_t root_dir_record BP(157, 190);
|
||||||
|
uint8_t vol_set_id BP(191, 318);
|
||||||
|
uint8_t publisher_id BP(319, 446);
|
||||||
|
uint8_t data_prep_id BP(447, 574);
|
||||||
|
uint8_t application_id BP(575, 702);
|
||||||
|
uint8_t copyright_file_id BP(703, 739);
|
||||||
|
uint8_t abstract_file_id BP(740, 776);
|
||||||
|
uint8_t bibliographic_file_id BP(777, 813);
|
||||||
|
uint8_t vol_creation_time BP(814, 830);
|
||||||
|
uint8_t vol_modification_time BP(831, 847);
|
||||||
|
uint8_t vol_expiration_time BP(848, 864);
|
||||||
|
uint8_t vol_effective_time BP(865, 881);
|
||||||
|
uint8_t file_structure_version BP(882, 882);
|
||||||
|
uint8_t reserved1 BP(883, 883);
|
||||||
|
uint8_t app_use BP(884, 1395);
|
||||||
|
uint8_t reserved2 BP(1396, 2048);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ecma119_vol_desc_terminator
|
||||||
|
{
|
||||||
|
uint8_t vol_desc_type BP(1, 1);
|
||||||
|
uint8_t std_identifier BP(2, 6);
|
||||||
|
uint8_t vol_desc_version BP(7, 7);
|
||||||
|
uint8_t reserved BP(8, 2048);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ecma119_dir_record
|
||||||
|
{
|
||||||
|
uint8_t len_dr BP(1, 1);
|
||||||
|
uint8_t len_xa BP(2, 2);
|
||||||
|
uint8_t block BP(3, 10);
|
||||||
|
uint8_t length BP(11, 18);
|
||||||
|
uint8_t recording_time BP(19, 25);
|
||||||
|
uint8_t flags BP(26, 26);
|
||||||
|
uint8_t file_unit_size BP(27, 27);
|
||||||
|
uint8_t interleave_gap_size BP(28, 28);
|
||||||
|
uint8_t vol_seq_number BP(29, 32);
|
||||||
|
uint8_t len_fi BP(33, 33);
|
||||||
|
uint8_t file_id BP(34, 34); /* 34 to 33+len_fi */
|
||||||
|
/* padding field (if len_fi is even) */
|
||||||
|
/* system use (len_dr - len_su + 1 to len_dr) */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ecma119_path_table_record
|
||||||
|
{
|
||||||
|
uint8_t len_di BP(1, 1);
|
||||||
|
uint8_t len_xa BP(2, 2);
|
||||||
|
uint8_t block BP(3, 6);
|
||||||
|
uint8_t parent BP(7, 8);
|
||||||
|
uint8_t dir_id BP(9, 9); /* 9 to 8+len_di */
|
||||||
|
/* padding field (if len_di is odd) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility function for writers that want to write their data all at once
|
||||||
|
* rather than block-by-block. This creates a buffer of size \p size, passes
|
||||||
|
* it to the given writer, then hands out block-sized chunks.
|
||||||
*/
|
*/
|
||||||
#define DIR_INF(a) ( (struct dir_write_info*) (a) )
|
void
|
||||||
#define FILE_INF(a) ( (struct file_write_info*) (a) )
|
ecma119_start_chunking(struct ecma119_write_target *t,
|
||||||
#define NODE_INF(a) ( (struct node_write_info*) (a) )
|
void (*)(struct ecma119_write_target*, uint8_t*),
|
||||||
|
off_t size,
|
||||||
|
uint8_t *buf);
|
||||||
|
|
||||||
#define GET_DIR_INF(a) ( (struct dir_write_info*) (a)->writer_data )
|
#endif /* LIBISO_ECMA119_H */
|
||||||
#define GET_FILE_INF(a) ( (struct file_write_info*) (a)->writer_data )
|
|
||||||
#define GET_NODE_INF(a) ( (struct node_write_info*) (a)->writer_data )
|
|
||||||
|
|
||||||
#define TARGET_ROOT(t) ( (t)->volset->volume[(t)->volnum]->root )
|
|
||||||
|
|
||||||
#define NODE_NAMELEN(n,i) strlen(iso_tree_node_get_name(ISO_NODE(n), i))
|
|
||||||
#define NODE_JOLLEN(n) ucslen(iso_tree_node_get_name(ISO_NODE(n), \
|
|
||||||
ISO_NAME_JOLIET))
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __ISO_ECMA119 */
|
|
||||||
|
@ -9,10 +9,11 @@
|
|||||||
* - Write the volume to a file or create a burn source for use with Libburn.
|
* - Write the volume to a file or create a burn source for use with Libburn.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __LIBISOFS
|
#ifndef LIBISO_LIBISOFS_H
|
||||||
#define __LIBISOFS
|
#define LIBISO_LIBISOFS_H
|
||||||
|
|
||||||
#include "libburn/libburn.h"
|
/* #include <libburn.h> */
|
||||||
|
struct burn_source;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data volume.
|
* Data volume.
|
||||||
@ -27,35 +28,11 @@ struct iso_volume;
|
|||||||
struct iso_volset;
|
struct iso_volset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directory on a volume.
|
* A node in the filesystem tree.
|
||||||
* @see tree.h for details.
|
|
||||||
*/
|
|
||||||
struct iso_tree_dir;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File on a volume.
|
|
||||||
* @see tree.h for details.
|
|
||||||
*/
|
|
||||||
struct iso_tree_file;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Either a file or a directory.
|
|
||||||
* \see tree.h
|
* \see tree.h
|
||||||
*/
|
*/
|
||||||
struct iso_tree_node;
|
struct iso_tree_node;
|
||||||
|
|
||||||
/**
|
|
||||||
* Possible versions of a file or directory name or identifier.
|
|
||||||
*/
|
|
||||||
enum iso_name_version {
|
|
||||||
ISO_NAME_FULL, /**< In the current locale. */
|
|
||||||
ISO_NAME_ISO, /**< Current ISO level identifier. */
|
|
||||||
ISO_NAME_ISO_L1, /**< ISO level 1 identifier. */
|
|
||||||
ISO_NAME_ISO_L2, /**< ISO level 2 identifier. */
|
|
||||||
ISO_NAME_ROCKRIDGE, /**< Rock Ridge file or directory name. */
|
|
||||||
ISO_NAME_JOLIET /**< Joliet identifier. */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ecma119_extension_flag {
|
enum ecma119_extension_flag {
|
||||||
ECMA119_ROCKRIDGE = (1<<0),
|
ECMA119_ROCKRIDGE = (1<<0),
|
||||||
ECMA119_JOLIET = (1<<1)
|
ECMA119_JOLIET = (1<<1)
|
||||||
@ -69,6 +46,11 @@ struct iso_volume *iso_volume_new(const char *volume_id,
|
|||||||
const char *publisher_id,
|
const char *publisher_id,
|
||||||
const char *data_preparer_id);
|
const char *data_preparer_id);
|
||||||
|
|
||||||
|
struct iso_volume *iso_volume_new_with_root(const char *volume_id,
|
||||||
|
const char *publisher_id,
|
||||||
|
const char *data_preparer_id,
|
||||||
|
struct iso_tree_node *root);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free a volume.
|
* Free a volume.
|
||||||
*/
|
*/
|
||||||
@ -77,7 +59,7 @@ void iso_volume_free(struct iso_volume *volume);
|
|||||||
/**
|
/**
|
||||||
* Get the root directory for a volume.
|
* Get the root directory for a volume.
|
||||||
*/
|
*/
|
||||||
struct iso_tree_dir *iso_volume_get_root(const struct iso_volume *volume);
|
struct iso_tree_node *iso_volume_get_root(const struct iso_volume *volume);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill in the volume identifier for a volume.
|
* Fill in the volume identifier for a volume.
|
||||||
@ -97,37 +79,6 @@ void iso_volume_set_publisher_id(struct iso_volume *volume,
|
|||||||
void iso_volume_set_data_preparer_id(struct iso_volume *volume,
|
void iso_volume_set_data_preparer_id(struct iso_volume *volume,
|
||||||
const char *data_preparer_id);
|
const char *data_preparer_id);
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current ISO level for a volume.
|
|
||||||
*/
|
|
||||||
int iso_volume_get_iso_level(const struct iso_volume *volume);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the current ISO level for a volume.
|
|
||||||
* ISO level must be 1 or 2.
|
|
||||||
*/
|
|
||||||
void iso_volume_set_iso_level(struct iso_volume *volume, int level);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See if Rock Ridge (POSIX) is enabled for a volume.
|
|
||||||
*/
|
|
||||||
int iso_volume_get_rockridge(const struct iso_volume *volume);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable or disable Rock Ridge (POSIX) for a volume.
|
|
||||||
*/
|
|
||||||
void iso_volume_set_rockridge(struct iso_volume *volume, int rockridge);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See if Joliet (Unicode) is enabled for a volume.
|
|
||||||
*/
|
|
||||||
int iso_volume_get_joliet(const struct iso_volume *volume);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable or disable Joliet (Unicode) for a volume.
|
|
||||||
*/
|
|
||||||
void iso_volume_set_joliet(struct iso_volume *volume, int joliet);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Volume Set consisting of only one volume.
|
* Create a new Volume Set consisting of only one volume.
|
||||||
* @param volume The first and only volume for the volset to contain.
|
* @param volume The first and only volume for the volset to contain.
|
||||||
@ -142,28 +93,14 @@ struct iso_volset *iso_volset_new(struct iso_volume *volume,
|
|||||||
*
|
*
|
||||||
* \param path The path, on the local filesystem, of the file.
|
* \param path The path, on the local filesystem, of the file.
|
||||||
*
|
*
|
||||||
* \pre \p parent is non-NULL
|
* \pre \p parent is NULL or is a directory.
|
||||||
* \pre \p path is non-NULL and is a valid path to a non-directory on the local
|
* \pre \p path is non-NULL and is a valid path to a non-directory on the local
|
||||||
* filesystem.
|
* filesystem.
|
||||||
* \return An iso_tree_file whose path is \p path and whose parent is \p parent.
|
* \return An iso_tree_node whose path is \p path and whose parent is \p parent.
|
||||||
*/
|
*/
|
||||||
struct iso_tree_file *iso_tree_add_file(struct iso_tree_dir *parent,
|
struct iso_tree_node *iso_tree_add_node(struct iso_tree_node *parent,
|
||||||
const char *path);
|
const char *path);
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a directory from the local filesystem to the tree.
|
|
||||||
* Warning: this only adds the directory itself, no files or subdirectories.
|
|
||||||
*
|
|
||||||
* \param path The path, on the local filesystem, of the directory.
|
|
||||||
*
|
|
||||||
* \pre \p parent is non-NULL
|
|
||||||
* \pre \p path is non-NULL and is a valid path to a directory on the local
|
|
||||||
* filesystem.
|
|
||||||
* \return a pointer to the newly created directory.
|
|
||||||
*/
|
|
||||||
struct iso_tree_dir *iso_tree_add_dir(struct iso_tree_dir *parent,
|
|
||||||
const char *path);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively add an existing directory to the tree.
|
* Recursively add an existing directory to the tree.
|
||||||
* Warning: when using this, you'll lose pointers to files or subdirectories.
|
* Warning: when using this, you'll lose pointers to files or subdirectories.
|
||||||
@ -172,18 +109,18 @@ struct iso_tree_dir *iso_tree_add_dir(struct iso_tree_dir *parent,
|
|||||||
*
|
*
|
||||||
* \param path The path, on the local filesystem, of the directory to add.
|
* \param path The path, on the local filesystem, of the directory to add.
|
||||||
*
|
*
|
||||||
* \pre \p parent is non-NULL
|
* \pre \p parent is NULL or is a directory.
|
||||||
* \pre \p path is non-NULL and is a valid path to a directory on the local
|
* \pre \p path is non-NULL and is a valid path to a directory on the local
|
||||||
* filesystem.
|
* filesystem.
|
||||||
* \return a pointer to the newly created directory.
|
* \return a pointer to the newly created directory.
|
||||||
*/
|
*/
|
||||||
struct iso_tree_dir *iso_tree_radd_dir(struct iso_tree_dir *parent,
|
struct iso_tree_node *iso_tree_radd_dir(struct iso_tree_node *parent,
|
||||||
const char *path);
|
const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new, empty directory on the volume.
|
* Creates a new, empty directory on the volume.
|
||||||
*
|
*
|
||||||
* \pre \p parent is non-NULL
|
* \pre \p parent is NULL or is a directory.
|
||||||
* \pre \p name is unique among the children and files belonging to \p parent.
|
* \pre \p name is unique among the children and files belonging to \p parent.
|
||||||
* Also, it doesn't contain '/' characters.
|
* Also, it doesn't contain '/' characters.
|
||||||
*
|
*
|
||||||
@ -191,35 +128,20 @@ struct iso_tree_dir *iso_tree_radd_dir(struct iso_tree_dir *parent,
|
|||||||
* POSIX attributes are the same as \p parent's.
|
* POSIX attributes are the same as \p parent's.
|
||||||
* \return a pointer to the newly created directory.
|
* \return a pointer to the newly created directory.
|
||||||
*/
|
*/
|
||||||
struct iso_tree_dir *iso_tree_add_new_dir(struct iso_tree_dir *parent,
|
struct iso_tree_node *iso_tree_add_new_dir(struct iso_tree_node *parent,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of a node.
|
* Set the name of a file (using the current locale).
|
||||||
*/
|
*/
|
||||||
const char *iso_tree_node_get_name(const struct iso_tree_node *node,
|
void iso_tree_node_set_name(struct iso_tree_node *file, const char *name);
|
||||||
enum iso_name_version ver);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the name of a file.
|
|
||||||
* The name you input here will be the full name and will be used to derive the
|
|
||||||
* ISO, RockRidge and Joliet names.
|
|
||||||
*/
|
|
||||||
void iso_tree_file_set_name(struct iso_tree_file *file, const char *name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the name of a directory.
|
|
||||||
* The name you input here will be the full name and will be used to derive the
|
|
||||||
* ISO, RockRidge and Joliet names.
|
|
||||||
*/
|
|
||||||
void iso_tree_dir_set_name(struct iso_tree_dir *dir, const char *name);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively print a directory to stdout.
|
* Recursively print a directory to stdout.
|
||||||
* \param spaces The initial number of spaces on the left. Set to 0 if you
|
* \param spaces The initial number of spaces on the left. Set to 0 if you
|
||||||
* supply a root directory.
|
* supply a root directory.
|
||||||
*/
|
*/
|
||||||
void iso_tree_print(const struct iso_tree_dir *root, int spaces);
|
void iso_tree_print(const struct iso_tree_node *root, int spaces);
|
||||||
|
|
||||||
/** Create a burn_source which can be used as a data source for a track
|
/** Create a burn_source which can be used as a data source for a track
|
||||||
*
|
*
|
||||||
@ -240,4 +162,4 @@ struct burn_source* iso_source_new_ecma119 (struct iso_volset *volumeset,
|
|||||||
int level,
|
int level,
|
||||||
int flags);
|
int flags);
|
||||||
|
|
||||||
#endif /* __LIBISOFS */
|
#endif /* LIBISO_LIBISOFS_H */
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||||
|
|
||||||
#include "rockridge.h"
|
#include "rockridge.h"
|
||||||
#include "tree.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "volume.h"
|
|
||||||
#include "ecma119.h"
|
#include "ecma119.h"
|
||||||
|
#include "ecma119_tree.h"
|
||||||
|
#include "tree.h"
|
||||||
#include "susp.h"
|
#include "susp.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -15,53 +15,50 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
/* create a PX field from the permissions on the current node. */
|
/* create a PX field from the permissions on the current node. */
|
||||||
unsigned char *rrip_make_PX(struct ecma119_write_target *t,
|
uint8_t *rrip_make_PX(struct ecma119_write_target *t,
|
||||||
struct iso_tree_node *node)
|
struct ecma119_tree_node *node)
|
||||||
{
|
{
|
||||||
unsigned char *PX = malloc(44);
|
uint8_t *PX = malloc(44);
|
||||||
|
|
||||||
PX[0] = 'P';
|
PX[0] = 'P';
|
||||||
PX[1] = 'X';
|
PX[1] = 'X';
|
||||||
PX[2] = 44;
|
PX[2] = 44;
|
||||||
PX[3] = 1;
|
PX[3] = 1;
|
||||||
iso_bb(&PX[4], node->attrib.st_mode, 4);
|
iso_bb(&PX[4], node->iso_self->attrib.st_mode, 4);
|
||||||
iso_bb(&PX[12], node->attrib.st_nlink, 4);
|
iso_bb(&PX[12], node->iso_self->attrib.st_nlink, 4);
|
||||||
iso_bb(&PX[20], node->attrib.st_uid, 4);
|
iso_bb(&PX[20], node->iso_self->attrib.st_uid, 4);
|
||||||
iso_bb(&PX[28], node->attrib.st_gid, 4);
|
iso_bb(&PX[28], node->iso_self->attrib.st_gid, 4);
|
||||||
iso_bb(&PX[36], node->attrib.st_ino, 4);
|
iso_bb(&PX[36], node->iso_self->attrib.st_ino, 4);
|
||||||
return PX;
|
return PX;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** See IEEE 1282 4.1.1 */
|
/** See IEEE 1282 4.1.1 */
|
||||||
void rrip_add_PX(struct ecma119_write_target *t, struct iso_tree_node *node)
|
void rrip_add_PX(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||||
{
|
{
|
||||||
susp_append(t, node, rrip_make_PX(t, node));
|
susp_append(t, &node->susp, rrip_make_PX(t, node));
|
||||||
|
if (node->type == ECMA119_DIR) {
|
||||||
|
susp_append(t, &node->dir.self_susp, rrip_make_PX(t, node));
|
||||||
|
susp_append(t, &node->dir.parent_susp, rrip_make_PX(t, node));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrip_add_PX_dir(struct ecma119_write_target *t, struct iso_tree_dir *dir)
|
void rrip_add_PN(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||||
{
|
{
|
||||||
susp_append(t, ISO_NODE(dir), rrip_make_PX(t, ISO_NODE(dir)));
|
uint8_t *PN = malloc(20);
|
||||||
susp_append_self(t, dir, rrip_make_PX(t, ISO_NODE(dir)));
|
|
||||||
susp_append_parent(t, dir, rrip_make_PX(t, ISO_NODE(dir)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void rrip_add_PN(struct ecma119_write_target *t, struct iso_tree_node *node)
|
|
||||||
{
|
|
||||||
unsigned char *PN = malloc(20);
|
|
||||||
|
|
||||||
PN[0] = 'P';
|
PN[0] = 'P';
|
||||||
PN[1] = 'N';
|
PN[1] = 'N';
|
||||||
PN[2] = 20;
|
PN[2] = 20;
|
||||||
PN[3] = 1;
|
PN[3] = 1;
|
||||||
iso_bb(&PN[4], node->attrib.st_dev >> 32, 4);
|
iso_bb(&PN[4], node->iso_self->attrib.st_dev >> 32, 4);
|
||||||
iso_bb(&PN[12], node->attrib.st_dev & 0xffffffff, 4);
|
iso_bb(&PN[12], node->iso_self->attrib.st_dev & 0xffffffff, 4);
|
||||||
susp_append(t, node, PN);
|
susp_append(t, &node->susp, PN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rrip_SL_append_comp(int *n, unsigned char ***comps,
|
static void rrip_SL_append_comp(int *n, uint8_t ***comps,
|
||||||
char *s, int size, char fl)
|
char *s, int size, char fl)
|
||||||
{
|
{
|
||||||
unsigned char *comp = malloc(size + 2);
|
uint8_t *comp = malloc(size + 2);
|
||||||
|
|
||||||
(*n)++;
|
(*n)++;
|
||||||
comp[0] = fl;
|
comp[0] = fl;
|
||||||
@ -75,7 +72,7 @@ static void rrip_SL_append_comp(int *n, unsigned char ***comps,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void rrip_SL_add_component(char *prev, char *cur, int *n_comp,
|
static void rrip_SL_add_component(char *prev, char *cur, int *n_comp,
|
||||||
unsigned char ***comps)
|
uint8_t ***comps)
|
||||||
{
|
{
|
||||||
int size = cur - prev;
|
int size = cur - prev;
|
||||||
|
|
||||||
@ -103,24 +100,24 @@ static void rrip_SL_add_component(char *prev, char *cur, int *n_comp,
|
|||||||
rrip_SL_append_comp(n_comp, comps, prev, size, 0);
|
rrip_SL_append_comp(n_comp, comps, prev, size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node)
|
void rrip_add_SL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||||
{
|
{
|
||||||
int ret, pathsize = 0;
|
int ret, pathsize = 0;
|
||||||
char *path = NULL, *cur, *prev;
|
char *path = NULL, *cur, *prev;
|
||||||
struct iso_tree_file *file = (struct iso_tree_file *)node;
|
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
unsigned char **comp = NULL;
|
uint8_t **comp = NULL;
|
||||||
int n_comp = 0;
|
int n_comp = 0;
|
||||||
int total_comp_len = 0;
|
int total_comp_len = 0;
|
||||||
int written = 0, pos;
|
int written = 0, pos;
|
||||||
|
|
||||||
unsigned char *SL;
|
uint8_t *SL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
pathsize += 128;
|
pathsize += 128;
|
||||||
path = realloc(path, pathsize);
|
path = realloc(path, pathsize);
|
||||||
ret = readlink(file->path, path, pathsize);
|
/* FIXME: what if the file is not on the local fs? */
|
||||||
|
ret = readlink(node->iso_self->loc.path, path, pathsize);
|
||||||
} while (ret == pathsize);
|
} while (ret == pathsize);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
fprintf(stderr, "Error: couldn't read symlink: %s\n",
|
fprintf(stderr, "Error: couldn't read symlink: %s\n",
|
||||||
@ -156,7 +153,7 @@ void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node)
|
|||||||
memcpy(&SL[pos], comp[j], comp[j][2]);
|
memcpy(&SL[pos], comp[j], comp[j][2]);
|
||||||
pos += comp[j][2];
|
pos += comp[j][2];
|
||||||
}
|
}
|
||||||
susp_append(t, node, SL);
|
susp_append(t, &node->susp, SL);
|
||||||
written = i - 1;
|
written = i - 1;
|
||||||
total_comp_len = comp[i][1];
|
total_comp_len = comp[i][1];
|
||||||
}
|
}
|
||||||
@ -173,7 +170,7 @@ void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node)
|
|||||||
memcpy(&SL[pos], comp[j], comp[j][1] + 2);
|
memcpy(&SL[pos], comp[j], comp[j][1] + 2);
|
||||||
pos += comp[j][1] + 2;
|
pos += comp[j][1] + 2;
|
||||||
}
|
}
|
||||||
susp_append(t, node, SL);
|
susp_append(t, &node->susp, SL);
|
||||||
|
|
||||||
free(path);
|
free(path);
|
||||||
/* free the components */
|
/* free the components */
|
||||||
@ -184,10 +181,10 @@ void rrip_add_SL(struct ecma119_write_target *t, struct iso_tree_node *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void rrip_add_NM_single(struct ecma119_write_target *t,
|
static void rrip_add_NM_single(struct ecma119_write_target *t,
|
||||||
struct iso_tree_node *node,
|
struct susp_info *susp,
|
||||||
char *name, int size, int flags)
|
char *name, int size, int flags)
|
||||||
{
|
{
|
||||||
unsigned char *NM = malloc(size + 5);
|
uint8_t *NM = malloc(size + 5);
|
||||||
|
|
||||||
NM[0] = 'N';
|
NM[0] = 'N';
|
||||||
NM[1] = 'M';
|
NM[1] = 'M';
|
||||||
@ -197,103 +194,107 @@ static void rrip_add_NM_single(struct ecma119_write_target *t,
|
|||||||
if (size) {
|
if (size) {
|
||||||
memcpy(&NM[5], name, size);
|
memcpy(&NM[5], name, size);
|
||||||
}
|
}
|
||||||
susp_append(t, node, NM);
|
susp_append(t, susp, NM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrip_add_NM(struct ecma119_write_target *t, struct iso_tree_node *node)
|
void
|
||||||
|
rrip_add_NM(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||||
{
|
{
|
||||||
struct iso_tree_file *file = (struct iso_tree_file *)node;
|
char *name = iso_p_fileid(node->iso_self->name);
|
||||||
int len = strlen(file->name.rockridge);
|
int len = name ? strlen(name) : 0;
|
||||||
char *pos = file->name.rockridge;
|
char *pos = name;
|
||||||
|
|
||||||
if (len == 1 && pos[0] == '.') {
|
if (!len)
|
||||||
rrip_add_NM_single(t, node, pos, 0, 1 << 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (len == 2 && !strncmp(pos, "..", 2)) {
|
|
||||||
rrip_add_NM_single(t, node, pos, 0, 1 << 2);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (node->type == ECMA119_DIR) {
|
||||||
|
rrip_add_NM_single(t, &node->dir.self_susp, pos, 0, 1 << 1);
|
||||||
|
rrip_add_NM_single(t, &node->dir.parent_susp, pos, 0, 1 << 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (len > 250) {
|
while (len > 250) {
|
||||||
rrip_add_NM_single(t, node, pos, 250, 1);
|
rrip_add_NM_single(t, &node->susp, pos, 250, 1);
|
||||||
len -= 250;
|
len -= 250;
|
||||||
pos += 250;
|
pos += 250;
|
||||||
}
|
}
|
||||||
rrip_add_NM_single(t, node, pos, len, 0);
|
rrip_add_NM_single(t, &node->susp, pos, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrip_add_CL(struct ecma119_write_target *t, struct iso_tree_node *node)
|
void rrip_add_CL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||||
{
|
{
|
||||||
unsigned char *CL = calloc(1, 12);
|
uint8_t *CL = calloc(1, 12);
|
||||||
|
|
||||||
CL[0] = 'C';
|
CL[0] = 'C';
|
||||||
CL[1] = 'L';
|
CL[1] = 'L';
|
||||||
CL[2] = 12;
|
CL[2] = 12;
|
||||||
CL[3] = 1;
|
CL[3] = 1;
|
||||||
susp_append(t, node, CL);
|
susp_append(t, &node->susp, CL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrip_add_PL(struct ecma119_write_target *t, struct iso_tree_dir *node)
|
void
|
||||||
|
rrip_add_PL(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||||
{
|
{
|
||||||
unsigned char *PL = calloc(1, 12);
|
uint8_t *PL = calloc(1, 12);
|
||||||
|
|
||||||
PL[0] = 'P';
|
PL[0] = 'P';
|
||||||
PL[1] = 'L';
|
PL[1] = 'L';
|
||||||
PL[2] = 12;
|
PL[2] = 12;
|
||||||
PL[3] = 1;
|
PL[3] = 1;
|
||||||
susp_append_parent(t, node, PL);
|
susp_append(t, &node->dir.parent_susp, PL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrip_add_RE(struct ecma119_write_target *t, struct iso_tree_node *node)
|
void
|
||||||
|
rrip_add_RE(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||||
{
|
{
|
||||||
unsigned char *RE = malloc(4);
|
uint8_t *RE = malloc(4);
|
||||||
|
|
||||||
RE[0] = 'R';
|
RE[0] = 'R';
|
||||||
RE[1] = 'E';
|
RE[1] = 'E';
|
||||||
RE[2] = 4;
|
RE[2] = 4;
|
||||||
RE[3] = 1;
|
RE[3] = 1;
|
||||||
susp_append(t, node, RE);
|
susp_append(t, &node->susp, RE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrip_add_TF(struct ecma119_write_target *t, struct iso_tree_node *node)
|
void
|
||||||
|
rrip_add_TF(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||||
{
|
{
|
||||||
unsigned char *TF = malloc(5 + 3 * 17);
|
uint8_t *TF = malloc(5 + 3 * 7);
|
||||||
|
|
||||||
TF[0] = 'T';
|
TF[0] = 'T';
|
||||||
TF[1] = 'F';
|
TF[1] = 'F';
|
||||||
TF[2] = 5 + 3 * 17;
|
TF[2] = 5 + 3 * 7;
|
||||||
TF[3] = 1;
|
TF[3] = 1;
|
||||||
TF[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7);
|
TF[4] = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 7);
|
||||||
iso_datetime_17(&TF[5], node->attrib.st_mtime);
|
iso_datetime_7(&TF[5], node->iso_self->attrib.st_mtime);
|
||||||
iso_datetime_17(&TF[22], node->attrib.st_atime);
|
iso_datetime_7(&TF[12], node->iso_self->attrib.st_atime);
|
||||||
iso_datetime_17(&TF[39], node->attrib.st_ctime);
|
iso_datetime_7(&TF[19], node->iso_self->attrib.st_ctime);
|
||||||
susp_append(t, node, TF);
|
susp_append(t, &node->susp, TF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rrip_finalize(struct ecma119_write_target *t, struct iso_tree_dir *dir)
|
void
|
||||||
|
rrip_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||||
{
|
{
|
||||||
struct dir_write_info *inf;
|
|
||||||
struct file_write_info *finf;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
inf = dir->writer_data;
|
assert(dir->type == ECMA119_DIR);
|
||||||
if (dir->parent != inf->real_parent) {
|
|
||||||
unsigned char *PL = susp_find(&inf->parent_susp, "PL");
|
|
||||||
|
|
||||||
iso_bb(&PL[4], inf->real_parent->block, 4);
|
if (dir->parent != dir->dir.real_parent) {
|
||||||
|
uint8_t *PL = susp_find(&dir->dir.parent_susp, "PL");
|
||||||
|
|
||||||
|
assert(PL);
|
||||||
|
iso_bb(&PL[4], dir->dir.real_parent->block, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < dir->nfiles; i++) {
|
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||||
finf = dir->files[i]->writer_data;
|
struct ecma119_tree_node *ch = dir->dir.children[i];
|
||||||
if (finf->real_me) {
|
|
||||||
unsigned char *CL = susp_find(&finf->susp, "CL");
|
|
||||||
|
|
||||||
iso_bb(&CL[4], finf->real_me->block, 4);
|
if (ch->type == ECMA119_FILE && ch->file.real_me) {
|
||||||
|
uint8_t *CL = susp_find(&ch->susp, "CL");
|
||||||
|
|
||||||
|
assert(CL);
|
||||||
|
iso_bb(&CL[4], ch->file.real_me->block, 4);
|
||||||
|
} else if (ch->type == ECMA119_DIR) {
|
||||||
|
rrip_finalize(t, ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < dir->nchildren; i++) {
|
|
||||||
rrip_finalize(t, dir->children[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,29 +2,25 @@
|
|||||||
|
|
||||||
/** Functions and structures used for Rock Ridge support. */
|
/** Functions and structures used for Rock Ridge support. */
|
||||||
|
|
||||||
#ifndef __ISO_ROCKRIDGE
|
#ifndef ISO_ROCKRIDGE_H
|
||||||
#define __ISO_ROCKRIDGE
|
#define ISO_ROCKRIDGE_H
|
||||||
|
|
||||||
struct ecma119_write_target;
|
struct ecma119_write_target;
|
||||||
struct iso_tree_node;
|
struct ecma119_tree_node;
|
||||||
struct iso_tree_dir;
|
|
||||||
|
|
||||||
void rrip_add_PX(struct ecma119_write_target *, struct iso_tree_node *);
|
void rrip_add_PX(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
void rrip_add_PN(struct ecma119_write_target *, struct iso_tree_node *);
|
void rrip_add_PN(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
void rrip_add_SL(struct ecma119_write_target *, struct iso_tree_node *);
|
void rrip_add_SL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
void rrip_add_NM(struct ecma119_write_target *, struct iso_tree_node *);
|
void rrip_add_NM(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
void rrip_add_CL(struct ecma119_write_target *, struct iso_tree_node *);
|
void rrip_add_CL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
void rrip_add_RE(struct ecma119_write_target *, struct iso_tree_node *);
|
void rrip_add_RE(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
void rrip_add_TF(struct ecma119_write_target *, struct iso_tree_node *);
|
void rrip_add_TF(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
|
|
||||||
/* This is special because it doesn't modify the susp fields of the directory
|
/* This is special because it doesn't modify the susp fields of the directory
|
||||||
* that gets passed to it; it modifies the susp fields of the ".." entry in
|
* that gets passed to it; it modifies the susp fields of the ".." entry in
|
||||||
* that directory. */
|
* that directory. */
|
||||||
void rrip_add_PL(struct ecma119_write_target *, struct iso_tree_dir *);
|
void rrip_add_PL(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
|
|
||||||
/* Add a PX field to the susp, self_susp and parent_susp entries */
|
void rrip_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
void rrip_add_PX_dir(struct ecma119_write_target *, struct iso_tree_dir *);
|
|
||||||
|
|
||||||
void rrip_finalize(struct ecma119_write_target *, struct iso_tree_dir *);
|
#endif /* ISO_ROCKRIDGE_H */
|
||||||
|
|
||||||
#endif /* __ISO_ROCKRIDGE */
|
|
||||||
|
216
libisofs/susp.c
216
libisofs/susp.c
@ -1,20 +1,25 @@
|
|||||||
/* vim: set noet ts=8 sts=8 sw=8 : */
|
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||||
|
|
||||||
#include "susp.h"
|
#include "susp.h"
|
||||||
#include "tree.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ecma119.h"
|
#include "ecma119.h"
|
||||||
|
#include "ecma119_tree.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static void susp_insert_direct(struct ecma119_write_target *t,
|
void susp_insert(struct ecma119_write_target *t,
|
||||||
struct susp_info *susp, unsigned char *data,
|
struct susp_info *susp,
|
||||||
int pos)
|
uint8_t *data,
|
||||||
|
int pos)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (pos < 0) {
|
||||||
|
pos = susp->n_susp_fields;
|
||||||
|
}
|
||||||
|
|
||||||
assert(pos <= susp->n_susp_fields);
|
assert(pos <= susp->n_susp_fields);
|
||||||
susp->n_susp_fields++;
|
susp->n_susp_fields++;
|
||||||
susp->susp_fields = realloc(susp->susp_fields,
|
susp->susp_fields = realloc(susp->susp_fields,
|
||||||
@ -27,60 +32,13 @@ static void susp_insert_direct(struct ecma119_write_target *t,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void susp_append(struct ecma119_write_target *t,
|
void susp_append(struct ecma119_write_target *t,
|
||||||
struct iso_tree_node *node, unsigned char *data)
|
struct susp_info *susp,
|
||||||
|
uint8_t *data)
|
||||||
{
|
{
|
||||||
struct dir_write_info *inf = node->writer_data;
|
susp_insert(t, susp, data, susp->n_susp_fields);
|
||||||
struct susp_info *susp = &inf->susp;
|
|
||||||
|
|
||||||
susp_insert_direct(t, susp, data, susp->n_susp_fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void susp_append_self(struct ecma119_write_target *t,
|
uint8_t *susp_find(struct susp_info *susp, const char *name)
|
||||||
struct iso_tree_dir *dir, unsigned char *data)
|
|
||||||
{
|
|
||||||
struct dir_write_info *inf = dir->writer_data;
|
|
||||||
struct susp_info *susp = &inf->self_susp;
|
|
||||||
|
|
||||||
susp_insert_direct(t, susp, data, susp->n_susp_fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
void susp_append_parent(struct ecma119_write_target *t,
|
|
||||||
struct iso_tree_dir *dir, unsigned char *data)
|
|
||||||
{
|
|
||||||
struct dir_write_info *inf = dir->writer_data;
|
|
||||||
struct susp_info *susp = &inf->parent_susp;
|
|
||||||
|
|
||||||
susp_insert_direct(t, susp, data, susp->n_susp_fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
void susp_insert(struct ecma119_write_target *t,
|
|
||||||
struct iso_tree_node *node, unsigned char *data, int pos)
|
|
||||||
{
|
|
||||||
struct dir_write_info *inf = node->writer_data;
|
|
||||||
struct susp_info *susp = &inf->susp;
|
|
||||||
|
|
||||||
susp_insert_direct(t, susp, data, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void susp_insert_self(struct ecma119_write_target *t,
|
|
||||||
struct iso_tree_dir *dir, unsigned char *data, int pos)
|
|
||||||
{
|
|
||||||
struct dir_write_info *inf = dir->writer_data;
|
|
||||||
struct susp_info *susp = &inf->self_susp;
|
|
||||||
|
|
||||||
susp_insert_direct(t, susp, data, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void susp_insert_parent(struct ecma119_write_target *t,
|
|
||||||
struct iso_tree_dir *dir, unsigned char *data, int pos)
|
|
||||||
{
|
|
||||||
struct dir_write_info *inf = dir->writer_data;
|
|
||||||
struct susp_info *susp = &inf->parent_susp;
|
|
||||||
|
|
||||||
susp_insert_direct(t, susp, data, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char *susp_find(struct susp_info *susp, const char *name)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -92,11 +50,15 @@ unsigned char *susp_find(struct susp_info *susp, const char *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* utility function for susp_add_CE because susp_add_CE needs to act 3 times
|
/** Utility function for susp_add_CE because susp_add_CE needs to act 3 times
|
||||||
* on directories (for the "." and ".." entries. */
|
* on directories (for the "." and ".." entries.
|
||||||
|
*
|
||||||
|
* \param len The amount of space available for the System Use area.
|
||||||
|
*/
|
||||||
#define CE_LEN 28
|
#define CE_LEN 28
|
||||||
static unsigned char *susp_add_single_CE(struct ecma119_write_target *t,
|
static unsigned char *susp_add_single_CE(struct ecma119_write_target *t,
|
||||||
struct susp_info *susp, int len)
|
struct susp_info *susp,
|
||||||
|
int len)
|
||||||
{
|
{
|
||||||
int susp_length = 0, tmp_len;
|
int susp_length = 0, tmp_len;
|
||||||
int i;
|
int i;
|
||||||
@ -138,33 +100,36 @@ static unsigned char *susp_add_single_CE(struct ecma119_write_target *t,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
try_add_CE(struct ecma119_write_target *t,
|
||||||
|
struct susp_info *susp,
|
||||||
|
size_t dirent_len)
|
||||||
|
{
|
||||||
|
uint8_t *CE = susp_add_single_CE(t, susp, 255 - dirent_len);
|
||||||
|
if (CE)
|
||||||
|
susp_insert(t, susp, CE, susp->n_fields_fit - 1);
|
||||||
|
}
|
||||||
|
|
||||||
/** See IEEE P1281 Draft Version 1.12/5.2. Because this function depends on the
|
/** See IEEE P1281 Draft Version 1.12/5.2. Because this function depends on the
|
||||||
* length of the other SUSP fields, it should always be calculated last. */
|
* length of the other SUSP fields, it should always be calculated last. */
|
||||||
void susp_add_CE(struct ecma119_write_target *t, struct iso_tree_node *node)
|
void
|
||||||
|
susp_add_CE(struct ecma119_write_target *t, struct ecma119_tree_node *node)
|
||||||
{
|
{
|
||||||
struct dir_write_info *inf = node->writer_data;
|
try_add_CE(t, &node->susp, node->dirent_len);
|
||||||
unsigned char *CE;
|
if (node->type == ECMA119_DIR) {
|
||||||
|
try_add_CE(t, &node->dir.self_susp, 34);
|
||||||
CE = susp_add_single_CE(t, &inf->susp, 255 - node->dirent_len);
|
try_add_CE(t, &node->dir.parent_susp, 34);
|
||||||
if (CE)
|
|
||||||
susp_insert(t, node, CE, inf->susp.n_fields_fit - 1);
|
|
||||||
if (S_ISDIR(node->attrib.st_mode)) {
|
|
||||||
CE = susp_add_single_CE(t, &inf->self_susp, 255 - 34);
|
|
||||||
if (CE)
|
|
||||||
susp_insert_self(t, (struct iso_tree_dir *)node, CE,
|
|
||||||
inf->self_susp.n_fields_fit - 1);
|
|
||||||
CE = susp_add_single_CE(t, &inf->parent_susp, 255 - 34);
|
|
||||||
if (CE)
|
|
||||||
susp_insert_parent(t, (struct iso_tree_dir *)node, CE,
|
|
||||||
inf->parent_susp.n_fields_fit - 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** See IEEE P1281 Draft Version 1.12/5.3 */
|
/** See IEEE P1281 Draft Version 1.12/5.3 */
|
||||||
void susp_add_SP(struct ecma119_write_target *t, struct iso_tree_dir *dir)
|
void
|
||||||
|
susp_add_SP(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||||
{
|
{
|
||||||
unsigned char *SP = malloc(7);
|
unsigned char *SP = malloc(7);
|
||||||
|
|
||||||
|
assert(dir->type == ECMA119_DIR);
|
||||||
|
|
||||||
SP[0] = 'S';
|
SP[0] = 'S';
|
||||||
SP[1] = 'P';
|
SP[1] = 'P';
|
||||||
SP[2] = (char)7;
|
SP[2] = (char)7;
|
||||||
@ -172,7 +137,7 @@ void susp_add_SP(struct ecma119_write_target *t, struct iso_tree_dir *dir)
|
|||||||
SP[4] = 0xbe;
|
SP[4] = 0xbe;
|
||||||
SP[5] = 0xef;
|
SP[5] = 0xef;
|
||||||
SP[6] = 0;
|
SP[6] = 0;
|
||||||
susp_append_self(t, dir, SP);
|
susp_append(t, &dir->dir.self_susp, SP);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@ -190,11 +155,14 @@ static void susp_add_ST(struct ecma119_write_target *t,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** See IEEE P1281 Draft Version 1.12/5.5 */
|
/** See IEEE P1281 Draft Version 1.12/5.5 FIXME: this is rockridge */
|
||||||
void susp_add_ER(struct ecma119_write_target *t, struct iso_tree_dir *dir)
|
void
|
||||||
|
rrip_add_ER(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||||
{
|
{
|
||||||
unsigned char *ER = malloc(182);
|
unsigned char *ER = malloc(182);
|
||||||
|
|
||||||
|
assert(dir->type == ECMA119_DIR);
|
||||||
|
|
||||||
ER[0] = 'E';
|
ER[0] = 'E';
|
||||||
ER[1] = 'R';
|
ER[1] = 'R';
|
||||||
ER[2] = 182;
|
ER[2] = 182;
|
||||||
@ -208,71 +176,71 @@ void susp_add_ER(struct ecma119_write_target *t, struct iso_tree_dir *dir)
|
|||||||
"FILE SYSTEM SEMANTICS.", 72);
|
"FILE SYSTEM SEMANTICS.", 72);
|
||||||
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
|
memcpy(&ER[89], "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, "
|
||||||
"PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
|
"PISCATAWAY, NJ, USA FOR THE 1282 SPECIFICATION.", 93);
|
||||||
susp_append_self(t, dir, ER);
|
susp_append(t, &dir->dir.self_susp, ER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate the location of the CE areas. Since CE areas don't need to be
|
||||||
|
* aligned to a block boundary, we contatenate all CE areas from a single
|
||||||
|
* directory and dump them immediately after all the directory records.
|
||||||
|
*
|
||||||
|
* Requires that the following be known:
|
||||||
|
* - position of the current directory (dir->block)
|
||||||
|
* - length of the current directory (dir->dir.len)
|
||||||
|
* - sum of the children's CE lengths (dir->dir.CE_len)
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
susp_fin_1_CE(struct ecma119_write_target *t,
|
||||||
|
struct susp_info *susp,
|
||||||
|
size_t block,
|
||||||
|
size_t *offset)
|
||||||
|
{
|
||||||
|
uint8_t *CE = susp->susp_fields[susp->n_fields_fit - 1];
|
||||||
|
|
||||||
|
if (!susp->CE_len) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iso_bb(&CE[4], block + (*offset) / t->block_size, 4);
|
||||||
|
iso_bb(&CE[12], (*offset) % t->block_size, 4);
|
||||||
|
*offset += susp->CE_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void susp_fin_CE(struct ecma119_write_target *t,
|
static void susp_fin_CE(struct ecma119_write_target *t,
|
||||||
struct iso_tree_dir *dir)
|
struct ecma119_tree_node *dir)
|
||||||
{
|
{
|
||||||
struct dir_write_info *inf = (struct dir_write_info *)
|
|
||||||
dir->writer_data;
|
|
||||||
struct node_write_info *cinf;
|
|
||||||
unsigned char *CE;
|
|
||||||
int i;
|
int i;
|
||||||
int CE_offset = inf->len;
|
size_t CE_offset = dir->dir.len;
|
||||||
|
|
||||||
if (inf->self_susp.CE_len) {
|
assert(dir->type == ECMA119_DIR);
|
||||||
CE = inf->self_susp.susp_fields[inf->self_susp.n_fields_fit -
|
|
||||||
1];
|
|
||||||
iso_bb(&CE[4], dir->block + CE_offset / 2048, 4);
|
|
||||||
iso_bb(&CE[12], CE_offset % 2048, 4);
|
|
||||||
CE_offset += inf->self_susp.CE_len;
|
|
||||||
}
|
|
||||||
if (inf->parent_susp.CE_len) {
|
|
||||||
CE = inf->parent_susp.susp_fields[inf->parent_susp.
|
|
||||||
n_fields_fit - 1];
|
|
||||||
iso_bb(&CE[4], dir->block + CE_offset / 2048, 4);
|
|
||||||
iso_bb(&CE[12], CE_offset % 2048, 4);
|
|
||||||
CE_offset += inf->parent_susp.CE_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < dir->nchildren; i++) {
|
susp_fin_1_CE(t, &dir->dir.self_susp, dir->block, &CE_offset);
|
||||||
cinf = dir->children[i]->writer_data;
|
susp_fin_1_CE(t, &dir->dir.parent_susp, dir->block, &CE_offset);
|
||||||
if (!cinf->susp.CE_len) {
|
|
||||||
continue;
|
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||||
}
|
struct ecma119_tree_node *ch = dir->dir.children[i];
|
||||||
CE = cinf->susp.susp_fields[cinf->susp.n_fields_fit - 1];
|
susp_fin_1_CE(t, &ch->susp, dir->block, &CE_offset);
|
||||||
iso_bb(&CE[4], dir->block + CE_offset / 2048, 4);
|
|
||||||
iso_bb(&CE[12], CE_offset % 2048, 4);
|
|
||||||
CE_offset += cinf->susp.CE_len;
|
|
||||||
}
|
}
|
||||||
for (i = 0; i < dir->nfiles; i++) {
|
assert(CE_offset == dir->dir.len + dir->dir.CE_len);
|
||||||
cinf = dir->files[i]->writer_data;
|
|
||||||
if (!cinf->susp.CE_len) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CE = cinf->susp.susp_fields[cinf->susp.n_fields_fit - 1];
|
|
||||||
iso_bb(&CE[4], dir->block + CE_offset / 2048, 4);
|
|
||||||
iso_bb(&CE[12], CE_offset % 2048, 4);
|
|
||||||
CE_offset += cinf->susp.CE_len;
|
|
||||||
}
|
|
||||||
assert(CE_offset == inf->len + inf->susp_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void susp_finalize(struct ecma119_write_target *t, struct iso_tree_dir *dir)
|
void
|
||||||
|
susp_finalize(struct ecma119_write_target *t, struct ecma119_tree_node *dir)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (dir->depth != 1) {
|
assert(dir->type = ECMA119_DIR);
|
||||||
|
|
||||||
|
if (dir->dir.depth != 1) {
|
||||||
susp_fin_CE(t, dir);
|
susp_fin_CE(t, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < dir->nchildren; i++) {
|
for (i = 0; i < dir->dir.nchildren; i++) {
|
||||||
susp_finalize(t, dir->children[i]);
|
if (dir->dir.children[i]->type == ECMA119_DIR)
|
||||||
|
susp_finalize(t, dir->dir.children[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void susp_write(struct ecma119_write_target *t, struct susp_info *susp,
|
void susp_write(struct ecma119_write_target *t,
|
||||||
|
struct susp_info *susp,
|
||||||
unsigned char *buf)
|
unsigned char *buf)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -6,17 +6,18 @@
|
|||||||
#ifndef __ISO_SUSP
|
#ifndef __ISO_SUSP
|
||||||
#define __ISO_SUSP
|
#define __ISO_SUSP
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/* SUSP is only present in standard ecma119 */
|
/* SUSP is only present in standard ecma119 */
|
||||||
struct ecma119_write_target;
|
struct ecma119_write_target;
|
||||||
struct iso_tree_node;
|
struct ecma119_tree_node;
|
||||||
struct iso_tree_dir;
|
|
||||||
|
|
||||||
/** This contains the information that needs to go in the SUSP area of a file.
|
/** This contains the information that needs to go in the SUSP area of a file.
|
||||||
*/
|
*/
|
||||||
struct susp_info
|
struct susp_info
|
||||||
{
|
{
|
||||||
int n_susp_fields; /**< Number of SUSP fields */
|
int n_susp_fields; /**< Number of SUSP fields */
|
||||||
unsigned char **susp_fields; /**< Data for each SUSP field */
|
uint8_t **susp_fields; /**< Data for each SUSP field */
|
||||||
|
|
||||||
/* the next 3 relate to CE and are filled out by susp_add_CE. */
|
/* the next 3 relate to CE and are filled out by susp_add_CE. */
|
||||||
int n_fields_fit; /**< How many of the above SUSP fields fit
|
int n_fields_fit; /**< How many of the above SUSP fields fit
|
||||||
@ -27,48 +28,34 @@ struct susp_info
|
|||||||
* will go in a CE area. */
|
* will go in a CE area. */
|
||||||
};
|
};
|
||||||
|
|
||||||
void susp_add_CE(struct ecma119_write_target *, struct iso_tree_node *);
|
void susp_add_CE(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
|
|
||||||
/* these next 2 are special because they don't modify the susp fields of the
|
/* these next 2 are special because they don't modify the susp fields of the
|
||||||
* directory that gets passed to them; they modify the susp fields of the
|
* directory; they modify the susp fields of the
|
||||||
* "." entry in the directory. */
|
* "." entry in the directory. */
|
||||||
void susp_add_SP(struct ecma119_write_target *, struct iso_tree_dir *);
|
void susp_add_SP(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
void susp_add_ER(struct ecma119_write_target *, struct iso_tree_dir *);
|
void rrip_add_ER(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
|
|
||||||
/** Once all the directories and files are laid out, recurse through the tree
|
/** Once all the directories and files are laid out, recurse through the tree
|
||||||
* and finalize all SUSP CE entries. */
|
* and finalize all SUSP CE entries. */
|
||||||
void susp_finalize(struct ecma119_write_target *, struct iso_tree_dir *);
|
void susp_finalize(struct ecma119_write_target *, struct ecma119_tree_node *);
|
||||||
|
|
||||||
void susp_append(struct ecma119_write_target *,
|
void susp_append(struct ecma119_write_target *,
|
||||||
struct iso_tree_node *,
|
struct susp_info *,
|
||||||
unsigned char *);
|
uint8_t *);
|
||||||
void susp_append_self(struct ecma119_write_target *,
|
|
||||||
struct iso_tree_dir *,
|
|
||||||
unsigned char *);
|
|
||||||
void susp_append_parent(struct ecma119_write_target *,
|
|
||||||
struct iso_tree_dir *,
|
|
||||||
unsigned char *);
|
|
||||||
void susp_insert(struct ecma119_write_target *,
|
void susp_insert(struct ecma119_write_target *,
|
||||||
struct iso_tree_node *,
|
struct susp_info *,
|
||||||
unsigned char *,
|
uint8_t *,
|
||||||
int pos);
|
int pos);
|
||||||
void susp_insert_self(struct ecma119_write_target *,
|
uint8_t *susp_find(struct susp_info *,
|
||||||
struct iso_tree_dir *,
|
const char *);
|
||||||
unsigned char *,
|
|
||||||
int pos);
|
|
||||||
void susp_insert_parent(struct ecma119_write_target *,
|
|
||||||
struct iso_tree_dir *,
|
|
||||||
unsigned char *,
|
|
||||||
int pos);
|
|
||||||
unsigned char *susp_find(struct susp_info *,
|
|
||||||
const char *);
|
|
||||||
|
|
||||||
void susp_write(struct ecma119_write_target *,
|
void susp_write(struct ecma119_write_target *,
|
||||||
struct susp_info *,
|
struct susp_info *,
|
||||||
unsigned char *);
|
uint8_t *);
|
||||||
void susp_write_CE(struct ecma119_write_target *,
|
void susp_write_CE(struct ecma119_write_target *,
|
||||||
struct susp_info *,
|
struct susp_info *,
|
||||||
unsigned char *);
|
uint8_t *);
|
||||||
|
|
||||||
void susp_free_fields(struct susp_info *);
|
void susp_free_fields(struct susp_info *);
|
||||||
|
|
||||||
|
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 : */
|
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||||
|
|
||||||
#include <dirent.h>
|
/**
|
||||||
#include <stdio.h>
|
* \file tree.c
|
||||||
|
*
|
||||||
|
* Implement filesystem trees.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <assert.h>
|
#include <dirent.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "libisofs.h"
|
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "volume.h"
|
#include "volume.h"
|
||||||
|
|
||||||
struct iso_tree_dir *iso_tree_new_root(struct iso_volume *volume)
|
static void
|
||||||
|
set_default_stat(struct stat *s)
|
||||||
{
|
{
|
||||||
struct iso_tree_dir *dir;
|
time_t now = time(NULL);
|
||||||
|
|
||||||
assert(volume);
|
memset(s, 0, sizeof(struct stat));
|
||||||
|
s->st_mode = 0777 | S_IFREG;
|
||||||
dir = calloc(1, sizeof(struct iso_tree_dir));
|
s->st_atime = s->st_mtime = s->st_ctime = now;
|
||||||
dir->attrib.st_mode = S_IFDIR;
|
|
||||||
dir->volume = volume;
|
|
||||||
|
|
||||||
return dir;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void iso_tree_free(struct iso_tree_dir *root)
|
static struct stat
|
||||||
|
get_attrib(const struct iso_tree_node *node)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
assert(root);
|
|
||||||
|
|
||||||
/* Free names. */
|
|
||||||
free(root->name.full);
|
|
||||||
free(root->name.iso1);
|
|
||||||
free(root->name.iso2);
|
|
||||||
free(root->name.rockridge);
|
|
||||||
free(root->name.joliet);
|
|
||||||
|
|
||||||
/* Free the children. */
|
|
||||||
for (i = 0; i < root->nchildren; i++)
|
|
||||||
iso_tree_free(root->children[i]);
|
|
||||||
free(root->children);
|
|
||||||
|
|
||||||
/* Free all files. */
|
|
||||||
for (i = 0; i < root->nfiles; i++) {
|
|
||||||
struct iso_tree_file *file = root->files[i];
|
|
||||||
|
|
||||||
free(file->path);
|
|
||||||
free(file->name.full);
|
|
||||||
free(file->name.iso1);
|
|
||||||
free(file->name.iso2);
|
|
||||||
free(file->name.rockridge);
|
|
||||||
free(file->name.joliet);
|
|
||||||
free(file);
|
|
||||||
}
|
|
||||||
free(root->files);
|
|
||||||
|
|
||||||
if (root->writer_data) {
|
|
||||||
fprintf(stderr, "Warning: freeing a directory with non-NULL "
|
|
||||||
"writer_data\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free ourself. */
|
|
||||||
free(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_tree_file *iso_tree_add_new_file(struct iso_tree_dir *parent,
|
|
||||||
const char *name)
|
|
||||||
{
|
|
||||||
struct iso_tree_file *file;
|
|
||||||
|
|
||||||
assert(parent && name);
|
|
||||||
|
|
||||||
file = calloc(1, sizeof(struct iso_tree_file));
|
|
||||||
file->path = calloc(1, 1);
|
|
||||||
file->parent = parent;
|
|
||||||
file->volume = parent->volume;
|
|
||||||
file->attrib = parent->attrib;
|
|
||||||
file->attrib.st_mode &= ~S_IFMT;
|
|
||||||
file->attrib.st_mode |= S_IFREG;
|
|
||||||
file->attrib.st_size = 0;
|
|
||||||
iso_tree_file_set_name(file, name);
|
|
||||||
|
|
||||||
/* Add the new file to the parent directory */
|
|
||||||
parent->nfiles++;
|
|
||||||
parent->files = realloc(parent->files, sizeof(void *) * parent->nfiles);
|
|
||||||
parent->files[parent->nfiles - 1] = file;
|
|
||||||
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct iso_tree_file *iso_tree_add_file(struct iso_tree_dir *parent,
|
|
||||||
const char *path)
|
|
||||||
{
|
|
||||||
struct iso_tree_file *file;
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int statret;
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
assert( parent != NULL && path != NULL );
|
if (node) {
|
||||||
statret = lstat(path, &st);
|
return node->attrib;
|
||||||
if (statret == -1) {
|
|
||||||
fprintf(stderr, "couldn't stat file %s: %s\n",
|
|
||||||
path, strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
set_default_stat(&st);
|
||||||
/* Set up path, parent and volume. */
|
return st;
|
||||||
file = calloc(1, sizeof(struct iso_tree_file));
|
|
||||||
file->path = strdup(path);
|
|
||||||
file->parent = parent;
|
|
||||||
file->volume = parent->volume;
|
|
||||||
file->attrib = st;
|
|
||||||
|
|
||||||
/* find the last component in the path */
|
|
||||||
name = strrchr(path, '/');
|
|
||||||
if (name == NULL) {
|
|
||||||
name = path;
|
|
||||||
} else {
|
|
||||||
name++;
|
|
||||||
}
|
|
||||||
iso_tree_file_set_name(file, name);
|
|
||||||
|
|
||||||
if (!S_ISREG(st.st_mode)) {
|
|
||||||
file->attrib.st_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the new file to the parent directory */
|
|
||||||
parent->nfiles++;
|
|
||||||
parent->files = realloc(parent->files, sizeof(void *) * parent->nfiles);
|
|
||||||
parent->files[parent->nfiles - 1] = file;
|
|
||||||
|
|
||||||
return file;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iso_tree_dir *iso_tree_add_dir(struct iso_tree_dir *parent,
|
static void
|
||||||
const char *path)
|
append_node(struct iso_tree_node *parent,
|
||||||
|
struct iso_tree_node *child)
|
||||||
{
|
{
|
||||||
struct iso_tree_dir *dir;
|
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && child);
|
||||||
struct stat st;
|
if (!parent)
|
||||||
int statret;
|
return;
|
||||||
char *pathcpy;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
assert( parent && path );
|
|
||||||
statret = stat(path, &st);
|
|
||||||
if (statret == -1) {
|
|
||||||
fprintf(stderr, "couldn't stat directory %s: %s\n",
|
|
||||||
path, strerror(errno));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dir = calloc(1, sizeof(struct iso_tree_dir));
|
|
||||||
dir->parent = parent;
|
|
||||||
dir->volume = parent->volume;
|
|
||||||
dir->attrib = st;
|
|
||||||
|
|
||||||
/* find the last component in the path. We need to copy the path because
|
|
||||||
* we modify it if there is a trailing slash. */
|
|
||||||
pathcpy = strdup(path);
|
|
||||||
name = strrchr(pathcpy, '/');
|
|
||||||
if (name == &pathcpy[strlen(pathcpy) - 1]) {
|
|
||||||
/* get rid of the trailing slash */
|
|
||||||
*name = '\0';
|
|
||||||
name = strrchr(pathcpy, '/');
|
|
||||||
}
|
|
||||||
if (name == NULL) {
|
|
||||||
name = pathcpy;
|
|
||||||
} else {
|
|
||||||
name++;
|
|
||||||
}
|
|
||||||
iso_tree_dir_set_name(dir, name);
|
|
||||||
free(pathcpy);
|
|
||||||
|
|
||||||
|
|
||||||
parent->nchildren++;
|
parent->nchildren++;
|
||||||
parent->children = realloc(parent->children,
|
parent->children =
|
||||||
parent->nchildren * sizeof(void*));
|
realloc(parent->children, parent->nchildren * sizeof(void*));
|
||||||
parent->children[parent->nchildren - 1] = dir;
|
parent->children[parent->nchildren-1] = child;
|
||||||
|
|
||||||
return dir;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iso_tree_dir *iso_tree_radd_dir(struct iso_tree_dir *parent,
|
struct iso_tree_node*
|
||||||
const char *path)
|
iso_tree_new_root(struct iso_volume *vol)
|
||||||
{
|
{
|
||||||
struct iso_tree_dir *nparent;
|
assert(vol);
|
||||||
|
|
||||||
|
if (vol->root) {
|
||||||
|
iso_tree_free(vol->root);
|
||||||
|
}
|
||||||
|
|
||||||
|
vol->root = calloc(1, sizeof(struct iso_tree_node));
|
||||||
|
vol->root->volume = vol;
|
||||||
|
set_default_stat(&vol->root->attrib);
|
||||||
|
vol->root->attrib.st_mode = S_IFDIR | 0777;
|
||||||
|
vol->root->loc.type = LIBISO_NONE;
|
||||||
|
return vol->root;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct iso_tree_node*
|
||||||
|
iso_tree_add_new_file(struct iso_tree_node *parent, const char *name)
|
||||||
|
{
|
||||||
|
struct iso_tree_node *f = calloc(1, sizeof(struct iso_tree_node));
|
||||||
|
|
||||||
|
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
|
||||||
|
|
||||||
|
f->volume = parent ? parent->volume : NULL;
|
||||||
|
f->parent = parent;
|
||||||
|
f->name = parent ? towcs(name) : NULL;
|
||||||
|
f->attrib = get_attrib(parent);
|
||||||
|
f->attrib.st_mode = 0777 | S_IFREG;
|
||||||
|
f->loc.type = LIBISO_NONE;
|
||||||
|
append_node(parent, f);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct iso_tree_node*
|
||||||
|
iso_tree_add_new_dir(struct iso_tree_node *parent, const char *name)
|
||||||
|
{
|
||||||
|
struct iso_tree_node *d = iso_tree_add_new_file(parent, name);
|
||||||
|
|
||||||
|
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && name);
|
||||||
|
|
||||||
|
d->attrib.st_mode = (d->attrib.st_mode & ~S_IFMT) | S_IFDIR;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct iso_tree_node*
|
||||||
|
iso_tree_add_node(struct iso_tree_node *parent, const char *path)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int statret;
|
struct iso_tree_node *ret;
|
||||||
|
|
||||||
|
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
|
||||||
|
|
||||||
|
if (lstat(path, &st) == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
p = strdup(path); /* because basename() might modify its arg */
|
||||||
|
|
||||||
|
/* it doesn't matter if we add a file or directory since we modify
|
||||||
|
* attrib anyway. */
|
||||||
|
ret = iso_tree_add_new_file(parent, basename(p));
|
||||||
|
ret->attrib = st;
|
||||||
|
ret->loc.type = LIBISO_FILESYS;
|
||||||
|
ret->loc.path = strdup(path);
|
||||||
|
free(p);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct iso_tree_node*
|
||||||
|
iso_tree_radd_dir (struct iso_tree_node *parent, const char *path)
|
||||||
|
{
|
||||||
|
struct iso_tree_node *new;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
|
|
||||||
assert( parent && path );
|
assert((!parent || S_ISDIR(parent->attrib.st_mode)) && path);
|
||||||
statret = stat(path, &st);
|
|
||||||
|
|
||||||
nparent = iso_tree_add_dir(parent, path);
|
new = iso_tree_add_node(parent, path);
|
||||||
|
if (!new || !S_ISDIR(new->attrib.st_mode)) {
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
/* Open the directory for reading and iterate over the directory
|
|
||||||
entries. */
|
|
||||||
dir = opendir(path);
|
dir = opendir(path);
|
||||||
|
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
fprintf(stderr, "couldn't open directory %s: %s\n",
|
warn("couldn't open directory %s: %s\n", path, strerror(errno));
|
||||||
path, strerror(errno));
|
return new;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((ent = readdir(dir))) {
|
while ((ent = readdir(dir))) {
|
||||||
char *child;
|
char child[strlen(ent->d_name) + strlen(path) + 2];
|
||||||
|
|
||||||
/* Skip current and parent directory entries. */
|
|
||||||
if (strcmp(ent->d_name, ".") == 0 ||
|
if (strcmp(ent->d_name, ".") == 0 ||
|
||||||
strcmp(ent->d_name, "..") == 0)
|
strcmp(ent->d_name, "..") == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Build the child's full pathname. */
|
sprintf(child, "%s/%s", path, ent->d_name);
|
||||||
child = iso_pathname(path, ent->d_name);
|
iso_tree_radd_dir(new, child);
|
||||||
|
|
||||||
/* Skip to the next entry on errors. */
|
|
||||||
if (stat(child, &st) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
|
||||||
iso_tree_radd_dir(nparent, child);
|
|
||||||
} else {
|
|
||||||
iso_tree_add_file(nparent, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(child);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
||||||
return nparent;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iso_tree_dir *iso_tree_add_new_dir(struct iso_tree_dir *parent,
|
void
|
||||||
const char *name)
|
iso_tree_free(struct iso_tree_node *root)
|
||||||
{
|
{
|
||||||
struct iso_tree_dir *dir;
|
size_t i;
|
||||||
|
|
||||||
assert( parent && name );
|
for (i=0; i < root->nchildren; i++) {
|
||||||
|
iso_tree_free(root->children[i]);
|
||||||
dir = calloc(1, sizeof(struct iso_tree_dir));
|
|
||||||
dir->parent = parent;
|
|
||||||
dir->volume = parent->volume;
|
|
||||||
|
|
||||||
iso_tree_dir_set_name(dir, name);
|
|
||||||
|
|
||||||
dir->attrib = parent->attrib;
|
|
||||||
dir->attrib.st_mtime = time(NULL);
|
|
||||||
dir->attrib.st_atime = time(NULL);
|
|
||||||
dir->attrib.st_ctime = time(NULL);
|
|
||||||
|
|
||||||
|
|
||||||
/* add the new directory to parent */
|
|
||||||
parent->nchildren++;
|
|
||||||
parent->children = realloc(parent->children,
|
|
||||||
parent->nchildren * sizeof(void*));
|
|
||||||
parent->children[parent->nchildren - 1] = dir;
|
|
||||||
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
void iso_tree_file_set_name(struct iso_tree_file *file, const char *name)
|
|
||||||
{
|
|
||||||
file->name.full = strdup(name);
|
|
||||||
file->name.iso1 = iso_1_fileid(name);
|
|
||||||
file->name.iso2 = iso_2_fileid(name);
|
|
||||||
file->name.rockridge = iso_p_filename(name);
|
|
||||||
file->name.joliet = iso_j_id(file->name.full);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_tree_node_get_name_nconst(const struct iso_tree_node *node,
|
|
||||||
enum iso_name_version ver)
|
|
||||||
{
|
|
||||||
if (ver == ISO_NAME_ISO) {
|
|
||||||
if (node->volume->iso_level == 1) {
|
|
||||||
return node->name.iso1;
|
|
||||||
} else {
|
|
||||||
return node->name.iso2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
free(root->name);
|
||||||
switch (ver) {
|
free(root->children);
|
||||||
case ISO_NAME_FULL:
|
free(root);
|
||||||
return node->name.full;
|
|
||||||
case ISO_NAME_ISO:
|
|
||||||
if (node->volume->iso_level == 1) {
|
|
||||||
return node->name.iso1;
|
|
||||||
} else {
|
|
||||||
return node->name.iso2;
|
|
||||||
}
|
|
||||||
case ISO_NAME_ISO_L1:
|
|
||||||
return node->name.iso1;
|
|
||||||
case ISO_NAME_ISO_L2:
|
|
||||||
return node->name.iso2;
|
|
||||||
case ISO_NAME_ROCKRIDGE:
|
|
||||||
return node->name.rockridge;
|
|
||||||
case ISO_NAME_JOLIET:
|
|
||||||
return (char*) node->name.joliet;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(0);
|
|
||||||
return NULL; /* just to shut up warnings */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *iso_tree_node_get_name(const struct iso_tree_node *node,
|
void
|
||||||
enum iso_name_version ver)
|
iso_tree_print(const struct iso_tree_node *root, int spaces)
|
||||||
{
|
{
|
||||||
return iso_tree_node_get_name_nconst(node, ver);
|
size_t i;
|
||||||
}
|
char sp[spaces+1];
|
||||||
|
|
||||||
void iso_tree_dir_set_name(struct iso_tree_dir *dir, const char *name)
|
memset(sp, ' ', spaces);
|
||||||
{
|
sp[spaces] = '\0';
|
||||||
dir->name.full = strdup(name);
|
|
||||||
/* Level 1 directory is a string of d-characters of maximum size 8. */
|
|
||||||
dir->name.iso1 = iso_d_str(name, 8, 0);
|
|
||||||
/* Level 2 directory is a string of d-characters of maximum size 31. */
|
|
||||||
dir->name.iso2 = iso_d_str(name, 31, 0);
|
|
||||||
dir->name.rockridge = iso_p_dirname(name);
|
|
||||||
dir->name.joliet = iso_j_id(dir->name.full);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compares file names for use with qsort. */
|
printf("%s%ls\n", sp, root->name);
|
||||||
int iso_node_cmp(const void *v1, const void *v2)
|
for (i=0; i < root->nchildren; i++) {
|
||||||
{
|
iso_tree_print(root->children[i], spaces+2);
|
||||||
struct iso_tree_node **f1 = (struct iso_tree_node **)v1;
|
|
||||||
struct iso_tree_node **f2 = (struct iso_tree_node **)v2;
|
|
||||||
|
|
||||||
return strcmp(iso_tree_node_get_name(*f1, ISO_NAME_FULL),
|
|
||||||
iso_tree_node_get_name(*f2, ISO_NAME_FULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
int iso_node_cmp_iso(const void *v1, const void *v2)
|
|
||||||
{
|
|
||||||
struct iso_tree_node **f1 = (struct iso_tree_node **)v1;
|
|
||||||
struct iso_tree_node **f2 = (struct iso_tree_node **)v2;
|
|
||||||
|
|
||||||
return strcmp(iso_tree_node_get_name(*f1, ISO_NAME_ISO),
|
|
||||||
iso_tree_node_get_name(*f2, ISO_NAME_ISO));
|
|
||||||
}
|
|
||||||
|
|
||||||
int iso_node_cmp_joliet(const void *v1, const void *v2)
|
|
||||||
{
|
|
||||||
struct iso_tree_node **f1 = (struct iso_tree_node **)v1;
|
|
||||||
struct iso_tree_node **f2 = (struct iso_tree_node **)v2;
|
|
||||||
|
|
||||||
return ucscmp((uint16_t*)iso_tree_node_get_name(*f1, ISO_NAME_JOLIET),
|
|
||||||
(uint16_t*)iso_tree_node_get_name(*f2, ISO_NAME_JOLIET));
|
|
||||||
}
|
|
||||||
|
|
||||||
void iso_tree_sort(struct iso_tree_dir *root)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
qsort(root->files, root->nfiles, sizeof(struct iso_tree_file *),
|
|
||||||
iso_node_cmp);
|
|
||||||
|
|
||||||
qsort(root->children, root->nchildren, sizeof(struct iso_tree_dir *),
|
|
||||||
iso_node_cmp);
|
|
||||||
|
|
||||||
for (i = 0; i < root->nchildren; i++)
|
|
||||||
iso_tree_sort(root->children[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void iso_tree_print(const struct iso_tree_dir *root, int spaces)
|
|
||||||
{
|
|
||||||
iso_tree_print_verbose(root, NULL, NULL, NULL, spaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
void iso_tree_print_verbose(const struct iso_tree_dir *root,
|
|
||||||
print_dir_callback dc, print_file_callback fc,
|
|
||||||
void *data, int spaces)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
for (i = 0; i < spaces; i++)
|
|
||||||
printf(" ");
|
|
||||||
|
|
||||||
/* Root directory doesn't have a name. */
|
|
||||||
if (root->name.full != NULL)
|
|
||||||
printf("%s", iso_tree_node_get_name(ISO_NODE(root),
|
|
||||||
ISO_NAME_ISO));
|
|
||||||
printf("/\n");
|
|
||||||
if (dc) dc(root, data, spaces);
|
|
||||||
|
|
||||||
spaces += 2;
|
|
||||||
|
|
||||||
for (j = 0; j < root->nchildren; j++) {
|
|
||||||
iso_tree_print_verbose(root->children[j], dc, fc, data,
|
|
||||||
spaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = 0; j < root->nfiles; j++) {
|
|
||||||
for (i = 0; i < spaces; i++)
|
|
||||||
printf(" ");
|
|
||||||
printf("%s\n",
|
|
||||||
iso_tree_node_get_name(ISO_NODE(root->files[j]),
|
|
||||||
ISO_NAME_ISO));
|
|
||||||
if (fc) fc(root->files[j], data, spaces);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
iso_tree_print_verbose(const struct iso_tree_node *root,
|
||||||
|
print_dir_callback dir,
|
||||||
|
print_file_callback file,
|
||||||
|
void *callback_data,
|
||||||
|
int spaces)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
(S_ISDIR(root->attrib.st_mode) ? dir : file)
|
||||||
|
(root, callback_data, spaces);
|
||||||
|
for (i=0; i < root->nchildren; i++) {
|
||||||
|
iso_tree_print_verbose(root->children[i], dir,
|
||||||
|
file, callback_data, spaces+2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
iso_tree_node_set_name(struct iso_tree_node *file, const char *name)
|
||||||
|
{
|
||||||
|
free(file->name);
|
||||||
|
file->name = towcs(name);
|
||||||
|
}
|
||||||
|
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 : */
|
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \file tree.h
|
* \file tree.h
|
||||||
*
|
*
|
||||||
* Extra declarations for use with the iso_tree_dir and iso_tree_file
|
* Declare the structure of a libisofs filesystem tree. The files in this
|
||||||
* structures.
|
* tree can come from either the local filesystem or from another .iso image
|
||||||
|
* (for multisession).
|
||||||
|
*
|
||||||
|
* This tree preserves as much information as it can about the files; names
|
||||||
|
* are stored in wchar_t and we preserve POSIX attributes. This tree does
|
||||||
|
* *not* include information that is necessary for writing out, for example,
|
||||||
|
* an ISO level 1 tree. That information will go in a different tree because
|
||||||
|
* the structure is sufficiently different.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ISO_TREE
|
#ifndef LIBISO_TREE_H
|
||||||
#define __ISO_TREE
|
#define LIBISO_TREE_H
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <time.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
#include "libisofs.h"
|
#include "libisofs.h"
|
||||||
|
|
||||||
/**
|
enum file_location {
|
||||||
* File or directory names or identifiers.
|
LIBISO_FILESYS,
|
||||||
*/
|
LIBISO_PREVSESSION,
|
||||||
struct iso_names
|
LIBISO_NONE /**< for files/dirs that were added with
|
||||||
{
|
* iso_tree_add_new_XXX. */
|
||||||
char *full; /**< Full version: either part of the path or
|
|
||||||
user input. */
|
|
||||||
char *iso1; /**< ISO level 1 identifier. */
|
|
||||||
char *iso2; /**< ISO level 2 identifier. */
|
|
||||||
char *rockridge; /**< Rock Ridge file or directory name. */
|
|
||||||
uint16_t *joliet; /**< Joliet identifier. */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directory on a volume.
|
* This tells us where to read the data from a file. Either we read from the
|
||||||
|
* local filesystem or we just point to the block on a previous session.
|
||||||
*/
|
*/
|
||||||
struct iso_tree_dir
|
struct iso_file_location
|
||||||
{
|
{
|
||||||
struct iso_tree_dir *parent; /**< \see iso_tree_node */
|
enum file_location type;
|
||||||
struct iso_volume *volume; /**< \see iso_tree_node */
|
/* union {*/
|
||||||
struct iso_names name; /**< \see iso_tree_node */
|
char *path; /* in the current locale */
|
||||||
struct stat attrib; /**< \see iso_tree_node */
|
uint32_t block;
|
||||||
off_t block; /**< \see iso_tree_node */
|
/* };*/
|
||||||
uint8_t dirent_len; /**< \see iso_tree_node */
|
|
||||||
void *writer_data; /**< \see iso_tree_node */
|
|
||||||
|
|
||||||
int depth; /**< The depth of this directory in the
|
|
||||||
* Directory Heirarchy. This is 1 for
|
|
||||||
* the root directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int nchildren; /**< Number of child directories. */
|
|
||||||
int nfiles; /**< Number of files in this directory.
|
|
||||||
*/
|
|
||||||
struct iso_tree_dir **children; /**< Child directories. */
|
|
||||||
struct iso_tree_file **files; /**< Files in this directory. */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File on a volume.
|
* A node in the filesystem tree.
|
||||||
*/
|
|
||||||
struct iso_tree_file
|
|
||||||
{
|
|
||||||
struct iso_tree_dir *parent; /**< \see iso_tree_node */
|
|
||||||
struct iso_volume *volume; /**< \see iso_tree_node */
|
|
||||||
struct iso_names name; /**< \see iso_tree_node */
|
|
||||||
struct stat attrib; /**< \see iso_tree_node */
|
|
||||||
off_t block; /**< \see iso_tree_node */
|
|
||||||
uint8_t dirent_len; /**< \see iso_tree_node */
|
|
||||||
void *writer_data; /**< \see iso_tree_node */
|
|
||||||
|
|
||||||
char *path; /**< Location of the file in the
|
|
||||||
* local filesystem. This can be a
|
|
||||||
* full or relative path. If this is
|
|
||||||
* NULL, then the file doesn't exist
|
|
||||||
* in the local filesystem and its
|
|
||||||
* size must be zero.
|
|
||||||
*
|
|
||||||
* FIXME: Allow references to files
|
|
||||||
* on other volumes belonging to the
|
|
||||||
* same volset as this file.
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fields in common between iso_tree_file and iso_tree_dir.
|
|
||||||
*/
|
*/
|
||||||
struct iso_tree_node
|
struct iso_tree_node
|
||||||
{
|
{
|
||||||
struct iso_tree_dir *parent; /**< The parent of this node. Must be
|
struct iso_volume *volume;
|
||||||
* non-NULL unless we are the
|
struct iso_tree_node *parent;
|
||||||
* root directory on a volume.
|
wchar_t *name;
|
||||||
*/
|
struct stat attrib; /**< The POSIX attributes of this node as
|
||||||
struct iso_volume *volume; /**< The volume to which this node
|
* documented in "man 2 stat". */
|
||||||
* belongs.
|
struct iso_file_location loc;
|
||||||
*/
|
/**< Only used for regular files and symbolic
|
||||||
struct iso_names name; /**< The name of this node in its parent
|
* links (ie. files for which we might have to
|
||||||
* directory. Must be non-NULL unless
|
* copy data). */
|
||||||
* we are the root directory on a
|
|
||||||
* volume.
|
|
||||||
*/
|
|
||||||
struct stat attrib; /**< The POSIX attributes of this
|
|
||||||
* node as documented in "man 2 stat".
|
|
||||||
*
|
|
||||||
* Any node that is not a regular
|
|
||||||
* file or a directory must have
|
|
||||||
* \p attrib.st_size set to zero. Any
|
|
||||||
* node that is a directory will have
|
|
||||||
* \p attrib.st_size filled out by the
|
|
||||||
* writer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* information used for writing */
|
size_t nchildren; /**< The number of children of this
|
||||||
off_t block; /**< The block at which this node's
|
* directory (if this is a directory). */
|
||||||
* data will be written.
|
struct iso_tree_node **children;
|
||||||
*/
|
|
||||||
uint8_t dirent_len; /**< The size of this node's
|
size_t block; /**< The block at which this file will
|
||||||
* Directory Record in its parent.
|
* reside on disk. We store this here as
|
||||||
* This does not include System Use
|
* well as in the various mangled trees
|
||||||
* fields, if present.
|
* because many different trees might point
|
||||||
*/
|
* to the same file and they need to share the
|
||||||
void *writer_data; /**< This is writer-specific data. It
|
* block location. */
|
||||||
* must be set to NULL when a node
|
|
||||||
* is created and it should be NULL
|
|
||||||
* again when the node is freed.
|
|
||||||
*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A macro to simplify casting between nodes and files/directories. */
|
|
||||||
#define ISO_NODE(a) ( (struct iso_tree_node*) (a) )
|
|
||||||
|
|
||||||
/** A macro to simplify casting between nodes and directories. */
|
|
||||||
#define ISO_DIR(a) ( (struct iso_tree_dir*) (a) )
|
|
||||||
|
|
||||||
/** A macro to simplify casting between nodes and files. */
|
|
||||||
#define ISO_FILE(a) ( (struct iso_tree_file*) (a) )
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new root directory for a volume.
|
* Create a new root directory for a volume.
|
||||||
*
|
*
|
||||||
* \param volume The volume for which to create a new root directory.
|
* \param vol The volume for which to create a new root directory.
|
||||||
*
|
*
|
||||||
* \pre \p volume is non-NULL.
|
* \pre \p vol is non-NULL.
|
||||||
* \post \p volume has a non-NULL, empty root directory.
|
* \post \p vol has a non-NULL, empty root directory with permissions 777.
|
||||||
* \return \p volume's new non-NULL, empty root directory.
|
* \return \p vol's new non-NULL, empty root directory.
|
||||||
*/
|
*/
|
||||||
struct iso_tree_dir *iso_tree_new_root(struct iso_volume *volume);
|
struct iso_tree_node *iso_tree_new_root(struct iso_volume *vol);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new, empty, file.
|
* Create a new, empty, file.
|
||||||
*
|
*
|
||||||
* \param parent The parent of the new file.
|
* \param parent The parent directory of the new file. If this is null, create
|
||||||
|
* and return a new file node without adding it to any tree.
|
||||||
* \param name The name of the new file, encoded in the current locale.
|
* \param name The name of the new file, encoded in the current locale.
|
||||||
*
|
|
||||||
* \pre \p parent is non-NULL.
|
|
||||||
* \pre \p name is non-NULL and it does not match any other file or directory
|
* \pre \p name is non-NULL and it does not match any other file or directory
|
||||||
* name in \p parent.
|
* name in \p parent.
|
||||||
* \post \p parent contains a file with the following properties:
|
* \post \p parent (if non-NULL) contains a file with the following properties:
|
||||||
* - the file's (full) name is \p name
|
* - the file's name is \p name (converted to wchar_t)
|
||||||
* - the file's POSIX permissions are the same as \p parent's
|
* - the file's POSIX permissions are the same as \p parent's
|
||||||
* - the file is a regular file
|
* - the file is a regular file
|
||||||
* - the file is empty
|
* - the file is empty
|
||||||
*
|
*
|
||||||
* \return \p parent's newly created file.
|
* \return \p parent's newly created file.
|
||||||
*/
|
*/
|
||||||
struct iso_tree_file *iso_tree_add_new_file(struct iso_tree_dir *parent,
|
struct iso_tree_node *iso_tree_add_new_file(struct iso_tree_node *parent,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -173,37 +108,7 @@ struct iso_tree_file *iso_tree_add_new_file(struct iso_tree_dir *parent,
|
|||||||
*
|
*
|
||||||
* \pre \p root is non-NULL.
|
* \pre \p root is non-NULL.
|
||||||
*/
|
*/
|
||||||
void iso_tree_free(struct iso_tree_dir *root);
|
void iso_tree_free(struct iso_tree_node *root);
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursively sort all the files and child directories in a directory.
|
|
||||||
*
|
|
||||||
* \param root The root of the directory heirarchy to sort.
|
|
||||||
*
|
|
||||||
* \pre \p root is non-NULL.
|
|
||||||
* \post For each directory \p dir in the directory heirarchy descended fro
|
|
||||||
* root, the fields in \p dir.children and \p dir.files are alphabetically
|
|
||||||
* sorted according to \p name.full.
|
|
||||||
*
|
|
||||||
* \see iso_names
|
|
||||||
*/
|
|
||||||
void iso_tree_sort(struct iso_tree_dir *root);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare the names of 2 nodes, \p *v1 and \p *v2. This is compatible with
|
|
||||||
* qsort.
|
|
||||||
*/
|
|
||||||
int iso_node_cmp(const void *v1, const void *v2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare the joliet names of 2 nodes, compatible with qsort.
|
|
||||||
*/
|
|
||||||
int iso_node_cmp_joliet(const void *v1, const void *v2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare the iso names of 2 nodes, compatible with qsort.
|
|
||||||
*/
|
|
||||||
int iso_node_cmp_iso(const void *v1, const void *v2);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A function that prints verbose information about a directory.
|
* A function that prints verbose information about a directory.
|
||||||
@ -214,7 +119,7 @@ int iso_node_cmp_iso(const void *v1, const void *v2);
|
|||||||
*
|
*
|
||||||
* \see iso_tree_print_verbose
|
* \see iso_tree_print_verbose
|
||||||
*/
|
*/
|
||||||
typedef void (*print_dir_callback) (const struct iso_tree_dir *dir,
|
typedef void (*print_dir_callback) (const struct iso_tree_node *dir,
|
||||||
void *data,
|
void *data,
|
||||||
int spaces);
|
int spaces);
|
||||||
/**
|
/**
|
||||||
@ -226,7 +131,7 @@ typedef void (*print_dir_callback) (const struct iso_tree_dir *dir,
|
|||||||
*
|
*
|
||||||
* \see iso_tree_print_verbose
|
* \see iso_tree_print_verbose
|
||||||
*/
|
*/
|
||||||
typedef void (*print_file_callback) (const struct iso_tree_file *file,
|
typedef void (*print_file_callback) (const struct iso_tree_node *file,
|
||||||
void *data,
|
void *data,
|
||||||
int spaces);
|
int spaces);
|
||||||
|
|
||||||
@ -243,17 +148,12 @@ typedef void (*print_file_callback) (const struct iso_tree_file *file,
|
|||||||
* \pre \p root is not NULL.
|
* \pre \p root is not NULL.
|
||||||
* \pre Neither of the callback functions modifies the directory heirarchy.
|
* \pre Neither of the callback functions modifies the directory heirarchy.
|
||||||
*/
|
*/
|
||||||
void iso_tree_print_verbose(const struct iso_tree_dir *root,
|
void iso_tree_print_verbose(const struct iso_tree_node *root,
|
||||||
print_dir_callback dir,
|
print_dir_callback dir,
|
||||||
print_file_callback file,
|
print_file_callback file,
|
||||||
void *callback_data,
|
void *callback_data,
|
||||||
int spaces);
|
int spaces);
|
||||||
|
|
||||||
/**
|
#define ISO_ISDIR(n) S_ISDIR(n->attrib.st_mode)
|
||||||
* Get a non-const version of the node name. This is used for name-mangling
|
|
||||||
* iso names. It should only be used internally in libisofs; all other users
|
#endif /* LIBISO_TREE_H */
|
||||||
* should only access the const name.
|
|
||||||
*/
|
|
||||||
char *iso_tree_node_get_name_nconst(const struct iso_tree_node *node,
|
|
||||||
enum iso_name_version ver);
|
|
||||||
#endif /* __ISO_TREE */
|
|
||||||
|
632
libisofs/util.c
632
libisofs/util.c
@ -1,136 +1,190 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||||
/* vim: set ts=8 sts=8 sw=8 noet : */
|
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||||
|
|
||||||
#include <ctype.h>
|
/**
|
||||||
|
* Utility functions for the Libisofs library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <wchar.h>
|
||||||
#include <iconv.h>
|
#include <iconv.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdio.h>
|
||||||
#include <langinfo.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
int valid_d_char(char c)
|
int div_up(int n, int div)
|
||||||
|
{
|
||||||
|
return (n + div - 1) / div;
|
||||||
|
}
|
||||||
|
|
||||||
|
int round_up(int n, int mul)
|
||||||
|
{
|
||||||
|
return div_up(n, mul) * mul;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *towcs(const char *str)
|
||||||
|
{
|
||||||
|
size_t len = strlen(str);
|
||||||
|
wchar_t *ret = malloc(sizeof(wchar_t) * (len + 1));
|
||||||
|
mbstate_t ps;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
memset(&ps, 0, sizeof(ps));
|
||||||
|
n = mbsrtowcs(ret, &str, len, &ps);
|
||||||
|
ret[len] = '\0';
|
||||||
|
|
||||||
|
if (n != len) {
|
||||||
|
free(ret);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *wcstoascii(const wchar_t *wsrc)
|
||||||
|
{
|
||||||
|
if (!wsrc)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
iconv_t conv = iconv_open("ASCII", "WCHAR_T");
|
||||||
|
size_t outbytes = wcslen(wsrc);
|
||||||
|
size_t inbytes = outbytes * sizeof(wchar_t);
|
||||||
|
char src_[inbytes + sizeof(wchar_t)];
|
||||||
|
char *src = src_;
|
||||||
|
char *ret_, *ret;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
if (conv == (iconv_t)-1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memcpy(src, wsrc, inbytes + sizeof(wchar_t));
|
||||||
|
ret = malloc(outbytes+1);
|
||||||
|
ret[outbytes] = '\0';
|
||||||
|
ret_ = ret;
|
||||||
|
|
||||||
|
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||||
|
if (n == -1) {
|
||||||
|
free(ret_);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return ret_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: C&P */
|
||||||
|
uint16_t *wcstoucs(const wchar_t *wsrc)
|
||||||
|
{
|
||||||
|
if (!wsrc)
|
||||||
|
return calloc(2, 1); /* empty UCS string */
|
||||||
|
|
||||||
|
iconv_t conv = iconv_open("UCS-2BE", "WCHAR_T");
|
||||||
|
size_t outbytes = wcslen(wsrc) * 2;
|
||||||
|
size_t inbytes = outbytes * sizeof(wchar_t) / 2;
|
||||||
|
char src_[inbytes + sizeof(wchar_t)];
|
||||||
|
char *src = src_;
|
||||||
|
char *ret_, *ret;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
if (conv == (iconv_t)-1)
|
||||||
|
return calloc(2, 1);
|
||||||
|
|
||||||
|
memcpy(src, wsrc, inbytes + sizeof(wchar_t));
|
||||||
|
ret = malloc(outbytes + sizeof(wchar_t));
|
||||||
|
ret[outbytes] = 0;
|
||||||
|
ret[outbytes+1] = 0;
|
||||||
|
ret_ = ret;
|
||||||
|
|
||||||
|
n = iconv(conv, &src, &inbytes, &ret, &outbytes);
|
||||||
|
if (n == -1) {
|
||||||
|
perror ("error in iconv conversion");
|
||||||
|
free(ret_);
|
||||||
|
return calloc(2, 1);
|
||||||
|
}
|
||||||
|
return (uint16_t*)ret_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int valid_d_char(char c)
|
||||||
{
|
{
|
||||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
|
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
int valid_a_char(char c)
|
static int valid_a_char(char c)
|
||||||
{
|
{
|
||||||
return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?') || (c >= 'A' &&
|
return (c >= ' ' && c <= '"') || (c >= '%' && c <= '?')
|
||||||
c <= 'Z')
|
|| (c >= 'A' && c <= 'Z')
|
||||||
|| (c == '_');
|
|| (c == '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
int valid_j_char(char msb, char lsb)
|
static int valid_j_char(uint16_t c)
|
||||||
{
|
{
|
||||||
return !(msb == '\0' &&
|
return !(c < (uint16_t)' ' || c == (uint16_t)'*' || c == (uint16_t)'/'
|
||||||
(lsb < ' ' || lsb == '*' || lsb == '/' || lsb == ':' ||
|
|| c == (uint16_t)':' || c == (uint16_t)';'
|
||||||
lsb == ';' || lsb == '?' || lsb == '\\'));
|
|| c == (uint16_t)'?' || c == (uint16_t)'\\');
|
||||||
}
|
}
|
||||||
|
|
||||||
int valid_p_char(char c)
|
/* FIXME: where are these documented? */
|
||||||
|
static int valid_p_char(char c)
|
||||||
{
|
{
|
||||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' &&
|
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
|
||||||
c <= 'z')
|
|| (c >= 'a' && c <= 'z')
|
||||||
|| (c == '.') || (c == '_') || (c == '-');
|
|| (c == '.') || (c == '_') || (c == '-');
|
||||||
}
|
}
|
||||||
|
|
||||||
char *iso_d_str(const char *src, int size, int pad)
|
static char *iso_dirid(const wchar_t *src, int size)
|
||||||
{
|
{
|
||||||
char *dest = strlen(src) > size ||
|
char *ret = wcstoascii(src);
|
||||||
pad ? malloc(size + 1) : malloc(strlen(src) + 1);
|
size_t len, i;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Try converting to upper-case before validating. */
|
if (!ret)
|
||||||
for (i = 0; i < size && src[i]; i++) {
|
|
||||||
char c = toupper(src[i]);
|
|
||||||
|
|
||||||
dest[i] = valid_d_char(c) ? c : '_';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Optionally pad with spaces and terminate with NULL. */
|
|
||||||
if (pad)
|
|
||||||
while (i < size)
|
|
||||||
dest[i++] = ' ';
|
|
||||||
dest[i] = '\0';
|
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_a_str(const char *src, int size)
|
|
||||||
{
|
|
||||||
char *dest = malloc(size + 1);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < size && src[i]; i++) {
|
|
||||||
char c = toupper(src[i]);
|
|
||||||
|
|
||||||
dest[i] = valid_a_char(c) ? c : '_';
|
|
||||||
}
|
|
||||||
while (i < size)
|
|
||||||
dest[i++] = ' ';
|
|
||||||
dest[i] = '\0';
|
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t *iso_j_str(const char *src)
|
|
||||||
{
|
|
||||||
int size = strlen(src) * 2;
|
|
||||||
uint16_t *dest = malloc(size + 2);
|
|
||||||
char *cpy, *in, *out;
|
|
||||||
size_t inleft, outleft;
|
|
||||||
iconv_t cd;
|
|
||||||
|
|
||||||
/* If the conversion is unavailable, return NULL. Obviously,
|
|
||||||
nl_langinfo(..) requires the locale to be set correctly. */
|
|
||||||
cd = iconv_open("UCS-2BE", nl_langinfo(CODESET));
|
|
||||||
if (cd == (iconv_t) - 1) {
|
|
||||||
free(dest);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
len = strlen(ret);
|
||||||
|
if (len > size) {
|
||||||
|
ret[size] = '\0';
|
||||||
|
len = size;
|
||||||
|
}
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
char c = toupper(ret[i]);
|
||||||
|
ret[i] = valid_d_char(c) ? c : '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In, out, inleft and outleft will be updated by iconv, that's why we
|
return ret;
|
||||||
need separate variables. */
|
|
||||||
cpy = strdup(src); /* iconv doesn't take const * chars, so we need our
|
|
||||||
* own copy. */
|
|
||||||
in = cpy;
|
|
||||||
out = (char*)dest;
|
|
||||||
inleft = strlen(cpy);
|
|
||||||
outleft = size;
|
|
||||||
iconv(cd, &in, &inleft, &out, &outleft);
|
|
||||||
|
|
||||||
/* Since we need to pad with NULLs, we can pad up to and including the
|
|
||||||
terminating NULLs. */
|
|
||||||
outleft += 2;
|
|
||||||
while (outleft) {
|
|
||||||
*out++ = '\0';
|
|
||||||
outleft--;
|
|
||||||
}
|
|
||||||
iconv_close(cd);
|
|
||||||
free(cpy);
|
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *iso_1_fileid(const char *src)
|
char *iso_1_dirid(const wchar_t *src)
|
||||||
{
|
{
|
||||||
char *dest = malloc(15); /* 15 = 8 (name) + 1 (.) + 3 (ext) + 2
|
return iso_dirid(src, 8);
|
||||||
(;1) + 1 (\0) */
|
}
|
||||||
char *dot = strrchr(src, '.'); /* Position of the last dot in the
|
|
||||||
|
char *iso_2_dirid(const wchar_t *src)
|
||||||
|
{
|
||||||
|
return iso_dirid(src, 31);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *iso_1_fileid(const wchar_t *wsrc)
|
||||||
|
{
|
||||||
|
char *src = wcstoascii(wsrc);
|
||||||
|
char *dest;
|
||||||
|
char *dot; /* Position of the last dot in the
|
||||||
filename, will be used to calculate
|
filename, will be used to calculate
|
||||||
lname and lext. */
|
lname and lext. */
|
||||||
int lname, lext, pos, i;
|
int lname, lext, pos, i;
|
||||||
|
|
||||||
|
if (!src)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dest = malloc(15); /* 15 = 8 (name) + 1 (.) + 3 (ext) + 2
|
||||||
|
(;1) + 1 (\0) */
|
||||||
|
dot = strrchr(src, '.');
|
||||||
|
|
||||||
lext = dot ? strlen(dot + 1) : 0;
|
lext = dot ? strlen(dot + 1) : 0;
|
||||||
lname = strlen(src) - lext - (dot ? 1 : 0);
|
lname = strlen(src) - lext - (dot ? 1 : 0);
|
||||||
|
|
||||||
/* If we can't build a filename, return NULL. */
|
/* If we can't build a filename, return NULL. */
|
||||||
if (lname == 0 && lext == 0) {
|
if (lname == 0 && lext == 0) {
|
||||||
|
free(src);
|
||||||
free(dest);
|
free(dest);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -156,16 +210,24 @@ char *iso_1_fileid(const char *src)
|
|||||||
dest[pos] = '\0';
|
dest[pos] = '\0';
|
||||||
dest = (char *)realloc(dest, pos + 1);
|
dest = (char *)realloc(dest, pos + 1);
|
||||||
|
|
||||||
|
free(src);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *iso_2_fileid(const char *src)
|
char *iso_2_fileid(const wchar_t *wsrc)
|
||||||
{
|
{
|
||||||
char *dest = malloc(34); /* 34 = 30 (name + ext) + 1 (.) + 2
|
char *src = wcstoascii(wsrc);
|
||||||
(;1) + 1 (\0) */
|
char *dest;
|
||||||
char *dot = strrchr(src, '.');
|
char *dot;
|
||||||
int lname, lext, lnname, lnext, pos, i;
|
int lname, lext, lnname, lnext, pos, i;
|
||||||
|
|
||||||
|
if (!src)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
dest = malloc(34); /* 34 = 30 (name + ext) + 1 (.) + 2
|
||||||
|
(;1) + 1 (\0) */
|
||||||
|
dot = strrchr(src, '.');
|
||||||
|
|
||||||
/* Since the maximum length can be divided freely over the name and
|
/* Since the maximum length can be divided freely over the name and
|
||||||
extension, we need to calculate their new lengths (lnname and
|
extension, we need to calculate their new lengths (lnname and
|
||||||
lnext). If the original filename is too long, we start by trimming
|
lnext). If the original filename is too long, we start by trimming
|
||||||
@ -177,12 +239,13 @@ char *iso_2_fileid(const char *src)
|
|||||||
} else {
|
} else {
|
||||||
lext = strlen(dot + 1);
|
lext = strlen(dot + 1);
|
||||||
lname = strlen(src) - lext - 1;
|
lname = strlen(src) - lext - 1;
|
||||||
lnext = (strlen(src) > 31 &&
|
lnext = (strlen(src) > 31 && lext > 3)
|
||||||
lext > 3) ? (lname < 27 ? 30 - lname : 3) : lext;
|
? (lname < 27 ? 30 - lname : 3) : lext;
|
||||||
lnname = (strlen(src) > 31) ? 30 - lnext : lname;
|
lnname = (strlen(src) > 31) ? 30 - lnext : lname;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lnname == 0 && lnext == 0) {
|
if (lnname == 0 && lnext == 0) {
|
||||||
|
free(src);
|
||||||
free(dest);
|
free(dest);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -206,276 +269,43 @@ char *iso_2_fileid(const char *src)
|
|||||||
dest[pos] = '\0';
|
dest[pos] = '\0';
|
||||||
dest = (char *)realloc(dest, pos + 1);
|
dest = (char *)realloc(dest, pos + 1);
|
||||||
|
|
||||||
|
free(src);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t *iso_j_id(char *src)
|
char *
|
||||||
|
iso_p_fileid(const wchar_t *src)
|
||||||
{
|
{
|
||||||
char *dest = malloc(136); /* 136 = 128 (name + ext) + 2 (\0 .) +
|
char *ret = wcstoascii(src);
|
||||||
4 (\0 ; \0 1) + 2 (\0 \0) */
|
size_t i, len;
|
||||||
char *dot = strrchr(src, '.');
|
|
||||||
int lname, lext, lcname, lcext, lnname, lnext, pos, i;
|
|
||||||
size_t inleft, outleft;
|
|
||||||
char *cname, *cext, *in, *out;
|
|
||||||
iconv_t cd;
|
|
||||||
|
|
||||||
if (dot == NULL || dot == src || *(dot + 1) == '\0') {
|
if (!ret)
|
||||||
lname = strlen(src);
|
|
||||||
lext = 0;
|
|
||||||
} else {
|
|
||||||
lext = strlen(dot + 1);
|
|
||||||
lname = strlen(src) - lext - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lname == 0 && lext == 0) {
|
|
||||||
free(dest);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
len = strlen(ret);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
cd = iconv_open("UCS-2BE", nl_langinfo(CODESET));
|
if (!valid_p_char(ret[i])) {
|
||||||
if (cd == (iconv_t) - 1) {
|
ret[i] = (uint16_t)'_';
|
||||||
free(dest);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We need to convert the name and extension first, in order to
|
|
||||||
calculate the number of characters they have. */
|
|
||||||
cname = malloc(lname * 2);
|
|
||||||
in = src;
|
|
||||||
out = cname;
|
|
||||||
inleft = lname;
|
|
||||||
outleft = lname * 2;
|
|
||||||
iconv(cd, &in, &inleft, &out, &outleft);
|
|
||||||
lcname = (lname * 2) - outleft;
|
|
||||||
iconv_close(cd);
|
|
||||||
|
|
||||||
if (lext) {
|
|
||||||
cd = iconv_open("UCS-2BE", nl_langinfo(CODESET));
|
|
||||||
if (cd == (iconv_t) - 1) {
|
|
||||||
free(dest);
|
|
||||||
free(cname);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
cext = malloc(lext * 2);
|
}
|
||||||
in = dot + 1;
|
return ret;
|
||||||
out = cext;
|
|
||||||
inleft = lext;
|
|
||||||
outleft = lext * 2;
|
|
||||||
iconv(cd, &in, &inleft, &out, &outleft);
|
|
||||||
lcext = (lext * 2) - outleft;
|
|
||||||
iconv_close(cd);
|
|
||||||
} else
|
|
||||||
lcext = 0;
|
|
||||||
|
|
||||||
/* Again, divide the available characters over name and extension, but
|
|
||||||
keep a minimum of three characters for the new extension. */
|
|
||||||
lnext = (lcname + lcext > 128 &&
|
|
||||||
lcext > 6) ? (lcname < 122 ? 128 - lcname : 6) : lcext;
|
|
||||||
lnname = (lcname + lcext > 128) ? 128 - lnext : lcname;
|
|
||||||
|
|
||||||
pos = 0;
|
|
||||||
/* Copy up to lnname bytes from the converted filename. */
|
|
||||||
for (i = 0; i < lnname; i = i + 2)
|
|
||||||
if (valid_j_char(cname[i], cname[i + 1])) {
|
|
||||||
dest[pos++] = cname[i];
|
|
||||||
dest[pos++] = cname[i + 1];
|
|
||||||
} else {
|
|
||||||
dest[pos++] = '\0';
|
|
||||||
dest[pos++] = '_';
|
|
||||||
}
|
|
||||||
/* Dot is now a 16 bit separator. */
|
|
||||||
dest[pos++] = '\0';
|
|
||||||
dest[pos++] = '.';
|
|
||||||
/* Copy up to lnext bytes from the converted extension, if any. */
|
|
||||||
for (i = 0; i < lnext; i = i + 2)
|
|
||||||
if (valid_j_char(cext[i], cext[i + 1])) {
|
|
||||||
dest[pos++] = cext[i];
|
|
||||||
dest[pos++] = cext[i + 1];
|
|
||||||
} else {
|
|
||||||
dest[pos++] = '\0';
|
|
||||||
dest[pos++] = '_';
|
|
||||||
}
|
|
||||||
/* Again, 2 bytes per character. */
|
|
||||||
dest[pos++] = '\0';
|
|
||||||
dest[pos++] = ';';
|
|
||||||
dest[pos++] = '\0';
|
|
||||||
dest[pos++] = '1';
|
|
||||||
dest[pos++] = '\0';
|
|
||||||
dest[pos] = '\0';
|
|
||||||
|
|
||||||
dest = (char *)realloc(dest, pos + 1);
|
|
||||||
free(cname);
|
|
||||||
if (lext)
|
|
||||||
free(cext);
|
|
||||||
|
|
||||||
/* Fill in the size in bytes (including the terminating NULLs) of the
|
|
||||||
destination string. */
|
|
||||||
return (uint16_t *) dest;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *iso_p_filename(const char *src)
|
uint16_t *
|
||||||
|
iso_j_id(const wchar_t *src)
|
||||||
{
|
{
|
||||||
char *dest = malloc(251); /* We can fit up to 250 characters in
|
uint16_t *j_str = wcstoucs(src);
|
||||||
a Rock Ridge name entry. */
|
size_t len = ucslen(j_str);
|
||||||
char *dot = strrchr(src, '.');
|
size_t n;
|
||||||
int lname, lext, lnname, lnext, pos, i;
|
|
||||||
|
|
||||||
if (dot == NULL || dot == src || *(dot + 1) == '\0') {
|
if (len > 128) {
|
||||||
lname = strlen(src);
|
j_str[128] = '\0';
|
||||||
lnname = (lname > 250) ? 250 : lname;
|
len = 128;
|
||||||
lext = lnext = 0;
|
|
||||||
} else {
|
|
||||||
lext = strlen(dot + 1);
|
|
||||||
lname = strlen(src) - lext - 1;
|
|
||||||
lnext = (strlen(src) > 250 &&
|
|
||||||
lext > 3) ? (lname < 246 ? 249 - lname : 3) : lext;
|
|
||||||
lnname = (strlen(src) > 250) ? 249 - lnext : lname;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lnname == 0 && lnext == 0) {
|
for (n = 0; n < len; n++)
|
||||||
free(dest);
|
if (!valid_j_char(j_str[n]))
|
||||||
return NULL;
|
j_str[n] = '_';
|
||||||
}
|
return j_str;
|
||||||
|
|
||||||
pos = 0;
|
|
||||||
for (i = 0; i < lnname; i++)
|
|
||||||
dest[pos++] = valid_p_char(src[i]) ? src[i] : '_';
|
|
||||||
if (lnext) {
|
|
||||||
dest[pos++] = '.';
|
|
||||||
for (i = 0; i < lnext; i++)
|
|
||||||
dest[pos++] =
|
|
||||||
valid_p_char(src[lname + 1 + i]) ?
|
|
||||||
src[lname + 1 + i] : '_';
|
|
||||||
}
|
|
||||||
dest[pos] = '\0';
|
|
||||||
dest = (char *)realloc(dest, pos + 1);
|
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_p_dirname(const char *src)
|
|
||||||
{
|
|
||||||
char *dest = strlen(src) > 250 ? malloc(251) : malloc(strlen(src) + 1);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (strlen(src) == 0) {
|
|
||||||
free(dest);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 250 && src[i]; i++)
|
|
||||||
dest[i] = valid_p_char(src[i]) ? src[i] : '_';
|
|
||||||
dest[i] = '\0';
|
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_pathname(const char *dir, const char *file)
|
|
||||||
{
|
|
||||||
char *path = malloc(strlen(dir) + strlen(file) + 2);
|
|
||||||
|
|
||||||
strcpy(path, dir);
|
|
||||||
path[strlen(dir)] = '/';
|
|
||||||
strcpy(path + strlen(dir) + 1, file);
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
void iso_a_strcpy(unsigned char *dest, int size, const char *src)
|
|
||||||
{
|
|
||||||
int i = 0, d = 0;
|
|
||||||
|
|
||||||
if (src)
|
|
||||||
for (; i < size && *src; ++i, ++src) {
|
|
||||||
char s = toupper(*src);
|
|
||||||
|
|
||||||
if (valid_a_char(s))
|
|
||||||
dest[d++] = s;
|
|
||||||
else
|
|
||||||
dest[d++] = '_';
|
|
||||||
}
|
|
||||||
for (; i < size; ++i) {
|
|
||||||
/* pad with spaces */
|
|
||||||
dest[d++] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void iso_d_strcpy(unsigned char *dest, int size, const char *src)
|
|
||||||
{
|
|
||||||
int i = 0, d = 0;
|
|
||||||
|
|
||||||
if (src)
|
|
||||||
for (; i < size && *src; ++i, ++src) {
|
|
||||||
char s = toupper(*src);
|
|
||||||
|
|
||||||
if (valid_d_char(s))
|
|
||||||
dest[d++] = s;
|
|
||||||
else
|
|
||||||
dest[d++] = '_';
|
|
||||||
}
|
|
||||||
for (; i < size; ++i) {
|
|
||||||
/* pad with spaces */
|
|
||||||
dest[d++] = ' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_a_strndup(const char *src, int size)
|
|
||||||
{
|
|
||||||
int i, d;
|
|
||||||
char *out;
|
|
||||||
|
|
||||||
out = malloc(size + 1);
|
|
||||||
for (i = d = 0; i < size && *src; ++i, ++src) {
|
|
||||||
char s = toupper(*src);
|
|
||||||
|
|
||||||
if (valid_a_char(s))
|
|
||||||
out[d++] = s;
|
|
||||||
else
|
|
||||||
out[d++] = '_';
|
|
||||||
}
|
|
||||||
out[d++] = '\0';
|
|
||||||
out = realloc(out, d); /* shrink the buffer to what we used */
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_d_strndup(const char *src, int size)
|
|
||||||
{
|
|
||||||
int i, d;
|
|
||||||
char *out;
|
|
||||||
|
|
||||||
out = malloc(size + 1);
|
|
||||||
for (i = d = 0; i < size && *src; ++i, ++src) {
|
|
||||||
char s = toupper(*src);
|
|
||||||
|
|
||||||
if (valid_d_char(s))
|
|
||||||
out[d++] = s;
|
|
||||||
else
|
|
||||||
out[d++] = '_';
|
|
||||||
}
|
|
||||||
out[d++] = '\0';
|
|
||||||
out = realloc(out, d); /* shrink the buffer to what we used */
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_strconcat(char sep, const char *a, const char *b)
|
|
||||||
{
|
|
||||||
char *out;
|
|
||||||
int la, lb;
|
|
||||||
|
|
||||||
la = strlen(a);
|
|
||||||
lb = strlen(b);
|
|
||||||
out = malloc(la + lb + 1 + (sep ? 1 : 0));
|
|
||||||
memcpy(out, a, la);
|
|
||||||
memcpy(out + la + (sep ? 1 : 0), b, lb);
|
|
||||||
if (sep)
|
|
||||||
out[la] = sep;
|
|
||||||
out[la + lb + (sep ? 1 : 0)] = '\0';
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *iso_strdup(const char *src)
|
|
||||||
{
|
|
||||||
return src ? strdup(src) : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void iso_lsb(uint8_t *buf, uint32_t num, int bytes)
|
void iso_lsb(uint8_t *buf, uint32_t num, int bytes)
|
||||||
@ -551,7 +381,6 @@ void iso_datetime_17(unsigned char *buf, time_t t)
|
|||||||
static int tzsetup = 0;
|
static int tzsetup = 0;
|
||||||
static int tzoffset;
|
static int tzoffset;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
char c[5];
|
|
||||||
|
|
||||||
if (t == (time_t) - 1) {
|
if (t == (time_t) - 1) {
|
||||||
/* unspecified time */
|
/* unspecified time */
|
||||||
@ -570,27 +399,13 @@ void iso_datetime_17(unsigned char *buf, time_t t)
|
|||||||
|
|
||||||
localtime_r(&t, &tm);
|
localtime_r(&t, &tm);
|
||||||
|
|
||||||
/* year */
|
sprintf((char*)&buf[0], "%04d", tm.tm_year + 1900);
|
||||||
sprintf(c, "%04d", tm.tm_year + 1900);
|
sprintf((char*)&buf[4], "%02d", tm.tm_mon + 1);
|
||||||
memcpy(&buf[0], c, 4);
|
sprintf((char*)&buf[6], "%02d", tm.tm_mday);
|
||||||
/* month */
|
sprintf((char*)&buf[8], "%02d", tm.tm_hour);
|
||||||
sprintf(c, "%02d", tm.tm_mon + 1);
|
sprintf((char*)&buf[10], "%02d", tm.tm_min);
|
||||||
memcpy(&buf[4], c, 2);
|
sprintf((char*)&buf[12], "%02d", MIN(59, tm.tm_sec));
|
||||||
/* day */
|
|
||||||
sprintf(c, "%02d", tm.tm_mday);
|
|
||||||
memcpy(&buf[6], c, 2);
|
|
||||||
/* hour */
|
|
||||||
sprintf(c, "%02d", tm.tm_hour);
|
|
||||||
memcpy(&buf[8], c, 2);
|
|
||||||
/* minute */
|
|
||||||
sprintf(c, "%02d", tm.tm_min);
|
|
||||||
memcpy(&buf[10], c, 2);
|
|
||||||
/* second */
|
|
||||||
sprintf(c, "%02d", MIN(59, tm.tm_sec));
|
|
||||||
memcpy(&buf[12], c, 2);
|
|
||||||
/* hundreths */
|
|
||||||
memcpy(&buf[14], "00", 2);
|
memcpy(&buf[14], "00", 2);
|
||||||
/* timezone */
|
|
||||||
buf[16] = tzoffset;
|
buf[16] = tzoffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,47 +426,6 @@ time_t iso_datetime_read_17(const uint8_t *buf)
|
|||||||
return mktime(&tm) - buf[16] * 60 * 60;
|
return mktime(&tm) - buf[16] * 60 * 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
void iso_split_filename(char *name, char **ext)
|
|
||||||
{
|
|
||||||
char *r;
|
|
||||||
|
|
||||||
r = strrchr(name, '.');
|
|
||||||
if (r) {
|
|
||||||
*r = '\0';
|
|
||||||
*ext = r + 1;
|
|
||||||
} else
|
|
||||||
*ext = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
void iso_filecpy(unsigned char *buf, int size, const char *name, int version)
|
|
||||||
{
|
|
||||||
char v[6];
|
|
||||||
int nl, vl;
|
|
||||||
|
|
||||||
assert(version >= 0);
|
|
||||||
assert(version < 0x8000);
|
|
||||||
|
|
||||||
nl = strlen(name);
|
|
||||||
|
|
||||||
memcpy(buf, name, nl);
|
|
||||||
|
|
||||||
if (!version)
|
|
||||||
assert(size >= strlen(name));
|
|
||||||
else {
|
|
||||||
sprintf(v, "%d", version);
|
|
||||||
vl = strlen(v);
|
|
||||||
assert(size >= nl + vl + 1);
|
|
||||||
|
|
||||||
buf[nl] = ';';
|
|
||||||
memcpy(&buf[nl + 1], v, vl);
|
|
||||||
|
|
||||||
nl += vl + 1;
|
|
||||||
}
|
|
||||||
/* pad with spaces */
|
|
||||||
if (nl < size)
|
|
||||||
memset(&buf[nl], ' ', size - nl);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ucslen(const uint16_t *str)
|
size_t ucslen(const uint16_t *str)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -661,20 +435,30 @@ size_t ucslen(const uint16_t *str)
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Although each character is 2 bytes, we actually compare byte-by-byte
|
||||||
|
* (thats what the spec says).
|
||||||
|
*/
|
||||||
int ucscmp(const uint16_t *s1, const uint16_t *s2)
|
int ucscmp(const uint16_t *s1, const uint16_t *s2)
|
||||||
{
|
{
|
||||||
int i;
|
const char *s = (const char*)s1;
|
||||||
|
const char *t = (const char*)s2;
|
||||||
|
size_t len1 = ucslen(s1);
|
||||||
|
size_t len2 = ucslen(s2);
|
||||||
|
size_t i, len = MIN(len1, len2) * 2;
|
||||||
|
|
||||||
for (i=0; 1; i++) {
|
for (i=0; i < len; i++) {
|
||||||
if (s1[i] < s2[i]) {
|
if (s[i] < t[i]) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (s1[i] > s2[i]) {
|
} else if (s[i] > t[i]) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (s1[i] == 0 && s2[i] == 0) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (len1 < len2)
|
||||||
|
return -1;
|
||||||
|
else if (len1 > len2)
|
||||||
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
163
libisofs/util.h
163
libisofs/util.h
@ -1,122 +1,95 @@
|
|||||||
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
||||||
|
/* vim: set noet ts=8 sts=8 sw=8 : */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility functions for the Libisofs library.
|
* Utility functions for the Libisofs library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ISO_UTIL
|
#ifndef LIBISO_UTIL_H
|
||||||
#define __ISO_UTIL
|
#define LIBISO_UTIL_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern inline int div_up(int n, int div)
|
||||||
|
{
|
||||||
|
return (n + div - 1) / div;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern inline int round_up(int n, int mul)
|
||||||
|
{
|
||||||
|
return div_up(n, mul) * mul;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t *towcs(const char *);
|
||||||
|
char *wcstoascii(const wchar_t *);
|
||||||
|
uint16_t *wcstoucs(const wchar_t*);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given character is a valid d-character.
|
* Create a level 1 directory identifier.
|
||||||
*/
|
*/
|
||||||
int valid_d_char(char c);
|
char *iso_1_dirid(const wchar_t *src);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given character is a valid a-character.
|
* Create a level 2 directory identifier.
|
||||||
*/
|
*/
|
||||||
int valid_a_char(char c);
|
char *iso_2_dirid(const wchar_t *src);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given character is part of the Joliet Allowed Character Set.
|
* Create a level 1 file identifier that consists of a name, extension and
|
||||||
*/
|
* version number. The resulting string will have a file name of maximum
|
||||||
int valid_j_char(char msb, char lsb);
|
* length 8, followed by a separator (.), an optional extension of maximum
|
||||||
|
* length 3, followed by a separator (;) and a version number (digit 1).
|
||||||
/**
|
|
||||||
* Checks if the given character is part of the POSIX Portable Filename Character Set.
|
|
||||||
*/
|
|
||||||
int valid_p_char(char c);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a string of d-characters of maximum size 'size', optionally padded with spaces if necessary.
|
|
||||||
* Can be used to create directory identifiers if padding is turned off.
|
|
||||||
*/
|
|
||||||
char *iso_d_str(const char *src, int size, int pad);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a string of a-characters of maximum size 'size', padded with spaces if necessary.
|
|
||||||
*/
|
|
||||||
char *iso_a_str(const char *src, int size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a string of j-characters of maximum size 'size', padded with NULLs if necessary.
|
|
||||||
* Requires the locale to be set correctly.
|
|
||||||
* @return NULL if the conversion from the current codeset to UCS-2BE is not available.
|
|
||||||
*/
|
|
||||||
uint16_t *iso_j_str(const char *src);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a level 1 file identifier that consists of a name, extension and version number.
|
|
||||||
* The resulting string will have a file name of maximum length 8, followed by a separator (.),
|
|
||||||
* an optional extension of maximum length 3, followed by a separator (;) and a version number (digit 1).
|
|
||||||
* @return NULL if the original name and extension both are of length 0.
|
* @return NULL if the original name and extension both are of length 0.
|
||||||
*/
|
*/
|
||||||
char *iso_1_fileid(const char *src);
|
char *iso_1_fileid(const wchar_t *src);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a level 2 file identifier that consists of a name, extension and version number.
|
* Create a level 2 file identifier that consists of a name, extension and
|
||||||
* The combined file name and extension length will not exceed 30, the name and extension will be separated (.),
|
* version number. The combined file name and extension length will not exceed
|
||||||
* and the extension will be followed by a separator (;) and a version number (digit 1).
|
* 30, the name and extension will be separated (.), and the extension will be
|
||||||
|
* followed by a separator (;) and a version number (digit 1).
|
||||||
* @return NULL if the original name and extension both are of length 0.
|
* @return NULL if the original name and extension both are of length 0.
|
||||||
*/
|
*/
|
||||||
char *iso_2_fileid(const char *src);
|
char *iso_2_fileid(const wchar_t *src);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a Joliet file or directory identifier that consists of a name, extension and version number.
|
* Create a Joliet file or directory identifier that consists of a name,
|
||||||
* The combined name and extension length will not exceed 128 bytes, the name and extension will be separated (.),
|
* extension and version number. The combined name and extension length will
|
||||||
* and the extension will be followed by a separator (;) and a version number (digit 1).
|
* not exceed 128 bytes, the name and extension will be separated (.),
|
||||||
* All characters consist of 2 bytes and the resulting string is NULL-terminated by a 2-byte NULL.
|
* and the extension will be followed by a separator (;) and a version number
|
||||||
* Requires the locale to be set correctly.
|
* (digit 1). All characters consist of 2 bytes and the resulting string is
|
||||||
|
* NULL-terminated by a 2-byte NULL. Requires the locale to be set correctly.
|
||||||
|
*
|
||||||
* @param size will be set to the size (in bytes) of the identifier.
|
* @param size will be set to the size (in bytes) of the identifier.
|
||||||
* @return NULL if the original name and extension both are of length 0 or the conversion from the current codeset to UCS-2BE is not available.
|
* @return NULL if the original name and extension both are of length 0 or the conversion from the current codeset to UCS-2BE is not available.
|
||||||
*/
|
*/
|
||||||
uint16_t *iso_j_id(char *src);
|
uint16_t *iso_j_id(const wchar_t *src);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* FIXME: what are the requirements for these next two? Is this for RR?
|
||||||
|
*
|
||||||
* Create a POSIX portable file name that consists of a name and extension.
|
* Create a POSIX portable file name that consists of a name and extension.
|
||||||
* The resulting file name will not exceed 250 characters.
|
* The resulting file name will not exceed 250 characters.
|
||||||
* @return NULL if the original name and extension both are of length 0.
|
* @return NULL if the original name and extension both are of length 0.
|
||||||
*/
|
*/
|
||||||
char *iso_p_filename(const char *src);
|
char *iso_p_fileid(const wchar_t *src);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a POSIX portable directory name.
|
* Create a POSIX portable directory name.
|
||||||
* The resulting directory name will not exceed 250 characters.
|
* The resulting directory name will not exceed 250 characters.
|
||||||
* @return NULL if the original name is of length 0.
|
* @return NULL if the original name is of length 0.
|
||||||
*/
|
*/
|
||||||
char *iso_p_dirname(const char *src);
|
char *iso_p_dirid(const wchar_t *src);
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a pathname out of a directory and file name.
|
|
||||||
*/
|
|
||||||
char *iso_pathname(const char *dir, const char *file);
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
||||||
|
|
||||||
/** Copy a string of a-characters, padding the unused part of the
|
|
||||||
destination buffer */
|
|
||||||
void iso_a_strcpy(unsigned char *dest, int size, const char *src);
|
|
||||||
|
|
||||||
/** Copy a string of d-characters, padding the unused part of the
|
|
||||||
destination buffer */
|
|
||||||
void iso_d_strcpy(unsigned char *dest, int size, const char *src);
|
|
||||||
|
|
||||||
/** Returns a null terminated string containing the first 'size' a-characters
|
|
||||||
from the source */
|
|
||||||
char *iso_a_strndup(const char *src, int size);
|
|
||||||
|
|
||||||
/** Returns a null terminated string containing the first 'size' d-characters
|
|
||||||
from the source */
|
|
||||||
char *iso_d_strndup(const char *src, int size);
|
|
||||||
|
|
||||||
char *iso_strconcat(char sep, const char *a, const char *b);
|
|
||||||
|
|
||||||
char *iso_strdup(const char *src);
|
|
||||||
|
|
||||||
void iso_lsb(uint8_t *buf, uint32_t num, int bytes);
|
void iso_lsb(uint8_t *buf, uint32_t num, int bytes);
|
||||||
void iso_msb(uint8_t *buf, uint32_t num, int bytes);
|
void iso_msb(uint8_t *buf, uint32_t num, int bytes);
|
||||||
@ -127,30 +100,22 @@ uint32_t iso_read_msb(const uint8_t *buf, int bytes);
|
|||||||
uint32_t iso_read_bb(const uint8_t *buf, int bytes);
|
uint32_t iso_read_bb(const uint8_t *buf, int bytes);
|
||||||
|
|
||||||
/** Records the date/time into a 7 byte buffer (9.1.5) */
|
/** Records the date/time into a 7 byte buffer (9.1.5) */
|
||||||
void iso_datetime_7(unsigned char *buf, time_t t);
|
void iso_datetime_7(uint8_t *buf, time_t t);
|
||||||
|
|
||||||
/** Records the date/time into a 17 byte buffer (8.4.26.1) */
|
/** Records the date/time into a 17 byte buffer (8.4.26.1) */
|
||||||
void iso_datetime_17(unsigned char *buf, time_t t);
|
void iso_datetime_17(uint8_t *buf, time_t t);
|
||||||
|
|
||||||
time_t iso_datetime_read_7(const uint8_t *buf);
|
time_t iso_datetime_read_7(const uint8_t *buf);
|
||||||
time_t iso_datetime_read_17(const uint8_t *buf);
|
time_t iso_datetime_read_17(const uint8_t *buf);
|
||||||
|
|
||||||
/** Removes the extension from the name, and returns the extension. The
|
/**
|
||||||
returned extension should _not_ be freed! */
|
* Like strlen, but for Joliet strings.
|
||||||
void iso_split_filename(char *name, char **ext);
|
*/
|
||||||
|
size_t ucslen(const uint16_t *str);
|
||||||
|
|
||||||
void iso_filecpy(unsigned char *buf, int size, const char *name, int version);
|
/**
|
||||||
|
* Like strcmp, but for Joliet strings.
|
||||||
|
*/
|
||||||
|
int ucscmp(const uint16_t *s1, const uint16_t *s2);
|
||||||
|
|
||||||
int iso_filename_len(const char *name, int iso_level);
|
#endif /* LIBISO_UTIL_H */
|
||||||
|
|
||||||
/* replacement for strlen for joliet names (wcslen doesn't work on machines
|
|
||||||
* with 32-bit wchar_t */
|
|
||||||
size_t ucslen(const uint16_t *);
|
|
||||||
|
|
||||||
/* replacement for strcmp for joliet names */
|
|
||||||
int ucscmp(const uint16_t*, const uint16_t*);
|
|
||||||
|
|
||||||
#define DIV_UP(n,div) ( ((n)+(div)-1) / (div) )
|
|
||||||
#define ROUND_UP(n,mul) ( DIV_UP(n,mul) * (mul) )
|
|
||||||
|
|
||||||
#endif /* __ISO_UTIL */
|
|
||||||
|
@ -2,50 +2,71 @@
|
|||||||
/* vim: set ts=8 sts=8 sw=8 noet : */
|
/* vim: set ts=8 sts=8 sw=8 noet : */
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "libisofs.h"
|
#include "libisofs.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "volume.h"
|
#include "volume.h"
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
struct iso_volset *iso_volset_new(struct iso_volume *vol, const char *id)
|
struct iso_volset*
|
||||||
|
iso_volset_new(struct iso_volume *vol, const char *id)
|
||||||
{
|
{
|
||||||
struct iso_volset *volset = calloc(1, sizeof(struct iso_volset));
|
struct iso_volset *volset = calloc(1, sizeof(struct iso_volset));
|
||||||
|
|
||||||
volset->volset_size = 1;
|
volset->volset_size = 1;
|
||||||
|
volset->refcount = 1;
|
||||||
volset->volume = malloc(sizeof(void *));
|
volset->volume = malloc(sizeof(void *));
|
||||||
volset->volume[0] = vol;
|
volset->volume[0] = vol;
|
||||||
volset->volset_id.cstr = strdup(id);
|
volset->volset_id = towcs(id);
|
||||||
volset->volset_id.jstr = iso_j_str(id);
|
|
||||||
|
vol->refcount++;
|
||||||
return volset;
|
return volset;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iso_volume *iso_volume_new(const char *volume_id,
|
void
|
||||||
const char *publisher_id,
|
iso_volset_free(struct iso_volset *volset)
|
||||||
const char *data_preparer_id)
|
{
|
||||||
|
if (--volset->refcount < 1) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < volset->volset_size; i++) {
|
||||||
|
iso_volume_free(volset->volume[i]);
|
||||||
|
}
|
||||||
|
free(volset->volume);
|
||||||
|
free(volset->volset_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct iso_volume*
|
||||||
|
iso_volume_new(const char *volume_id,
|
||||||
|
const char *publisher_id,
|
||||||
|
const char *data_preparer_id)
|
||||||
|
{
|
||||||
|
return iso_volume_new_with_root(volume_id,
|
||||||
|
publisher_id,
|
||||||
|
data_preparer_id,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct iso_volume*
|
||||||
|
iso_volume_new_with_root(const char *volume_id,
|
||||||
|
const char *publisher_id,
|
||||||
|
const char *data_preparer_id,
|
||||||
|
struct iso_tree_node *root)
|
||||||
{
|
{
|
||||||
struct iso_volume *volume;
|
struct iso_volume *volume;
|
||||||
|
|
||||||
volume = calloc(1, sizeof(struct iso_volume));
|
volume = calloc(1, sizeof(struct iso_volume));
|
||||||
volume->refcount = 1;
|
volume->refcount = 1;
|
||||||
|
|
||||||
/* Get a new root directory. */
|
volume->root = root ? root : iso_tree_new_root(volume);
|
||||||
volume->root = iso_tree_new_root(volume);
|
|
||||||
|
|
||||||
/* Set these fields, if given. */
|
if (volume_id != NULL)
|
||||||
if (volume_id != NULL) {
|
volume->volume_id = towcs(volume_id);
|
||||||
volume->volume_id.cstr = strdup(volume_id);
|
if (publisher_id != NULL)
|
||||||
volume->volume_id.jstr = iso_j_str(volume_id);
|
volume->publisher_id = towcs(publisher_id);
|
||||||
}
|
if (data_preparer_id != NULL)
|
||||||
if (publisher_id != NULL) {
|
volume->data_preparer_id = towcs(data_preparer_id);
|
||||||
volume->publisher_id.cstr = strdup(publisher_id);
|
|
||||||
volume->publisher_id.jstr = iso_j_str(publisher_id);
|
|
||||||
}
|
|
||||||
if (data_preparer_id != NULL) {
|
|
||||||
volume->data_preparer_id.cstr = strdup(data_preparer_id);
|
|
||||||
volume->data_preparer_id.jstr = iso_j_str(data_preparer_id);
|
|
||||||
}
|
|
||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,18 +76,15 @@ void iso_volume_free(struct iso_volume *volume)
|
|||||||
if (--volume->refcount < 1) {
|
if (--volume->refcount < 1) {
|
||||||
iso_tree_free(volume->root);
|
iso_tree_free(volume->root);
|
||||||
|
|
||||||
free(volume->volume_id.cstr);
|
free(volume->volume_id);
|
||||||
free(volume->volume_id.jstr);
|
free(volume->publisher_id);
|
||||||
free(volume->publisher_id.cstr);
|
free(volume->data_preparer_id);
|
||||||
free(volume->publisher_id.jstr);
|
|
||||||
free(volume->data_preparer_id.cstr);
|
|
||||||
free(volume->data_preparer_id.jstr);
|
|
||||||
|
|
||||||
free(volume);
|
free(volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iso_tree_dir *iso_volume_get_root(const struct iso_volume *volume)
|
struct iso_tree_node *iso_volume_get_root(const struct iso_volume *volume)
|
||||||
{
|
{
|
||||||
return volume->root;
|
return volume->root;
|
||||||
}
|
}
|
||||||
|
@ -5,35 +5,25 @@
|
|||||||
* Extra declarations for use with the iso_volume structure.
|
* Extra declarations for use with the iso_volume structure.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ISO_VOLUME
|
#ifndef LIBISO_VOLUME_H
|
||||||
#define __ISO_VOLUME
|
#define LIBISO_VOLUME_H
|
||||||
|
|
||||||
#include "libisofs.h"
|
#include "libisofs.h"
|
||||||
|
|
||||||
struct iso_string
|
|
||||||
{
|
|
||||||
char *cstr;
|
|
||||||
uint16_t *jstr;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data volume.
|
* Data volume.
|
||||||
*/
|
*/
|
||||||
struct iso_volume
|
struct iso_volume
|
||||||
{
|
{
|
||||||
int refcount; /**< Number of used references to th
|
int refcount; /**< Number of used references to this
|
||||||
volume. */
|
volume. */
|
||||||
|
|
||||||
struct iso_tree_dir *root; /**< Root of the directory tree for the
|
struct iso_tree_node *root; /**< Root of the directory tree for the
|
||||||
volume. */
|
volume. */
|
||||||
|
|
||||||
unsigned rockridge:1;
|
wchar_t *volume_id; /**< Volume identifier. */
|
||||||
unsigned joliet:1;
|
wchar_t *publisher_id; /**< Volume publisher. */
|
||||||
unsigned iso_level:2;
|
wchar_t *data_preparer_id; /**< Volume data preparer. */
|
||||||
|
|
||||||
struct iso_string volume_id; /**< Volume identifier. */
|
|
||||||
struct iso_string publisher_id; /**< Volume publisher. */
|
|
||||||
struct iso_string data_preparer_id; /**< Volume data preparer. */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -48,7 +38,7 @@ struct iso_volset
|
|||||||
int volset_size; /**< The number of volumes in this
|
int volset_size; /**< The number of volumes in this
|
||||||
volume set. */
|
volume set. */
|
||||||
|
|
||||||
struct iso_string volset_id; /**< The id of this volume set, encoded
|
wchar_t *volset_id; /**< The id of this volume set, encoded
|
||||||
in the current locale. */
|
in the current locale. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
51
test/iso.c
51
test/iso.c
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include "libisofs/libisofs.h"
|
#include "libisofs.h"
|
||||||
#include "libburn/libburn.h"
|
#include "libburn.h"
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <err.h>
|
||||||
|
|
||||||
#define SECSIZE 2048
|
#define SECSIZE 2048
|
||||||
|
|
||||||
@ -44,13 +44,12 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
struct iso_volset *volset;
|
struct iso_volset *volset;
|
||||||
struct iso_volume *volume;
|
struct iso_volume *volume;
|
||||||
|
struct iso_tree_node *root;
|
||||||
struct burn_source *src;
|
struct burn_source *src;
|
||||||
unsigned char buf[2048];
|
unsigned char buf[2048];
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
int c;
|
int c;
|
||||||
int level=1, flags=0;
|
int level=1, flags=0;
|
||||||
DIR *dir;
|
|
||||||
struct dirent *ent;
|
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, optstring)) != -1) {
|
while ((c = getopt(argc, argv, optstring)) != -1) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
@ -87,45 +86,15 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
fd = fopen(argv[optind+1], "w");
|
fd = fopen(argv[optind+1], "w");
|
||||||
if (!fd) {
|
if (!fd) {
|
||||||
perror("error opening output file");
|
err(1, "error opening output file");
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
volume = iso_volume_new( "VOLID", "PUBID", "PREPID" );
|
root = iso_tree_radd_dir(NULL, argv[optind]);
|
||||||
|
if (!root) {
|
||||||
|
err(1, "error opening input directory");
|
||||||
|
}
|
||||||
|
volume = iso_volume_new_with_root( "VOLID", "PUBID", "PREPID", root );
|
||||||
volset = iso_volset_new( volume, "VOLSETID" );
|
volset = iso_volset_new( volume, "VOLSETID" );
|
||||||
dir = opendir(argv[optind]);
|
|
||||||
if (!dir) {
|
|
||||||
perror("error opening input directory");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( (ent = readdir(dir)) ) {
|
|
||||||
struct stat st;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = malloc(strlen(argv[optind]) + strlen(ent->d_name) + 2);
|
|
||||||
strcpy(name, argv[optind]);
|
|
||||||
strcat(name, "/");
|
|
||||||
strcat(name, ent->d_name);
|
|
||||||
if (lstat(name, &st) == -1) {
|
|
||||||
fprintf(stderr, "error opening file %s: %s\n",
|
|
||||||
name, strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
|
||||||
iso_tree_radd_dir(iso_volume_get_root(volume), name);
|
|
||||||
} else {
|
|
||||||
iso_tree_add_file(iso_volume_get_root(volume), name);
|
|
||||||
}
|
|
||||||
free(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
iso_tree_print(iso_volume_get_root(volume), 0);
|
|
||||||
|
|
||||||
src = iso_source_new_ecma119(volset, 0, level, flags);
|
src = iso_source_new_ecma119(volset, 0, level, flags);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user