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)  

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