"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libisofs/tree.c" (30 Jan 2021, 47717 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tree.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    1 /*
    2  * Copyright (c) 2007 Vreixo Formoso
    3  * Copyright (c) 2011 - 2015 Thomas Schmitt
    4  * 
    5  * This file is part of the libisofs project; you can redistribute it and/or 
    6  * modify it under the terms of the GNU General Public License version 2 
    7  * or later as published by the Free Software Foundation. 
    8  * See COPYING file for details.
    9  */
   10 
   11 /*
   12  * Functions that act on the iso tree.
   13  */
   14 
   15 #ifdef HAVE_CONFIG_H
   16 #include "../config.h"
   17 #endif
   18 
   19 #include "libisofs.h"
   20 #include "node.h"
   21 #include "image.h"
   22 #include "fsource.h"
   23 #include "builder.h"
   24 #include "messages.h"
   25 #include "tree.h"
   26 #include "util.h"
   27 
   28 #include <stdlib.h>
   29 #include <string.h>
   30 #include <time.h>
   31 #include <limits.h>
   32 #include <stdio.h>
   33 #include <fnmatch.h>
   34 
   35 
   36 /**
   37  * Add a new directory to the iso tree.
   38  * 
   39  * @param parent 
   40  *      the dir where the new directory will be created
   41  * @param name
   42  *      name for the new dir. If a node with same name already exists on
   43  *      parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
   44  * @param dir
   45  *      place where to store a pointer to the newly created dir. No extra
   46  *      ref is added, so you will need to call iso_node_ref() if you really
   47  *      need it. You can pass NULL in this parameter if you don't need the
   48  *      pointer.
   49  * @return
   50  *     number of nodes in dir if success, < 0 otherwise
   51  *     Possible errors:
   52  *         ISO_NULL_POINTER, if parent or name are NULL
   53  *         ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
   54  */
   55 int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir)
   56 {
   57     int ret;
   58     char *n;
   59     IsoDir *node;
   60     IsoNode **pos;
   61     time_t now;
   62 
   63     if (parent == NULL || name == NULL) {
   64         return ISO_NULL_POINTER;
   65     }
   66     if (dir) {
   67         *dir = NULL;
   68     }
   69 
   70     /* find place where to insert and check if it exists */
   71     if (iso_dir_exists(parent, name, &pos)) {
   72         /* a node with same name already exists */
   73         return ISO_NODE_NAME_NOT_UNIQUE;
   74     }
   75 
   76     n = strdup(name);
   77     ret = iso_node_new_dir(n, &node);
   78     if (ret < 0) {
   79         free(n);
   80         return ret;
   81     }
   82 
   83     /* permissions from parent */
   84     iso_node_set_permissions((IsoNode*)node, parent->node.mode);
   85     iso_node_set_uid((IsoNode*)node, parent->node.uid);
   86     iso_node_set_gid((IsoNode*)node, parent->node.gid);
   87     iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
   88 
   89     /* current time */
   90     iso_nowtime(&now, 0);
   91     iso_node_set_atime((IsoNode*)node, now);
   92     iso_node_set_ctime((IsoNode*)node, now);
   93     iso_node_set_mtime((IsoNode*)node, now);
   94 
   95     if (dir) {
   96         *dir = node;
   97     }
   98 
   99     /* add to dir */
  100     return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
  101 }
  102 
  103 int iso_image_add_new_dir(IsoImage *image, IsoDir *parent, const char *name,
  104                           IsoDir **dir)
  105 {
  106     int ret;
  107     char *namept;
  108 
  109     ret = iso_image_truncate_name(image, name, &namept, 0);
  110     if (ret < 0)
  111         return ret;
  112     ret = iso_tree_add_new_dir(parent, namept, dir);
  113     return ret;
  114 }
  115 
  116 /**
  117  * Add a new symlink to the directory tree. Permissions are set to 0777, 
  118  * owner and hidden atts are taken from parent. You can modify any of them 
  119  * later.
  120  *  
  121  * @param parent 
  122  *      the dir where the new symlink will be created
  123  * @param name
  124  *      name for the new dir. If a node with same name already exists on
  125  *      parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
  126  * @param dest
  127  *      destination of the link
  128  * @param link
  129  *      place where to store a pointer to the newly created link. No extra
  130  *      ref is added, so you will need to call iso_node_ref() if you really
  131  *      need it. You can pass NULL in this parameter if you don't need the
  132  *      pointer
  133  * @return
  134  *     number of nodes in parent if success, < 0 otherwise
  135  *     Possible errors:
  136  *         ISO_NULL_POINTER, if parent, name or dest are NULL
  137  *         ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
  138  *         ISO_OUT_OF_MEM
  139  */
  140 int iso_tree_add_new_symlink(IsoDir *parent, const char *name,
  141                              const char *dest, IsoSymlink **link)
  142 {
  143     int ret;
  144     char *n, *d;
  145     IsoSymlink *node;
  146     IsoNode **pos;
  147     time_t now;
  148 
  149     if (parent == NULL || name == NULL || dest == NULL) {
  150         return ISO_NULL_POINTER;
  151     }
  152     if (link) {
  153         *link = NULL;
  154     }
  155 
  156     /* find place where to insert */
  157     if (iso_dir_exists(parent, name, &pos)) {
  158         /* a node with same name already exists */
  159         return ISO_NODE_NAME_NOT_UNIQUE;
  160     }
  161 
  162     n = strdup(name);
  163     d = strdup(dest);
  164     ret = iso_node_new_symlink(n, d, &node);
  165     if (ret < 0) {
  166         free(n);
  167         free(d);
  168         return ret;
  169     }
  170 
  171     /* permissions from parent */
  172     iso_node_set_permissions((IsoNode*)node, 0777);
  173     iso_node_set_uid((IsoNode*)node, parent->node.uid);
  174     iso_node_set_gid((IsoNode*)node, parent->node.gid);
  175     iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
  176 
  177     /* current time */
  178     iso_nowtime(&now, 0);
  179     iso_node_set_atime((IsoNode*)node, now);
  180     iso_node_set_ctime((IsoNode*)node, now);
  181     iso_node_set_mtime((IsoNode*)node, now);
  182 
  183     if (link) {
  184         *link = node;
  185     }
  186 
  187     /* add to dir */
  188     return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
  189 }
  190 
  191 int iso_image_add_new_symlink(IsoImage *image, IsoDir *parent,
  192                               const char *name, const char *dest,
  193                               IsoSymlink **link)
  194 {
  195     int ret;
  196     char *namept;
  197 
  198     ret = iso_image_truncate_name(image, name, &namept, 0);
  199     if (ret < 0)
  200         return ret;
  201     ret = iso_tree_add_new_symlink(parent, namept, dest, link);
  202     return ret;
  203 }
  204 
  205 /**
  206  * Add a new special file to the directory tree. As far as libisofs concerns,
  207  * an special file is a block device, a character device, a FIFO (named pipe)
  208  * or a socket. You can choose the specific kind of file you want to add
  209  * by setting mode properly (see man 2 stat).
  210  * 
  211  * Note that special files are only written to image when Rock Ridge 
  212  * extensions are enabled. Moreover, a special file is just a directory entry
  213  * in the image tree, no data is written beyond that.
  214  * 
  215  * Owner and hidden atts are taken from parent. You can modify any of them 
  216  * later.
  217  * 
  218  * @param parent
  219  *      the dir where the new special file will be created
  220  * @param name
  221  *      name for the new special file. If a node with same name already exists 
  222  *      on parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
  223  * @param mode
  224  *      file type and permissions for the new node. Note that you can't
  225  *      specify any kind of file here, only special types are allowed. i.e,
  226  *      S_IFSOCK, S_IFBLK, S_IFCHR and S_IFIFO are valid types; S_IFLNK, 
  227  *      S_IFREG and S_IFDIR aren't.
  228  * @param dev
  229  *      device ID, equivalent to the st_rdev field in man 2 stat.
  230  * @param special
  231  *      place where to store a pointer to the newly created special file. No 
  232  *      extra ref is added, so you will need to call iso_node_ref() if you 
  233  *      really need it. You can pass NULL in this parameter if you don't need 
  234  *      the pointer.
  235  * @return
  236  *     number of nodes in parent if success, < 0 otherwise
  237  *     Possible errors:
  238  *         ISO_NULL_POINTER, if parent, name or dest are NULL
  239  *         ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
  240  *         ISO_OUT_OF_MEM
  241  * 
  242  */
  243 int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode,
  244                              dev_t dev, IsoSpecial **special)
  245 {
  246     int ret;
  247     char *n;
  248     IsoSpecial *node;
  249     IsoNode **pos;
  250     time_t now;
  251 
  252     if (parent == NULL || name == NULL) {
  253         return ISO_NULL_POINTER;
  254     }
  255     if (S_ISLNK(mode) || S_ISREG(mode) || S_ISDIR(mode)) {
  256         return ISO_WRONG_ARG_VALUE;
  257     }
  258     if (special) {
  259         *special = NULL;
  260     }
  261 
  262     /* find place where to insert */
  263     if (iso_dir_exists(parent, name, &pos)) {
  264         /* a node with same name already exists */
  265         return ISO_NODE_NAME_NOT_UNIQUE;
  266     }
  267 
  268     n = strdup(name);
  269     ret = iso_node_new_special(n, mode, dev, &node);
  270     if (ret < 0) {
  271         free(n);
  272         return ret;
  273     }
  274 
  275     /* atts from parent */
  276     iso_node_set_uid((IsoNode*)node, parent->node.uid);
  277     iso_node_set_gid((IsoNode*)node, parent->node.gid);
  278     iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
  279 
  280     /* current time */
  281     iso_nowtime(&now, 0);
  282     iso_node_set_atime((IsoNode*)node, now);
  283     iso_node_set_ctime((IsoNode*)node, now);
  284     iso_node_set_mtime((IsoNode*)node, now);
  285 
  286     if (special) {
  287         *special = node;
  288     }
  289 
  290     /* add to dir */
  291     return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
  292 }
  293 
  294 int iso_image_add_new_special(IsoImage *image, IsoDir *parent,
  295                               const char *name, mode_t mode,
  296                               dev_t dev, IsoSpecial **special)
  297 {
  298     int ret;
  299     char *namept;
  300 
  301     ret = iso_image_truncate_name(image, name, &namept, 0);
  302     if (ret < 0)
  303         return ret;
  304     ret = iso_tree_add_new_special(parent, namept, mode, dev, special);
  305     return ret;
  306 }
  307 
  308 /**
  309  * Add a new regular file to the iso tree. Permissions are set to 0444, 
  310  * owner and hidden atts are taken from parent. You can modify any of them 
  311  * later.
  312  *  
  313  * @param parent 
  314  *      the dir where the new file will be created
  315  * @param name
  316  *      name for the new file. If a node with same name already exists on
  317  *      parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE.
  318  * @param stream
  319  *      IsoStream for the contents of the file
  320  * @param file
  321  *      place where to store a pointer to the newly created file. No extra
  322  *      ref is added, so you will need to call iso_node_ref() if you really
  323  *      need it. You can pass NULL in this parameter if you don't need the
  324  *      pointer
  325  * @return
  326  *     number of nodes in parent if success, < 0 otherwise
  327  *     Possible errors:
  328  *         ISO_NULL_POINTER, if parent, name or dest are NULL
  329  *         ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists
  330  *         ISO_OUT_OF_MEM
  331  * 
  332  * @since 0.6.4
  333  */
  334 int iso_tree_add_new_file(IsoDir *parent, const char *name, IsoStream *stream, 
  335                           IsoFile **file)
  336 {
  337     int ret;
  338     char *n;
  339     IsoFile *node;
  340     IsoNode **pos;
  341     time_t now;
  342 
  343     if (parent == NULL || name == NULL || stream == NULL) {
  344         return ISO_NULL_POINTER;
  345     }
  346     if (file) {
  347         *file = NULL;
  348     }
  349 
  350     /* find place where to insert */
  351     if (iso_dir_exists(parent, name, &pos)) {
  352         /* a node with same name already exists */
  353         return ISO_NODE_NAME_NOT_UNIQUE;
  354     }
  355 
  356     n = strdup(name);
  357     ret = iso_node_new_file(n, stream, &node);
  358     if (ret < 0) {
  359         free(n);
  360         return ret;
  361     }
  362 
  363     /* permissions from parent */
  364     iso_node_set_permissions((IsoNode*)node, 0444);
  365     iso_node_set_uid((IsoNode*)node, parent->node.uid);
  366     iso_node_set_gid((IsoNode*)node, parent->node.gid);
  367     iso_node_set_hidden((IsoNode*)node, parent->node.hidden);
  368 
  369     /* current time */
  370     iso_nowtime(&now, 0);
  371     iso_node_set_atime((IsoNode*)node, now);
  372     iso_node_set_ctime((IsoNode*)node, now);
  373     iso_node_set_mtime((IsoNode*)node, now);
  374 
  375     if (file) {
  376         *file = node;
  377     }
  378 
  379     /* add to dir */
  380     return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER);
  381 }
  382 
  383 int iso_image_add_new_file(IsoImage *image, IsoDir *parent, const char *name,
  384                            IsoStream *stream, IsoFile **file)
  385 {
  386     int ret;
  387     char *namept;
  388 
  389     ret = iso_image_truncate_name(image, name, &namept, 0);
  390     if (ret < 0)
  391         return ret;
  392     ret = iso_tree_add_new_file(parent, namept, stream, file);
  393     return ret;
  394 }
  395 
  396 /**
  397  * Set whether to follow or not symbolic links when added a file from a source
  398  * to IsoImage.
  399  */
  400 void iso_tree_set_follow_symlinks(IsoImage *image, int follow)
  401 {
  402     image->follow_symlinks = follow ? 1 : 0;
  403 }
  404 
  405 /**
  406  * Get current setting for follow_symlinks.
  407  * 
  408  * @see iso_tree_set_follow_symlinks
  409  */
  410 int iso_tree_get_follow_symlinks(IsoImage *image)
  411 {
  412     return image->follow_symlinks;
  413 }
  414 
  415 /**
  416  * Set whether to skip or not hidden files when adding a directory recursibely.
  417  * Default behavior is to not ignore them, i.e., to add hidden files to image.
  418  */
  419 void iso_tree_set_ignore_hidden(IsoImage *image, int skip)
  420 {
  421     image->ignore_hidden = skip ? 1 : 0;
  422 }
  423 
  424 /**
  425  * Get current setting for ignore_hidden.
  426  * 
  427  * @see iso_tree_set_ignore_hidden
  428  */
  429 int iso_tree_get_ignore_hidden(IsoImage *image)
  430 {
  431     return image->ignore_hidden;
  432 }
  433 
  434 void iso_tree_set_replace_mode(IsoImage *image, enum iso_replace_mode mode)
  435 {
  436     image->replace = mode;
  437 }
  438 
  439 enum iso_replace_mode iso_tree_get_replace_mode(IsoImage *image)
  440 {
  441     return image->replace;
  442 }
  443 
  444 /**
  445  * Set whether to skip or not special files. Default behavior is to not skip
  446  * them. Note that, despite of this setting, special files won't never be added
  447  * to an image unless RR extensions were enabled.
  448  * 
  449  * @param skip 
  450  *      Bitmask to determine what kind of special files will be skipped:
  451  *          bit0: ignore FIFOs
  452  *          bit1: ignore Sockets
  453  *          bit2: ignore char devices
  454  *          bit3: ignore block devices
  455  */
  456 void iso_tree_set_ignore_special(IsoImage *image, int skip)
  457 {
  458     image->ignore_special = skip & 0x0F;
  459 }
  460 
  461 /**
  462  * Get current setting for ignore_special.
  463  * 
  464  * @see iso_tree_set_ignore_special
  465  */
  466 int iso_tree_get_ignore_special(IsoImage *image)
  467 {
  468     return image->ignore_special;
  469 }
  470 
  471 /**
  472  * Set a callback function that libisofs will call for each file that is
  473  * added to the given image by a recursive addition function. This includes
  474  * image import.
  475  *  
  476  * @param report
  477  *      pointer to a function that will be called just before a file will be 
  478  *      added to the image. You can control whether the file will be in fact 
  479  *      added or ignored.
  480  *      This function should return 1 to add the file, 0 to ignore it and 
  481  *      continue, < 0 to abort the process
  482  *      NULL is allowed if you don't want any callback.
  483  */
  484 void iso_tree_set_report_callback(IsoImage *image, 
  485                                   int (*report)(IsoImage*, IsoFileSource*))
  486 {
  487     image->report = report;
  488 }
  489 
  490 /**
  491  * Add a excluded path. These are paths that won't never added to image,
  492  * and will be excluded even when adding recursively its parent directory.
  493  * 
  494  * For example, in
  495  * 
  496  * iso_tree_add_exclude(image, "/home/user/data/private");
  497  * iso_tree_add_dir_rec(image, root, "/home/user/data");
  498  * 
  499  * the directory /home/user/data/private won't be added to image.
  500  * 
  501  * @return
  502  *      1 on success, < 0 on error
  503  */
  504 int iso_tree_add_exclude(IsoImage *image, const char *path)
  505 {
  506     if (image == NULL || path == NULL) {
  507         return ISO_NULL_POINTER;
  508     }
  509     image->excludes = realloc(image->excludes, ++image->nexcludes * 
  510                               sizeof(void*));
  511     if (image->excludes == NULL) {
  512         return ISO_OUT_OF_MEM;
  513     }
  514     image->excludes[image->nexcludes - 1] = strdup(path);
  515     if (image->excludes[image->nexcludes - 1] == NULL) {
  516         return ISO_OUT_OF_MEM;
  517     }
  518     return ISO_SUCCESS;
  519 }
  520 
  521 /**
  522  * Remove a previously added exclude.
  523  * 
  524  * @see iso_tree_add_exclude
  525  * @return
  526  *      1 on success, 0 exclude do not exists, < 0 on error
  527  */
  528 int iso_tree_remove_exclude(IsoImage *image, const char *path)
  529 {
  530     size_t i, j;
  531 
  532     if (image == NULL || path == NULL) {
  533         return ISO_NULL_POINTER;
  534     }
  535 
  536     for (i = 0; (int) i < image->nexcludes; ++i) {
  537         if (strcmp(image->excludes[i], path) == 0) {
  538             /* exclude found */
  539             free(image->excludes[i]);
  540             --image->nexcludes;
  541             for (j = i; (int) j < image->nexcludes; ++j) {
  542                 image->excludes[j] = image->excludes[j+1]; 
  543             }
  544             image->excludes = realloc(image->excludes, image->nexcludes * 
  545                                       sizeof(void*));
  546             return ISO_SUCCESS;
  547         }
  548     }
  549     return 0;
  550 }
  551 
  552 static
  553 int iso_tree_add_node_builder(IsoImage *image, IsoDir *parent,
  554                               IsoFileSource *src, IsoNodeBuilder *builder,
  555                               IsoNode **node)
  556 {
  557     int result;
  558     IsoNode *new;
  559     IsoNode **pos;
  560     char *name = NULL, *namept;
  561 
  562     if (parent == NULL || src == NULL || builder == NULL) {
  563         result = ISO_NULL_POINTER; goto ex;
  564     }
  565     if (node) {
  566         *node = NULL;
  567     }
  568 
  569     name = iso_file_source_get_name(src);
  570 
  571     result = iso_image_truncate_name(image, name, &namept, 0);
  572     if (result < 0)
  573         return result;
  574 
  575     /* find place where to insert */
  576     result = iso_dir_exists(parent, namept, &pos);
  577     if (result) {
  578         /* a node with same name already exists */
  579         result = ISO_NODE_NAME_NOT_UNIQUE; goto ex;
  580     }
  581 
  582     result = builder->create_node(builder, image, src, namept, &new);
  583     if (result < 0)
  584         goto ex;
  585 
  586     if (node) {
  587         *node = new;
  588     }
  589 
  590     /* finally, add node to parent */
  591     result = iso_dir_insert(parent, (IsoNode*)new, pos, ISO_REPLACE_NEVER);
  592 ex:
  593     if (name != NULL)
  594         free(name);
  595     return result;
  596 }
  597 
  598 int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path,
  599                       IsoNode **node)
  600 {
  601     int result;
  602     IsoFilesystem *fs;
  603     IsoFileSource *file;
  604 
  605     if (image == NULL || parent == NULL || path == NULL) {
  606         return ISO_NULL_POINTER;
  607     }
  608 
  609     fs = image->fs;
  610     result = fs->get_by_path(fs, path, &file);
  611     if (result < 0) {
  612         return result;
  613     }
  614     result = iso_tree_add_node_builder(image, parent, file, image->builder,
  615                                        node);
  616     /* free the file */
  617     iso_file_source_unref(file);
  618     return result;
  619 }
  620 
  621 int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, 
  622                           const char *path, IsoNode **node)
  623 {
  624     int result;
  625     IsoFilesystem *fs;
  626     IsoFileSource *file;
  627     IsoNode *new;
  628     IsoNode **pos;
  629     char *namept;
  630 
  631     if (image == NULL || parent == NULL || name == NULL || path == NULL) {
  632         return ISO_NULL_POINTER;
  633     }
  634 
  635     if (node) {
  636         *node = NULL;
  637     }
  638 
  639     result = iso_image_truncate_name(image, name, &namept, 0);
  640     if (result < 0)
  641         return result;
  642 
  643     /* find place where to insert */
  644     result = iso_dir_exists(parent, namept, &pos);
  645     if (result) {
  646         /* a node with same name already exists */
  647         return ISO_NODE_NAME_NOT_UNIQUE;
  648     }
  649 
  650     fs = image->fs;
  651     result = fs->get_by_path(fs, path, &file);
  652     if (result < 0) {
  653         return result;
  654     }
  655 
  656     result = image->builder->create_node(image->builder, image, file,
  657                                          namept, &new);
  658     
  659     /* free the file */
  660     iso_file_source_unref(file);
  661     
  662     if (result < 0) {
  663         return result;
  664     }
  665     
  666     if (node) {
  667         *node = new;
  668     }
  669 
  670     /* finally, add node to parent */
  671     return iso_dir_insert(parent, new, pos, ISO_REPLACE_NEVER);
  672 }
  673 
  674 int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, 
  675                                   const char *name, const char *path, 
  676                                   off_t offset, off_t size,
  677                                   IsoNode **node)
  678 {
  679     int result;
  680     struct stat info;
  681     IsoFilesystem *fs;
  682     IsoFileSource *src;
  683     IsoFile *new;
  684     IsoNode **pos;
  685     IsoStream *stream;
  686     char *namept;
  687 
  688     if (image == NULL || parent == NULL || name == NULL || path == NULL) {
  689         return ISO_NULL_POINTER;
  690     }
  691 
  692     if (node) {
  693         *node = NULL;
  694     }
  695 
  696     result = iso_image_truncate_name(image, name, &namept, 0);
  697     if (result < 0)
  698         return result;
  699 
  700     /* find place where to insert */
  701     result = iso_dir_exists(parent, namept, &pos);
  702     if (result) {
  703         /* a node with same name already exists */
  704         return ISO_NODE_NAME_NOT_UNIQUE;
  705     }
  706 
  707     fs = image->fs;
  708     result = fs->get_by_path(fs, path, &src);
  709     if (result < 0) {
  710         return result;
  711     }
  712 
  713     result = iso_file_source_stat(src, &info);
  714     if (result < 0) {
  715         iso_file_source_unref(src);
  716         return result;
  717     }
  718     if (!S_ISREG(info.st_mode)) {
  719         return ISO_WRONG_ARG_VALUE;
  720     }
  721     if (offset >= info.st_size) {
  722         return ISO_WRONG_ARG_VALUE;
  723     }
  724 
  725     /* force regular file */
  726     result = image->builder->create_file(image->builder, image, src, &new);
  727     
  728     /* free the file */
  729     iso_file_source_unref(src);
  730     
  731     if (result < 0) {
  732         return result;
  733     }
  734     
  735     /* replace file iso stream with a cut-out-stream */
  736     result = iso_cut_out_stream_new(src, offset, size, &stream);
  737     if (result < 0) {
  738         iso_node_unref((IsoNode*)new);
  739         return result;
  740     }
  741     iso_stream_unref(new->stream);
  742     new->stream = stream;
  743     
  744     result = iso_node_set_name((IsoNode*)new, namept);
  745     if (result < 0) {
  746         iso_node_unref((IsoNode*)new);
  747         return result;
  748     }
  749 
  750     if (node) {
  751         *node = (IsoNode*)new;
  752     }
  753 
  754     /* finally, add node to parent */
  755     return iso_dir_insert(parent, (IsoNode*)new, pos, ISO_REPLACE_NEVER);
  756 }
  757 
  758 static
  759 int check_excludes(IsoImage *image, const char *path)
  760 {
  761     int i;
  762 
  763     for (i = 0; i < image->nexcludes; ++i) {
  764         char *exclude = image->excludes[i];
  765         if (exclude[0] == '/') {
  766             /* absolute exclude, must completely match path */
  767             if (!fnmatch(exclude, path, FNM_PERIOD|FNM_PATHNAME)) {
  768                 return 1;
  769             }
  770         } else {
  771             /* relative exclude, it is enough if a part of the path matches */
  772             char *pos = (char*)path;
  773             while (pos != NULL) {
  774                 pos++;
  775                 if (!fnmatch(exclude, pos, FNM_PERIOD|FNM_PATHNAME)) {
  776                     return 1;
  777                 }
  778                 pos = strchr(pos, '/');
  779             }
  780         }
  781     }
  782     return 0;
  783 }
  784 
  785 static
  786 int check_hidden(IsoImage *image, const char *name)
  787 {
  788     return (image->ignore_hidden && name[0] == '.');
  789 }
  790 
  791 static
  792 int check_special(IsoImage *image, mode_t mode)
  793 {
  794     if (image->ignore_special != 0) {
  795         switch(mode &  S_IFMT) {
  796         case S_IFBLK:
  797             return image->ignore_special & 0x08 ? 1 : 0;
  798         case S_IFCHR:
  799             return image->ignore_special & 0x04 ? 1 : 0;
  800         case S_IFSOCK:
  801             return image->ignore_special & 0x02 ? 1 : 0;
  802         case S_IFIFO:
  803             return image->ignore_special & 0x01 ? 1 : 0;
  804         default:
  805             return 0;
  806         }
  807     }
  808     return 0;
  809 }
  810 
  811 
  812 static
  813 void ascii_increment(char *name, int len, int pos, int rollover_carry)
  814 {
  815      int c;
  816 
  817 again:;
  818      if (pos < 0 || pos >= len)
  819          pos = len - 1;
  820      c = name[pos];
  821      if (c >= '0' && c < '9') {
  822          c++;
  823      } else if (c == '9') {
  824          c = 'A';
  825      } else if (c >= 'A' && c < 'Z') {
  826          c++;
  827      } else if (c == 'Z') {
  828          c = '_';
  829      } else if (c == '_') {
  830          c = 'a';
  831      } else if (c >= 'a' && c < 'z') {
  832          c++;
  833      } else if (c == 'z') {
  834          c = '0';
  835          name[pos] = c;
  836          pos--;
  837          if (pos >= 0 || rollover_carry)
  838              goto again;
  839          return;
  840      } else {
  841          if (pos == len - 1 || name[pos + 1] == '.')
  842              c = '_'; /* Make first change less riddling */
  843          else
  844              c = '0'; /* But else use the full range of valid characters */
  845      }
  846      name[pos] = c;
  847 }
  848 
  849 static
  850 int insert_underscores(char *name, int *len, int *at_pos, int count,
  851                        char **new_name)
  852 {
  853     int ret;
  854 
  855     LIBISO_ALLOC_MEM(*new_name, char, count + *len + 1);
  856     if (*at_pos > 0)
  857         memcpy(*new_name, name, *at_pos);
  858     if (count > 0)
  859         memset(*new_name + *at_pos, '_', count);
  860     if (*len > *at_pos)
  861         memcpy(*new_name + *at_pos + count, name + *at_pos, *len - *at_pos);
  862     (*new_name)[count + *len] = 0;
  863     *len += count;
  864     *at_pos += count;
  865     ret= ISO_SUCCESS;
  866 ex:;
  867     return ret;
  868 }
  869 
  870 static
  871 int make_incrementable_name(char **name, char **unique_name, int *low_pos,
  872                             int *rollover_carry, int *pre_check) 
  873 {
  874     char *dpt, *npt;
  875     int first, len, ret;
  876     
  877     /* The incrementable part of the file shall have at least 7 characters.
  878        There may be up to pow(2.0,32.0)*2048/33 = 266548273400 files.
  879        The set of increment result characters has 63 elements.
  880        pow(63.0,7.0) is nearly 15 times larger than 266548273400.
  881     */
  882     static int min_incr = 7;
  883 
  884     /* At most two suffixes of total length up to 12, like .tar.bz2,
  885        shall be preserved. The incrementable part will eventually be
  886        padded up.
  887        Incrementing begins before the last suffix in any case. But when this
  888        rolls over on short prefixes, then long last suffixes will get used
  889        as high characters of the incremental part. This is indicated by
  890        *rollover_carry which corresponds to the parameter of ascii_increment()
  891        with the same name.
  892     */
  893     static int max_suffix = 12;
  894 
  895     *rollover_carry = 0;
  896     *pre_check = 0;
  897 
  898     len = strlen(*name);
  899 
  900     /* Check if the part before the first dot is long enough.
  901        If not, then preserve the last two short suffixes.
  902     */
  903     dpt = strchr(*name, '.');
  904     if (dpt != NULL)
  905         if ((dpt - *name) < min_incr)
  906             dpt = strrchr(*name, '.');
  907     if (dpt != NULL) {
  908         first= (dpt - *name);
  909         if (dpt > *name && len - first < max_suffix) {
  910             for(npt = dpt - 1; npt >= *name && *npt != '.'; npt--);
  911             if (npt >= *name) {
  912                 if (len - (npt - *name) <= max_suffix) {
  913                     first= (npt - *name);
  914                     dpt = npt;
  915                 }
  916             }
  917         }
  918     } else
  919         first= len;
  920     if (first < min_incr && (len - first) <= max_suffix) {
  921         ret = insert_underscores(*name, &len, &first, min_incr - first,
  922                                  unique_name);
  923         if (ret < 0)
  924             goto ex;
  925         *pre_check = 1; /* It might now already be unique */
  926 
  927     } else if (len < 64) {
  928         /* Insert an underscore to preserve the original name at least for the
  929            first few increments
  930         */
  931         ret = insert_underscores(*name, &len, &first, 1, unique_name);
  932         if (ret < 0)
  933             goto ex;
  934         *pre_check = 1;
  935 
  936     } else {
  937         LIBISO_ALLOC_MEM(*unique_name, char, len + 1);
  938         memcpy(*unique_name, *name, len);
  939         if (first < min_incr)
  940             *rollover_carry = 1; /* Do not get caged before the dots */
  941     }
  942     (*unique_name)[len] = 0;
  943     *low_pos = first - 1;
  944     ret = 1;
  945 ex:;
  946     return(ret);
  947 }
  948 
  949 static
  950 int make_really_unique_name(IsoDir *parent, char **name, char **unique_name,
  951                             IsoNode ***pos, int flag)
  952 {
  953     int ret, rollover_carry = 0, pre_check = 0, ascii_idx = -1, len;
  954 
  955     ret = make_incrementable_name(name, unique_name, &ascii_idx,
  956                                   &rollover_carry, &pre_check);
  957     if (ret < 0)
  958         goto ex;
  959     len = strlen(*unique_name);
  960     while (1) {
  961         if (!pre_check)
  962             ascii_increment(*unique_name, len, ascii_idx, !!rollover_carry);
  963         else
  964             pre_check = 0;
  965         ret = iso_dir_exists(parent, *unique_name, pos);
  966         if (ret < 0)
  967             goto ex;
  968         if (ret == 0)
  969     break;
  970     }
  971     *name = *unique_name;
  972     ret = ISO_SUCCESS;
  973 ex:;
  974     if (ret < 0) {
  975         LIBISO_FREE_MEM(*unique_name);
  976         *unique_name = NULL;
  977     }
  978     return ret;
  979 }
  980 
  981 /**
  982  * Recursively add a given directory to the image tree.
  983  * 
  984  * @return
  985  *      1 continue, < 0 error (ISO_CANCELED stop)
  986  */
  987 int iso_add_dir_src_rec(IsoImage *image, IsoDir *parent, IsoFileSource *dir)
  988 {
  989     int ret, dir_is_open = 0;
  990     IsoNodeBuilder *builder;
  991     IsoFileSource *file;
  992     IsoNode **pos;
  993     struct stat info;
  994     char *name, *path, *allocated_name = NULL;
  995     IsoNode *new;
  996     enum iso_replace_mode replace;
  997 
  998     ret = iso_file_source_open(dir);
  999     if (ret < 0) {
 1000         path = iso_file_source_get_path(dir);
 1001         /* instead of the probable error, we throw a sorry event */
 1002     if (path != NULL) {
 1003             ret = iso_msg_submit(image->id, ISO_FILE_CANT_ADD, ret, 
 1004                                  "Can't open dir %s", path);
 1005             free(path);
 1006         } else {
 1007             ret = iso_msg_submit(image->id, ISO_NULL_POINTER, ret,
 1008                            "Can't open dir. NULL pointer caught as dir name");
 1009         }
 1010         goto ex;
 1011     }
 1012     dir_is_open = 1;
 1013 
 1014     builder = image->builder;
 1015     
 1016     /* iterate over all directory children */
 1017     while (1) {
 1018         int skip = 0;
 1019 
 1020         ret = iso_file_source_readdir(dir, &file);
 1021         if (ret <= 0) {
 1022             if (ret < 0) {
 1023                 /* error reading dir */
 1024                 ret = iso_msg_submit(image->id, ret, ret, "Error reading dir");
 1025                 goto ex;
 1026             }
 1027     break; /* End of directory */
 1028         }
 1029 
 1030         path = iso_file_source_get_path(file);
 1031         if (path == NULL) {
 1032             ret = iso_msg_submit(image->id, ISO_NULL_POINTER, ret, 
 1033                                  "NULL pointer caught as file path");
 1034             goto ex;
 1035         }
 1036         name = strrchr(path, '/') + 1;
 1037 
 1038         if (image->follow_symlinks) {
 1039             ret = iso_file_source_stat(file, &info);
 1040         } else {
 1041             ret = iso_file_source_lstat(file, &info);
 1042         }
 1043         if (ret < 0) {
 1044             ret = iso_msg_submit(image->id, ISO_FILE_CANT_ADD, ret,
 1045                                  "Error when adding file %s", path);
 1046             goto dir_rec_continue;
 1047         }
 1048 
 1049         if (check_excludes(image, path)) {
 1050             iso_msg_debug(image->id, "Skipping excluded file %s", path);
 1051             skip = 1;
 1052         } else if (check_hidden(image, name)) {
 1053             iso_msg_debug(image->id, "Skipping hidden file %s", path);
 1054             skip = 1;
 1055         } else if (check_special(image, info.st_mode)) {
 1056             iso_msg_debug(image->id, "Skipping special file %s", path);
 1057             skip = 1;
 1058         }
 1059 
 1060         if (skip) {
 1061             goto dir_rec_continue;
 1062         }
 1063 
 1064         replace = image->replace;
 1065 
 1066         /* find place where to insert */
 1067         ret = iso_dir_exists(parent, name, &pos);
 1068         if (ret) {
 1069             /* Resolve name collision
 1070                e.g. caused by fs_image.c:make_hopefully_unique_name() 
 1071             */
 1072             LIBISO_FREE_MEM(allocated_name); allocated_name = NULL;
 1073             ret = make_really_unique_name(parent, &name, &allocated_name, &pos,
 1074                                           0);
 1075             if (ret < 0)
 1076                 goto ex;
 1077             image->collision_warnings++;
 1078             if (image->collision_warnings < ISO_IMPORT_COLL_WARN_MAX) {
 1079                 ret = iso_msg_submit(image->id, ISO_IMPORT_COLLISION, 0, 
 1080                          "File name collision resolved with %s . Now: %s",
 1081                          path, name);
 1082                 if (ret < 0)
 1083                     goto ex;
 1084             }
 1085         }
 1086 
 1087         /* if we are here we must insert. Give user a chance for cancel */
 1088         if (image->report) {
 1089             int r = image->report(image, file);
 1090             if (r <= 0) {
 1091                 ret = (r < 0 ? ISO_CANCELED : ISO_SUCCESS);
 1092                 goto dir_rec_continue;
 1093             }
 1094         }
 1095         ret = builder->create_node(builder, image, file, name, &new);
 1096         if (ret < 0) {
 1097             ret = iso_msg_submit(image->id, ISO_FILE_CANT_ADD, ret,
 1098                          "Error when adding file %s", path);
 1099             goto dir_rec_continue;
 1100         }
 1101 
 1102         /* ok, node has correctly created, we need to add it */
 1103         ret = iso_dir_insert(parent, new, pos, replace);
 1104         if (ret < 0) {
 1105             iso_node_unref(new);
 1106             if (ret != (int) ISO_NODE_NAME_NOT_UNIQUE) {
 1107                 /* error */
 1108                 goto dir_rec_continue;
 1109             } else {
 1110                 /* file ignored because a file with same node already exists */
 1111                 iso_msg_debug(image->id, "Skipping file %s. A node with same "
 1112                               "file already exists", path);
 1113                 ret = 0;
 1114             }
 1115         } else {
 1116             iso_msg_debug(image->id, "Added file %s", path);
 1117         }
 1118 
 1119         /* finally, if the node is a directory we need to recurse */
 1120         if (new->type == LIBISO_DIR && S_ISDIR(info.st_mode)) {
 1121             ret = iso_add_dir_src_rec(image, (IsoDir*)new, file);
 1122         }
 1123 
 1124 dir_rec_continue:;
 1125         free(path);
 1126         iso_file_source_unref(file);
 1127         
 1128         /* check for error severity to decide what to do */
 1129         if (ret < 0) {
 1130             ret = iso_msg_submit(image->id, ret, 0, NULL);
 1131             if (ret < 0)
 1132                 goto ex;
 1133         }
 1134     } /* while */
 1135 
 1136     ret = ISO_SUCCESS;
 1137 ex:;
 1138     if (dir_is_open)
 1139         iso_file_source_close(dir);
 1140     LIBISO_FREE_MEM(allocated_name);
 1141     return ret;
 1142 }
 1143 
 1144 int iso_tree_add_dir_rec(IsoImage *image, IsoDir *parent, const char *dir)
 1145 {
 1146     int result;
 1147     struct stat info;
 1148     IsoFilesystem *fs;
 1149     IsoFileSource *file;
 1150 
 1151     if (image == NULL || parent == NULL || dir == NULL) {
 1152         return ISO_NULL_POINTER;
 1153     }
 1154 
 1155     fs = image->fs;
 1156     result = fs->get_by_path(fs, dir, &file);
 1157     if (result < 0) {
 1158         return result;
 1159     }
 1160 
 1161     /* we also allow dir path to be a symlink to a dir */
 1162     result = iso_file_source_stat(file, &info);
 1163     if (result < 0) {
 1164         iso_file_source_unref(file);
 1165         return result;
 1166     }
 1167 
 1168     if (!S_ISDIR(info.st_mode)) {
 1169         iso_file_source_unref(file);
 1170         return ISO_FILE_IS_NOT_DIR;
 1171     }
 1172     result = iso_add_dir_src_rec(image, parent, file);
 1173     iso_file_source_unref(file);
 1174     return result;
 1175 }
 1176 
 1177 /* @param flag bit0= truncate according to image truncate mode and length
 1178 */
 1179 int iso_tree_path_to_node_flag(IsoImage *image, const char *path,
 1180                                IsoNode **node, int flag)
 1181 {
 1182     int result;
 1183     IsoNode *n;
 1184     IsoDir *dir;
 1185     char *ptr, *brk_info = NULL, *component;
 1186 
 1187     if (image == NULL || path == NULL) {
 1188         return ISO_NULL_POINTER;
 1189     }
 1190 
 1191     /* get the first child at the root of the image that is "/" */
 1192     dir = image->root;
 1193     n = (IsoNode *)dir;
 1194     if (!strcmp(path, "/")) {
 1195         if (node) {
 1196             *node = n;
 1197         }
 1198         return ISO_SUCCESS;
 1199     }
 1200 
 1201     ptr = strdup(path);
 1202     if (ptr == NULL)
 1203         return ISO_OUT_OF_MEM;
 1204     result = 0;
 1205 
 1206     /* get the first component of the path */
 1207     component = strtok_r(ptr, "/", &brk_info);
 1208     while (component) {
 1209         if (n->type != LIBISO_DIR) {
 1210             n = NULL;
 1211             result = 0;
 1212             break;
 1213         }
 1214         dir = (IsoDir *)n;
 1215 
 1216         if ((flag & 1) && image->truncate_mode == 1) {
 1217             result = iso_dir_get_node_trunc(dir, image->truncate_length,
 1218                                             component, &n);
 1219         } else {
 1220             result = iso_dir_get_node(dir, component, &n);
 1221         }
 1222         if (result != 1) {
 1223             n = NULL;
 1224             break;
 1225         }
 1226 
 1227         component = strtok_r(NULL, "/", &brk_info);
 1228     }
 1229 
 1230     free(ptr);
 1231     if (node) {
 1232         *node = n;
 1233     }
 1234     return result;
 1235 }
 1236 
 1237 int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node)
 1238 {
 1239     return iso_tree_path_to_node_flag(image, path, node, 0);
 1240 }
 1241 
 1242 int iso_image_path_to_node(IsoImage *image, const char *path, IsoNode **node)
 1243 {
 1244     return iso_tree_path_to_node_flag(image, path, node, 1);
 1245 }
 1246 
 1247 char *iso_tree_get_node_path(IsoNode *node)
 1248 {
 1249     char *path = NULL, *parent_path = NULL;
 1250 
 1251     if (node == NULL || node->parent == NULL)
 1252         return NULL;
 1253     
 1254     if ((IsoNode*)node->parent == node) {
 1255         return strdup("/");
 1256     } else {
 1257         parent_path = iso_tree_get_node_path((IsoNode*)node->parent);
 1258         if (parent_path == NULL)
 1259             goto ex;
 1260         if (strlen(parent_path) == 1) {
 1261             path = calloc(1, strlen(node->name) + 2);
 1262             if (path == NULL)
 1263                 goto ex;
 1264             sprintf(path, "/%s", node->name);
 1265         } else {
 1266             path = calloc(1, strlen(parent_path) + strlen(node->name) + 2);
 1267             if (path == NULL)
 1268                 goto ex;
 1269             sprintf(path, "%s/%s", parent_path, node->name);
 1270         }
 1271     }
 1272 ex:;
 1273     if (parent_path != NULL)
 1274         free(parent_path);
 1275     return path;
 1276 }
 1277 
 1278 /* Note: No reference is taken to the found node.
 1279    @param flag bit0= recursion
 1280 */
 1281 int iso_tree_get_node_of_block(IsoImage *image, IsoDir *dir, uint32_t block,
 1282                                IsoNode **found, uint32_t *next_above, int flag)
 1283 {
 1284     int ret, section_count, i;
 1285     IsoDirIter *iter = NULL;
 1286     IsoNode *node;
 1287     IsoDir *subdir;
 1288     IsoFile *file;
 1289     struct iso_file_section *sections = NULL;
 1290     uint32_t na = 0;
 1291 
 1292     if (dir == NULL)
 1293         dir = image->root;
 1294 
 1295     ret = iso_dir_get_children(dir, &iter);
 1296     while (iso_dir_iter_next(iter, &node) == 1 ) {
 1297 
 1298         if (ISO_NODE_IS_FILE(node)) {
 1299             file = (IsoFile *) node;
 1300             ret = iso_file_get_old_image_sections(file, &section_count,
 1301                                                   &sections, 0);
 1302             if (ret <= 0)
 1303     continue;
 1304             for (i = 0; i < section_count; i++) {
 1305                 if (sections[i].block <= block &&
 1306                     block - sections[i].block <
 1307                                   (((off_t) sections[i].size) + 2047) / 2048) {
 1308                     *found = node;
 1309                     ret = 1; goto ex;
 1310                 }
 1311                 if ((na == 0 || sections[i].block < na) &&
 1312                                                      sections[i].block > block)
 1313                     na = sections[i].block;
 1314             }
 1315             free(sections); sections = NULL;
 1316         } else if (ISO_NODE_IS_DIR(node)) {
 1317             subdir = (IsoDir *) node;
 1318             ret = iso_tree_get_node_of_block(image, subdir, block, found, &na,
 1319                                              1);
 1320             if (ret != 0)
 1321                 goto ex;
 1322         }
 1323     }
 1324     if (next_above != NULL && (na  > 0 || !(flag & 1)))
 1325         if (*next_above == 0 || *next_above > na || !(flag & 1))
 1326             *next_above = na;
 1327     ret = 0;
 1328 ex:
 1329     if (sections != NULL)
 1330         free(sections);
 1331     if (iter != NULL)
 1332         iso_dir_iter_free(iter);
 1333     return ret;
 1334 }
 1335 
 1336 
 1337 /* ------------------------- tree cloning ------------------------------ */
 1338 
 1339 static
 1340 int iso_tree_copy_node_attr(IsoNode *old_node, IsoNode *new_node, int flag)
 1341 {
 1342     int ret;
 1343 
 1344     new_node->mode = old_node->mode;
 1345     new_node->uid = old_node->uid;
 1346     new_node->gid = old_node->gid;
 1347     new_node->atime = old_node->atime;
 1348     new_node->mtime = old_node->mtime;
 1349     new_node->ctime = old_node->ctime;
 1350     new_node->hidden = old_node->hidden;
 1351     ret = iso_node_clone_xinfo(old_node, new_node, 0);
 1352     if (ret < 0)
 1353         return ret;
 1354     return ISO_SUCCESS;
 1355 }
 1356 
 1357 /*
 1358   @param flag bit0= merge directory with *new_node
 1359 */
 1360 static
 1361 int iso_tree_clone_dir(IsoDir *old_dir,
 1362                        IsoDir *new_parent, char *new_name, IsoNode **new_node,
 1363                        int flag)
 1364 {
 1365     IsoDir *new_dir = NULL;
 1366     IsoNode *sub_node = NULL, *new_sub_node = NULL;
 1367     IsoDirIter *iter = NULL;
 1368     int ret;
 1369 
 1370     if (flag & 1) {
 1371         new_dir = (IsoDir *) *new_node;
 1372     } else {
 1373         *new_node = NULL;
 1374         ret = iso_tree_add_new_dir(new_parent, new_name, &new_dir);
 1375         if (ret < 0)
 1376            return ret;
 1377     }
 1378     /* Avoid traversal of target directory to allow cloning of old_dir to a
 1379        subordinate of old_dir.
 1380     */
 1381     iso_node_take((IsoNode *) new_dir);
 1382 
 1383     ret = iso_dir_get_children(old_dir, &iter);
 1384     if (ret < 0)
 1385         goto ex;
 1386     while(1) {
 1387         ret = iso_dir_iter_next(iter, &sub_node);
 1388         if (ret == 0)
 1389     break;
 1390         ret = iso_tree_clone(sub_node, new_dir, sub_node->name, &new_sub_node,
 1391                              flag & 1);
 1392         if (ret < 0)
 1393             goto ex;
 1394     }
 1395 
 1396     /* Now graft in the new tree resp. graft back the merged tree */
 1397     ret = iso_dir_add_node(new_parent, (IsoNode *) new_dir, 0);
 1398     if (ret < 0)
 1399         goto ex;
 1400 
 1401     if (!(flag & 1))
 1402         *new_node = (IsoNode *) new_dir;
 1403     ret = ISO_SUCCESS;
 1404 ex:;
 1405     if (iter != NULL)
 1406         iso_dir_iter_free(iter);
 1407     if (ret < 0 && new_dir != NULL) {
 1408     if (flag & 1) {
 1409             /* graft back the merged tree (eventually with half copy) */
 1410             iso_dir_add_node(new_parent, (IsoNode *) new_dir, 0);
 1411         } else {
 1412             iso_node_remove_tree((IsoNode *) new_dir, NULL);
 1413             *new_node = NULL;
 1414         }
 1415     }
 1416     return ret;
 1417 }
 1418 
 1419 static
 1420 int iso_tree_clone_file(IsoFile *old_file,
 1421                         IsoDir *new_parent, char *new_name, IsoNode **new_node,
 1422                         int flag)
 1423 {
 1424     IsoStream *new_stream = NULL;
 1425     IsoFile *new_file = NULL;
 1426     int ret;
 1427 
 1428     *new_node = NULL;
 1429 
 1430     ret = iso_stream_clone(old_file->stream, &new_stream, 0);
 1431     if (ret < 0)
 1432         return ret;
 1433 
 1434     ret = iso_tree_add_new_file(new_parent, new_name, new_stream, &new_file);
 1435     if (ret < 0)
 1436         goto ex;
 1437     new_stream = NULL; /* now owned by new_file */
 1438     new_file->sort_weight = old_file->sort_weight;
 1439     *new_node = (IsoNode *) new_file;
 1440     ret = ISO_SUCCESS;
 1441 ex:;
 1442     if (new_stream != NULL)
 1443         iso_stream_unref(new_stream);
 1444     return ret;
 1445 }
 1446 
 1447 static
 1448 int iso_tree_clone_symlink(IsoSymlink *node,
 1449                         IsoDir *new_parent, char *new_name, IsoNode **new_node,
 1450                         int flag)
 1451 {
 1452     IsoSymlink *new_sym;
 1453     int ret;
 1454 
 1455     *new_node = NULL;
 1456 
 1457     ret = iso_tree_add_new_symlink(new_parent, new_name, node->dest, &new_sym);
 1458     if (ret < 0)
 1459         return ret;
 1460     new_sym->fs_id = node->fs_id;
 1461     new_sym->st_dev = node->st_dev;
 1462     new_sym->st_ino = node->st_ino;
 1463     *new_node = (IsoNode *) new_sym;
 1464     return ISO_SUCCESS;
 1465 }
 1466 
 1467 static
 1468 int iso_tree_clone_special(IsoSpecial *node,
 1469                         IsoDir *new_parent, char *new_name, IsoNode **new_node,
 1470                         int flag)
 1471 {
 1472     IsoSpecial *new_spec;
 1473     IsoNode *iso_node;
 1474     int ret;
 1475 
 1476     iso_node = (IsoNode *) node;
 1477     ret = iso_tree_add_new_special(new_parent, new_name, iso_node->mode,
 1478                                    node->dev, &new_spec);
 1479     if (ret < 0)
 1480         return ret;
 1481     new_spec->fs_id = node->fs_id;
 1482     new_spec->st_dev = node->st_dev;
 1483     new_spec->st_ino = node->st_ino;
 1484     *new_node = (IsoNode *) new_spec;
 1485     return ISO_SUCCESS;
 1486 }
 1487 
 1488 
 1489 /* @param flag bit0= Merge directories rather than ISO_NODE_NAME_NOT_UNIQUE.
 1490                bit1= issue warning in case of truncation
 1491 */
 1492 int iso_tree_clone_trunc(IsoNode *node, IsoDir *new_parent, 
 1493                          char *new_name_in, IsoNode **new_node, 
 1494                          int truncate_length, int flag)
 1495 {
 1496     int ret = ISO_SUCCESS;
 1497     char *new_name, *trunc = NULL;
 1498 
 1499     *new_node = NULL;
 1500     new_name = new_name_in;
 1501     if (truncate_length >= 64 && (int) strlen(new_name) > truncate_length) {
 1502         trunc = strdup(new_name);
 1503         if (trunc == 0) {
 1504             ret = ISO_OUT_OF_MEM;
 1505             goto ex;
 1506         }
 1507         ret = iso_truncate_rr_name(1, truncate_length, trunc, !(flag & 2));
 1508         if (ret < 0)
 1509             goto ex;
 1510         new_name = trunc;
 1511     }
 1512     if (iso_dir_get_node(new_parent, new_name, new_node) == 1) {
 1513         if (! (node->type == LIBISO_DIR && (*new_node)->type == LIBISO_DIR &&
 1514                (flag & 1))) {
 1515             *new_node = NULL;
 1516             ret = ISO_NODE_NAME_NOT_UNIQUE;
 1517             goto ex;
 1518         }
 1519     } else
 1520         flag &= ~1;
 1521 
 1522     if (node->type == LIBISO_DIR) {
 1523         ret = iso_tree_clone_dir((IsoDir *) node, new_parent, new_name,
 1524                                  new_node, flag & 1);
 1525     } else if (node->type == LIBISO_FILE) {
 1526         ret = iso_tree_clone_file((IsoFile *) node, new_parent, new_name, 
 1527                                   new_node, 0);
 1528     } else if (node->type == LIBISO_SYMLINK) {
 1529         ret = iso_tree_clone_symlink((IsoSymlink *) node, new_parent, new_name,
 1530                                   new_node, 0);
 1531     } else if (node->type == LIBISO_SPECIAL) {
 1532         ret = iso_tree_clone_special((IsoSpecial *) node, new_parent, new_name,
 1533                                     new_node, 0);
 1534     } else if (node->type == LIBISO_BOOT) {
 1535         ret = ISO_SUCCESS; /* API says they are silently ignored */
 1536     }
 1537     if (ret < 0)
 1538         goto ex;
 1539     if (flag & 1) {
 1540         ret = 2; /* merged two directories, *new_node is not new */
 1541         goto ex;
 1542     }
 1543     ret = iso_tree_copy_node_attr(node, *new_node, 0);
 1544 
 1545 ex:;
 1546     if (trunc != NULL)
 1547         free(trunc);
 1548     return ret;
 1549 }
 1550 
 1551 
 1552 /* API */
 1553 int iso_tree_clone(IsoNode *node,
 1554                    IsoDir *new_parent, char *new_name, IsoNode **new_node,
 1555                    int flag)
 1556 {
 1557     return iso_tree_clone_trunc(node, new_parent, new_name, new_node, 0,
 1558                                 flag & 1); 
 1559 }
 1560 
 1561 
 1562 /* API */
 1563 int iso_image_tree_clone(IsoImage *image, IsoNode *node, IsoDir *new_parent,
 1564                          char *new_name, IsoNode **new_node, int flag)
 1565 {
 1566     int length, ret;
 1567 
 1568     if (image->truncate_mode == 0)
 1569         length = 0;
 1570     else
 1571         length = image->truncate_length;
 1572     ret = iso_tree_clone_trunc(node, new_parent, new_name, new_node, length,
 1573                                flag & 3);
 1574     return ret;
 1575 }
 1576 
 1577 
 1578 int iso_tree_resolve_symlink(IsoImage *img, IsoSymlink *sym, IsoNode **res,
 1579                              int *depth, int flag)
 1580 {
 1581     IsoDir *cur_dir = NULL;
 1582     IsoNode *n, *resolved_node;
 1583     char *dest, *dest_start, *dest_end;
 1584     int ret = 0;
 1585     unsigned int comp_len, dest_len;
 1586 
 1587     dest = sym->dest;
 1588     dest_len = strlen(dest);
 1589 
 1590     if (dest[0] == '/') {
 1591 
 1592         /* ??? How to resolve absolute links without knowing the
 1593                path of the future mount point ?
 1594            ??? Would it be better to throw error ? 
 1595            I can only assume that it gets mounted at / during some stage
 1596            of booting.
 1597         */;
 1598 
 1599         cur_dir = img->root;
 1600         dest_end = dest;
 1601     } else {
 1602         cur_dir = sym->node.parent;
 1603         if (cur_dir == NULL)
 1604             cur_dir = img->root;
 1605         dest_end = dest - 1;
 1606     }
 1607 
 1608     while (dest_end < dest + dest_len) {
 1609         dest_start = dest_end + 1;
 1610         dest_end = strchr(dest_start, '/');
 1611         if (dest_end == NULL)
 1612             dest_end = dest_start + strlen(dest_start);
 1613         comp_len = dest_end - dest_start;
 1614         if (comp_len == 0 || (comp_len == 1 && dest_start[0] == '.'))
 1615     continue;
 1616         if (comp_len == 2 && dest_start[0] == '.' && dest_start[1] == '.') {
 1617             cur_dir = cur_dir->node.parent;
 1618             if (cur_dir == NULL) /* link shoots over root */
 1619                 return ISO_DEAD_SYMLINK;
 1620     continue;
 1621         }
 1622 
 1623         /* Search node in cur_dir */
 1624         for (n = cur_dir->children; n != NULL; n = n->next)
 1625             if (strncmp(dest_start, n->name, comp_len) == 0 &&
 1626                 strlen(n->name) == comp_len)
 1627         break;
 1628         if (n == NULL)
 1629             return ISO_DEAD_SYMLINK;
 1630 
 1631         if (n->type == LIBISO_DIR) {
 1632             cur_dir = (IsoDir *) n;
 1633         } else if (n->type == LIBISO_SYMLINK) {
 1634             if (*depth >= LIBISO_MAX_LINK_DEPTH)
 1635                 return ISO_DEEP_SYMLINK;
 1636             (*depth)++;
 1637             ret = iso_tree_resolve_symlink(img, (IsoSymlink *) n,
 1638                                            &resolved_node, depth, 0);
 1639             if (ret < 0)
 1640                 return ret;
 1641             if (resolved_node->type != LIBISO_DIR) {
 1642                 n = resolved_node;
 1643                 goto leaf_type;
 1644             }
 1645             cur_dir = (IsoDir *) resolved_node;
 1646         } else {
 1647 leaf_type:;
 1648             if (dest_end < dest + dest_len) /* attempt to dive into file */
 1649                 return ISO_DEAD_SYMLINK;
 1650             *res = n;
 1651             return ISO_SUCCESS;
 1652         }
 1653     }
 1654     *res = (IsoNode *) cur_dir;
 1655     return ISO_SUCCESS;
 1656 }
 1657