From 17e9955f93cf100144ce79091c94799059e54a02 Mon Sep 17 00:00:00 2001 From: Vreixo Formoso Date: Sun, 6 Jan 2008 17:38:31 +0100 Subject: [PATCH] Begin Joliet support. Creation of Joliet writer and Joliet tree. --- Makefile.am | 2 + src/ecma119.c | 7 + src/ecma119.h | 3 + src/ecma119_tree.h | 2 +- src/joliet.c | 318 +++++++++++++++++++++++++++++++++++++++++++++ src/joliet.h | 60 +++++++++ 6 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 src/joliet.c create mode 100644 src/joliet.h diff --git a/Makefile.am b/Makefile.am index d9f13da..a2c24e8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,6 +44,8 @@ src_libisofs_la_SOURCES = \ src/rockridge.h \ src/rockridge.c \ src/rockridge_read.c \ + src/joliet.h \ + src/joliet.c \ src/data_source.c libinclude_HEADERS = \ src/libisofs.h diff --git a/src/ecma119.c b/src/ecma119.c index 27e6739..d2997ea 100644 --- a/src/ecma119.c +++ b/src/ecma119.c @@ -26,6 +26,12 @@ #include #include +/* + * TODO image with more than 65535 directories have path_table related problems + * due to 16 bits parent id. Note that this problem only affects to folders + * that are parent of another folder. + */ + static void ecma119_image_free(Ecma119Image *t) { @@ -822,6 +828,7 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts, Ecma119Image **img) target->ino = 0; target->omit_version_numbers = opts->omit_version_numbers; target->allow_deep_paths = opts->allow_deep_paths; + target->joliet_longer_paths = 0; //TODO target->sort_files = opts->sort_files; target->replace_uid = opts->replace_uid ? 1 : 0; diff --git a/src/ecma119.h b/src/ecma119.h index ca7f995..71b79ce 100644 --- a/src/ecma119.h +++ b/src/ecma119.h @@ -36,6 +36,9 @@ struct ecma119_image /* relaxed constraints */ unsigned int omit_version_numbers :1; unsigned int allow_deep_paths :1; + + /** Allow paths on Joliet tree to be larger than 240 bytes */ + unsigned int joliet_longer_paths :1; // int relaxed_constraints; /**< see ecma119_relaxed_constraints_flag */ /* diff --git a/src/ecma119_tree.h b/src/ecma119_tree.h index fc53f92..54a9f3a 100644 --- a/src/ecma119_tree.h +++ b/src/ecma119_tree.h @@ -21,7 +21,7 @@ enum ecma119_node_type { }; /** - * Struct with info about a node representing a tree + * Struct with info about a node representing a directory */ struct ecma119_dir_info { diff --git a/src/joliet.c b/src/joliet.c new file mode 100644 index 0000000..cee3ac6 --- /dev/null +++ b/src/joliet.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2007 Vreixo Formoso + * Copyright (c) 2007 Mario Danic + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See COPYING file for details. + */ + +#include "joliet.h" +#include "messages.h" +#include "writer.h" +#include "error.h" +#include "image.h" +#include "filesrc.h" + +#include + +static +int get_joliet_name(Ecma119Image *t, IsoNode *iso, uint16_t **name) +{ + int ret; + uint16_t *ucs_name; + uint16_t *jname = NULL; + + if (iso->name == NULL) { + /* it is not necessarily an error, it can be the root */ + return ISO_SUCCESS; + } + + ret = str2ucs(t->input_charset, iso->name, &ucs_name); + if (ret < 0) { + iso_msg_debug(t->image->messenger, "Can't convert %s", iso->name); + return ret; + } + + // TODO add support for relaxed constraints + jname = iso_j_id(ucs_name); + free(ucs_name); + if (jname != NULL) { + *name = jname; + return ISO_SUCCESS; + } else { + /* + * only possible if mem error, as check for empty names is done + * in public tree + */ + return ISO_MEM_ERROR; + } +} + +static +void joliet_node_free(JolietNode *node) +{ + if (node == NULL) { + return; + } + if (node->type == JOLIET_DIR) { + int i; + for (i = 0; i < node->info.dir.nchildren; i++) { + joliet_node_free(node->info.dir.children[i]); + } + free(node->info.dir.children); + //free(node->info.dir); + } + iso_node_unref(node->node); + free(node); +} + +/** + * Create a low level Joliet node + * @return + * 1 success, 0 ignored, < 0 error + */ +static +int create_node(Ecma119Image *t, IsoNode *iso, JolietNode **node) +{ + int ret; + JolietNode *joliet; + + joliet = calloc(1, sizeof(JolietNode)); + if (joliet == NULL) { + return ISO_MEM_ERROR; + } + + if (iso->type == LIBISO_DIR) { + IsoDir *dir = (IsoDir*) iso; + joliet->info.dir.children = calloc(sizeof(void*), dir->nchildren); + if (joliet->info.dir.children == NULL) { + free(joliet); + return ISO_MEM_ERROR; + } + joliet->type = JOLIET_DIR; + } else if (iso->type == LIBISO_FILE) { + /* it's a file */ + off_t size; + IsoFileSrc *src; + IsoFile *file = (IsoFile*) iso; + + size = iso_stream_get_size(file->stream); + if (size > (off_t)0xffffffff) { + iso_msg_note(t->image->messenger, LIBISO_FILE_IGNORED, + "File \"%s\" can't be added to image because is " + "greater than 4GB", iso->name); + free(joliet); + return 0; + } + + ret = iso_file_src_create(t, file, &src); + if (ret < 0) { + free(joliet); + return ret; + } + joliet->info.file = src; + joliet->type = JOLIET_FILE; + } else { + /* should never happen */ + //TODO handle boot nodes?!? + free(joliet); + return ISO_ERROR; + } + + /* take a ref to the IsoNode */ + joliet->node = iso; + iso_node_ref(iso); + + return ISO_SUCCESS; +} + +/** + * Create the low level Joliet tree from the high level ISO tree. + * + * @return + * 1 success, 0 file ignored, < 0 error + */ +static +int create_tree(Ecma119Image *t, IsoNode *iso, JolietNode **tree, int pathlen) +{ + int ret, max_path; + JolietNode *node; + uint16_t *jname = NULL; + + if (t == NULL || iso == NULL || tree == NULL) { + return ISO_NULL_POINTER; + } + + if (iso->hidden & LIBISO_HIDE_ON_JOLIET) { + /* file will be ignored */ + return 0; + } + ret = get_joliet_name(t, iso, &jname); + if (ret < 0) { + return ret; + } + max_path = pathlen + 1 + (jname ? ucslen(jname) * 2 : 0); + if (!t->joliet_longer_paths && max_path > 240) { + /* + * Wow!! Joliet is even more restrictive than plain ISO-9660, + * that allows up to 255 bytes!! + */ + iso_msg_note(t->image->messenger, LIBISO_FILE_IGNORED, + "File \"%s\" can't be added to Joliet tree, because " + "its path length is larger than 240", iso->name); + free(jname); + return 0; + } + + switch (iso->type) { + case LIBISO_FILE: + ret = create_node(t, iso, &node); + break; + case LIBISO_DIR: + { + IsoNode *pos; + IsoDir *dir = (IsoDir*)iso; + ret = create_node(t, iso, &node); + if (ret < 0) { + free(jname); + return ret; + } + pos = dir->children; + while (pos) { + int cret; + JolietNode *child; + cret = create_tree(t, pos, &child, max_path); + if (cret < 0) { + /* error */ + joliet_node_free(node); + ret = cret; + break; + } else if (cret == ISO_SUCCESS) { + /* add child to this node */ + int nchildren = node->info.dir.nchildren++; + node->info.dir.children[nchildren] = child; + child->parent = node; + } + pos = pos->next; + } + } + break; + case LIBISO_BOOT: + //TODO + return 0; + break; + case LIBISO_SYMLINK: + case LIBISO_SPECIAL: + iso_msg_note(t->image->messenger, LIBISO_JOLIET_WRONG_FILE_TYPE, + "Can't add %s to Joliet tree. This kind of files can only" + " be added to a Rock Ridget tree. Skipping.", iso->name); + ret = 0; + break; + default: + /* should never happen */ + return ISO_ERROR; + } + if (ret <= 0) { + free(jname); + return ret; + } + node->name = jname; + *tree = node; + return ISO_SUCCESS; +} + +static +int joliet_tree_create(IsoImageWriter *writer) +{ + int ret; + JolietNode *root; + Ecma119Image *t; + + if (writer == NULL || writer->target == NULL) { + return ISO_NULL_POINTER; + } + + t = writer->target; + + ret = create_tree(t, (IsoNode*)t->image->root, &root, 0); + if (ret <= 0) { + if (ret == 0) { + /* unexpected error, root ignored!! This can't happen */ + ret = ISO_ERROR; + } + return ret; + } + + /* the Joliet tree is stored in the writer data field */ + writer->data = root; + + iso_msg_debug(t->image->messenger, "Sorting the Joliet tree..."); + //TODO sort_tree(root); + + iso_msg_debug(t->image->messenger, "Mangling Joliet names..."); + // TODO ret = mangle_tree(writer, 1); + + return ISO_SUCCESS; +} + +static +int joliet_writer_compute_data_blocks(IsoImageWriter *writer) +{ + //TODO + return -1; +} + +static +int joliet_writer_write_vol_desc(IsoImageWriter *writer) +{ + //TODO + return -1; +} + +static +int joliet_writer_write_data(IsoImageWriter *writer) +{ + //TODO + return -1; +} + +static +int joliet_writer_free_data(IsoImageWriter *writer) +{ + /* free the Joliet tree */ + joliet_node_free(writer->data); + return ISO_SUCCESS; +} + +int joliet_writer_create(Ecma119Image *target) +{ + int ret; + IsoImageWriter *writer; + + writer = malloc(sizeof(IsoImageWriter)); + if (writer == NULL) { + return ISO_MEM_ERROR; + } + + writer->compute_data_blocks = joliet_writer_compute_data_blocks; + writer->write_vol_desc = joliet_writer_write_vol_desc; + writer->write_data = joliet_writer_write_data; + writer->free_data = joliet_writer_free_data; + writer->data = NULL; //TODO store joliet tree here + writer->target = target; + + iso_msg_debug(target->image->messenger, + "Creating low level Joliet tree..."); + ret = joliet_tree_create(writer); + if (ret < 0) { + return ret; + } + + /* add this writer to image */ + target->writers[target->nwriters++] = writer; + + /* we need the volume descriptor */ + target->curblock++; + return ISO_SUCCESS; +} diff --git a/src/joliet.h b/src/joliet.h new file mode 100644 index 0000000..26f5940 --- /dev/null +++ b/src/joliet.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2007 Vreixo Formoso + * Copyright (c) 2007 Mario Danic + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See COPYING file for details. + */ + +/** + * Declare Joliet related structures. + */ + +#ifndef LIBISO_JOLIET_H +#define LIBISO_JOLIET_H + +#include "libisofs.h" +#include "ecma119.h" + +typedef struct joliet_node JolietNode; + +enum joliet_node_type { + JOLIET_FILE, + JOLIET_DIR +}; + +struct joliet_dir_info { + JolietNode **children; + size_t nchildren; + size_t len; + size_t block; +}; + +struct joliet_node +{ + uint16_t *name; /**< Name in UCS-2BE. */ + //size_t dirent_len; + + JolietNode *parent; + + IsoNode *node; /*< reference to the iso node */ + + enum joliet_node_type type; + union { + IsoFileSrc *file; + //TODO change with a pointer + struct joliet_dir_info dir; + } info; +}; + +/** + * Create a IsoWriter to deal with Joliet estructures, and add it to the given + * target. + * + * @return + * 1 on success, < 0 on error + */ +int joliet_writer_create(Ecma119Image *target); + +#endif /* LIBISO_JOLIET_H */