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