diff --git a/Makefile.am b/Makefile.am index 21b797d..430078f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -156,27 +156,31 @@ demo_isoms_SOURCES = demo/iso_ms.c # demo_isogrow_SOURCES = demo/iso_grow.c -## Build unit test +## ts A90428 , ticket 147, The test code does not use the API and is totally +## outdated in its creation of mocked objects. +## A volunteer is needed to rewrite it using the API. + +# ## Build unit test -check_PROGRAMS = \ - test/test - -test_test_CPPFLAGS = -Ilibisofs -test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) \ - $(libisofs_libisofs_la_LIBADD) -lcunit -test_test_LDFLAGS = -L.. -lm - -test_test_SOURCES = \ - test/test.h \ - test/test.c \ - test/test_node.c \ - test/test_image.c \ - test/test_tree.c \ - test/test_util.c \ - test/test_rockridge.c \ - test/test_stream.c \ - test/mocked_fsrc.h \ - test/mocked_fsrc.c +# check_PROGRAMS = \ +# test/test +# +# test_test_CPPFLAGS = -Ilibisofs +# test_test_LDADD = $(libisofs_libisofs_la_OBJECTS) \ +# $(libisofs_libisofs_la_LIBADD) -lcunit +# test_test_LDFLAGS = -L.. -lm +# +# test_test_SOURCES = \ +# test/test.h \ +# test/test.c \ +# test/test_node.c \ +# test/test_image.c \ +# test/test_tree.c \ +# test/test_util.c \ +# test/test_rockridge.c \ +# test/test_stream.c \ +# test/mocked_fsrc.h \ +# test/mocked_fsrc.c ## ========================================================================= ## diff --git a/libisofs/ecma119_tree.c b/libisofs/ecma119_tree.c index 31745b8..c0c68c5 100644 --- a/libisofs/ecma119_tree.c +++ b/libisofs/ecma119_tree.c @@ -95,7 +95,10 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name) static int create_ecma119_node(Ecma119Image *img, IsoNode *iso, Ecma119Node **node) { + int ret; Ecma119Node *ecma; + unsigned int fs_id; + dev_t dev_id; ecma = calloc(1, sizeof(Ecma119Node)); if (ecma == NULL) { @@ -109,11 +112,28 @@ int create_ecma119_node(Ecma119Image *img, IsoNode *iso, Ecma119Node **node) /* TODO #00009 : add true support for harlinks and inode numbers */ ecma->nlink = 1; - /* >>> ts A90426 : unite this with fs_give_ino_number() when it gets - an inode recycling mode - */ + /* >>> One needs to find groups of nodes with identical id numbers + resp. with other reasons for being hard links. + This will replace the file source unifier by rbtree + in iso_file_src_create() and iso_file_src_add(). + */ + + /*ts A90428 */ +#ifdef Libisofs_hardlink_prooF + + ret = iso_node_get_id(iso, &fs_id, &dev_id, &(ecma->ino), 1); + if (ret < 0) { + return ret; + } else if (ret == 0) { + ecma->ino = img_give_ino_number(img->image, 0); + } + +#else /* Libisofs_hardlink_prooF */ + ecma->ino = ++img->ino; +#endif /* ! Libisofs_hardlink_prooF */ + *node = ecma; return ISO_SUCCESS; } diff --git a/libisofs/filesrc.c b/libisofs/filesrc.c index b66c41d..21f3ff9 100644 --- a/libisofs/filesrc.c +++ b/libisofs/filesrc.c @@ -17,6 +17,8 @@ #include #include +/* ts A90427 : introduced test (n1 == n2) and flattened block nesting +*/ int iso_file_src_cmp(const void *n1, const void *n2) { const IsoFileSrc *f1, *f2; @@ -24,6 +26,12 @@ int iso_file_src_cmp(const void *n1, const void *n2) dev_t dev_id1, dev_id2; ino_t ino_id1, ino_id2; off_t size1, size2; + + if (n1 == n2) { + return 0; /* Normally just a shortcut. + But important if Libisofs_file_src_cmp_non_zerO */ + } + f1 = (const IsoFileSrc *)n1; f2 = (const IsoFileSrc *)n2; @@ -31,37 +39,36 @@ int iso_file_src_cmp(const void *n1, const void *n2) iso_stream_get_id(f2->stream, &fs_id2, &dev_id2, &ino_id2); #ifdef Libisofs_file_src_cmp_non_zerO - if (fs_id1 == 0 && dev_id1 == 0 && ino_id1 == 0) + if (fs_id1 == 0 && dev_id1 == 0 && ino_id1 == 0) { return -1; - if (fs_id2 == 0 && dev_id2 == 0 && ino_id2 == 0) + } else if (fs_id2 == 0 && dev_id2 == 0 && ino_id2 == 0) return 1; + } #endif if (fs_id1 < fs_id2) { return -1; } else if (fs_id1 > fs_id2) { return 1; - } else { - /* files belong to the same fs */ - if (dev_id1 > dev_id2) { - return -1; - } else if (dev_id1 < dev_id2) { - return 1; - } else if (ino_id1 < ino_id2) { - return -1; - } else if (ino_id1 > ino_id2) { - return 1; - } else { - size1 = iso_stream_get_size(f1->stream); - size2 = iso_stream_get_size(f2->stream); - if (size1 < size2) { - return -1; - } else if (size1 > size2) { - return 1; - } - return 0; - } } + /* files belong to the same fs */ + if (dev_id1 > dev_id2) { + return -1; + } else if (dev_id1 < dev_id2) { + return 1; + } else if (ino_id1 < ino_id2) { + return -1; + } else if (ino_id1 > ino_id2) { + return 1; + } + size1 = iso_stream_get_size(f1->stream); + size2 = iso_stream_get_size(f2->stream); + if (size1 < size2) { + return -1; + } else if (size1 > size2) { + return 1; + } + return 0; } int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src) diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index 7a68119..1e49b53 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -88,6 +88,14 @@ struct iso_read_opts * attribute "isofs.cs" of root directory */ int auto_input_charset; + + /* ts A90425 */ + /** + * Hand out new inode numbers and overwrite eventually read PX inode + * numbers. This will split apart any hardlinks. + */ + int make_new_ino : 1 ; + }; /** @@ -137,6 +145,7 @@ enum read_rr_ext { RR_EXT_112 = 2 /*< RR extensions conforming version 1.12 */ }; + /** * Private data for the image IsoFilesystem */ @@ -264,6 +273,15 @@ typedef struct /* Inode number generator counter */ ino_t inode_counter; + /* ts A90425 */ + /* PX inode number status + bit0= there were nodes with PX inode numbers + bit1= there were nodes with PX but without inode numbers + bit2= there were nodes without PX + bit3= there were nodes with faulty PX + */ + int px_ino_status; + } _ImageFsData; typedef struct image_fs_data ImageFileSourceData; @@ -1070,6 +1088,8 @@ char *get_name(_ImageFsData *fsdata, const char *str, size_t len) } +#ifndef Libisofs_hardlink_prooF + /** * A global counter for default inode numbers for the ISO image filesystem. * @param fs The filesystem where the number shall be used @@ -1087,11 +1107,13 @@ ino_t fs_give_ino_number(IsoImageFilesystem *fs, int flag) if (fsdata->inode_counter == 0) { /* >>> raise alert because of inode rollover */; - + } return fsdata->inode_counter; } +#endif /* ! Libisofs_hardlink_prooF */ + /** * @@ -1135,6 +1157,8 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, size_t cs_value_length = 0; char msg[160]; + int has_px = 0; + #ifdef Libisofs_with_zliB uint8_t zisofs_alg[2], zisofs_hs4 = 0, zisofs_bsl2 = 0; uint32_t zisofs_usize = 0; @@ -1147,6 +1171,7 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, fsdata = (_ImageFsData*)fs->data; memset(&atts, 0, sizeof(struct stat)); + atts.st_nlink = 1; /* * First of all, check for unsupported ECMA-119 features @@ -1275,12 +1300,23 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, continue; if (SUSP_SIG(sue, 'P', 'X')) { + /* ts A90426 */ + has_px = 1; ret = read_rr_PX(sue, &atts); if (ret < 0) { /* notify and continue */ ret = iso_msg_submit(fsdata->msgid, ISO_WRONG_RR_WARN, ret, "Invalid PX entry"); + fsdata->px_ino_status |= 8; + } if (ret == 2) { + if (fsdata->inode_counter < atts.st_ino) + fsdata->inode_counter = atts.st_ino; + fsdata->px_ino_status |= 1; + + } else { + fsdata->px_ino_status |= 2; } + } else if (SUSP_SIG(sue, 'T', 'F')) { ret = read_rr_TF(sue, &atts); if (ret < 0) { @@ -1536,6 +1572,11 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, } } + /* ts A90426 */ + if (!has_px) { + fsdata->px_ino_status |= 4; + } + /* * if we haven't RR extensions, or no NM entry is present, * we use the name in directory record @@ -1596,12 +1637,29 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, /* but the real name is the name of the placeholder */ ifsdata = (ImageFileSourceData*) (*src)->data; ifsdata->name = name; + + /* >>> ts A90427 : What about final treatment ? + How does directory relocation relate to inode + numbers and hard links ? + */ + return ISO_SUCCESS; } +#ifdef Libisofs_hardlink_prooF + + /* ts A90426 : + Production of missing inode numbers is delayed until the image is + complete. Then all nodes which shall get a new inode number will + be served. + */ + +#else /* Libisofs_hardlink_prooF */ #ifdef Libisofs_new_fs_image_inO + /* >>> ts A90426 : this ifdef shall become a read option */ + if (fsdata->rr != RR_EXT_112) { if (fsdata->rr == 0) { atts.st_nlink = 1; @@ -1611,6 +1669,7 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, #else /* Libisofs_new_fs_image_inO */ + /* ts Nov 25 2008: TODO This seems not fully consistent with read_rr_PX() which decides by (px->len_sue[0] == 44) whether an inode number is present or not. @@ -1642,7 +1701,8 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, /* Ticket 144: This produces duplicate numbers with empty files. */ atts.st_ino = (ino_t) iso_read_bb(record->block, 4, NULL); -#endif +#endif /* ! Libisofs_patch_ticket_144 */ + if (fsdata->rr == 0) { atts.st_nlink = 1; } @@ -1650,6 +1710,8 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, #endif /* ! Libisofs_new_fs_image_inO */ +#endif /* ! Libisofs_hardlink_prooF */ + /* * if we haven't RR extensions, or a needed TF time stamp is not present, * we use plain iso recording time @@ -1974,7 +2036,6 @@ void ifs_fs_free(IsoFilesystem *fs) free(data->copyright_file_id); free(data->abstract_file_id); free(data->biblio_file_id); - free(data->input_charset); free(data->local_charset); free(data); @@ -2273,6 +2334,8 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, data->msgid = msgid; data->aaip_load = !opts->noaaip; data->aaip_version = -1; + data->inode_counter = 0; + data->px_ino_status = 0; #ifndef Libisofs_setlocale_in_iniT /* ??? ts Nov 25 2008 : @@ -2718,15 +2781,35 @@ int image_builder_create_node(IsoNodeBuilder *builder, IsoImage *image, ret = src_aa_to_node(src, new, 0); if (ret < 0) { - /* todo: stuff any possible memory leak here */ - if (name != NULL) - free(name); - free(new); - return ret; + goto failure; } +#ifdef Libisofs_hardlink_prooF + + /* ts A90428 */ + /* Attach ino as xinfo if valid and no IsoStream is involved */ + if (info.st_ino != 0 && (info.st_mode & S_IFMT) != S_IFREG + && (info.st_mode & S_IFMT) != S_IFDIR) { + + /* >>> ??? is there any sense in equipping directories with + persistent inode numbers ? */ + + ret = iso_node_set_ino(new, info.st_ino, 0); + if (ret < 0) + goto failure; + } + +#endif /* Libisofs_hardlink_prooF */ + *node = new; return ISO_SUCCESS; + +failure:; + /* todo: stuff any possible memory leak here */ + if (name != NULL) + free(name); + free(new); + return ret; } /** @@ -2763,7 +2846,8 @@ int iso_image_builder_new(IsoNodeBuilder *old, IsoNodeBuilder **builder) * accessible from the ISO filesystem. */ static -int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoFileSource **src) +int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoImage *image, + IsoFileSource **src) { int ret; struct stat atts; @@ -2780,18 +2864,25 @@ int create_boot_img_filesrc(IsoImageFilesystem *fs, IsoFileSource **src) memset(&atts, 0, sizeof(struct stat)); atts.st_mode = S_IFREG; +#ifdef Libisofs_hardlink_prooF + + /* ts A90427 : img_give_ino_number() is coordinated with existing inos */ + atts.st_ino = img_give_ino_number(image, 0); + +#else /* Libisofs_hardlink_prooF */ + #ifdef Libisofs_new_fs_image_inO atts.st_ino = fs_give_ino_number(fs, 0); #else /* Libisofs_new_fs_image_inO */ - /* ts A90426 : >>> need a unique inode for El-Torito boot image */ - atts.st_ino = fsdata->imgblock; /* not the best solution, but... */ #endif /* ! Libisofs_new_fs_image_inO */ +#endif /* ! Libisofs_hardlink_prooF */ + atts.st_nlink = 1; /* @@ -2953,12 +3044,40 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, goto import_revert; } +#ifdef Libisofs_hardlink_prooF + + /* ts A90428 */ + /* Take over inode management from IsoImageFilesystem. + data->inode_counter is supposed to hold the maximum PX inode number. + */ + image->inode_counter = data->inode_counter; + + /* ts A90426 */ + if ((data->px_ino_status & (2 | 4 | 8)) || opts->make_new_ino) { + + /* >>> ??? is there any benefit with stable ino for directories ? + if so: add 4 to img_make_inos(flag) + */ + ret = img_make_inos(image, image->root, 8 | 2 | !!opts->make_new_ino); + if (ret < 0) { + iso_node_builder_unref(image->builder); + goto import_revert; + } + + /* <<< debugging */ + } else { + /* <<< just for the duplicate inode check */ + img_collect_inos(image, image->root, 0); + } + +#endif /* ! Libisofs_hardlink_prooF */ + if (data->eltorito) { /* if catalog and image nodes were not filled, we create them here */ if (image->bootcat->image->image == NULL) { IsoFileSource *src; IsoNode *node; - ret = create_boot_img_filesrc(fs, &src); + ret = create_boot_img_filesrc(fs, image, &src); if (ret < 0) { iso_node_builder_unref(image->builder); goto import_revert; diff --git a/libisofs/image.c b/libisofs/image.c index 693e8cf..d9c419a 100644 --- a/libisofs/image.c +++ b/libisofs/image.c @@ -14,6 +14,7 @@ #include #include +#include /** * Create a new image, empty. @@ -73,6 +74,9 @@ int iso_image_new(const char *name, IsoImage **image) } img->builder_ignore_acl = 1; img->builder_ignore_ea = 1; + img->inode_counter = 0; + img->used_inodes = NULL; + img->used_inodes_start = 0; *image = img; return ISO_SUCCESS; } @@ -119,6 +123,11 @@ void iso_image_unref(IsoImage *image) free(image->copyright_file_id); free(image->abstract_file_id); free(image->biblio_file_id); + + /* ts A90428 */ + if (image->used_inodes != NULL) + free(image->used_inodes); + free(image); } } @@ -318,3 +327,217 @@ void iso_image_set_ignore_aclea(IsoImage *image, int what) image->builder_ignore_ea = !!(what & 2); } + +/* ts A90428 */ +static +int img_register_ino(IsoImage *image, IsoNode *node, int flag) +{ + int ret; + ino_t ino; + unsigned int fs_id; + dev_t dev_id; + + ret = iso_node_get_id(node, &fs_id, &dev_id, &ino, 1); + if (ret < 0) + return ret; + if (ret > 0 && ino >= image->used_inodes_start && + ino < image->used_inodes_start + ISO_USED_INODE_RANGE) { + + /* <<< */ + if (ino && + image->used_inodes[(ino - image->used_inodes_start) / 8] + & (1 << (ino % 8))) + fprintf(stderr, + "libisofs_DEBUG: found duplicate inode number %.f\n", + (double) ino); + + image->used_inodes[(ino - image->used_inodes_start) / 8] + |= (1 << (ino % 8)); + } + return 1; +} + + +/* ts A90428 */ +/* Collect the bitmap of used inode numbers in the range of + _ImageFsData.used_inodes_start + ISO_USED_INODE_RANGE + @param flag bit0= recursion is active +*/ +int img_collect_inos(IsoImage *image, IsoDir *dir, int flag) +{ + int ret, register_dir = 1; + IsoDirIter *iter; + IsoNode *node; + IsoDir *subdir; + + if (dir == NULL) + dir = image->root; + if (image->used_inodes == NULL) { + image->used_inodes = calloc(ISO_USED_INODE_RANGE / 8, 1); + if (image->used_inodes == NULL) + return ISO_OUT_OF_MEM; + } else if(!(flag & 1)) { + memset(image->used_inodes, 0, ISO_USED_INODE_RANGE / 8); + } else { + register_dir = 0; + } + if (register_dir) { + node = (IsoNode *) dir; + ret = img_register_ino(image, node, 0); + if (ret < 0) + return ret; + } + + ret = iso_dir_get_children(dir, &iter); + if (ret < 0) + return ret; + while (iso_dir_iter_next(iter, &node) == 1 ) { + ret = img_register_ino(image, node, 0); + if (ret < 0) + if (ret < 0) + goto ex; + if (iso_node_get_type(node) == LIBISO_DIR) { + subdir = (IsoDir *) node; + ret = img_collect_inos(image, subdir, flag | 1); + if (ret < 0) + goto ex; + } + } + ret = 1; +ex:; + iso_dir_iter_free(iter); + return ret; +} + + +/* ts A90428 */ +/** + * A global counter for inode numbers for the ISO image filesystem. + * On image import it gets maxed by the eventual inode numbers from PX + * entries. Up to the first 32 bit rollover it simply increments the counter. + * After the first rollover it uses a look ahead bitmap which gets filled + * by a full tree traversal. It covers the next inode numbers to come + * (somewhere between 1 and ISO_USED_INODE_RANGE which is quite many) + * and advances when being exhausted. + * @param image The image where the number shall be used + * @param flag bit0= reset count (Caution: image must get new inos then) + * @return + * Since ino_t 0 is used as default and considered self-unique, + * the value 0 should only be returned in case of error. + */ +ino_t img_give_ino_number(IsoImage *image, int flag) +{ + int ret; + ino_t new_ino, ino_idx; + static uint64_t limit = 0xffffffff; + + if (flag & 1) { + image->inode_counter = 0; + if (image->used_inodes != NULL) + free(image->used_inodes); + image->used_inodes = NULL; + image->used_inodes_start = 0; + } + new_ino = image->inode_counter + 1; + if (image->used_inodes == NULL) { + if (new_ino > 0 && new_ino <= limit) { + image->inode_counter = new_ino; + return image->inode_counter; + } + } + /* Look for free number in used territory */ + while (1) { + if (new_ino <= 0 || new_ino > limit || + new_ino >= image->used_inodes_start + ISO_USED_INODE_RANGE ) { + + /* Collect a bitmap of used inode numbers ahead */ + + image->used_inodes_start += ISO_USED_INODE_RANGE; + if (image->used_inodes_start > 0xffffffff || + image->used_inodes_start <= 0) + image->used_inodes_start = 0; + ret = img_collect_inos(image, NULL, 0); + if (ret < 0) + goto return_result; /* >>> need error return value */ + + new_ino = image->used_inodes_start + !image->used_inodes_start; + } + ino_idx = (new_ino - image->used_inodes_start) / 8; + if (!(image->used_inodes[ino_idx] & (1 << (new_ino % 8)))) { + image->used_inodes[ino_idx] |= (1 << (new_ino % 8)); + break; + } + new_ino++; + } +return_result:; + image->inode_counter = new_ino; + return image->inode_counter; +} + + +/* @param flag bit0= overwrite any ino, else only ino == 0 + bit1= install inode with non-data, non-directory files + bit2= install inode with directories +*/ +static +int img_update_ino(IsoImage *image, IsoNode *node, int flag) +{ + int ret; + ino_t ino; + unsigned int fs_id; + dev_t dev_id; + + ret = iso_node_get_id(node, &fs_id, &dev_id, &ino, 1); + if (ret < 0) + return ret; + if (ret == 0) + ino = 0; + if (((flag & 1) || ino == 0) && + (iso_node_get_type(node) == LIBISO_FILE || (flag & 2)) && + ((flag & 4) || iso_node_get_type(node) != LIBISO_DIR)) { + ret = iso_node_set_unique_id(node, image, 0); + if (ret < 0) + return ret; + } + return 1; +} + + +/* @param flag bit0= overwrite any ino, else only ino == 0 + bit1= install inode with non-data, non-directory files + bit2= install inode with directories + bit3= with bit2: install inode on parameter dir +*/ +int img_make_inos(IsoImage *image, IsoDir *dir, int flag) +{ + int ret; + IsoDirIter *iter; + IsoNode *node; + IsoDir *subdir; + + if (flag & 8) { + node = (IsoNode *) dir; + ret = img_update_ino(image, node, flag & 7); + if (ret < 0) + goto ex; + } + ret = iso_dir_get_children(dir, &iter); + if (ret < 0) + return ret; + while (iso_dir_iter_next(iter, &node) == 1) { + ret = img_update_ino(image, node, flag & 7); + if (ret < 0) + goto ex; + if (iso_node_get_type(node) == LIBISO_DIR) { + subdir = (IsoDir *) node; + ret = img_make_inos(image, subdir, flag & ~8); + if (ret < 0) + goto ex; + } + } + ret = 1; +ex:; + iso_dir_iter_free(iter); + return ret; +} + diff --git a/libisofs/image.h b/libisofs/image.h index eac3e9e..a56fc8a 100644 --- a/libisofs/image.h +++ b/libisofs/image.h @@ -13,6 +13,14 @@ #include "fsource.h" #include "builder.h" +/* Size of a inode recycling window. Each new window causes a tree traversal. + Window memory consumption is ISO_USED_INODE_RANGE / 8. + This must be a power of 2 smaller than 30 bit and larger than 8 bit. + Here: 32 kB memory for 256k inodes. +*/ +#define ISO_USED_INODE_RANGE (1 << 18) + + /* * Image is a context for image manipulation. * Global objects such as the message_queues must belogn to that @@ -121,6 +129,59 @@ struct Iso_Image */ void *user_data; void (*user_data_free)(void *ptr); + + /* ts A90427 */ + /** + * Inode number management. inode_counter is taken over from + * IsoImageFilesystem._ImageFsData after image import. + * It is to be used with img_give_ino_number() + */ + ino_t inode_counter; + /* + * A bitmap of used inode numbers in an interval beginning at + * used_inodes_start and holding ISO_USED_INODE_RANGE bits. + * If a bit is set, then the corresponding inode number is occupied. + * This interval is kept around inode_counter and eventually gets + * advanced by ISO_USED_INODE_RANGE numbers in a tree traversal + * done by img_collect_inos(). + */ + uint8_t *used_inodes; + ino_t used_inodes_start; + }; + + +/* ts A90428 */ +/* Collect the bitmap of used inode numbers in the range of + _ImageFsData.used_inodes_start + ISO_USED_INODE_RANGE + @param flag bit0= recursion is active +*/ +int img_collect_inos(IsoImage *image, IsoDir *dir, int flag); + +/* ts A90428 */ +/** + * A global counter for inode numbers for the ISO image filesystem. + * On image import it gets maxed by the eventual inode numbers from PX + * entries. Up to the first 32 bit rollover it simply increments the counter. + * After the first rollover it uses a look ahead bitmap which gets filled + * by a full tree traversal. It covers the next inode numbers to come + * (somewhere between 1 and ISO_USED_INODE_RANGE which is quite many) + * and advances when being exhausted. + * @param image The image where the number shall be used + * @param flag bit0= reset count (Caution: image must get new inos then) + * @return + * Since ino_t 0 is used as default and considered self-unique, + * the value 0 should only be returned in case of error. + */ +ino_t img_give_ino_number(IsoImage *image, int flag); + +/* ts A90428 */ +/* @param flag bit0= overwrite any ino, else only ino == 0 + bit1= install inode with non-data, non-directory files + bit2= install inode with directories + bit3= with bit2: install inode on parameter dir +*/ +int img_make_inos(IsoImage *image, IsoDir *dir, int flag); + #endif /*LIBISO_IMAGE_H_*/ diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 45878a7..da33960 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -5002,18 +5002,6 @@ int iso_gzip_get_refcounts(off_t *gzip_count, off_t *gunzip_count, int flag); /** El-Torito image is hidden (WARNING,HIGH, -335) */ #define ISO_EL_TORITO_HIDDEN 0xD030FEB1 -/** Read error occured with IsoDataSource (SORRY,HIGH, -513) */ -#define ISO_DATA_SOURCE_SORRY 0xE030FCFF - -/** Read error occured with IsoDataSource (MISHAP,HIGH, -513) */ -#define ISO_DATA_SOURCE_MISHAP 0xE430FCFF - -/** Read error occured with IsoDataSource (FAILURE,HIGH, -513) */ -#define ISO_DATA_SOURCE_FAILURE 0xE830FCFF - -/** Read error occured with IsoDataSource (FATAL,HIGH, -513) */ -#define ISO_DATA_SOURCE_FATAL 0xF030FCFF - /** AAIP info with ACL or xattr in ISO image will be ignored (NOTE, HIGH, -336) */ @@ -5070,6 +5058,25 @@ int iso_gzip_get_refcounts(off_t *gzip_count, off_t *gunzip_count, int flag); #define ISO_ZLIB_EARLY_EOF 0xE830FEA1 +/* ! PLACE NEW ERROR CODES HERE ! */ + + +/** Read error occured with IsoDataSource (SORRY,HIGH, -513) */ +#define ISO_DATA_SOURCE_SORRY 0xE030FCFF + +/** Read error occured with IsoDataSource (MISHAP,HIGH, -513) */ +#define ISO_DATA_SOURCE_MISHAP 0xE430FCFF + +/** Read error occured with IsoDataSource (FAILURE,HIGH, -513) */ +#define ISO_DATA_SOURCE_FAILURE 0xE830FCFF + +/** Read error occured with IsoDataSource (FATAL,HIGH, -513) */ +#define ISO_DATA_SOURCE_FATAL 0xF030FCFF + + +/* ! PLACE NEW ERROR CODES ABOVE. NOT HERE ! */ + + /* ------------------------------------------------------------------------- */ #ifdef LIBISOFS_WITHOUT_LIBBURN @@ -5268,9 +5275,24 @@ struct burn_source { #define Libisofs_aaip_2_0 yes +/* Encapsulation : Use iso_iconv*() wrappers. + They can print errno messages and they + can avoid iconv() if the identical mapping is desired. + One could install own simple conversion capabilities. +*/ +#define Libisofs_with_iso_iconV yes + + /* ---------------------------- Experiments ---------------------------- */ +/* Hardlinks : Override Libisofs_new_fs_image_inO and preserve inode numbers + from session to session. + >>> STILL IMMATURE. DO NOT USE YET. +*/ +#define Libisofs_hardlink_prooF yes + + /* Experiment: Ignore PX inode numbers, have boot image inode number counted by fs_give_ino_number() */ @@ -5301,12 +5323,5 @@ struct burn_source { */ -/* Experiment: Use iso_iconv*() wrappers. - They can print errno messages and they - can avoid iconv() if the identical mapping is desired. - One could install own simple conversion capabilities. -*/ -#define Libisofs_with_iso_iconV yes - #endif /*LIBISO_LIBISOFS_H_*/ diff --git a/libisofs/node.c b/libisofs/node.c index 5004c7b..6ba7a70 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -8,6 +8,7 @@ */ #include "libisofs.h" +#include "image.h" #include "node.h" #include "stream.h" #include "aaip_0_2.h" @@ -2239,3 +2240,112 @@ int iso_node_zf_by_magic(IsoNode *node, int flag) return total_ret; } + +/* <<< ts A90427 : to some other source module ? In what .h ? */ +int iso_px_ino_xinfo_func(void *data, int flag) +{ + if (flag == 1) { + free(data); + } + return 1; +} + + +/* ts A90427 */ +/* + * @param flag + * bit0= do only retrieve id if node is in imported ISO image + * or has an explicit xinfo inode number + * @return + * 1= reply is valid from stream, 2= reply is valid from xinfo + * 0= no id available, <0= error + */ +int iso_node_get_id(IsoNode *node, unsigned int *fs_id, dev_t *dev_id, + ino_t *ino_id, int flag) +{ + int ret; + IsoFile *file; + void *xipt; + + ret = iso_node_get_xinfo(node, iso_px_ino_xinfo_func, &xipt); + if (ret < 0) + return ret; + if (ret == 1) { + *fs_id = ISO_IMAGE_FS_ID; + *dev_id = 0; + *ino_id = *((ino_t *) xipt); + return 2; + } + + if (node->type == LIBISO_FILE) { + file= (IsoFile *) node; + iso_stream_get_id(file->stream, fs_id, dev_id, ino_id); + if (*fs_id != ISO_IMAGE_FS_ID && (flag & 1)) + return 0; + return 1; + } + return 0; +} + + +/* ts A90427 */ +static +int iso_node_set_ino_xinfo(IsoNode *node, ino_t ino, int flag) +{ + int ret; + void *xipt; + + if (flag & 1) { + ret = iso_node_remove_xinfo(node, iso_px_ino_xinfo_func); + if (ret < 0) + return ret; + } + xipt = calloc(1, sizeof(ino_t)); + if (xipt == NULL) + return ISO_OUT_OF_MEM; + memcpy(xipt, &ino, sizeof(ino_t)); + ret = iso_node_add_xinfo(node, iso_px_ino_xinfo_func, xipt); + return ret; +} + + +/* ts A90427 */ +int iso_node_set_ino(IsoNode *node, ino_t ino, int flag) +{ + int ret; + IsoFile *file; + void *xipt; + + ret = iso_node_get_xinfo(node, iso_px_ino_xinfo_func, &xipt); + if (ret < 0) + return ret; + if (ret == 1) { + ret = iso_node_set_ino_xinfo(node, ino, 1); + if (ret < 0) + return ret; + return 2; + } + if (node->type == LIBISO_FILE) { + file= (IsoFile *) node; + ret = iso_stream_set_image_ino(file->stream, ino, 0); + if (ret < 0 || ret == 1) + return ret; + } + ret = iso_node_set_ino_xinfo(node, ino, 0); + if (ret < 0) + return ret; + return 2; +} + + +/* ts A90427 */ +int iso_node_set_unique_id(IsoNode *node, IsoImage *image, int flag) +{ + int ret; + ino_t ino; + + ino = img_give_ino_number(image, 0); + ret = iso_node_set_ino(node, ino, 0); + return ret; +} + diff --git a/libisofs/node.h b/libisofs/node.h index 62014dc..6bec92b 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -399,4 +399,29 @@ struct zisofs_zf_info { int iso_file_zf_by_magic(IsoFile *file, int flag); + +/* ts A90427 : might become API */ +/* + * @param flag + * bit0= do only retrieve id if node is in imported ISO image + * or has an explicit xinfo inode number + * @return + * 1= reply is valid from stream, 2= reply is valid from xinfo + * 0= no id available, <0= error + */ +int iso_node_get_id(IsoNode *node, unsigned int *fs_id, dev_t *dev_id, + ino_t *ino_id, int flag); + +/* ts A90427 */ +/* Set a new unique inode ISO image number to the given node. + * This number shall eventually persist during image generation. + */ +int iso_node_set_unique_id(IsoNode *node, IsoImage *image, int flag); + +/* ts A90427 */ +/* Use this with extreme care. Duplicate inode numbers will indicate hardlink + * relationship between the nodes. + */ +int iso_node_set_ino(IsoNode *node, ino_t ino, int flag); + #endif /*LIBISO_NODE_H_*/ diff --git a/libisofs/rockridge.h b/libisofs/rockridge.h index 23f5e9e..5a9d370 100644 --- a/libisofs/rockridge.h +++ b/libisofs/rockridge.h @@ -263,7 +263,9 @@ void susp_iter_free(SuspIterator *iter); * Fills a struct stat with the values of a Rock Ridge PX entry (RRIP, 4.1.1). * * @return - * 1 on success, < 0 on error + * < 0 on error + * 1 on success with no inode number, + * 2 on success with inode number, */ int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st); diff --git a/libisofs/rockridge_read.c b/libisofs/rockridge_read.c index 77c107f..1933968 100644 --- a/libisofs/rockridge_read.c +++ b/libisofs/rockridge_read.c @@ -169,11 +169,15 @@ int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st) st->st_nlink = iso_read_bb(px->data.PX.links, 4, NULL); st->st_uid = iso_read_bb(px->data.PX.uid, 4, NULL); st->st_gid = iso_read_bb(px->data.PX.gid, 4, NULL); + st->st_ino = 0; if (px->len_sue[0] == 44) { /* this corresponds to RRIP 1.12, so we have inode serial number */ st->st_ino = iso_read_bb(px->data.PX.serial, 4, NULL); + + /* ts A90426 : Indicate that st_ino is valid */ + return 2; } - return ISO_SUCCESS; + return 1; } /** diff --git a/libisofs/stream.c b/libisofs/stream.c index 5ceb268..1218d9e 100644 --- a/libisofs/stream.c +++ b/libisofs/stream.c @@ -672,8 +672,12 @@ void iso_stream_get_file_name(IsoStream *stream, char *name) IsoStream *iso_stream_get_input_stream(IsoStream *stream, int flag) { - IsoStreamIface* class = stream->class; + IsoStreamIface* class; + if (stream == NULL) { + return ISO_NULL_POINTER; + } + class = stream->class; if (class->version < 2) return NULL; return class->get_input_stream(stream, 0); @@ -709,3 +713,18 @@ ex:; return path; } +/* ts A90427 */ +/* @return 1 = ok , 0 = not an ISO image stream , <0 = error */ +int iso_stream_set_image_ino(IsoStream *stream, ino_t ino, int flag) +{ + if (stream == NULL) { + return ISO_NULL_POINTER; + } + if (stream->class == &fsrc_stream_class) { + FSrcStreamData *fsrc_data = stream->data; + fsrc_data->ino_id = ino; + return 1; + } + return 0; +} + diff --git a/libisofs/stream.h b/libisofs/stream.h index 5585bc0..e3da41a 100644 --- a/libisofs/stream.h +++ b/libisofs/stream.h @@ -74,4 +74,12 @@ int iso_stream_get_src_zf(IsoStream *stream, int *header_size_div4, int *block_size_log2, uint32_t *uncompressed_size, int flag); +/* ts A90427 */ +/** + * Set the inode number of a stream that is based on FSrcStreamData, i.e. + * stems from the imported ISO image. + * @return 1 = ok , 0 = not an ISO image stream , <0 = error + */ +int iso_stream_set_image_ino(IsoStream *stream, ino_t ino, int flag); + #endif /*STREAM_H_*/