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