"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libisofs/node.c" (30 Jan 2021, 84135 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 "node.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) 2009 - 2020 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 #ifdef HAVE_CONFIG_H
   12 #include "../config.h"
   13 #endif
   14 
   15 #include "libisofs.h"
   16 #include "image.h"
   17 #include "node.h"
   18 #include "stream.h"
   19 #include "aaip_0_2.h"
   20 #include "messages.h"
   21 #include "util.h"
   22 #include "eltorito.h"
   23 
   24 
   25 #include <stdlib.h>
   26 #include <string.h>
   27 #include <time.h>
   28 #include <limits.h>
   29 #include <stdio.h>
   30 
   31 
   32 struct dir_iter_data
   33 {
   34     /* points to the last visited child, to NULL before start */
   35     IsoNode *pos;
   36 
   37     /* Some control flags.
   38      * bit 0 -> 1 if next called, 0 reset at start or on deletion
   39      */
   40     int flag;
   41 };
   42 
   43 /**
   44  * Increments the reference counting of the given node.
   45  */
   46 void iso_node_ref(IsoNode *node)
   47 {
   48     ++node->refcount;
   49 }
   50 
   51 /**
   52  * Decrements the reference counting of the given node.
   53  * If it reach 0, the node is free, and, if the node is a directory,
   54  * its children will be unref() too.
   55  */
   56 void iso_node_unref(IsoNode *node)
   57 {
   58     if (node == NULL)
   59         return;
   60     if (--node->refcount == 0) {
   61         switch (node->type) {
   62         case LIBISO_DIR:
   63             {
   64                 IsoNode *child = ((IsoDir*)node)->children;
   65                 while (child != NULL) {
   66                     IsoNode *tmp = child->next;
   67                     child->parent = NULL;
   68                     iso_node_unref(child);
   69                     child = tmp;
   70                 }
   71             }
   72             break;
   73         case LIBISO_FILE:
   74             {
   75                 IsoFile *file = (IsoFile*) node;
   76                 iso_stream_unref(file->stream);
   77             }
   78             break;
   79         case LIBISO_SYMLINK:
   80             {
   81                 IsoSymlink *link = (IsoSymlink*) node;
   82                 free(link->dest);
   83             }
   84             break;
   85         case LIBISO_BOOT:
   86             {
   87                 IsoBoot *bootcat = (IsoBoot *) node;
   88                 if (bootcat->content != NULL)
   89                     free(bootcat->content);
   90             }
   91             break;
   92         default:
   93             /* other kind of nodes does not need to delete anything here */
   94             break;
   95         }
   96 
   97         if (node->xinfo) {
   98             IsoExtendedInfo *info = node->xinfo;
   99             while (info != NULL) {
  100                 IsoExtendedInfo *tmp = info->next;
  101 
  102                 /* free extended info */
  103                 info->process(info->data, 1);
  104                 free(info);
  105                 info = tmp;
  106             }
  107         }
  108         free(node->name);
  109         free(node);
  110     }
  111 }
  112 
  113 /**
  114  * Add extended information to the given node. Extended info allows
  115  * applications (and libisofs itself) to add more information to an IsoNode.
  116  * You can use this facilities to associate new information with a given
  117  * node.
  118  *
  119  * Each node keeps a list of added extended info, meaning you can add several
  120  * extended info data to each node. Each extended info you add is identified
  121  * by the proc parameter, a pointer to a function that knows how to manage
  122  * the external info data. Thus, in order to add several types of extended
  123  * info, you need to define a "proc" function for each type.
  124  *
  125  * @param node
  126  *      The node where to add the extended info
  127  * @param proc
  128  *      A function pointer used to identify the type of the data, and that
  129  *      knows how to manage it
  130  * @param data
  131  *      Extended info to add.
  132  * @return
  133  *      1 if success, 0 if the given node already has extended info of the
  134  *      type defined by the "proc" function, < 0 on error
  135  */
  136 int iso_node_add_xinfo(IsoNode *node, iso_node_xinfo_func proc, void *data)
  137 {
  138     IsoExtendedInfo *info;
  139     IsoExtendedInfo *pos;
  140 
  141     if (node == NULL || proc == NULL) {
  142         return ISO_NULL_POINTER;
  143     }
  144 
  145     pos = node->xinfo;
  146     while (pos != NULL) {
  147         if (pos->process == proc) {
  148             return 0; /* extended info already added */
  149         }
  150         pos = pos->next;
  151     }
  152 
  153     info = malloc(sizeof(IsoExtendedInfo));
  154     if (info == NULL) {
  155         return ISO_OUT_OF_MEM;
  156     }
  157     info->next = node->xinfo;
  158     info->data = data;
  159     info->process = proc;
  160     node->xinfo = info;
  161     return ISO_SUCCESS;
  162 }
  163 
  164 /**
  165  * Remove the given extended info (defined by the proc function) from the
  166  * given node.
  167  *
  168  * @return
  169  *      1 on success, 0 if node does not have extended info of the requested
  170  *      type, < 0 on error
  171  */
  172 int iso_node_remove_xinfo(IsoNode *node, iso_node_xinfo_func proc)
  173 {
  174     IsoExtendedInfo *pos, *prev;
  175 
  176     if (node == NULL || proc == NULL) {
  177         return ISO_NULL_POINTER;
  178     }
  179 
  180     prev = NULL;
  181     pos = node->xinfo;
  182     while (pos != NULL) {
  183         if (pos->process == proc) {
  184             /* this is the extended info we want to remove */
  185             pos->process(pos->data, 1);
  186 
  187             if (prev != NULL) {
  188                 prev->next = pos->next;
  189             } else {
  190                 node->xinfo = pos->next;
  191             }
  192             free(pos);
  193             return ISO_SUCCESS;
  194         }
  195         prev = pos;
  196         pos = pos->next;
  197     }
  198     /* requested xinfo not found */
  199     return 0;
  200 }
  201 
  202 /**
  203  * Get the given extended info (defined by the proc function) from the
  204  * given node.
  205  *
  206  * @param data
  207  *      Will be filled with the extended info corresponding to the given proc
  208  *      function
  209  * @return
  210  *      1 on success, 0 if node does not have extended info of the requested
  211  *      type, < 0 on error
  212  */
  213 int iso_node_get_xinfo(IsoNode *node, iso_node_xinfo_func proc, void **data)
  214 {
  215     IsoExtendedInfo *pos;
  216 
  217     if (node == NULL || proc == NULL || data == NULL) {
  218         return ISO_NULL_POINTER;
  219     }
  220 
  221     *data = NULL;
  222     pos = node->xinfo;
  223     while (pos != NULL) {
  224         if (pos->process == proc) {
  225             /* this is the extended info we want */
  226             *data = pos->data;
  227             return ISO_SUCCESS;
  228         }
  229         pos = pos->next;
  230     }
  231     /* requested xinfo not found */
  232     return 0;
  233 }
  234 
  235 /* API */
  236 int iso_node_get_next_xinfo(IsoNode *node, void **handle,
  237                             iso_node_xinfo_func *proc, void **data)
  238 {
  239     IsoExtendedInfo *xinfo;
  240 
  241     if (node == NULL || handle == NULL || proc == NULL || data == NULL)
  242         return ISO_NULL_POINTER;
  243     *proc = NULL;
  244     *data = NULL;
  245     xinfo = (IsoExtendedInfo *) *handle;
  246     if (xinfo == NULL)
  247         xinfo = node->xinfo;
  248     else
  249         xinfo = xinfo->next;
  250     *handle = xinfo;
  251     if (xinfo == NULL)
  252         return 0;
  253     *proc = xinfo->process;
  254     *data = xinfo->data;
  255     return ISO_SUCCESS;
  256 }
  257 
  258 int iso_node_remove_all_xinfo(IsoNode *node, int flag)
  259 {
  260     IsoExtendedInfo *pos, *next;
  261 
  262     for (pos = node->xinfo; pos != NULL; pos = next) {
  263         next = pos->next;
  264         pos->process(pos->data, 1);
  265         free((char *) pos);
  266     }
  267     node->xinfo = NULL;
  268     return ISO_SUCCESS;
  269 }
  270 
  271 static
  272 int iso_node_revert_xinfo_list(IsoNode *node, int flag)
  273 {
  274 
  275     IsoExtendedInfo *pos, *next, *prev = NULL;
  276 
  277     for (pos = node->xinfo; pos != NULL; pos = next) {
  278         next = pos->next;
  279         pos->next = prev;
  280         prev = pos;
  281     }
  282     node->xinfo = prev;
  283     return ISO_SUCCESS;
  284 }
  285 
  286 int iso_node_clone_xinfo(IsoNode *from_node, IsoNode *to_node, int flag)
  287 {
  288     void *handle = NULL, *data, *new_data;
  289     iso_node_xinfo_func proc;
  290     iso_node_xinfo_cloner cloner;
  291     int ret;
  292 
  293     iso_node_remove_all_xinfo(to_node, 0);
  294     while (1) {
  295         ret = iso_node_get_next_xinfo(from_node, &handle, &proc, &data);
  296         if (ret <= 0)
  297     break;
  298         ret = iso_node_xinfo_get_cloner(proc, &cloner, 0);
  299         if (ret == 0)
  300             return ISO_XINFO_NO_CLONE;
  301         if (ret < 0)
  302             return ret;
  303         ret = (*cloner)(data, &new_data, 0);
  304         if (ret < 0)
  305     break;
  306         ret = iso_node_add_xinfo(to_node, proc, new_data);
  307         if (ret < 0)
  308     break;
  309     }
  310     if (ret < 0) {
  311         iso_node_remove_all_xinfo(to_node, 0);
  312     } else {
  313         ret = iso_node_revert_xinfo_list(to_node, 0);
  314     }
  315     return ret;
  316 }
  317 
  318 /**
  319  * Get the type of an IsoNode.
  320  */
  321 enum IsoNodeType iso_node_get_type(IsoNode *node)
  322 {
  323     return node->type;
  324 }
  325 
  326 /**
  327  * Set the name of a node.
  328  *
  329  * @param name  The name in UTF-8 encoding
  330  * @param truncate_length (<64 = return on oversized name )
  331  * @param flag  bit0= issue warning in case of truncation
  332  */
  333 int iso_node_set_name_trunc(IsoNode *node, const char *in_name,
  334                            int truncate_length, int flag)
  335 {
  336     char *new, *name, *trunc = NULL;
  337     int ret;
  338 
  339     if ((IsoNode*)node->parent == node) {
  340         /* you can't change name of the root node */
  341         ret = ISO_WRONG_ARG_VALUE;
  342         goto ex;
  343     }
  344 
  345     name = (char *) in_name;
  346     if (truncate_length >= 64) {
  347         trunc = strdup(name);
  348         if (trunc == 0) {
  349             ret = ISO_OUT_OF_MEM;
  350             goto ex;
  351         }
  352         ret = iso_truncate_rr_name(1, truncate_length, trunc, !(flag & 1));
  353         if (ret < 0)
  354             goto ex;
  355         name = trunc;
  356     }
  357     /* check if the name is valid */
  358     ret = iso_node_is_valid_name(name);
  359     if (ret < 0)
  360         goto ex;
  361 
  362     if (node->parent != NULL) {
  363         /* check if parent already has a node with same name */
  364         if (iso_dir_get_node(node->parent, name, NULL) == 1) {
  365             ret = ISO_NODE_NAME_NOT_UNIQUE;
  366             goto ex;
  367         }
  368     }
  369 
  370     new = strdup(name);
  371     if (new == NULL) {
  372         ret = ISO_OUT_OF_MEM;
  373         goto ex;
  374     }
  375     free(node->name);
  376     node->name = new;
  377     if (node->parent != NULL) {
  378         IsoDir *parent;
  379         int res;
  380         /* take and add again to ensure correct children order */
  381         parent = node->parent;
  382         iso_node_take(node);
  383         res = iso_dir_add_node(parent, node, 0);
  384         if (res < 0) {
  385             ret = res;
  386             goto ex;
  387         }
  388     }
  389     ret = ISO_SUCCESS;
  390 ex:
  391     if (trunc != NULL)
  392         free(trunc);
  393     return ret;
  394 }
  395 
  396 int iso_node_set_name(IsoNode *node, const char *name)
  397 {
  398     return iso_node_set_name_trunc(node, name, 0, 0);
  399 }
  400 
  401 int iso_image_set_node_name(IsoImage *image, IsoNode *node, const char *name,
  402                             int flag)
  403 {
  404     if (image->truncate_mode == 0)
  405         if ((int) strlen(name) > image->truncate_length)
  406             return ISO_RR_NAME_TOO_LONG;
  407     return iso_node_set_name_trunc(node, name, image->truncate_length, flag);
  408 }
  409 
  410 /**
  411  * Get the name of a node (in UTF-8).
  412  * The returned string belongs to the node and should not be modified nor
  413  * freed. Use strdup if you really need your own copy.
  414  */
  415 const char *iso_node_get_name(const IsoNode *node)
  416 {
  417     static char *root = {""};
  418 
  419     if (node->name == NULL)
  420         return root;
  421     return node->name;
  422 }
  423 
  424 /**
  425  * See API function iso_node_set_permissions()
  426  *
  427  * @param flag  bit0= do not adjust ACL
  428  * @return      >0 success , <0 error
  429  */
  430 int iso_node_set_perms_internal(IsoNode *node, mode_t mode, int flag)
  431 {
  432     int ret;
  433 
  434     node->mode = (node->mode & S_IFMT) | (mode & ~S_IFMT);
  435 
  436     /* If the node has ACL info : update ACL */
  437     ret = 1;
  438     if (!(flag & 1))
  439         ret = iso_node_set_acl_text(node, "", "", 2);
  440 
  441     return ret;
  442 }
  443 
  444 /**
  445  * Set the permissions for the node. This attribute is only useful when
  446  * Rock Ridge extensions are enabled.
  447  *
  448  * @param mode
  449  *     bitmask with the permissions of the node, as specified in 'man 2 stat'.
  450  *     The file type bitfields will be ignored, only file permissions will be
  451  *     modified.
  452  */
  453 void iso_node_set_permissions(IsoNode *node, mode_t mode)
  454 {
  455      iso_node_set_perms_internal(node, mode, 0);
  456 }
  457 
  458 
  459 /**
  460  * Get the permissions for the node
  461  */
  462 mode_t iso_node_get_permissions(const IsoNode *node)
  463 {
  464     return node->mode & ~S_IFMT;
  465 }
  466 
  467 /**
  468  * Get the mode of the node, both permissions and file type, as specified in
  469  * 'man 2 stat'.
  470  */
  471 mode_t iso_node_get_mode(const IsoNode *node)
  472 {
  473     return node->mode;
  474 }
  475 
  476 /**
  477  * Set the user id for the node. This attribute is only useful when
  478  * Rock Ridge extensions are enabled.
  479  */
  480 void iso_node_set_uid(IsoNode *node, uid_t uid)
  481 {
  482     node->uid = uid;
  483 }
  484 
  485 /**
  486  * Get the user id of the node.
  487  */
  488 uid_t iso_node_get_uid(const IsoNode *node)
  489 {
  490     return node->uid;
  491 }
  492 
  493 /**
  494  * Set the group id for the node. This attribute is only useful when
  495  * Rock Ridge extensions are enabled.
  496  */
  497 void iso_node_set_gid(IsoNode *node, gid_t gid)
  498 {
  499     node->gid = gid;
  500 }
  501 
  502 /**
  503  * Get the group id of the node.
  504  */
  505 gid_t iso_node_get_gid(const IsoNode *node)
  506 {
  507     return node->gid;
  508 }
  509 
  510 /**
  511  * Set the time of last modification of the file
  512  */
  513 void iso_node_set_mtime(IsoNode *node, time_t time)
  514 {
  515     node->mtime = time;
  516 }
  517 
  518 /**
  519  * Get the time of last modification of the file
  520  */
  521 time_t iso_node_get_mtime(const IsoNode *node)
  522 {
  523     return node->mtime;
  524 }
  525 
  526 /**
  527  * Set the time of last access to the file
  528  */
  529 void iso_node_set_atime(IsoNode *node, time_t time)
  530 {
  531     node->atime = time;
  532 }
  533 
  534 /**
  535  * Get the time of last access to the file
  536  */
  537 time_t iso_node_get_atime(const IsoNode *node)
  538 {
  539     return node->atime;
  540 }
  541 
  542 /**
  543  * Set the time of last status change of the file
  544  */
  545 void iso_node_set_ctime(IsoNode *node, time_t time)
  546 {
  547     node->ctime = time;
  548 }
  549 
  550 /**
  551  * Get the time of last status change of the file
  552  */
  553 time_t iso_node_get_ctime(const IsoNode *node)
  554 {
  555     return node->ctime;
  556 }
  557 
  558 void iso_node_set_hidden(IsoNode *node, int hide_attrs)
  559 {
  560     /* you can't hide root node */
  561     if ((IsoNode*)node->parent != node) {
  562         node->hidden = hide_attrs;
  563     }
  564 }
  565 
  566 int iso_node_get_hidden(IsoNode *node)
  567 {
  568     return node->hidden;
  569 }
  570 
  571 
  572 /**
  573  * Add a new node to a dir. Note that this function don't add a new ref to
  574  * the node, so you don't need to free it, it will be automatically freed
  575  * when the dir is deleted. Of course, if you want to keep using the node
  576  * after the dir life, you need to iso_node_ref() it.
  577  *
  578  * @param dir
  579  *     the dir where to add the node
  580  * @param child
  581  *     the node to add. You must ensure that the node hasn't previously added
  582  *     to other dir, and that the node name is unique inside the child.
  583  *     Otherwise this function will return a failure, and the child won't be
  584  *     inserted.
  585  * @param replace
  586  *     if the dir already contains a node with the same name, whether to
  587  *     replace or not the old node with this.
  588  * @return
  589  *     number of nodes in dir if success, < 0 otherwise
  590  */
  591 int iso_dir_add_node(IsoDir *dir, IsoNode *child,
  592                      enum iso_replace_mode replace)
  593 {
  594     IsoNode **pos;
  595 
  596     if (dir == NULL || child == NULL) {
  597         return ISO_NULL_POINTER;
  598     }
  599     if ((IsoNode*)dir == child) {
  600         return ISO_WRONG_ARG_VALUE;
  601     }
  602 
  603     /*
  604      * check if child is already added to another dir, or if child
  605      * is the root node, where parent == itself
  606      */
  607     if (child->parent != NULL || child->parent == (IsoDir*)child) {
  608         return ISO_NODE_ALREADY_ADDED;
  609     }
  610 
  611     iso_dir_find(dir, child->name, &pos);
  612     return iso_dir_insert(dir, child, pos, replace);
  613 }
  614 
  615 /**
  616  * Locate a node inside a given dir.
  617  *
  618  * @param name
  619  *     The name of the node
  620  * @param node
  621  *     Location for a pointer to the node, it will filled with NULL if the dir
  622  *     doesn't have a child with the given name.
  623  *     The node will be owned by the dir and shouldn't be unref(). Just call
  624  *     iso_node_ref() to get your own reference to the node.
  625  *     Note that you can pass NULL is the only thing you want to do is check
  626  *     if a node with such name already exists on dir.
  627  * @return
  628  *     1 node found, 0 child has no such node, < 0 error
  629  *     Possible errors:
  630  *         ISO_NULL_POINTER, if dir or name are NULL
  631  */
  632 int iso_dir_get_node(IsoDir *dir, const char *name, IsoNode **node)
  633 {
  634     int ret;
  635     IsoNode **pos;
  636     if (dir == NULL || name == NULL) {
  637         return ISO_NULL_POINTER;
  638     }
  639 
  640     ret = iso_dir_exists(dir, name, &pos);
  641     if (ret == 0) {
  642         if (node) {
  643             *node = NULL;
  644         }
  645         return 0; /* node not found */
  646     }
  647 
  648     if (node) {
  649         *node = *pos;
  650     }
  651     return 1;
  652 }
  653 
  654 int iso_dir_get_node_trunc(IsoDir *dir, int truncate_length,
  655                            const char *name, IsoNode **node)
  656 {
  657     int ret;
  658     char *trunc = NULL;
  659 
  660     if ((int) strlen(name) <= truncate_length) {
  661         ret = iso_dir_get_node(dir, name, node);
  662         return ret;
  663     }
  664     trunc = strdup(name);
  665     if (trunc == NULL)
  666         return ISO_OUT_OF_MEM;
  667     ret = iso_truncate_rr_name(1, truncate_length, trunc, 1);
  668     if (ret < 0)
  669         goto ex;
  670     ret = iso_dir_get_node(dir, trunc, node);
  671     if (ret == 0)
  672         ret = 2;
  673 ex:;
  674     LIBISO_FREE_MEM(trunc);
  675     return ret;
  676 }
  677 
  678 /* API */
  679 int iso_image_dir_get_node(IsoImage *image, IsoDir *dir,
  680                            const char *name, IsoNode **node, int flag)
  681 {
  682     int ret;
  683 
  684     if (image->truncate_mode == 0 || (flag & 1))
  685         ret = iso_dir_get_node(dir, name, node);
  686     else
  687         ret = iso_dir_get_node_trunc(dir, image->truncate_length, name, node);
  688     return ret;
  689 }
  690 
  691 /**
  692  * Get the number of children of a directory.
  693  *
  694  * @return
  695  *     >= 0 number of items, < 0 error
  696  *     Possible errors:
  697  *         ISO_NULL_POINTER, if dir is NULL
  698  */
  699 int iso_dir_get_children_count(IsoDir *dir)
  700 {
  701     if (dir == NULL) {
  702         return ISO_NULL_POINTER;
  703     }
  704     return dir->nchildren;
  705 }
  706 
  707 static
  708 int iter_next(IsoDirIter *iter, IsoNode **node)
  709 {
  710     struct dir_iter_data *data;
  711     if (iter == NULL || node == NULL) {
  712         return ISO_NULL_POINTER;
  713     }
  714 
  715     data = iter->data;
  716 
  717     /* clear next flag */
  718     data->flag &= ~0x01;
  719 
  720     if (data->pos == NULL) {
  721         /* we are at the beginning */
  722         data->pos = iter->dir->children;
  723         if (data->pos == NULL) {
  724             /* empty dir */
  725             *node = NULL;
  726             return 0;
  727         }
  728     } else {
  729         if (data->pos->parent != iter->dir) {
  730             /* this can happen if the node has been moved to another dir */
  731             /* TODO specific error */
  732             return ISO_ERROR;
  733         }
  734         if (data->pos->next == NULL) {
  735             /* no more children */
  736             *node = NULL;
  737             return 0;
  738         } else {
  739             /* free reference to current position */
  740             iso_node_unref(data->pos); /* it is never last ref!! */
  741 
  742             /* advance a position */
  743             data->pos = data->pos->next;
  744         }
  745     }
  746 
  747     /* ok, take a ref to the current position, to prevent internal errors
  748      * if deleted somewhere */
  749     iso_node_ref(data->pos);
  750     data->flag |= 0x01; /* set next flag */
  751 
  752     /* return pointed node */
  753     *node = data->pos;
  754     return ISO_SUCCESS;
  755 }
  756 
  757 /**
  758  * Check if there're more children.
  759  *
  760  * @return
  761  *     1 dir has more elements, 0 no, < 0 error
  762  *     Possible errors:
  763  *         ISO_NULL_POINTER, if iter is NULL
  764  */
  765 static
  766 int iter_has_next(IsoDirIter *iter)
  767 {
  768     struct dir_iter_data *data;
  769     if (iter == NULL) {
  770         return ISO_NULL_POINTER;
  771     }
  772     data = iter->data;
  773     if (data->pos == NULL) {
  774         return iter->dir->children == NULL ? 0 : 1;
  775     } else {
  776         return data->pos->next == NULL ? 0 : 1;
  777     }
  778 }
  779 
  780 static
  781 void iter_free(IsoDirIter *iter)
  782 {
  783     struct dir_iter_data *data;
  784     data = iter->data;
  785     if (data->pos != NULL) {
  786         iso_node_unref(data->pos);
  787     }
  788     free(data);
  789 }
  790 
  791 static IsoNode** iso_dir_find_node(IsoDir *dir, IsoNode *node)
  792 {
  793     IsoNode **pos;
  794     pos = &(dir->children);
  795     while (*pos != NULL && *pos != node) {
  796         pos = &((*pos)->next);
  797     }
  798     return pos;
  799 }
  800 
  801 /**
  802  * Removes a child from a directory.
  803  * The child is not freed, so you will become the owner of the node. Later
  804  * you can add the node to another dir (calling iso_dir_add_node), or free
  805  * it if you don't need it (with iso_node_unref).
  806  *
  807  * @return
  808  *     1 on success, < 0 error
  809  */
  810 int iso_node_take(IsoNode *node)
  811 {
  812     IsoNode **pos;
  813     IsoDir* dir;
  814 
  815     if (node == NULL) {
  816         return ISO_NULL_POINTER;
  817     }
  818     dir = node->parent;
  819     if (dir == NULL) {
  820         return ISO_NODE_NOT_ADDED_TO_DIR;
  821     }
  822 
  823     /* >>> Do not take root directory ! (dir == node) ? */;
  824 
  825     pos = iso_dir_find_node(dir, node);
  826     if (pos == NULL) {
  827         /* should never occur */
  828         return ISO_ASSERT_FAILURE;
  829     }
  830 
  831     /* notify iterators just before remove */
  832     iso_notify_dir_iters(node, 0);
  833 
  834     *pos = node->next;
  835     node->parent = NULL;
  836     node->next = NULL;
  837     dir->nchildren--;
  838     return ISO_SUCCESS;
  839 }
  840 
  841 /**
  842  * Removes a child from a directory and free (unref) it.
  843  * If you want to keep the child alive, you need to iso_node_ref() it
  844  * before this call, but in that case iso_node_take() is a better
  845  * alternative.
  846  *
  847  * @return
  848  *     1 on success, < 0 error
  849  */
  850 int iso_node_remove(IsoNode *node)
  851 {
  852     int ret;
  853     ret = iso_node_take(node);
  854     if (ret == ISO_SUCCESS) {
  855         iso_node_unref(node);
  856     }
  857     return ret;
  858 }
  859 
  860 /* API */
  861 int iso_node_remove_tree(IsoNode *node, IsoDirIter *boss_iter)
  862 {
  863     IsoDirIter *iter = NULL;
  864     IsoNode *sub_node;
  865     int ret;
  866 
  867     if (node->type != LIBISO_DIR) {
  868 
  869         /* >>> Do not remove root directory ! (node->parent == node) ? */;
  870 
  871         ret = iso_dir_get_children((IsoDir *) node, &iter);
  872         if (ret < 0)
  873             goto ex;
  874         while(1) {
  875             ret = iso_dir_iter_next(iter, &sub_node);
  876             if (ret == 0)
  877         break;
  878             ret = iso_node_remove_tree(sub_node, iter);
  879             if (ret < 0)
  880                 goto ex;
  881         }
  882         if (node->parent == NULL) {
  883             /* node is not grafted into a boss directory */
  884             iso_node_unref(node);
  885             goto ex;
  886         }
  887     }
  888     if (boss_iter != NULL)
  889         ret = iso_dir_iter_remove(boss_iter);
  890     else
  891         ret = iso_node_remove(node);
  892 ex:;
  893     if (iter != NULL)
  894         iso_dir_iter_free(iter);
  895     return ret;
  896 }
  897 
  898 /*
  899  * Get the parent of the given iso tree node. No extra ref is added to the
  900  * returned directory, you must take your ref. with iso_node_ref() if you
  901  * need it.
  902  *
  903  * If node is the root node, the same node will be returned as its parent.
  904  *
  905  * This returns NULL if the node doesn't pertain to any tree
  906  * (it was removed/take).
  907  */
  908 IsoDir *iso_node_get_parent(IsoNode *node)
  909 {
  910     return node->parent;
  911 }
  912 
  913 /* TODO #00005 optimize iso_dir_iter_take */
  914 static
  915 int iter_take(IsoDirIter *iter)
  916 {
  917     struct dir_iter_data *data;
  918     if (iter == NULL) {
  919         return ISO_NULL_POINTER;
  920     }
  921 
  922     data = iter->data;
  923 
  924     if (!(data->flag & 0x01)) {
  925         return ISO_ERROR; /* next not called or end of dir */
  926     }
  927 
  928     if (data->pos == NULL) {
  929         return ISO_ASSERT_FAILURE;
  930     }
  931 
  932     /* clear next flag */
  933     data->flag &= ~0x01;
  934 
  935     return iso_node_take(data->pos);
  936 }
  937 
  938 static
  939 int iter_remove(IsoDirIter *iter)
  940 {
  941     int ret;
  942     IsoNode *pos;
  943     struct dir_iter_data *data;
  944 
  945     if (iter == NULL) {
  946         return ISO_NULL_POINTER;
  947     }
  948     data = iter->data;
  949     pos = data->pos;
  950 
  951     ret = iter_take(iter);
  952     if (ret == ISO_SUCCESS) {
  953         /* remove node */
  954         iso_node_unref(pos);
  955     }
  956     return ret;
  957 }
  958 
  959 void iter_notify_child_taken(IsoDirIter *iter, IsoNode *node)
  960 {
  961     IsoNode *pos, *pre;
  962     struct dir_iter_data *data;
  963     data = iter->data;
  964 
  965     if (data->pos == node) {
  966         pos = iter->dir->children;
  967         pre = NULL;
  968         while (pos != NULL && pos != data->pos) {
  969             pre = pos;
  970             pos = pos->next;
  971         }
  972         if (pos == NULL || pos != data->pos) {
  973             return;
  974         }
  975 
  976         /* dispose iterator reference */
  977         iso_node_unref(data->pos);
  978 
  979         if (pre == NULL) {
  980             /* node is a first position */
  981             iter->dir->children = pos->next;
  982             data->pos = NULL;
  983         } else {
  984             pre->next = pos->next;
  985             data->pos = pre;
  986             iso_node_ref(pre); /* take iter ref */
  987         }
  988     }
  989 }
  990 
  991 static
  992 struct iso_dir_iter_iface iter_class = {
  993         iter_next,
  994         iter_has_next,
  995         iter_free,
  996         iter_take,
  997         iter_remove,
  998         iter_notify_child_taken
  999 };
 1000 
 1001 int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter)
 1002 {
 1003     IsoDirIter *it;
 1004     struct dir_iter_data *data;
 1005 
 1006     if (dir == NULL || iter == NULL) {
 1007         return ISO_NULL_POINTER;
 1008     }
 1009     it = malloc(sizeof(IsoDirIter));
 1010     if (it == NULL) {
 1011         return ISO_OUT_OF_MEM;
 1012     }
 1013     data = malloc(sizeof(struct dir_iter_data));
 1014     if (data == NULL) {
 1015         free(it);
 1016         return ISO_OUT_OF_MEM;
 1017     }
 1018 
 1019     it->class = &iter_class;
 1020     it->dir = (IsoDir*)dir;
 1021     data->pos = NULL;
 1022     data->flag = 0x00;
 1023     it->data = data;
 1024 
 1025     if (iso_dir_iter_register(it) < 0) {
 1026         free(it);
 1027         return ISO_OUT_OF_MEM;
 1028     }
 1029 
 1030     iso_node_ref((IsoNode*)dir); /* tak a ref to the dir */
 1031     *iter = it;
 1032     return ISO_SUCCESS;
 1033 }
 1034 
 1035 int iso_dir_iter_next(IsoDirIter *iter, IsoNode **node)
 1036 {
 1037     if (iter == NULL || node == NULL) {
 1038         return ISO_NULL_POINTER;
 1039     }
 1040     return iter->class->next(iter, node);
 1041 }
 1042 
 1043 int iso_dir_iter_has_next(IsoDirIter *iter)
 1044 {
 1045     if (iter == NULL) {
 1046         return ISO_NULL_POINTER;
 1047     }
 1048     return iter->class->has_next(iter);
 1049 }
 1050 
 1051 void iso_dir_iter_free(IsoDirIter *iter)
 1052 {
 1053     if (iter != NULL) {
 1054         iso_dir_iter_unregister(iter);
 1055         iter->class->free(iter);
 1056         iso_node_unref((IsoNode*)iter->dir);
 1057         free(iter);
 1058     }
 1059 }
 1060 
 1061 int iso_dir_iter_take(IsoDirIter *iter)
 1062 {
 1063     if (iter == NULL) {
 1064         return ISO_NULL_POINTER;
 1065     }
 1066     return iter->class->take(iter);
 1067 }
 1068 
 1069 int iso_dir_iter_remove(IsoDirIter *iter)
 1070 {
 1071     if (iter == NULL) {
 1072         return ISO_NULL_POINTER;
 1073     }
 1074     return iter->class->remove(iter);
 1075 }
 1076 
 1077 /**
 1078  * Get the destination of a node.
 1079  * The returned string belongs to the node and should not be modified nor
 1080  * freed. Use strdup if you really need your own copy.
 1081  */
 1082 const char *iso_symlink_get_dest(const IsoSymlink *link)
 1083 {
 1084     return link->dest;
 1085 }
 1086 
 1087 /**
 1088  * Set the destination of a link.
 1089  */
 1090 int iso_symlink_set_dest(IsoSymlink *link, const char *dest)
 1091 {
 1092     char *d;
 1093     int ret;
 1094 
 1095     ret = iso_node_is_valid_link_dest(dest);
 1096     if (ret < 0)
 1097         return ret;
 1098     d = strdup(dest);
 1099     if (d == NULL) {
 1100         return ISO_OUT_OF_MEM;
 1101     }
 1102     free(link->dest);
 1103     link->dest = d;
 1104     return ISO_SUCCESS;
 1105 }
 1106 
 1107 /**
 1108  * Sets the order in which a node will be written on image. High weihted files
 1109  * will be written first, so in a disc them will be written near the center.
 1110  *
 1111  * @param node
 1112  *      The node which weight will be changed. If it's a dir, this function
 1113  *      will change the weight of all its children. For nodes other that dirs
 1114  *      or regular files, this function has no effect.
 1115  * @param w
 1116  *      The weight as a integer number, the greater this value is, the
 1117  *      closer from the beginning of image the file will be written.
 1118  */
 1119 void iso_node_set_sort_weight(IsoNode *node, int w)
 1120 {
 1121     if (node->type == LIBISO_DIR) {
 1122         IsoNode *child = ((IsoDir*)node)->children;
 1123         while (child) {
 1124             iso_node_set_sort_weight(child, w);
 1125             child = child->next;
 1126         }
 1127     } else if (node->type == LIBISO_FILE) {
 1128         ((IsoFile*)node)->sort_weight = w;
 1129         ((IsoFile*)node)->explicit_weight = 1;
 1130     }
 1131 }
 1132 
 1133 /**
 1134  * Get the sort weight of a file.
 1135  */
 1136 int iso_file_get_sort_weight(IsoFile *file)
 1137 {
 1138     return file->sort_weight;
 1139 }
 1140 
 1141 /**
 1142  * Get the size of the file, in bytes
 1143  */
 1144 off_t iso_file_get_size(IsoFile *file)
 1145 {
 1146     return iso_stream_get_size(file->stream);
 1147 }
 1148 
 1149 /**
 1150  * Get the IsoStream that represents the contents of the given IsoFile.
 1151  *
 1152  * If you open() the stream, it should be close() before image generation.
 1153  *
 1154  * @return
 1155  *      The IsoStream. No extra ref is added, so the IsoStream belong to the
 1156  *      IsoFile, and it may be freed together with it. Add your own ref with
 1157  *      iso_stream_ref() if you need it.
 1158  *
 1159  * @since 0.6.4
 1160  */
 1161 IsoStream *iso_file_get_stream(IsoFile *file)
 1162 {
 1163     return file->stream;
 1164 }
 1165 
 1166 /**
 1167  * Get the device id (major/minor numbers) of the given block or
 1168  * character device file. The result is undefined for other kind
 1169  * of special files, of first be sure iso_node_get_mode() returns either
 1170  * S_IFBLK or S_IFCHR.
 1171  *
 1172  * @since 0.6.6
 1173  */
 1174 dev_t iso_special_get_dev(IsoSpecial *special)
 1175 {
 1176     return special->dev;
 1177 }
 1178 
 1179 /**
 1180  * Get the block lba of a file node, if it was imported from an old image.
 1181  *
 1182  * @param file
 1183  *      The file
 1184  * @param lba
 1185  *      Will be filled with the kba
 1186  * @param flag
 1187  *      Reserved for future usage, submit 0
 1188  * @return
 1189  *      1 if lba is valid (file comes from old image), 0 if file was newly
 1190  *      added, i.e. it does not come from an old image, < 0 error
 1191  *
 1192  * @since 0.6.4
 1193  */
 1194 int iso_file_get_old_image_lba(IsoFile *file, uint32_t *lba, int flag)
 1195 {
 1196     int ret;
 1197     int section_count;
 1198     struct iso_file_section *sections = NULL;
 1199 
 1200     if (file == NULL || lba == NULL) {
 1201         return ISO_NULL_POINTER;
 1202     }
 1203     ret = iso_file_get_old_image_sections(file, &section_count, &sections, 0);
 1204     if (ret <= 0)
 1205         return ret;
 1206     if (section_count != 1) {
 1207         if (sections != NULL)
 1208             free(sections);
 1209         return ISO_WRONG_ARG_VALUE;
 1210     }
 1211     *lba = sections[0].block;
 1212     free(sections);
 1213     return 1;
 1214 }
 1215 
 1216 
 1217 /*
 1218  * Like iso_file_get_old_image_lba(), but take an IsoNode.
 1219  *
 1220  * @return
 1221  *      1 if lba is valid (file comes from old image), 0 if file was newly
 1222  *      added, i.e. it does not come from an old image, 2 node type has no
 1223  *      LBA (no regular file), < 0 error
 1224  *
 1225  * @since 0.6.4
 1226  */
 1227 int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag)
 1228 {
 1229     if (node == NULL) {
 1230         return ISO_NULL_POINTER;
 1231     }
 1232     if (ISO_NODE_IS_FILE(node)) {
 1233         return iso_file_get_old_image_lba((IsoFile*)node, lba, flag);
 1234     } else {
 1235         return 2;
 1236     }
 1237 }
 1238 
 1239 /**
 1240  * Check if a given name is valid for an iso node.
 1241  *
 1242  * @return
 1243  *     1 if yes, 0 if not
 1244  */
 1245 int iso_node_is_valid_name(const char *name)
 1246 {
 1247     /* a name can't be NULL */
 1248     if (name == NULL) {
 1249         return ISO_NULL_POINTER;
 1250     }
 1251 
 1252     /* guard against the empty string or big names... */
 1253     if (name[0] == '\0')
 1254         goto rr_reserved;
 1255     if (strlen(name) > LIBISOFS_NODE_NAME_MAX)
 1256         return ISO_RR_NAME_TOO_LONG;
 1257 
 1258     /* ...against "." and ".." names... */
 1259     if (!strcmp(name, ".") || !strcmp(name, ".."))
 1260         goto rr_reserved;
 1261 
 1262     /* ...and against names with '/' */
 1263     if (strchr(name, '/') != NULL)
 1264         goto rr_reserved;
 1265 
 1266     return 1;
 1267 
 1268 rr_reserved:;
 1269 /* # define Libisofs_debug_rr_reserveD */
 1270 #ifdef Libisofs_debug_rr_reserveD
 1271     fprintf(stderr, "libisofs_DEBUG: ISO_RR_NAME_RESERVED with '%s'\n", name);
 1272 #endif
 1273     
 1274     return ISO_RR_NAME_RESERVED;
 1275 }
 1276 
 1277 /**
 1278  * Check if a given path is valid for the destination of a link.
 1279  *
 1280  * @return
 1281  *     1 if yes, 0 if not
 1282  */
 1283 int iso_node_is_valid_link_dest(const char *dest)
 1284 {
 1285     int ret;
 1286     char *ptr, *brk_info, *component;
 1287 
 1288     /* a dest can't be NULL */
 1289     if (dest == NULL) {
 1290         return ISO_NULL_POINTER;
 1291     }
 1292 
 1293     /* guard against the empty string or big dest... */
 1294     if (dest[0] == '\0') {
 1295 #ifdef Libisofs_debug_rr_reserveD
 1296         fprintf(stderr, "libisofs_DEBUG: ISO_RR_NAME_RESERVED by empty link target\n");
 1297 #endif
 1298         return ISO_RR_NAME_RESERVED;
 1299     }
 1300     if (strlen(dest) > LIBISOFS_NODE_PATH_MAX)
 1301         return ISO_RR_PATH_TOO_LONG;
 1302 
 1303     /* check that all components are valid */
 1304     if (!strcmp(dest, "/")) {
 1305         /* "/" is a valid component */
 1306         return 1;
 1307     }
 1308 
 1309     ptr = strdup(dest);
 1310     if (ptr == NULL) {
 1311         return ISO_OUT_OF_MEM;
 1312     }
 1313 
 1314     ret = 1;
 1315     component = strtok_r(ptr, "/", &brk_info);
 1316     while (component) {
 1317         if (strcmp(component, ".") && strcmp(component, "..")) {
 1318             ret = iso_node_is_valid_name(component);
 1319             if (ret < 0) {
 1320                 break;
 1321             }
 1322         }
 1323         component = strtok_r(NULL, "/", &brk_info);
 1324     }
 1325     free(ptr);
 1326 
 1327     return ret;
 1328 }
 1329 
 1330 void iso_dir_find(IsoDir *dir, const char *name, IsoNode ***pos)
 1331 {
 1332     *pos = &(dir->children);
 1333     while (**pos != NULL && strcmp((**pos)->name, name) < 0) {
 1334         *pos = &((**pos)->next);
 1335     }
 1336 }
 1337 
 1338 int iso_dir_exists(IsoDir *dir, const char *name, IsoNode ***pos)
 1339 {
 1340     IsoNode **node;
 1341 
 1342     iso_dir_find(dir, name, &node);
 1343     if (pos) {
 1344         *pos = node;
 1345     }
 1346     return (*node != NULL && !strcmp((*node)->name, name)) ? 1 : 0;
 1347 }
 1348 
 1349 int iso_dir_insert(IsoDir *dir, IsoNode *node, IsoNode **pos,
 1350                    enum iso_replace_mode replace)
 1351 {
 1352     if (*pos != NULL && !strcmp((*pos)->name, node->name)) {
 1353         /* a node with same name already exists */
 1354         switch(replace) {
 1355         case ISO_REPLACE_NEVER:
 1356             return ISO_NODE_NAME_NOT_UNIQUE;
 1357         case ISO_REPLACE_IF_NEWER:
 1358             if ((*pos)->mtime >= node->mtime) {
 1359                 /* old file is newer */
 1360                 return ISO_NODE_NAME_NOT_UNIQUE;
 1361             }
 1362             break;
 1363         case ISO_REPLACE_IF_SAME_TYPE_AND_NEWER:
 1364             if ((*pos)->mtime >= node->mtime) {
 1365                 /* old file is newer */
 1366                 return ISO_NODE_NAME_NOT_UNIQUE;
 1367             }
 1368             if ((node->mode & S_IFMT) != ((*pos)->mode & S_IFMT)) {
 1369                 /* different file types */
 1370                 return ISO_NODE_NAME_NOT_UNIQUE;
 1371             }
 1372             break;
 1373         case ISO_REPLACE_IF_SAME_TYPE:
 1374             if ((node->mode & S_IFMT) != ((*pos)->mode & S_IFMT)) {
 1375                 /* different file types */
 1376                 return ISO_NODE_NAME_NOT_UNIQUE;
 1377             }
 1378             break;
 1379         case ISO_REPLACE_ALWAYS:
 1380             break;
 1381         default:
 1382             /* CAN'T HAPPEN */
 1383             return ISO_ASSERT_FAILURE;
 1384         }
 1385 
 1386         /* if we are reach here we have to replace */
 1387         node->next = (*pos)->next;
 1388         (*pos)->parent = NULL;
 1389         (*pos)->next = NULL;
 1390         iso_node_unref(*pos);
 1391         *pos = node;
 1392         node->parent = dir;
 1393         return dir->nchildren;
 1394     }
 1395 
 1396     node->next = *pos;
 1397     *pos = node;
 1398     node->parent = dir;
 1399 
 1400     return ++dir->nchildren;
 1401 }
 1402 
 1403 /* iterators are stored in a linked list */
 1404 struct iter_reg_node {
 1405     IsoDirIter *iter;
 1406     struct iter_reg_node *next;
 1407 };
 1408 
 1409 /* list header */
 1410 static
 1411 struct iter_reg_node *iter_reg = NULL;
 1412 
 1413 /**
 1414  * Add a new iterator to the registry. The iterator register keeps track of
 1415  * all iterators being used, and are notified when directory structure
 1416  * changes.
 1417  */
 1418 int iso_dir_iter_register(IsoDirIter *iter)
 1419 {
 1420     struct iter_reg_node *new;
 1421     new = malloc(sizeof(struct iter_reg_node));
 1422     if (new == NULL) {
 1423         return ISO_OUT_OF_MEM;
 1424     }
 1425     new->iter = iter;
 1426     new->next = iter_reg;
 1427     iter_reg = new;
 1428     return ISO_SUCCESS;
 1429 }
 1430 
 1431 /**
 1432  * Unregister a directory iterator.
 1433  */
 1434 void iso_dir_iter_unregister(IsoDirIter *iter)
 1435 {
 1436     struct iter_reg_node **pos;
 1437     pos = &iter_reg;
 1438     while (*pos != NULL && (*pos)->iter != iter) {
 1439         pos = &(*pos)->next;
 1440     }
 1441     if (*pos) {
 1442         struct iter_reg_node *tmp = (*pos)->next;
 1443         free(*pos);
 1444         *pos = tmp;
 1445     }
 1446 }
 1447 
 1448 void iso_notify_dir_iters(IsoNode *node, int flag)
 1449 {
 1450     struct iter_reg_node *pos = iter_reg;
 1451     while (pos != NULL) {
 1452         IsoDirIter *iter = pos->iter;
 1453         if (iter->dir == node->parent) {
 1454             iter->class->notify_child_taken(iter, node);
 1455         }
 1456         pos = pos->next;
 1457     }
 1458 }
 1459 
 1460 int iso_node_new_root(IsoDir **root)
 1461 {
 1462     IsoDir *dir;
 1463     time_t now;
 1464 
 1465     dir = calloc(1, sizeof(IsoDir));
 1466     if (dir == NULL) {
 1467         return ISO_OUT_OF_MEM;
 1468     }
 1469     dir->node.refcount = 1;
 1470     dir->node.type = LIBISO_DIR;
 1471     iso_nowtime(&now, 0);
 1472     dir->node.atime = dir->node.ctime = dir->node.mtime = now;
 1473     dir->node.mode = S_IFDIR | 0555;
 1474 
 1475     /* set parent to itself, to prevent root to be added to another dir */
 1476     dir->node.parent = dir;
 1477     *root = dir;
 1478     return ISO_SUCCESS;
 1479 }
 1480 
 1481 int iso_node_new_dir(char *name, IsoDir **dir)
 1482 {
 1483     IsoDir *new;
 1484     int ret;
 1485 
 1486     if (dir == NULL || name == NULL) {
 1487         return ISO_NULL_POINTER;
 1488     }
 1489 
 1490     /* check if the name is valid */
 1491     ret = iso_node_is_valid_name(name);
 1492     if (ret < 0)
 1493         return ret;
 1494 
 1495     new = calloc(1, sizeof(IsoDir));
 1496     if (new == NULL) {
 1497         return ISO_OUT_OF_MEM;
 1498     }
 1499     new->node.refcount = 1;
 1500     new->node.type = LIBISO_DIR;
 1501     new->node.name = name;
 1502     new->node.mode = S_IFDIR;
 1503     *dir = new;
 1504     return ISO_SUCCESS;
 1505 }
 1506 
 1507 int iso_node_new_file(char *name, IsoStream *stream, IsoFile **file)
 1508 {
 1509     IsoFile *new;
 1510     int ret;
 1511 
 1512     if (file == NULL || name == NULL || stream == NULL) {
 1513         return ISO_NULL_POINTER;
 1514     }
 1515 
 1516     /* check if the name is valid */
 1517     ret = iso_node_is_valid_name(name);
 1518     if (ret < 0)
 1519         return ret;
 1520 
 1521     new = calloc(1, sizeof(IsoFile));
 1522     if (new == NULL) {
 1523         return ISO_OUT_OF_MEM;
 1524     }
 1525     new->node.refcount = 1;
 1526     new->node.type = LIBISO_FILE;
 1527     new->node.name = name;
 1528     new->node.mode = S_IFREG;
 1529     new->from_old_session = 0;
 1530     new->explicit_weight = 0;
 1531     new->sort_weight = 0;
 1532     new->stream = stream;
 1533 
 1534     *file = new;
 1535     return ISO_SUCCESS;
 1536 }
 1537 
 1538 int iso_node_new_symlink(char *name, char *dest, IsoSymlink **link)
 1539 {
 1540     IsoSymlink *new;
 1541     int ret;
 1542 
 1543     if (link == NULL || name == NULL || dest == NULL) {
 1544         return ISO_NULL_POINTER;
 1545     }
 1546 
 1547     /* check if the name is valid */
 1548     ret = iso_node_is_valid_name(name);
 1549     if (ret < 0)
 1550         return ret;
 1551 
 1552     /* check if destination is valid */
 1553     ret = iso_node_is_valid_link_dest(dest);
 1554     if (ret < 0) 
 1555         return ret;
 1556 
 1557     new = calloc(1, sizeof(IsoSymlink));
 1558     if (new == NULL) {
 1559         return ISO_OUT_OF_MEM;
 1560     }
 1561     new->node.refcount = 1;
 1562     new->node.type = LIBISO_SYMLINK;
 1563     new->node.name = name;
 1564     new->dest = dest;
 1565     new->node.mode = S_IFLNK;
 1566     new->fs_id = 0;
 1567     new->st_dev = 0;
 1568     new->st_ino = 0;
 1569     *link = new;
 1570     return ISO_SUCCESS;
 1571 }
 1572 
 1573 int iso_node_new_special(char *name, mode_t mode, dev_t dev,
 1574                          IsoSpecial **special)
 1575 {
 1576     IsoSpecial *new;
 1577     int ret;
 1578 
 1579     if (special == NULL || name == NULL) {
 1580         return ISO_NULL_POINTER;
 1581     }
 1582     if (S_ISLNK(mode) || S_ISREG(mode) || S_ISDIR(mode)) {
 1583         return ISO_WRONG_ARG_VALUE;
 1584     }
 1585 
 1586     /* check if the name is valid */
 1587     ret = iso_node_is_valid_name(name);
 1588     if (ret < 0)
 1589         return ret;
 1590 
 1591     new = calloc(1, sizeof(IsoSpecial));
 1592     if (new == NULL) {
 1593         return ISO_OUT_OF_MEM;
 1594     }
 1595     new->node.refcount = 1;
 1596     new->node.type = LIBISO_SPECIAL;
 1597     new->node.name = name;
 1598 
 1599     new->node.mode = mode;
 1600     new->dev = dev;
 1601     new->fs_id = 0;
 1602     new->st_dev = 0;
 1603     new->st_ino = 0;
 1604     *special = new;
 1605     return ISO_SUCCESS;
 1606 }
 1607 
 1608 
 1609 /* @param flag    bit0= inverse: cleanout everything but del_name
 1610 */
 1611 static
 1612 int attrs_cleanout_name(char *del_name, size_t *num_attrs, char **names,
 1613                         size_t *value_lengths, char **values, int flag)
 1614 {
 1615     size_t i, w;
 1616 
 1617     for (w = i = 0; i < *num_attrs; i++) {
 1618         if ((strcmp(names[i], del_name) == 0) ^ (flag & 1)) {
 1619             if (names[i] != NULL)
 1620                 free(names[i]);
 1621             if (values[i] != NULL)
 1622                 free(values[i]);
 1623              names[i] = values[i] = NULL;
 1624     continue;
 1625         }
 1626         if (w == i) {
 1627             w++;
 1628     continue;
 1629         }
 1630         names[w] = names[i];
 1631         value_lengths[w] = value_lengths[i];
 1632         values[w] = values[i];
 1633         names[i] = values[i] = NULL;
 1634         value_lengths[i] = 0;
 1635         w++;
 1636     }
 1637     *num_attrs = w;
 1638     return 1;
 1639 }
 1640 
 1641 
 1642 /**
 1643  * Backend of iso_node_get_attrs() with parameter node replaced by the
 1644  * AAIP string from where to get the attribute list.
 1645  * All other parameter specs apply.
 1646  */
 1647 int iso_aa_get_attrs(unsigned char *aa_string, size_t *num_attrs,
 1648               char ***names, size_t **value_lengths, char ***values, int flag)
 1649 {
 1650     struct aaip_state *aaip= NULL;
 1651     unsigned char *rpt;
 1652     size_t len, todo, consumed;
 1653     int is_done = 0, first_round= 1, ret;
 1654 
 1655     if (flag & (1 << 15))
 1656         aaip_get_decoded_attrs(&aaip, num_attrs, names,
 1657                                value_lengths, values, 1 << 15);
 1658     *num_attrs = 0;
 1659     *names = NULL;
 1660     *value_lengths = NULL;
 1661     *values = NULL;
 1662     if (flag & (1 << 15))
 1663         return 1;
 1664 
 1665     rpt = aa_string;
 1666     len = aaip_count_bytes(rpt, 0);
 1667     while (!is_done) {
 1668         todo = len - (rpt - aa_string);
 1669         if (todo > 2048)
 1670             todo = 2048;
 1671         if (todo == 0) {
 1672            /* Out of data while still prompted to submit */
 1673            ret = ISO_AAIP_BAD_AASTRING;
 1674            goto ex;
 1675         }
 1676         /* Allow 1 million bytes of memory consumption, 100,000 attributes */
 1677         ret = aaip_decode_attrs(&aaip, (size_t) 1000000, (size_t) 100000,
 1678                                 rpt, todo, &consumed, first_round);
 1679         rpt+= consumed;
 1680         first_round= 0;
 1681         if (ret == 1)
 1682             continue;
 1683         if (ret == 2)
 1684              break;
 1685 
 1686          /* aaip_decode_attrs() reports error */
 1687          ret = ISO_AAIP_BAD_AASTRING;
 1688          goto ex;
 1689     }
 1690 
 1691     if ((size_t) (rpt - aa_string) != len) {
 1692          /* aaip_decode_attrs() returns 2 but still bytes are left */
 1693          ret = ISO_AAIP_BAD_AASTRING;
 1694          goto ex;
 1695     }
 1696 
 1697     ret = aaip_get_decoded_attrs(&aaip, num_attrs, names,
 1698                                  value_lengths, values, 0);
 1699     if (ret != 1) {
 1700          /* aaip_get_decoded_attrs() failed */
 1701          ret = ISO_AAIP_BAD_AASTRING;
 1702          goto ex;
 1703     }
 1704     if (!(flag & 1)) {
 1705         /* Clean out eventual ACL attribute resp. all other xattr */
 1706         attrs_cleanout_name("", num_attrs, *names, *value_lengths, *values,
 1707                             !!(flag & 4));
 1708     }
 1709 
 1710     ret = 1;
 1711 ex:;
 1712     aaip_decode_attrs(&aaip, (size_t) 1000000, (size_t) 100000,
 1713                       rpt, todo, &consumed, 1 << 15);
 1714     return ret;
 1715 }
 1716 
 1717 
 1718 /**
 1719  * Search given name. Eventually calloc() and copy value. Add trailing 0 byte
 1720  * for caller convenience.
 1721  *
 1722  * @return 1= found , 0= not found , <0 error
 1723  */
 1724 int iso_aa_lookup_attr(unsigned char *aa_string, char *name,
 1725                        size_t *value_length, char **value, int flag)
 1726 {
 1727     size_t num_attrs = 0, *value_lengths = NULL;
 1728     char **names = NULL, **values = NULL;
 1729     int i, ret = 0, found = 0;
 1730 
 1731     ret = iso_aa_get_attrs(aa_string, &num_attrs, &names,
 1732                            &value_lengths, &values, 0);
 1733     if (ret < 0)
 1734         return ret;
 1735     for (i = 0; i < (int) num_attrs; i++) {
 1736         if (strcmp(names[i], name))
 1737     continue;
 1738         *value_length = value_lengths[i];
 1739         *value = calloc(*value_length + 1, 1);
 1740         if (*value == NULL) {
 1741             found = ISO_OUT_OF_MEM;
 1742     break;
 1743         }
 1744         if (*value_length > 0)
 1745             memcpy(*value, values[i], *value_length);
 1746         (*value)[*value_length] = 0;
 1747         found = 1;
 1748     break;
 1749     }
 1750     iso_aa_get_attrs(aa_string, &num_attrs, &names,
 1751                      &value_lengths, &values, 1 << 15);
 1752     return found;
 1753 }
 1754 
 1755 
 1756 /* API */
 1757 int iso_node_lookup_attr(IsoNode *node, char *name,
 1758                          size_t *value_length, char **value, int flag)
 1759 {
 1760     void *xipt;
 1761     unsigned char *aa_string = NULL;
 1762     int ret;
 1763 
 1764     *value_length= 0;
 1765     *value= NULL;
 1766     ret = iso_node_get_xinfo(node, aaip_xinfo_func, &xipt);
 1767     if (ret != 1)
 1768         return 0;
 1769     aa_string = (unsigned char *) xipt;
 1770     ret = iso_aa_lookup_attr(aa_string, name, value_length, value, 0);
 1771     return ret;
 1772 }
 1773 
 1774 
 1775 /* API */
 1776 int iso_node_get_attrs(IsoNode *node, size_t *num_attrs,
 1777               char ***names, size_t **value_lengths, char ***values, int flag)
 1778 {
 1779     void *xipt;
 1780     unsigned char *aa_string = NULL;
 1781     int ret;
 1782 
 1783     if (flag & (1 << 15)) {
 1784         iso_aa_get_attrs(aa_string, num_attrs, names, value_lengths, values,
 1785                          1 << 15);
 1786         return 1;
 1787     }
 1788     *num_attrs = 0;
 1789     *names = NULL;
 1790     *value_lengths = NULL;
 1791     *values = NULL;
 1792     ret = iso_node_get_xinfo(node, aaip_xinfo_func, &xipt);
 1793     if (ret != 1)
 1794         return 1;
 1795     aa_string = (unsigned char *) xipt;
 1796     ret = iso_aa_get_attrs(aa_string, num_attrs, names, value_lengths, values,
 1797                            flag);
 1798     return ret;
 1799 }
 1800 
 1801 
 1802 /* Enlarge attribute list */
 1803 static
 1804 int attr_enlarge_list(char ***names, size_t **value_lengths, char ***values,
 1805                       size_t new_num, int flag)
 1806 {
 1807     void *newpt;
 1808 
 1809     newpt = realloc(*names, new_num * sizeof(char *));
 1810     if (newpt == NULL) 
 1811         return ISO_OUT_OF_MEM;
 1812     *names = (char **) newpt;
 1813     newpt = realloc(*values, new_num * sizeof(char *));
 1814     if (newpt == NULL) 
 1815         return ISO_OUT_OF_MEM;
 1816     *values = (char **) newpt;
 1817     newpt = realloc(*value_lengths, new_num * sizeof(size_t));
 1818     if (newpt == NULL) 
 1819         return ISO_OUT_OF_MEM;
 1820     *value_lengths = (size_t *) newpt;
 1821     return 1;
 1822 }
 1823 
 1824 
 1825 /* Merge attribute list of node and given new attribute list into
 1826    attribute list returned by  m_* parameters.
 1827    The m_* parameters have finally to be freed by a call with bit15 set.
 1828    @param flag          Bitfield for control purposes
 1829                         bit0= delete all old names which begin by "user."     
 1830                               (but not if bit2 is set)
 1831                         bit2= delete the given names rather than overwrite
 1832                               their content
 1833                         bit3= with bit0: delete all old non-"isofs." names
 1834                         bit4= do not overwrite value of empty name
 1835                         bit5= do not overwrite isofs attributes 
 1836                         bit15= release memory and return 1
 1837 */
 1838 static
 1839 int iso_node_merge_xattr(IsoNode *node, size_t num_attrs, char **names,
 1840                          size_t *value_lengths, char **values,
 1841                          size_t *m_num_attrs, char ***m_names,
 1842                          size_t **m_value_lengths, char ***m_values, int flag)
 1843 {
 1844     int ret;
 1845     size_t new_names = 0, deleted = 0, i, j, w;
 1846 
 1847     if (flag & (1 << 15)) {
 1848         iso_node_get_attrs(node, m_num_attrs, m_names, m_value_lengths,
 1849                            m_values, 1 << 15);
 1850         return 1;
 1851     }
 1852 
 1853     ret = iso_node_get_attrs(node, m_num_attrs, m_names, m_value_lengths,
 1854                              m_values, 1);
 1855     if (ret < 0)
 1856         return ret;
 1857 
 1858     if ((flag & 1) && (!(flag & 4))) {
 1859         /* Delete unmatched settable pairs */
 1860         for (j = 0; j < *m_num_attrs; j++) {
 1861             if (strncmp((*m_names)[j], "isofs.", 6) == 0)
 1862                 continue;
 1863             if (strncmp((*m_names)[j], "user.", 5) != 0 && !(flag & 8))
 1864                 continue;
 1865             for (i = 0; i < num_attrs; i++) {
 1866                 if (names[i] == NULL || (*m_names)[j] == NULL)
 1867                     continue;
 1868                 if (strcmp(names[i], (*m_names)[j]) == 0)
 1869                     break;
 1870             }
 1871             if (i >= num_attrs) {    
 1872                 /* Delete unmatched pair */
 1873                 free((*m_names)[j]);
 1874                 (*m_names)[j] = NULL;
 1875                 deleted++;
 1876             }
 1877         }
 1878     }
 1879 
 1880     /* Handle existing names, count non-existing names */
 1881     for (i = 0; i < num_attrs; i++) {
 1882         if (names[i] == NULL)
 1883             continue;
 1884         if (names[i][0] == 0 && (flag & 16))
 1885             continue;
 1886         if ((flag & 32) && strncmp(names[i], "isofs.", 6) == 0)
 1887             continue;
 1888         for (j = 0; j < *m_num_attrs; j++) {
 1889             if ((*m_names)[j] == NULL)
 1890                 continue;
 1891             if (strcmp(names[i], (*m_names)[j]) == 0) {
 1892                 if ((*m_values)[j] != NULL)
 1893                     free((*m_values)[j]);
 1894                 (*m_values)[j] = NULL;
 1895                 (*m_value_lengths)[j] = 0;
 1896                 if (flag & 4) {
 1897                     /* Delete pair */
 1898                     free((*m_names)[j]);
 1899                     (*m_names)[j] = NULL;
 1900                     deleted++;
 1901                 } else {
 1902                     (*m_values)[j] = calloc(value_lengths[i] + 1, 1);
 1903                     if ((*m_values)[j] == NULL)
 1904                         return ISO_OUT_OF_MEM;
 1905                     memcpy((*m_values)[j], values[i], value_lengths[i]);
 1906                     (*m_values)[j][value_lengths[i]] = 0;
 1907                     (*m_value_lengths)[j] = value_lengths[i];
 1908                 }
 1909                 break;
 1910             }
 1911         }
 1912         if (j >= *m_num_attrs)
 1913             new_names++;
 1914     }
 1915 
 1916     if (new_names > 0 && (flag & 4)) {
 1917 
 1918         /* >>> warn of non-existing name on delete ? */;
 1919 
 1920     } else if (new_names > 0) {
 1921         ret = attr_enlarge_list(m_names, m_value_lengths, m_values,
 1922                                 *m_num_attrs + new_names, 0);
 1923         if (ret < 0)
 1924             return ret;
 1925 
 1926         /* Set new pairs */;
 1927         w = *m_num_attrs;
 1928         for (i = 0; i < num_attrs; i++) {
 1929             if (names[i] == NULL)
 1930                 continue;
 1931             if (names[i][0] == 0 && (flag & 16))
 1932                 continue;
 1933             if ((flag & 32) && strncmp(names[i], "isofs.", 6) == 0)
 1934                 continue;
 1935             for (j = 0; j < *m_num_attrs; j++) {
 1936                 if ((*m_names)[j] == NULL)
 1937                     continue;
 1938                 if (strcmp(names[i], (*m_names)[j]) == 0)
 1939                     continue;
 1940             }
 1941             if (j < *m_num_attrs) /* Name is not new */ 
 1942                 continue;
 1943             (*m_names)[w] = strdup(names[i]);
 1944             if ((*m_names)[w] == NULL)
 1945                 return ISO_OUT_OF_MEM;
 1946             (*m_values)[w] = calloc(value_lengths[i] + 1, 1);
 1947             if ((*m_values)[w] == NULL)
 1948                 return ISO_OUT_OF_MEM;
 1949             memcpy((*m_values)[w], values[i], value_lengths[i]);
 1950             (*m_values)[w][value_lengths[i]] = 0;
 1951             (*m_value_lengths)[w] = value_lengths[i];
 1952             w++;
 1953         }
 1954         *m_num_attrs = w;
 1955     }
 1956     if (deleted > 0) {
 1957         /* Garbage collection */
 1958         w = 0;
 1959         for (j = 0; j < *m_num_attrs; j++) {
 1960             if ((*m_names)[j] == NULL)
 1961                 continue;
 1962             (*m_names)[w] = (*m_names)[j];
 1963             (*m_values)[w] = (*m_values)[j];
 1964             (*m_value_lengths)[w] = (*m_value_lengths)[j];
 1965             w++;
 1966         }
 1967         *m_num_attrs = w;
 1968     }
 1969     return 1;
 1970 }
 1971 
 1972 
 1973 int iso_node_set_attrs(IsoNode *node, size_t num_attrs, char **names,
 1974                        size_t *value_lengths, char **values, int flag)
 1975 {
 1976     int ret, acl_saved = 0;
 1977     ssize_t sret;
 1978     size_t result_len, m_num = 0, *m_value_lengths = NULL, i;
 1979     unsigned char *result = NULL;
 1980     char *a_acl = NULL, *d_acl = NULL, **m_names = NULL, **m_values = NULL;
 1981 
 1982     if (!(flag & 8))
 1983         for (i = 0; i < num_attrs; i++)
 1984             if (strncmp(names[i], "user.", 5) != 0 && names[i][0] != 0) 
 1985                 return ISO_AAIP_NON_USER_NAME;  
 1986     if ((flag & (2 | 4 | 16)) || !(flag & 8)) {
 1987         /* Merge old and new lists */
 1988         ret = iso_node_merge_xattr(
 1989                   node, num_attrs, names, value_lengths, values,
 1990                   &m_num, &m_names, &m_value_lengths, &m_values,
 1991                   (flag & 4) | (!(flag & 2)) | ((!(flag & 1)) << 4) |
 1992                   ((flag & 16) << 1) | (flag & 8));
 1993         if (ret < 0)
 1994             goto ex;
 1995         num_attrs = m_num;
 1996         names = m_names;
 1997         value_lengths = m_value_lengths;
 1998         values = m_values;
 1999     } else if (!(flag & 1)) {
 2000         iso_node_get_acl_text(node, &a_acl, &d_acl, 16);
 2001         acl_saved = 1;
 2002     }
 2003 
 2004     if (num_attrs == 0) {
 2005         ret = iso_node_remove_xinfo(node, aaip_xinfo_func);
 2006         if (ret < 0)
 2007             goto ex;
 2008         if (acl_saved && (a_acl != NULL || d_acl != NULL)) {
 2009             ret = iso_node_set_acl_text(node, a_acl, d_acl, 0);
 2010             if (ret < 0)
 2011                 goto ex;
 2012         }
 2013         ret = 1;
 2014         goto ex;
 2015     }
 2016     sret = aaip_encode(num_attrs, names, value_lengths, values,
 2017                        &result_len, &result, 0);
 2018     if (sret < 0) {
 2019         ret = sret;
 2020         goto ex;
 2021     }
 2022 
 2023     ret = iso_node_remove_xinfo(node, aaip_xinfo_func);
 2024     if (ret < 0) {
 2025         if (result != NULL)
 2026             free(result);
 2027         goto ex;
 2028     }
 2029     if (sret > 0) {
 2030         ret = iso_node_add_xinfo(node, aaip_xinfo_func, result);
 2031         if (ret < 0)
 2032             goto ex;
 2033         if (ret == 0) {
 2034 
 2035             /* >>> something is messed up with xinfo:
 2036                    an aa_string still exists */;
 2037 
 2038             ret = ISO_ERROR;
 2039             goto ex;
 2040         }
 2041         if (acl_saved) {
 2042             ret = iso_node_set_acl_text(node, a_acl, d_acl, 0);
 2043             if (ret < 0)
 2044                 goto ex;
 2045         }
 2046     }
 2047     ret = 1;
 2048 ex:;
 2049     /* Dispose eventual merged list */
 2050     iso_node_merge_xattr(node, num_attrs, names, value_lengths, values,
 2051                        &m_num, &m_names, &m_value_lengths, &m_values, 1 << 15);
 2052     return ret;
 2053 } 
 2054 
 2055 
 2056 static
 2057 int iso_decode_acl(unsigned char *v_data, size_t v_len, size_t *consumed,
 2058                    char **text, size_t *text_fill, int flag)
 2059 {
 2060     int ret;
 2061 
 2062     *text= NULL;
 2063     ret = aaip_decode_acl(v_data, v_len,
 2064                           consumed, NULL, (size_t) 0, text_fill, 1);
 2065     if (ret <= 0)
 2066         return 0;
 2067     if (*text_fill == 0)
 2068         return ret;
 2069     *text = calloc(*text_fill + 42, 1); /* 42 for aaip_update_acl_st_mode */
 2070     if (*text == NULL)
 2071         return ISO_OUT_OF_MEM;
 2072     ret = aaip_decode_acl(v_data, v_len,
 2073                           consumed, *text, *text_fill, text_fill, 0);
 2074     if (ret <= 0) {
 2075         free(*text);
 2076         *text= NULL;
 2077         return 0;
 2078     }
 2079     return ret;
 2080 }
 2081 
 2082 
 2083 /**
 2084  * Backend of iso_node_get_acl_text() with parameter node replaced by the
 2085  * attribute list from where to get the ACL and by the associated st_mode
 2086  * permission bits. All other parameter specs apply.
 2087  */
 2088 static
 2089 int iso_attr_get_acl_text(size_t num_attrs, char **names,
 2090                           size_t *value_lengths, char **values, mode_t st_mode,
 2091                           char **access_text, char **default_text, int flag)
 2092 {
 2093     size_t i, consumed, text_fill = 0;
 2094     size_t v_len;
 2095     unsigned char *v_data;
 2096     int ret, from_posix= 0;
 2097 
 2098     if (flag & (1 << 15)) {
 2099         if (*access_text != NULL)
 2100             free(*access_text);
 2101         *access_text = NULL;
 2102         if (*default_text != NULL)
 2103             free(*default_text);
 2104         *default_text = NULL;
 2105         return 1;
 2106     }
 2107 
 2108     *access_text = *default_text = NULL;
 2109     for(i = 0; i < num_attrs; i++) {
 2110         if (names[i][0]) /* searching the empty name */
 2111             continue;
 2112 
 2113         v_data = (unsigned char *) values[i];
 2114         v_len = value_lengths[i];
 2115 
 2116         /* "access" ACL  */
 2117         ret = iso_decode_acl(v_data, v_len,
 2118                              &consumed, access_text, &text_fill, 0);
 2119         if (ret <= 0)
 2120             goto bad_decode;
 2121         if (ret == 2) {
 2122             v_data += consumed;
 2123             v_len -= consumed;
 2124             ret = iso_decode_acl(v_data, v_len,
 2125                                  &consumed, default_text, &text_fill, 0);
 2126             if (ret == 0)
 2127                 goto bad_decode;
 2128         }
 2129         break;
 2130     }
 2131     
 2132     if (*access_text == NULL && !(flag & 16)) {
 2133         from_posix = 1;
 2134         *access_text = calloc(42, 1); /* 42 for aaip_update_acl_st_mode */
 2135     }
 2136     if (*access_text != NULL) {
 2137         aaip_add_acl_st_mode(*access_text, st_mode, 0);
 2138         text_fill = strlen(*access_text);
 2139     }
 2140 
 2141     if (*access_text == NULL && *default_text == NULL)
 2142         ret = 0;
 2143     else
 2144         ret = 1 + from_posix;
 2145 ex:;
 2146     return ret;
 2147 
 2148 bad_decode:;
 2149     ret = ISO_AAIP_BAD_ACL;
 2150     goto ex;
 2151 }
 2152 
 2153 
 2154 int iso_node_get_acl_text(IsoNode *node,
 2155                           char **access_text, char **default_text, int flag)
 2156 {
 2157     size_t num_attrs = 0, *value_lengths = NULL;
 2158     char **names = NULL, **values = NULL;
 2159     mode_t st_mode = 0;
 2160     int ret;
 2161 
 2162     if (flag & (1 << 15)) {
 2163         iso_attr_get_acl_text(num_attrs, names, value_lengths, values, st_mode,
 2164                               access_text, default_text, 1 << 15);
 2165         return 1;
 2166     }
 2167     ret = iso_node_get_attrs(node, &num_attrs, &names,
 2168                              &value_lengths, &values, 1);
 2169     if (ret < 0)
 2170         return ret;
 2171     st_mode = iso_node_get_permissions(node);
 2172     ret = iso_attr_get_acl_text(num_attrs, names, value_lengths, values,
 2173                                 st_mode, access_text, default_text, flag);
 2174     iso_node_get_attrs(node, &num_attrs, &names,
 2175                        &value_lengths, &values, 1 << 15); /* free memory */
 2176     return ret;
 2177 }
 2178 
 2179 
 2180 int iso_aa_get_acl_text(unsigned char *aa_string, mode_t st_mode,
 2181                         char **access_text, char **default_text, int flag)
 2182 {
 2183     int ret;
 2184     size_t num_attrs = 0, *value_lengths = NULL;
 2185     char **names = NULL, **values = NULL;
 2186 
 2187     if (flag & (1 << 15)) {
 2188         iso_attr_get_acl_text(num_attrs, names, value_lengths, values, st_mode,
 2189                               access_text, default_text, 1 << 15);
 2190         return 1;
 2191     }
 2192     ret = iso_aa_get_attrs(aa_string, &num_attrs, &names,
 2193                            &value_lengths, &values, 1);
 2194     if (ret < 0)
 2195         goto ex;
 2196     ret = iso_attr_get_acl_text(num_attrs, names, value_lengths, values,
 2197                                 st_mode, access_text, default_text, flag);
 2198 ex:;
 2199     iso_aa_get_attrs(aa_string, &num_attrs, &names, &value_lengths, &values,
 2200                      1 << 15);
 2201     return ret;
 2202 }
 2203 
 2204 
 2205 int iso_node_set_acl_text(IsoNode *node, char *access_text, char *default_text,
 2206                           int flag)
 2207 {
 2208     size_t num_attrs = 0, *value_lengths = NULL, i, j, consumed;
 2209     size_t a_text_fill = 0, d_text_fill = 0;
 2210     size_t v_len, acl_len= 0;
 2211     char **names = NULL, **values = NULL, *a_text = NULL, *d_text = NULL;
 2212 
 2213     unsigned char *v_data, *acl= NULL;
 2214     int ret;
 2215     mode_t st_mode;
 2216 
 2217     st_mode = iso_node_get_permissions(node);
 2218     if (!(flag & 2)) { /* want not to update ACL by st_mode */
 2219 
 2220         /* >>> validate and rectify text */;
 2221 
 2222     }
 2223 
 2224     ret = iso_node_get_attrs(node, &num_attrs, &names,
 2225                              &value_lengths, &values, 1);
 2226     if (ret < 0)
 2227         return ret;
 2228 
 2229     for(i = 0; i < num_attrs; i++) {
 2230         if (names[i][0]) /* searching the empty name */
 2231             continue;
 2232         v_data = (unsigned char *) values[i];
 2233         v_len = value_lengths[i];
 2234         if (flag & 2) { /* update "access" ACL by st_mode */
 2235             /* read "access" ACL */
 2236             ret = iso_decode_acl(v_data, v_len, &consumed,
 2237                                  &a_text, &a_text_fill, 0);
 2238             if (ret == 0)
 2239                 goto bad_decode;
 2240             if (ret < 0)
 2241                 goto ex;
 2242             if (ret == 2) {
 2243                 /* read "default" ACL */
 2244                 v_data += consumed;
 2245                 v_len -= consumed;
 2246                 ret = iso_decode_acl(v_data, v_len, &consumed, &d_text,
 2247                                      &d_text_fill, 0);
 2248                 if (ret == 0)
 2249                     goto bad_decode;
 2250                 if (ret < 0)
 2251                     goto ex;
 2252             }
 2253             /* Update "access" ACL by st_mode */
 2254             if (a_text == NULL) {
 2255                 ret = 1;
 2256                 goto ex;
 2257             }
 2258             ret = aaip_cleanout_st_mode(a_text, &st_mode,  8);
 2259             if (ret < 0) {
 2260                 ret = ISO_AAIP_BAD_ACL_TEXT;
 2261                 goto ex;
 2262             }
 2263             ret = aaip_encode_both_acl(a_text, d_text, st_mode,
 2264                                        &acl_len, &acl,
 2265                                        2 | 8 | ((flag & 4) << 2));
 2266         } else {
 2267             ret = 1;
 2268             if (access_text != NULL || default_text != NULL)
 2269                 ret = aaip_encode_both_acl(access_text, default_text, st_mode,
 2270                                            &acl_len, &acl,
 2271                                            2 | 8 | ((flag & 4) << 2));
 2272         }
 2273         if (ret == -1)
 2274             ret = ISO_OUT_OF_MEM;
 2275         else if (ret <= 0 && ret >= -3)
 2276             ret = ISO_AAIP_BAD_ACL_TEXT;
 2277         if (ret <= 0)
 2278             goto ex;
 2279 
 2280         if(acl == NULL) { /* Delete whole ACL attribute */
 2281             /* Update S_IRWXG by eventual "group::" ACL entry.
 2282                With ACL it reflected the "mask::" entry.
 2283             */
 2284             if (a_text != NULL)
 2285                 free(a_text);
 2286             ret = iso_decode_acl(v_data, v_len, &consumed,
 2287                                  &a_text, &a_text_fill, 0);
 2288             if (ret == 0)
 2289                 goto bad_decode;
 2290             if (ret < 0)
 2291                 goto ex;
 2292             ret = aaip_cleanout_st_mode(a_text, &st_mode, 4 | 16);
 2293             if (ret < 0)
 2294                 goto ex;
 2295             iso_node_set_perms_internal(node, st_mode, 1);
 2296 
 2297             /* Delete the attribute pair */
 2298             if (values[i] != NULL)
 2299                 free(values[i]);
 2300             for (j = i + 1; j < num_attrs; j++) {
 2301                  names[j - 1] = names[j];
 2302                  value_lengths[j - 1] = value_lengths[j];
 2303                  values[j - 1] = values[j];
 2304             }
 2305             num_attrs--;
 2306         } else {
 2307             /* replace variable value */;
 2308             if (values[i] != NULL)
 2309                 free(values[i]);
 2310             values[i] = (char *) acl;
 2311             acl = NULL;
 2312             value_lengths[i] = acl_len;
 2313         }
 2314 
 2315         /* Encode attributes and attach to node */
 2316         ret = iso_node_set_attrs(node, num_attrs, names, value_lengths, values,
 2317                                  1 | 8);
 2318         if (ret <= 0)
 2319             goto ex;
 2320         goto update_perms;
 2321     }
 2322 
 2323     /* There is no ACL yet */
 2324     if ((flag & 2) || (access_text == NULL && default_text == NULL)) {
 2325         /* thus no need to update ACL by st_mode or to delete ACL */
 2326         ret = 1;
 2327         goto ex;
 2328     }
 2329     ret = aaip_encode_both_acl(access_text, default_text,
 2330                                st_mode, &acl_len, &acl,
 2331                                2 | 8 | ((flag & 4) << 2));
 2332     if (ret < -3)
 2333         goto ex;
 2334     if (ret <= 0) {
 2335         ret = ISO_AAIP_BAD_ACL_TEXT;
 2336         goto ex;
 2337     }
 2338 
 2339     ret = attr_enlarge_list(&names, &value_lengths, &values, num_attrs + 1, 0);
 2340     if (ret < 0)
 2341         goto ex;
 2342 
 2343     /* Set new ACL attribute */
 2344     names[num_attrs] = strdup("");
 2345     if (names[num_attrs] == NULL) {
 2346         ret = ISO_OUT_OF_MEM;
 2347         goto ex;
 2348     }
 2349     values[num_attrs] = (char *) acl;
 2350     acl = NULL;
 2351     value_lengths[num_attrs] = acl_len;
 2352     num_attrs++;
 2353     
 2354     /* Encode attributes and attach to node */
 2355     ret = iso_node_set_attrs(node, num_attrs, names, value_lengths, values,
 2356                              1 | 8);
 2357     if (ret < 0)
 2358         goto ex;
 2359 
 2360 update_perms:;
 2361     if(access_text != NULL && !(flag & (1 | 2))) {
 2362         /* Update node permissions by acl_text */
 2363         st_mode = iso_node_get_permissions(node);
 2364         ret = aaip_cleanout_st_mode(access_text, &st_mode, 4);
 2365         if (ret < 0) {
 2366             ret = ISO_AAIP_BAD_ACL_TEXT;
 2367             goto ex;
 2368         }
 2369         iso_node_set_perms_internal(node, st_mode, 1);
 2370     }
 2371 
 2372     ret = 1;
 2373 ex:;
 2374     iso_node_get_attrs(node, &num_attrs, &names,
 2375                        &value_lengths, &values, 1 << 15); /* free memory */
 2376     if (a_text != NULL)
 2377         free(a_text);
 2378     if (d_text != NULL)
 2379         free(d_text);
 2380     if(acl != NULL)
 2381        free(acl);
 2382     return ret;
 2383 
 2384 bad_decode:;
 2385     ret = ISO_AAIP_BAD_ACL;
 2386     goto ex;
 2387 }
 2388 
 2389 
 2390 mode_t iso_node_get_perms_wo_acl(const IsoNode *node)
 2391 {
 2392     mode_t st_mode;
 2393     int ret;
 2394     char *a_text = NULL, *d_text = NULL;
 2395 
 2396     st_mode = iso_node_get_permissions(node);
 2397 
 2398     ret = iso_node_get_acl_text((IsoNode *) node, &a_text, &d_text, 16);
 2399     if (ret != 1) 
 2400         goto ex;
 2401     aaip_cleanout_st_mode(a_text, &st_mode, 4 | 16);
 2402 ex:;
 2403     iso_node_get_acl_text((IsoNode *) node, &a_text, &d_text, 1 << 15);
 2404     return st_mode;
 2405 }
 2406 
 2407 
 2408 /* Function to identify and manage ZF parameters.
 2409  * data is supposed to be a pointer to struct zisofs_zf_info
 2410  */
 2411 int zisofs_zf_xinfo_func(void *data, int flag)
 2412 {
 2413     if (flag & 1) {
 2414         free(data);
 2415     }
 2416     return 1;
 2417 }
 2418 
 2419 /* The iso_node_xinfo_cloner function which gets associated to
 2420  * zisofs_zf_xinfo_func by iso_init() resp. iso_init_with_flag() via
 2421  * iso_node_xinfo_make_clonable()
 2422  */
 2423 int zisofs_zf_xinfo_cloner(void *old_data, void **new_data, int flag)
 2424 {
 2425     *new_data = NULL;
 2426     if (flag)
 2427         return ISO_XINFO_NO_CLONE;
 2428     if (old_data == NULL)
 2429         return 0;
 2430     *new_data = calloc(1, sizeof(struct zisofs_zf_info));
 2431     if (*new_data == NULL)
 2432         return ISO_OUT_OF_MEM;
 2433     memcpy(*new_data, old_data, sizeof(struct zisofs_zf_info));
 2434     return (int) sizeof(struct zisofs_zf_info);
 2435 }
 2436 
 2437 /* Checks whether a file effectively bears a zisofs file header and eventually
 2438  * marks this by a struct zisofs_zf_info as xinfo of the file node.
 2439  * @param flag bit0= inquire the most original stream of the file
 2440  *             bit1= permission to overwrite existing zisofs_zf_info
 2441  *             bit2= if no zisofs header is found:
 2442  *                   create xinfo with parameters which indicate no zisofs
 2443  *             bit8-bit15= maximum zisofs version to be recognized (0 means 1)
 2444  * @return 1= zf xinfo added, 0= no zisofs data found ,
 2445  *         2= found existing zf xinfo and flag bit1 was not set
 2446  *         <0 means error
 2447  */
 2448 int iso_file_zf_by_magic(IsoFile *file, int flag)
 2449 {
 2450     int ret, stream_type, header_size_div4, block_size_log2, version;
 2451     uint64_t uncompressed_size;
 2452     IsoStream *stream, *input_stream;
 2453     struct zisofs_zf_info *zf = NULL;
 2454     void *xipt;
 2455     uint8_t algo[2];
 2456 
 2457     /* Intimate friendship with this function in filters/zisofs.c */
 2458     int ziso_is_zisofs_stream(IsoStream *stream, int *stream_type,
 2459                               uint8_t zisofs_algo[2],
 2460                               int *header_size_div4, int *block_size_log2,
 2461                               uint64_t *uncompressed_size, int flag);
 2462 
 2463     ret = iso_node_get_xinfo((IsoNode *) file, zisofs_zf_xinfo_func, &xipt);
 2464     if (ret == 1) {
 2465         if (!(flag & 2))
 2466             return 2;
 2467         ret = iso_node_remove_xinfo((IsoNode *) file, zisofs_zf_xinfo_func);
 2468         if (ret < 0)
 2469             return ret;
 2470     }
 2471     input_stream = stream = iso_file_get_stream(file);
 2472     while (flag & 1) {
 2473         input_stream = iso_stream_get_input_stream(stream, 0);
 2474         if (input_stream == NULL)
 2475     break;
 2476         stream = input_stream;
 2477     }
 2478     version = ((flag >> 8) & 0xff);
 2479     algo[0] = algo[1] = 0;
 2480     ret = ziso_is_zisofs_stream(stream, &stream_type, algo, &header_size_div4,
 2481                                 &block_size_log2, &uncompressed_size, 3);
 2482     if (ret < 0)
 2483         return ret;
 2484     if (version < 2 && ret > 0 && (algo[0] != 'p' || algo[1] != 'z'))
 2485         ret = 0;
 2486     if (ret != 1 || stream_type != 2) {
 2487         if (!(flag & 4))
 2488             return 0;
 2489         algo[0] = algo[1] = 0;
 2490         header_size_div4 = 0;
 2491         block_size_log2 = 0;
 2492         uncompressed_size = 0;
 2493     }
 2494     zf = calloc(1, sizeof(struct zisofs_zf_info));
 2495     if (zf == NULL)
 2496         return ISO_OUT_OF_MEM;
 2497     zf->zisofs_algo[0] = algo[0];
 2498     zf->zisofs_algo[1] = algo[1];
 2499     zf->uncompressed_size = uncompressed_size;
 2500     zf->header_size_div4 = header_size_div4;
 2501     zf->block_size_log2 = block_size_log2;
 2502     ret = iso_node_add_xinfo((IsoNode *) file, zisofs_zf_xinfo_func, zf);
 2503     return ret;
 2504 }
 2505 
 2506 
 2507 /* API */
 2508 int iso_node_zf_by_magic(IsoNode *node, int flag)
 2509 {
 2510     int ret = 1, total_ret = 0, hflag;
 2511     IsoFile *file;
 2512     IsoNode *pos;
 2513     IsoDir *dir;
 2514 
 2515     if (node->type == LIBISO_FILE)
 2516         return iso_file_zf_by_magic((IsoFile *) node, flag & 0xff06);
 2517     if (node->type != LIBISO_DIR || (flag & 8))
 2518         return 0;
 2519 
 2520     dir = (IsoDir *) node;
 2521     pos = dir->children;
 2522     while (pos) {
 2523         ret = 1;
 2524         if (pos->type == LIBISO_FILE) {
 2525             file = (IsoFile *) pos;
 2526             if ((flag & 16) && file->from_old_session)
 2527                 return 0;
 2528             if (!((flag & 1) && file->from_old_session)) {
 2529                 if (strncmp(file->stream->class->type, "ziso", 4) == 0)
 2530                     return 1; /* The stream is enough of marking */
 2531                 if (strncmp(file->stream->class->type, "osiz", 4) == 0) {
 2532                     if (flag & 2)
 2533                         iso_node_remove_xinfo(pos, zisofs_zf_xinfo_func);
 2534                     return 0; /* Will not be zisofs format */
 2535                 }
 2536             }
 2537             hflag = flag & 0xff06;
 2538             if ((flag & 1) && file->from_old_session)
 2539                 hflag |= 1;
 2540             ret = iso_file_zf_by_magic(file, hflag);
 2541         } else if (pos->type == LIBISO_DIR) {
 2542             ret = iso_node_zf_by_magic(pos, flag);
 2543         }
 2544         if (ret < 0) {
 2545             total_ret = ret;
 2546             ret = iso_msg_submit(-1, ret, 0, NULL);
 2547             if (ret < 0) {
 2548                 return ret; /* cancel due error threshold */
 2549             }
 2550         } else if (total_ret >= 0) {
 2551             total_ret |= ret;
 2552         }
 2553         pos = pos->next;
 2554     }
 2555     return total_ret;
 2556 }
 2557 
 2558 
 2559 int iso_px_ino_xinfo_func(void *data, int flag)
 2560 {
 2561     if (flag == 1) {
 2562         free(data);
 2563     }
 2564     return 1;
 2565 }
 2566 
 2567 /* The iso_node_xinfo_cloner function which gets associated to
 2568  * iso_px_ino_xinfo_func by iso_init() resp. iso_init_with_flag() via
 2569  * iso_node_xinfo_make_clonable()
 2570  */
 2571 int iso_px_ino_xinfo_cloner(void *old_data, void **new_data, int flag)
 2572 {
 2573     *new_data = NULL;
 2574     if (flag)
 2575         return ISO_XINFO_NO_CLONE; 
 2576     *new_data = calloc(1, sizeof(ino_t));
 2577     if (*new_data == NULL)
 2578         return ISO_OUT_OF_MEM;
 2579     memcpy(*new_data, old_data, sizeof(ino_t));
 2580     return (int) sizeof(ino_t);
 2581 }
 2582 
 2583 /*
 2584  * @param flag
 2585  *     bit0= do only retrieve id if node is in imported ISO image
 2586  *           or has an explicit xinfo inode number
 2587  * @return
 2588  *     1= reply is valid from stream, 2= reply is valid from xinfo
 2589  *     0= no id available,           <0= error
 2590  *     (fs_id, dev_id, ino_id) will be (0,0,0) in case of return <= 0
 2591  */
 2592 int iso_node_get_id(IsoNode *node, unsigned int *fs_id, dev_t *dev_id,
 2593                     ino_t *ino_id, int flag)
 2594 {
 2595     int ret;
 2596     IsoFile *file;
 2597     IsoSymlink *symlink;
 2598     IsoSpecial *special;
 2599     void *xipt;
 2600     
 2601     ret = iso_node_get_xinfo(node, iso_px_ino_xinfo_func, &xipt);
 2602     if (ret < 0)
 2603         goto no_id;
 2604     if (ret == 1) {
 2605         *fs_id = ISO_IMAGE_FS_ID;
 2606         *dev_id = 0;
 2607         *ino_id = *((ino_t *) xipt);
 2608         return 2;
 2609     }
 2610 
 2611     if (node->type == LIBISO_FILE) {
 2612         file= (IsoFile *) node;
 2613         iso_stream_get_id(file->stream, fs_id, dev_id, ino_id);
 2614         if (*fs_id != ISO_IMAGE_FS_ID && (flag & 1)) {
 2615             ret = 0;
 2616             goto no_id;
 2617         }
 2618         return 1;
 2619 
 2620     } else if (node->type == LIBISO_SYMLINK) {
 2621         symlink = (IsoSymlink *) node;
 2622         if (symlink->fs_id != ISO_IMAGE_FS_ID && (flag & 1)) {
 2623             ret = 0;
 2624             goto no_id;
 2625         }
 2626         *fs_id = symlink->fs_id;
 2627         *dev_id = symlink->st_dev;
 2628         *ino_id = symlink->st_ino;
 2629         return 1;
 2630 
 2631     } else if (node->type == LIBISO_SPECIAL) {
 2632         special = (IsoSpecial *) node;
 2633         if (special->fs_id != ISO_IMAGE_FS_ID && (flag & 1)) {
 2634             ret = 0;
 2635             goto no_id;
 2636         }
 2637         *fs_id = special->fs_id;
 2638         *dev_id = special->st_dev;
 2639         *ino_id = special->st_ino;
 2640         return 1;
 2641 
 2642     }
 2643 
 2644     ret = 0;
 2645 no_id:;
 2646     *fs_id = 0;
 2647     *dev_id = 0;
 2648     *ino_id = 0;
 2649     return ret;
 2650 }
 2651 
 2652 
 2653 static
 2654 int iso_node_set_ino_xinfo(IsoNode *node, ino_t ino, int flag)
 2655 {
 2656     int ret;
 2657     void *xipt;
 2658 
 2659     if (flag & 1) {
 2660         ret = iso_node_remove_xinfo(node, iso_px_ino_xinfo_func);
 2661         if (ret < 0)
 2662             return ret;
 2663     }
 2664     xipt = calloc(1, sizeof(ino_t));
 2665     if (xipt == NULL)
 2666         return ISO_OUT_OF_MEM;
 2667     memcpy(xipt, &ino, sizeof(ino_t));
 2668     ret = iso_node_add_xinfo(node, iso_px_ino_xinfo_func, xipt);
 2669     return ret;
 2670 }
 2671 
 2672 int iso_node_set_ino(IsoNode *node, ino_t ino, int flag)
 2673 {
 2674     int ret;
 2675     IsoFile *file;
 2676     IsoSymlink *symlink;
 2677     IsoSpecial *special;
 2678     void *xipt;
 2679     
 2680     ret = iso_node_get_xinfo(node, iso_px_ino_xinfo_func, &xipt);
 2681     if (ret < 0)
 2682         return ret;
 2683     if (ret == 1) {
 2684         ret = iso_node_set_ino_xinfo(node, ino, 1);
 2685         if (ret < 0)
 2686             return ret;
 2687         return 2;
 2688     }
 2689     if (node->type == LIBISO_FILE) {
 2690         file= (IsoFile *) node;
 2691         ret = iso_stream_set_image_ino(file->stream, ino, 0);
 2692         if (ret < 0 || ret == 1)
 2693             return ret;
 2694         /* ret == 0 means that the stream is not from loaded ISO image */
 2695 
 2696     } else if (node->type == LIBISO_SYMLINK) {
 2697         symlink = (IsoSymlink *) node;
 2698         if (symlink->fs_id == ISO_IMAGE_FS_ID) {
 2699             symlink->st_ino = ino;
 2700             return 1;
 2701         }
 2702 
 2703     } else if (node->type == LIBISO_SPECIAL) {
 2704         special = (IsoSpecial *) node;
 2705         if (special->fs_id == ISO_IMAGE_FS_ID) {
 2706             special->st_ino = ino;
 2707             return 1;
 2708         }
 2709 
 2710     }
 2711     ret = iso_node_set_ino_xinfo(node, ino, 0);
 2712     if (ret < 0)
 2713         return ret;
 2714     return 2;
 2715 }
 2716 
 2717 
 2718 int iso_node_set_unique_id(IsoNode *node, IsoImage *image, int flag)
 2719 {
 2720     int ret;
 2721     ino_t ino;
 2722 
 2723     ino = img_give_ino_number(image, 0);
 2724     ret = iso_node_set_ino(node, ino, 0);
 2725     return ret;
 2726 }
 2727 
 2728 /*
 2729  * Note to programmers: It is crucial not to break the following constraints.
 2730  * Anti-symmetry: cmp(X,Y) == - cmp(Y,X)
 2731  * Transitivity : if cmp(A,B) < 0 && cmp(B,C) < 0 then cmp(A,C) < 0
 2732  *                if cmp(A,B) == 0 && cmp(B,C) == 0 then cmp(A,C) == 0
 2733  * A big transitivity hazard are tests which do not apply to some nodes.
 2734  * In this case for any A that is applicable and any B that is not applicable
 2735  * the comparison must have the same non-zero result. I.e. a pair of applicable
 2736  * and non-applicable node must return that non-zero result before the test
 2737  * for a pair of applicable nodes would happen.
 2738  * 
 2739  * @param flag
 2740  *     bit0= compare stat properties and attributes 
 2741  *     bit1= treat all nodes with image ino == 0 as unique
 2742  */
 2743 int iso_node_cmp_flag(IsoNode *n1, IsoNode *n2, int flag)
 2744 {
 2745     int ret1, ret2;
 2746     unsigned int fs_id1, fs_id2;
 2747     dev_t dev_id1, dev_id2;
 2748     ino_t ino_id1, ino_id2;
 2749     IsoFile *f1 = NULL, *f2 = NULL;
 2750     IsoSymlink *l1 = NULL, *l2 = NULL;
 2751     IsoSpecial *s1 = NULL, *s2 = NULL;
 2752     void *x1, *x2;
 2753 
 2754     if (n1 == n2)
 2755         return 0;
 2756     if (n1->type != n2->type)
 2757         return (n1->type < n2->type ? -1 : 1);
 2758 
 2759     /* Imported or explicit ISO image node id has priority */
 2760     ret1 = (iso_node_get_id(n1, &fs_id1, &dev_id1, &ino_id1, 1) > 0);
 2761     ret2 = (iso_node_get_id(n2, &fs_id2, &dev_id2, &ino_id2, 1) > 0);
 2762     if (ret1 != ret2)
 2763         return (ret1 < ret2 ? -1 : 1);
 2764     if (ret1) {
 2765         /* fs_id and dev_id do not matter here.
 2766            Both nodes have explicit inode numbers of the emerging image.
 2767          */
 2768         if (ino_id1 != ino_id2)
 2769             return (ino_id1 < ino_id2 ? -1 : 1);
 2770         if (ino_id1 == 0) /* Image ino 0 is always unique */
 2771             return (n1 < n2 ? -1 : 1);
 2772         goto image_inode_match;
 2773     }
 2774 
 2775     if (n1->type == LIBISO_FILE) {
 2776 
 2777         f1 = (IsoFile *) n1;
 2778         f2 = (IsoFile *) n2;
 2779         ret1 = iso_stream_cmp_ino(f1->stream, f2->stream, 0);
 2780         if (ret1)
 2781             return ret1;
 2782         goto inode_match;
 2783 
 2784     } else if (n1->type == LIBISO_SYMLINK) {
 2785 
 2786         l1 = (IsoSymlink *) n1;
 2787         l2 = (IsoSymlink *) n2;
 2788         fs_id1 = l1->fs_id;
 2789         dev_id1 = l1->st_dev;
 2790         ino_id1 = l1->st_ino;
 2791         fs_id2 = l2->fs_id;
 2792         dev_id2 = l2->st_dev;
 2793         ino_id2 = l2->st_ino;
 2794 
 2795     } else if (n1->type == LIBISO_SPECIAL) {
 2796 
 2797         s1 = (IsoSpecial *) n1;
 2798         s2 = (IsoSpecial *) n2;
 2799         fs_id1 = s1->fs_id;
 2800         dev_id1 = s1->st_dev;
 2801         ino_id1 = s1->st_ino;
 2802         fs_id2 = s2->fs_id;
 2803         dev_id2 = s2->st_dev;
 2804         ino_id2 = s2->st_ino;
 2805 
 2806     } else {
 2807         return (n1 < n2 ? -1 : 1); /* case n1 == n2 is handled above */
 2808     }
 2809     if (fs_id1 != fs_id2)
 2810         return (fs_id1 < fs_id2 ? -1 : 1);
 2811     if (dev_id1 != dev_id2)
 2812         return (dev_id1 < dev_id2 ? -1 : 1);
 2813     if (ino_id1 != ino_id2)
 2814         return (ino_id1 < ino_id2 ? -1 : 1);
 2815     if (fs_id1 == 0 && dev_id1 == 0 && ino_id1 == 0)
 2816         return (n1 < n2 ? -1 : 1);
 2817 
 2818 inode_match:;
 2819 
 2820     if (flag & 2) {
 2821         /* What comes here has no predefined image ino resp. image_ino == 0 .
 2822            Regard this as not equal.
 2823         */
 2824         return (n1 < n2 ? -1 : 1);
 2825     }
 2826 
 2827 image_inode_match:;
 2828 
 2829     if (!(flag & 1))
 2830         return 0;
 2831     if (n1->type == LIBISO_SYMLINK) {
 2832         l1 = (IsoSymlink *) n1;
 2833         l2 = (IsoSymlink *) n2;
 2834         ret1 = strcmp(l1->dest, l2->dest);
 2835         if (ret1)
 2836             return ret1;
 2837     } else if (n1->type == LIBISO_SPECIAL) {
 2838         s1 = (IsoSpecial *) n1;
 2839         s2 = (IsoSpecial *) n2;
 2840         if (s1->dev != s2->dev)
 2841             return (s1->dev < s2->dev ? -1 : 1);
 2842     }
 2843 
 2844     if (n1->mode != n2->mode)
 2845         return (n1->mode < n2->mode ? -1 : 1);
 2846     if (n1->uid != n2->uid)
 2847         return (n1->uid < n2->uid ? -1 : 1);
 2848     if (n1->gid != n2->gid)
 2849         return (n1->gid < n2->gid ? -1 : 1);
 2850     if (n1->atime != n2->atime)
 2851         return (n1->atime < n2->atime ? -1 : 1);
 2852     if (n1->mtime != n2->mtime)
 2853         return (n1->mtime < n2->mtime ? -1 : 1);
 2854     if (n1->ctime != n2->ctime)
 2855         return (n1->ctime < n2->ctime ? -1 : 1);
 2856 
 2857     /* Compare xinfo */
 2858     /* :( cannot compare general xinfo because data length is not known :( */
 2859 
 2860     /* compare aa_string */
 2861     ret1 = iso_node_get_xinfo(n1, aaip_xinfo_func, &x1);
 2862     ret2 = iso_node_get_xinfo(n2, aaip_xinfo_func, &x2);
 2863     if (ret1 != ret2)
 2864         return (ret1 < ret2 ? -1 : 1);
 2865     if (ret1 == 1) {
 2866         ret1 = aaip_count_bytes((unsigned char *) x1, 0);
 2867         ret2 = aaip_count_bytes((unsigned char *) x2, 0);
 2868         if (ret1 != ret2)
 2869             return (ret1 < ret2 ? -1 : 1);
 2870         ret1 = memcmp(x1, x2, ret1);
 2871         if (ret1)
 2872             return ret1;
 2873     }
 2874 
 2875     return 0;
 2876 }
 2877 
 2878 /* API */
 2879 int iso_node_cmp_ino(IsoNode *n1, IsoNode *n2, int flag)
 2880 {
 2881     return iso_node_cmp_flag(n1, n2, 1);
 2882 }
 2883 
 2884 
 2885 /* @param flag bit0= delete isofs.cx rather than setting it
 2886 */
 2887 int iso_file_set_isofscx(IsoFile *file, unsigned int checksum_index,
 2888                          int flag)
 2889 {
 2890     static char *names = "isofs.cx";
 2891     static size_t value_lengths[1] = {4};
 2892     unsigned char value[4];
 2893     char *valuept;
 2894     int i, ret;
 2895 
 2896     valuept= (char *) value;
 2897     if (flag & 1) {
 2898         ret = iso_node_set_attrs((IsoNode *) file, (size_t) 1,
 2899                              &names, value_lengths, &valuept, 4 | 8);
 2900         return ret;
 2901     }
 2902     for(i = 0; i < 4; i++)
 2903         value[3 - i] = (checksum_index >> (8 * i)) & 0xff;
 2904     ret = iso_node_set_attrs((IsoNode *) file, (size_t) 1,
 2905                              &names, value_lengths, &valuept, 2 | 8);
 2906     return ret;
 2907 }
 2908 
 2909 
 2910 int iso_root_set_isofsca(IsoNode *node, uint32_t start_lba, uint32_t end_lba,
 2911                          uint32_t count, uint32_t size, char *typetext,
 2912                          int flag)
 2913 {
 2914     char buffer[5 + 5 + 5 + 2 + 81], *wpt = buffer, *valuept = buffer;
 2915     int result_len, ret;
 2916     static char *names = "isofs.ca";
 2917     static size_t value_lengths[1];
 2918 
 2919     /* Set value of isofs.ca with
 2920        4 byte START, 4 byte END, 4 byte COUNT, SIZE = 16,  MD5 */
 2921     iso_util_encode_len_bytes(start_lba, wpt, 4, &result_len, 0);
 2922     wpt += result_len;
 2923     iso_util_encode_len_bytes(end_lba, wpt, 4, &result_len, 0);
 2924     wpt += result_len;
 2925     iso_util_encode_len_bytes(count, wpt, 4, &result_len, 0);
 2926     wpt += result_len;
 2927     iso_util_encode_len_bytes(size, wpt, 1, &result_len, 0);
 2928     wpt += result_len;
 2929     strncpy(wpt, typetext, 80);
 2930     if (strlen(typetext) > 80)
 2931         wpt += 80;
 2932     else
 2933         wpt += strlen(typetext);
 2934     value_lengths[0] = wpt - buffer;
 2935     ret = iso_node_set_attrs(node, (size_t) 1,
 2936                              &names, value_lengths, &valuept, 2 | 8);
 2937     return ret;
 2938 }
 2939 
 2940 
 2941 int iso_root_get_isofsca(IsoNode *node, uint32_t *start_lba, uint32_t *end_lba,
 2942                          uint32_t *count, uint32_t *size, char typetext[81],
 2943                          int flag)
 2944 {
 2945     int ret, len;
 2946     size_t value_len;
 2947     char *value = NULL, *rpt;
 2948 
 2949     ret = iso_node_lookup_attr(node, "isofs.ca", &value_len, &value, 0);
 2950     if (ret <= 0)
 2951         goto ex;
 2952 
 2953     /* Parse value of isofs.ca with
 2954        4 byte START, 4 byte END, 4 byte COUNT, SIZE = 16,  MD5 */
 2955     rpt = value;
 2956     iso_util_decode_len_bytes(start_lba, rpt, &len,
 2957                               value_len - (rpt - value), 0);
 2958     rpt += len + 1;
 2959     iso_util_decode_len_bytes(end_lba, rpt, &len,
 2960                               value_len - (rpt - value), 0);
 2961     rpt += len + 1;
 2962     iso_util_decode_len_bytes(count, rpt, &len,
 2963                               value_len - (rpt - value), 0);
 2964     rpt += len + 1;
 2965     iso_util_decode_len_bytes(size, rpt, &len,
 2966                               value_len - (rpt - value), 0);
 2967     rpt += len + 1;
 2968     len = value_len - (rpt - value);
 2969     if (len > 80)
 2970         len = 80;
 2971     memcpy(typetext, rpt, len);
 2972     typetext[len] = 0;
 2973 
 2974     ret= ISO_SUCCESS;
 2975 ex:;
 2976     if (value != NULL)
 2977         free(value);
 2978     return ret;
 2979 }
 2980 
 2981 
 2982 int iso_root_set_isofsnt(IsoNode *node, uint32_t truncate_mode,
 2983                          uint32_t truncate_length, int flag)
 2984 {
 2985     char buffer[5 + 5], *wpt = buffer, *valuept = buffer;
 2986     int result_len, ret;
 2987     static char *names = "isofs.nt";
 2988     static size_t value_lengths[1];
 2989 
 2990     iso_util_encode_len_bytes(truncate_mode, wpt, 0, &result_len, 0);
 2991     wpt += result_len;
 2992     iso_util_encode_len_bytes(truncate_length, wpt, 0, &result_len, 0);
 2993     wpt += result_len;
 2994     value_lengths[0] = wpt - buffer;
 2995     ret = iso_node_set_attrs(node, (size_t) 1,
 2996                              &names, value_lengths, &valuept, 2 | 8);
 2997     return ret;
 2998 }
 2999 
 3000 
 3001 int iso_root_get_isofsnt(IsoNode *node, uint32_t *truncate_mode,
 3002                          uint32_t *truncate_length, int flag)
 3003 {
 3004     int ret, len;
 3005     size_t value_len;
 3006     char *value = NULL, *rpt;
 3007 
 3008     ret = iso_node_lookup_attr(node, "isofs.nt", &value_len, &value, 0);
 3009     if (ret <= 0)
 3010         goto ex;
 3011 
 3012     rpt = value;
 3013     iso_util_decode_len_bytes(truncate_mode, rpt, &len,
 3014                               value_len - (rpt - value), 0);
 3015     rpt += len + 1;
 3016     iso_util_decode_len_bytes(truncate_length, rpt, &len,
 3017                               value_len - (rpt - value), 0);
 3018     ret= ISO_SUCCESS;
 3019 ex:;
 3020     if (value != NULL)
 3021         free(value);
 3022     return ret;
 3023 }
 3024 
 3025 
 3026 /* API */
 3027 int iso_file_get_md5(IsoImage *image, IsoFile *file, char md5[16], int flag)
 3028 {
 3029     int ret, i;
 3030     size_t value_len;
 3031     char *value = NULL;
 3032     uint32_t idx = 0;
 3033     void *xipt;
 3034 
 3035     /* xinfo MD5 overrides everything else */
 3036     ret = iso_node_get_xinfo((IsoNode *) file, checksum_md5_xinfo_func, &xipt);
 3037     if (ret == 1) {
 3038         memcpy(md5, (char *) xipt, 16);
 3039         return 1;
 3040     }
 3041 
 3042     if (image->checksum_array == NULL)
 3043         return 0;
 3044     ret = iso_node_lookup_attr((IsoNode *) file, "isofs.cx",
 3045                                &value_len, &value, 0);
 3046     if (ret <= 0)
 3047         goto ex;
 3048     if (value_len > 4) {
 3049         ret = 0;
 3050         goto ex;
 3051     }
 3052     for (i = 0; i < (int) value_len; i++)
 3053         idx = (idx << 8) | ((unsigned char *) value)[i];
 3054     if (idx == 0 || idx > image->checksum_idx_count - 1) {
 3055                                        /* (last index is not MD5 of a file) */
 3056         ret = 0;
 3057         goto ex;
 3058     }
 3059     if (!(flag & 1)) {
 3060         memcpy(md5, image->checksum_array + ((size_t) 16) * ((size_t) idx),
 3061                16);
 3062     }
 3063     ret = 1;
 3064 ex:;
 3065     if (value != NULL)
 3066         free(value);
 3067     return ret;
 3068 }
 3069 
 3070 
 3071 /* API */
 3072 int iso_file_make_md5(IsoFile *file, int flag)
 3073 {
 3074     int ret, dig = 0;
 3075     char *md5 = NULL;
 3076 
 3077     if (file->from_old_session)
 3078         dig = 1;
 3079     md5 = calloc(16, 1);
 3080     if (md5 == NULL) 
 3081         return ISO_OUT_OF_MEM;
 3082     ret = iso_stream_make_md5(file->stream, md5, dig);
 3083     if (ret < 0) {
 3084         free(md5);
 3085         return ret;
 3086     }
 3087     iso_node_remove_xinfo((IsoNode *) file, checksum_md5_xinfo_func);
 3088     ret = iso_node_add_xinfo((IsoNode *) file, checksum_md5_xinfo_func, md5);
 3089     if (ret == 0)
 3090         ret = ISO_ERROR; /* should not happen after iso_node_remove_xinfo() */
 3091     if (ret < 0) {
 3092         free(md5);
 3093         return ret;
 3094     }
 3095     return 1;
 3096 }
 3097 
 3098 
 3099