xorriso  1.5.4.pl02
About: GNU xorriso creates, loads, manipulates and writes ISO 9660 filesystem images with Rock Ridge extensions. It is suitable for incremental data backup and for production of bootable ISO 9660 images. GNU xorriso is a statical compilation of the libraries libburn, libisofs, libisoburn, and libjte.
  Fossies Dox: xorriso-1.5.4.pl02.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

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