diff --git a/.bzrignore b/.bzrignore index 860a9ed..582b34e 100644 --- a/.bzrignore +++ b/.bzrignore @@ -27,3 +27,4 @@ test/test demo/lsl demo/cat demo/tree +demo/ecma119tree diff --git a/Makefile.am b/Makefile.am index c17cb9f..167f68a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,7 +31,10 @@ src_libisofs_la_SOURCES = \ src/util.c \ src/filesrc.h \ src/filesrc.c \ - src/ecma119.h + src/ecma119.h \ + src/ecma119.c \ + src/ecma119_tree.h \ + src/ecma119_tree.c libinclude_HEADERS = \ src/libisofs.h @@ -41,7 +44,8 @@ libinclude_HEADERS = \ noinst_PROGRAMS = \ demo/lsl \ demo/cat \ - demo/tree + demo/tree \ + demo/ecma119tree demo_lsl_CPPFLAGS = -Isrc demo_lsl_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS) @@ -55,6 +59,10 @@ demo_tree_CPPFLAGS = -Isrc demo_tree_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_tree_SOURCES = demo/tree.c +demo_ecma119tree_CPPFLAGS = -Isrc +demo_ecma119tree_LDADD = $(src_libisofs_la_OBJECTS) $(THREAD_LIBS) +demo_ecma119tree_SOURCES = demo/ecma119_tree.c + ## Build unit test diff --git a/demo/ecma119_tree.c b/demo/ecma119_tree.c new file mode 100644 index 0000000..5d1af58 --- /dev/null +++ b/demo/ecma119_tree.c @@ -0,0 +1,111 @@ +/* + * Little program that imports a directory to iso image, generates the + * ecma119 low level tree and prints it. + * Note that this is not an API example, but a little program for test + * purposes. + */ + +#include "libisofs.h" +#include "ecma119.h" +#include "ecma119_tree.h" +#include +#include +#include +#include +#include + +static void +print_permissions(mode_t mode) +{ + char perm[10]; + + //TODO suid, sticky... + + perm[9] = '\0'; + perm[8] = mode & S_IXOTH ? 'x' : '-'; + perm[7] = mode & S_IWOTH ? 'w' : '-'; + perm[6] = mode & S_IROTH ? 'r' : '-'; + perm[5] = mode & S_IXGRP ? 'x' : '-'; + perm[4] = mode & S_IWGRP ? 'w' : '-'; + perm[3] = mode & S_IRGRP ? 'r' : '-'; + perm[2] = mode & S_IXUSR ? 'x' : '-'; + perm[1] = mode & S_IWUSR ? 'w' : '-'; + perm[0] = mode & S_IRUSR ? 'r' : '-'; + printf("[%s]",perm); +} + +static void +print_dir(Ecma119Node *dir, int level) +{ + int i; + char sp[level * 2 + 1]; + + for (i = 0; i < level * 2; i += 2) { + sp[i] = '|'; + sp[i+1] = ' '; + } + + sp[level * 2-1] = '-'; + sp[level * 2] = '\0'; + + for (i = 0; i < dir->info.dir.nchildren; i++) { + Ecma119Node *child = dir->info.dir.children[i]; + + if (child->type == ECMA119_DIR) { + printf("%s+[D] ", sp); + print_permissions(iso_node_get_permissions(child->node)); + printf(" %s\n", child->iso_name); + print_dir(child, level+1); + } else if (child->type == ECMA119_FILE) { + printf("%s-[F] ", sp); + print_permissions(iso_node_get_permissions(child->node)); + printf(" %s {%p}\n", child->iso_name, (void*)child->info.file); + } else { + printf("%s-[????] ", sp); + } + } +} + +int main(int argc, char **argv) +{ + int result; + IsoImage *image; + Ecma119Image *ecma119; + Ecma119Node *tree; + + if (argc != 2) { + printf ("You need to specify a valid path\n"); + return 1; + } + + result = iso_image_new("volume_id", &image); + if (result < 0) { + printf ("Error creating image\n"); + return 1; + } + iso_image_set_msgs_severities(image, "NEVER", "ALL", ""); + + result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[1]); + if (result < 0) { + printf ("Error adding directory %d\n", result); + return 1; + } + + ecma119 = calloc(1, sizeof(Ecma119Image)); + ecma119->iso_level = 1; + + /* create low level tree */ + result = ecma119_tree_create(ecma119, (IsoNode*)iso_image_get_root(image), &tree); + if (result < 0) { + printf ("Error creating ecma-119 tree: %d\n", result); + return 1; + } + + printf("================= ECMA-119 TREE =================\n"); + print_dir(tree, 0); + printf("\n\n"); + + ecma119_node_free(tree); + iso_image_unref(image); + return 0; +} diff --git a/demo/lsl.c b/demo/lsl.c index ee59c5a..6dae4c1 100644 --- a/demo/lsl.c +++ b/demo/lsl.c @@ -59,6 +59,7 @@ print_file_src(IsoFileSource *file) file->lstat(file, &info); print_type(info.st_mode); print_permissions(info.st_mode); + printf(" {%ld,%ld} ", (long)info.st_dev, (long)info.st_ino); name = file->get_name(file); printf(" %s", name); free(name); diff --git a/demo/tree.c b/demo/tree.c index 1d4f837..154a6df 100644 --- a/demo/tree.c +++ b/demo/tree.c @@ -1,6 +1,5 @@ /* - * Little program that reads an existing ISO image and prints its - * contents to stdout. + * Little program that import a directory and prints the resulting iso tree. */ #include "libisofs.h" diff --git a/src/ecma119.c b/src/ecma119.c new file mode 100644 index 0000000..85476de --- /dev/null +++ b/src/ecma119.c @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2007 Vreixo Formoso + * + * 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 "ecma119.h" diff --git a/src/ecma119.h b/src/ecma119.h index 8b3f10a..826b95f 100644 --- a/src/ecma119.h +++ b/src/ecma119.h @@ -10,9 +10,11 @@ #define LIBISO_ECMA119_H_ typedef struct ecma119_image Ecma119Image; +typedef struct ecma119_node Ecma119Node; typedef struct Iso_File_Src IsoFileSrc; struct ecma119_image { + Ecma119Node *root; unsigned int iso_level:2; diff --git a/src/ecma119_tree.c b/src/ecma119_tree.c new file mode 100644 index 0000000..dd8b4de --- /dev/null +++ b/src/ecma119_tree.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2007 Vreixo Formoso + * + * 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 "ecma119_tree.h" +#include "ecma119.h" +#include "error.h" +#include "node.h" +#include "util.h" +#include "filesrc.h" + +#include +#include + +static +int set_iso_name(Ecma119Image *img, IsoNode *iso, Ecma119Node *node) +{ + int ret; + char *ascii_name; + + if (iso->name == NULL) { + /* it is not necessarily an error, it can be the root */ + return ISO_SUCCESS; + } + + // TODO add support for other input charset + ret = str2ascii("UTF-8", iso->name, &ascii_name); + if (ret < 0) { + return ret; + } + + // TODO add support for relaxed constraints + if (iso->type == LIBISO_DIR) { + if (img->iso_level == 1) { + iso_dirid(ascii_name, 8); + } else { + iso_dirid(ascii_name, 31); + } + } else { + if (img->iso_level == 1) { + iso_1_fileid(ascii_name); + } else { + iso_2_fileid(ascii_name); + } + } + node->iso_name = ascii_name; + return ISO_SUCCESS; +} + +static +int create_ecma119_node(Ecma119Image *img, IsoNode *iso, Ecma119Node **node) +{ + int ret; + Ecma119Node *ecma; + + ecma = calloc(1, sizeof(Ecma119Node)); + if (ecma == NULL) { + return ISO_MEM_ERROR; + } + + ret = set_iso_name(img, iso, ecma); + if (ret < 0) { + free(ecma); + return ret; + } + + /* take a ref to the IsoNode */ + ecma->node = iso; + iso_node_ref(iso); + + // TODO what to do with full name? For now, not a problem, as we + // haven't support for charset conversion. However, one we had it, + // we need to choose whether to do it here (consumes more memory) + // or on writting + *node = ecma; + return ISO_SUCCESS; +} + +/** + * Create a new ECMA-119 node representing a directory from a iso directory + * node. + */ +static +int create_dir(Ecma119Image *img, IsoDir *iso, Ecma119Node **node) +{ + int ret; + Ecma119Node **children; + + children = calloc(1, sizeof(void*) * iso->nchildren); + if (children == NULL) { + return ISO_MEM_ERROR; + } + + ret = create_ecma119_node(img, (IsoNode*)iso, node); + if (ret < 0) { + free(children); + return ret; + } + (*node)->type = ECMA119_DIR; + (*node)->info.dir.nchildren = 0; + (*node)->info.dir.children = children; + return ISO_SUCCESS; +} + +/** + * Create a new ECMA-119 node representing a regular file from a iso file + * node. + */ +static +int create_file(Ecma119Image *img, IsoFile *iso, Ecma119Node **node) +{ + int ret; + IsoFileSrc *src; + + ret = iso_file_src_create(img, iso, &src); + if (ret < 0) { + return ret; + } + + ret = create_ecma119_node(img, (IsoNode*)iso, node); + if (ret < 0) { + /* + * the src doesn't need to be freed, it is free together with + * the Ecma119Image + */ + return ret; + } + (*node)->type = ECMA119_FILE; + (*node)->info.file = src; + + return ret; +} + +void ecma119_node_free(Ecma119Node *node) +{ + if (node->type == ECMA119_DIR) { + int i; + for (i = 0; i < node->info.dir.nchildren; i++) { + ecma119_node_free(node->info.dir.children[i]); + } + free(node->info.dir.children); + } + free(node->iso_name); + iso_node_unref(node->node); + //TODO? free(node->name); + free(node); +} + +/** + * + * @return + * 1 success, 0 node ignored, < 0 error + * + */ +static +int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree) +{ + int ret; + Ecma119Node *node; + + if (image == NULL || iso == NULL || tree == NULL) { + return ISO_NULL_POINTER; + } + + if (iso->hidden & LIBISO_HIDE_ON_RR) { + /* file will be ignored */ + return 0; + } + + switch(iso->type) { + case LIBISO_FILE: + ret = create_file(image, (IsoFile*)iso, &node); + break; + case LIBISO_SYMLINK: + //TODO only supported with RR + return 0; + break; + case LIBISO_SPECIAL: + //TODO only supported with RR + return 0; + break; + case LIBISO_BOOT: + //TODO + return 0; + break; + case LIBISO_DIR: + { + IsoNode *pos; + IsoDir *dir = (IsoDir*)iso; + ret = create_dir(image, dir, &node); + if (ret < 0) { + return ret; + } + pos = dir->children; + while (pos) { + Ecma119Node *child; + ret = create_tree(image, pos, &child); + if (ret < 0) { + /* error */ + ecma119_node_free(node); + return ret; + } else if (ret == 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; + default: + /* should never happen */ + return ISO_ERROR; + } + if (ret < 0) { + return ret; + } + *tree = node; + return ISO_SUCCESS; +} + +int ecma119_tree_create(Ecma119Image *img, IsoNode *iso, Ecma119Node **tree) +{ + int ret; + ret = create_tree(img, iso, tree); + if (ret < 0) { + return ret; + } + + /* + * TODO + * - take care about dirs whose level is over 8 + * - sort files in dir + * - mangle names + */ + + return ISO_SUCCESS; +} diff --git a/src/ecma119_tree.h b/src/ecma119_tree.h new file mode 100644 index 0000000..4230e29 --- /dev/null +++ b/src/ecma119_tree.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2007 Vreixo Formoso + * + * 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. + */ + +#ifndef LIBISO_ECMA119_TREE_H_ +#define LIBISO_ECMA119_TREE_H_ + +#include "libisofs.h" +#include "ecma119.h" + +enum ecma119_node_type { + ECMA119_FILE, + ECMA119_DIR +}; + +/** + * Struct with info about a node representing a tree + */ +struct ecma119_dir_info { + /* Block where the directory entries will be written on image */ + size_t block; + + size_t nchildren; + Ecma119Node **children; +}; + +/** + * A node for a tree containing all the information necessary for writing + * an ISO9660 volume. + */ +struct ecma119_node +{ + /** + * Name in ASCII, conforming to selected ISO level. + * Version number is not include, it is added on the fly + */ + char *iso_name; + + // TODO mmm, is this needed? + // or should we compute charset translation on-the-fly? + //char *name; /**< full name, in output charset (UTF-8 for now) */ + + Ecma119Node *parent; + + IsoNode *node; /*< reference to the iso node */ + + enum ecma119_node_type type; /**< file, symlink, directory or placeholder */ + union { + IsoFileSrc *file; + struct ecma119_dir_info dir; + } info; +}; + +/** + * + */ +int ecma119_tree_create(Ecma119Image *img, IsoNode *iso, Ecma119Node **tree); + +/** + * Free an Ecma119Node, and its children if node is a dir + */ +void ecma119_node_free(Ecma119Node *node); + +#endif /*LIBISO_ECMA119_TREE_H_*/