From d20da80767dae2256d3a251809a42359ee3f941a Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 28 Apr 2009 22:40:15 +0200 Subject: [PATCH] Transfering inode numbers from PX entries to IsoNode during image import and using these numbers in PX entries during next image generation. This also answers the concerns about PX without ino in RRIP 1.12 and PX with ino in RRIP 1.10 images produced by mkisofs. --- Makefile.am | 44 ++++---- libisofs/ecma119_tree.c | 26 ++++- libisofs/filesrc.c | 51 +++++---- libisofs/fs_image.c | 143 ++++++++++++++++++++++-- libisofs/image.c | 223 ++++++++++++++++++++++++++++++++++++++ libisofs/image.h | 61 +++++++++++ libisofs/libisofs.h | 53 +++++---- libisofs/node.c | 110 +++++++++++++++++++ libisofs/node.h | 25 +++++ libisofs/rockridge.h | 4 +- libisofs/rockridge_read.c | 6 +- libisofs/stream.c | 21 +++- libisofs/stream.h | 8 ++ 13 files changed, 696 insertions(+), 79 deletions(-) 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_*/