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  */
iso_node_ref(IsoNode * node)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  */
iso_node_unref(IsoNode * node)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  */
iso_node_add_xinfo(IsoNode * node,iso_node_xinfo_func proc,void * data)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  */
iso_node_remove_xinfo(IsoNode * node,iso_node_xinfo_func proc)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  */
iso_node_get_xinfo(IsoNode * node,iso_node_xinfo_func proc,void ** data)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 */
iso_node_get_next_xinfo(IsoNode * node,void ** handle,iso_node_xinfo_func * proc,void ** data)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 
iso_node_remove_all_xinfo(IsoNode * node,int flag)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
iso_node_revert_xinfo_list(IsoNode * node,int flag)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 
iso_node_clone_xinfo(IsoNode * from_node,IsoNode * to_node,int flag)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  */
iso_node_get_type(IsoNode * node)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  */
iso_node_set_name_trunc(IsoNode * node,const char * in_name,int truncate_length,int flag)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 
iso_node_set_name(IsoNode * node,const char * name)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 
iso_image_set_node_name(IsoImage * image,IsoNode * node,const char * name,int flag)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  */
iso_node_get_name(const IsoNode * node)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  */
iso_node_set_perms_internal(IsoNode * node,mode_t mode,int flag)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  */
iso_node_set_permissions(IsoNode * node,mode_t mode)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  */
iso_node_get_permissions(const IsoNode * node)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  */
iso_node_get_mode(const IsoNode * node)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  */
iso_node_set_uid(IsoNode * node,uid_t uid)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  */
iso_node_get_uid(const IsoNode * node)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  */
iso_node_set_gid(IsoNode * node,gid_t gid)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  */
iso_node_get_gid(const IsoNode * node)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  */
iso_node_set_mtime(IsoNode * node,time_t time)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  */
iso_node_get_mtime(const IsoNode * node)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  */
iso_node_set_atime(IsoNode * node,time_t time)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  */
iso_node_get_atime(const IsoNode * node)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  */
iso_node_set_ctime(IsoNode * node,time_t time)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  */
iso_node_get_ctime(const IsoNode * node)553 time_t iso_node_get_ctime(const IsoNode *node)
554 {
555     return node->ctime;
556 }
557 
iso_node_set_hidden(IsoNode * node,int hide_attrs)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 
iso_node_get_hidden(IsoNode * node)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  */
iso_dir_add_node(IsoDir * dir,IsoNode * child,enum iso_replace_mode replace)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  */
iso_dir_get_node(IsoDir * dir,const char * name,IsoNode ** node)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 
iso_dir_get_node_trunc(IsoDir * dir,int truncate_length,const char * name,IsoNode ** node)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 */
iso_image_dir_get_node(IsoImage * image,IsoDir * dir,const char * name,IsoNode ** node,int flag)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  */
iso_dir_get_children_count(IsoDir * dir)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
iter_next(IsoDirIter * iter,IsoNode ** node)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
iter_has_next(IsoDirIter * iter)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
iter_free(IsoDirIter * iter)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 
iso_dir_find_node(IsoDir * dir,IsoNode * node)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  */
iso_node_take(IsoNode * node)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  */
iso_node_remove(IsoNode * node)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 */
iso_node_remove_tree(IsoNode * node,IsoDirIter * boss_iter)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  */
iso_node_get_parent(IsoNode * node)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
iter_take(IsoDirIter * iter)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
iter_remove(IsoDirIter * iter)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 
iter_notify_child_taken(IsoDirIter * iter,IsoNode * node)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 
iso_dir_get_children(const IsoDir * dir,IsoDirIter ** iter)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 
iso_dir_iter_next(IsoDirIter * iter,IsoNode ** node)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 
iso_dir_iter_has_next(IsoDirIter * iter)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 
iso_dir_iter_free(IsoDirIter * iter)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 
iso_dir_iter_take(IsoDirIter * iter)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 
iso_dir_iter_remove(IsoDirIter * iter)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  */
iso_symlink_get_dest(const IsoSymlink * link)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  */
iso_symlink_set_dest(IsoSymlink * link,const char * dest)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  */
iso_node_set_sort_weight(IsoNode * node,int w)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  */
iso_file_get_sort_weight(IsoFile * file)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  */
iso_file_get_size(IsoFile * file)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  */
iso_file_get_stream(IsoFile * file)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  */
iso_special_get_dev(IsoSpecial * special)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  */
iso_file_get_old_image_lba(IsoFile * file,uint32_t * lba,int flag)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  */
iso_node_get_old_image_lba(IsoNode * node,uint32_t * lba,int flag)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  */
iso_node_is_valid_name(const char * name)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  */
iso_node_is_valid_link_dest(const char * dest)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 
iso_dir_find(IsoDir * dir,const char * name,IsoNode *** pos)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 
iso_dir_exists(IsoDir * dir,const char * name,IsoNode *** pos)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 
iso_dir_insert(IsoDir * dir,IsoNode * node,IsoNode ** pos,enum iso_replace_mode replace)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  */
iso_dir_iter_register(IsoDirIter * iter)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  */
iso_dir_iter_unregister(IsoDirIter * iter)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 
iso_notify_dir_iters(IsoNode * node,int flag)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 
iso_node_new_root(IsoDir ** root)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 
iso_node_new_dir(char * name,IsoDir ** dir)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 
iso_node_new_file(char * name,IsoStream * stream,IsoFile ** file)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 
iso_node_new_symlink(char * name,char * dest,IsoSymlink ** link)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 
iso_node_new_special(char * name,mode_t mode,dev_t dev,IsoSpecial ** special)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
attrs_cleanout_name(char * del_name,size_t * num_attrs,char ** names,size_t * value_lengths,char ** values,int flag)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  */
iso_aa_get_attrs(unsigned char * aa_string,size_t * num_attrs,char *** names,size_t ** value_lengths,char *** values,int flag)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  */
iso_aa_lookup_attr(unsigned char * aa_string,char * name,size_t * value_length,char ** value,int flag)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 */
iso_node_lookup_attr(IsoNode * node,char * name,size_t * value_length,char ** value,int flag)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 */
iso_node_get_attrs(IsoNode * node,size_t * num_attrs,char *** names,size_t ** value_lengths,char *** values,int flag)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
attr_enlarge_list(char *** names,size_t ** value_lengths,char *** values,size_t new_num,int flag)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
iso_node_merge_xattr(IsoNode * node,size_t num_attrs,char ** names,size_t * value_lengths,char ** values,size_t * m_num_attrs,char *** m_names,size_t ** m_value_lengths,char *** m_values,int flag)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 
iso_node_set_attrs(IsoNode * node,size_t num_attrs,char ** names,size_t * value_lengths,char ** values,int flag)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
iso_decode_acl(unsigned char * v_data,size_t v_len,size_t * consumed,char ** text,size_t * text_fill,int flag)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
iso_attr_get_acl_text(size_t num_attrs,char ** names,size_t * value_lengths,char ** values,mode_t st_mode,char ** access_text,char ** default_text,int flag)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 
iso_node_get_acl_text(IsoNode * node,char ** access_text,char ** default_text,int flag)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 
iso_aa_get_acl_text(unsigned char * aa_string,mode_t st_mode,char ** access_text,char ** default_text,int flag)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 
iso_node_set_acl_text(IsoNode * node,char * access_text,char * default_text,int flag)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 
iso_node_get_perms_wo_acl(const IsoNode * node)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  */
zisofs_zf_xinfo_func(void * data,int flag)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  */
zisofs_zf_xinfo_cloner(void * old_data,void ** new_data,int flag)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  */
iso_file_zf_by_magic(IsoFile * file,int flag)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 */
iso_node_zf_by_magic(IsoNode * node,int flag)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 
iso_px_ino_xinfo_func(void * data,int flag)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  */
iso_px_ino_xinfo_cloner(void * old_data,void ** new_data,int flag)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  */
iso_node_get_id(IsoNode * node,unsigned int * fs_id,dev_t * dev_id,ino_t * ino_id,int flag)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
iso_node_set_ino_xinfo(IsoNode * node,ino_t ino,int flag)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 
iso_node_set_ino(IsoNode * node,ino_t ino,int flag)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 
iso_node_set_unique_id(IsoNode * node,IsoImage * image,int flag)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  */
iso_node_cmp_flag(IsoNode * n1,IsoNode * n2,int flag)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 */
iso_node_cmp_ino(IsoNode * n1,IsoNode * n2,int flag)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 */
iso_file_set_isofscx(IsoFile * file,unsigned int checksum_index,int flag)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 
iso_root_set_isofsca(IsoNode * node,uint32_t start_lba,uint32_t end_lba,uint32_t count,uint32_t size,char * typetext,int flag)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 
iso_root_get_isofsca(IsoNode * node,uint32_t * start_lba,uint32_t * end_lba,uint32_t * count,uint32_t * size,char typetext[81],int flag)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 
iso_root_set_isofsnt(IsoNode * node,uint32_t truncate_mode,uint32_t truncate_length,int flag)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 
iso_root_get_isofsnt(IsoNode * node,uint32_t * truncate_mode,uint32_t * truncate_length,int flag)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 */
iso_file_get_md5(IsoImage * image,IsoFile * file,char md5[16],int flag)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 */
iso_file_make_md5(IsoFile * file,int flag)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 
3100