diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index 3e0a516..fce88b5 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -887,6 +887,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->rockridge = opts->rockridge; target->joliet = opts->joliet; target->iso1999 = opts->iso1999; + target->hardlinks = opts->hardlinks; target->aaip = opts->aaip; target->always_gmt = opts->always_gmt; target->ino = 0; @@ -901,6 +902,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->relaxed_vol_atts = opts->relaxed_vol_atts; target->joliet_longer_paths = opts->joliet_longer_paths; target->rrip_version_1_10 = opts->rrip_version_1_10; + target->rrip_1_10_px_ino = opts->rrip_1_10_px_ino; target->aaip_susp_1_10 = opts->aaip_susp_1_10; target->dir_rec_mtime = opts->dir_rec_mtime; target->sort_files = opts->sort_files; @@ -1427,6 +1429,15 @@ int iso_write_opts_set_iso1999(IsoWriteOpts *opts, int enable) return ISO_SUCCESS; } +int iso_write_opts_set_hardlinks(IsoWriteOpts *opts, int enable) +{ + if (opts == NULL) { + return ISO_NULL_POINTER; + } + opts->hardlinks = enable ? 1 : 0; + return ISO_SUCCESS; +} + int iso_write_opts_set_aaip(IsoWriteOpts *opts, int enable) { if (opts == NULL) { @@ -1526,6 +1537,15 @@ int iso_write_opts_set_rrip_version_1_10(IsoWriteOpts *opts, int oldvers) return ISO_SUCCESS; } +int iso_write_opts_set_rrip_1_10_px_ino(IsoWriteOpts *opts, int enable) +{ + if (opts == NULL) { + return ISO_NULL_POINTER; + } + opts->rrip_1_10_px_ino = enable ? 1 : 0; + return ISO_SUCCESS; +} + int iso_write_opts_set_aaip_susp_1_10(IsoWriteOpts *opts, int oldvers) { if (opts == NULL) { diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index 90a46fe..9b28ac9 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -115,6 +115,14 @@ struct iso_write_opts { */ unsigned int rrip_version_1_10 :1; + /* ts A90509 */ + /** Write field PX with file serial number even with RRIP-1.10 */ + unsigned int rrip_1_10_px_ino :1; + + /* ts A90508 */ + /* See iso_write_opts_set_hardlinks() */ + unsigned int hardlinks:1; + /** * Write AAIP as extension according to SUSP 1.10 rather than SUSP 1.12. * I.e. without announcing it by an ER field and thus without the need @@ -269,7 +277,10 @@ struct ecma119_image unsigned int eltorito :1; unsigned int iso1999 :1; - unsigned int aaip :1; /* whether to write eventual ACLs and EAs */ + /* ts A90508 */ + unsigned int hardlinks:1; /* see iso_write_opts_set_hardlinks() */ + + unsigned int aaip :1; /* see iso_write_opts_set_aaip() */ /* allways write timestamps in GMT */ unsigned int always_gmt :1; @@ -291,6 +302,10 @@ struct ecma119_image /** Write old fashioned RRIP-1.10 rather than RRIP-1.12 */ unsigned int rrip_version_1_10 :1; + /* ts A90509 */ + /** Write field PX with file serial number even with RRIP-1.10 */ + unsigned int rrip_1_10_px_ino :1; + /* Write AAIP as extension according to SUSP 1.10 rather than SUSP 1.12. */ unsigned int aaip_susp_1_10 :1; @@ -318,6 +333,8 @@ struct ecma119_image */ int sort_files; + + /* ts A90508 : <<< this is on its way out */ /** * In the CD, each file must have an unique inode number. So each * time we add a new file, this is incremented. diff --git a/libisofs/ecma119_tree.c b/libisofs/ecma119_tree.c index c8be8e4..426e43a 100644 --- a/libisofs/ecma119_tree.c +++ b/libisofs/ecma119_tree.c @@ -889,80 +889,55 @@ int make_node_array(Ecma119Image *img, Ecma119Node *dir, return result; } -/* ts A90503 */ +/* ts A90508 */ +/* + * @param flag + * bit0= compare stat properties and attributes + * bit1= treat all nodes with image ino == 0 as unique + */ static -int ecma119_node_cmp(const void *v1, const void *v2) +int ecma119_node_cmp_flag(const void *v1, const void *v2, int flag) { - int ret1, ret2; + int ret; Ecma119Node *n1, *n2; - unsigned int fs_id1, fs_id2; - dev_t dev_id1, dev_id2; - ino_t ino_id1, ino_id2; n1 = *((Ecma119Node **) v1); n2 = *((Ecma119Node **) v2); if (n1 == n2) return 0; - - /* Imported or explicite ISO image node id has absolute priority */ - ret1 = (iso_node_get_id(n1->node, &fs_id1, &dev_id1, &ino_id1, 1) > 0); - ret2 = (iso_node_get_id(n2->node, &fs_id2, &dev_id2, &ino_id2, 1) > 0); - if (ret1 != ret2) - return (ret1 < ret2 ? -1 : 1); - if (ret1) { - /* fs_id and dev_id do not matter here. - Both nodes have explicite inode numbers of the emerging image. - */ - return (ino_id1 < ino_id2 ? -1 : ino_id1 > ino_id2 ? 1 : 0); - } - - if (n1->type < n2->type) - return -1; - if (n1->type > n2->type) - return 1; - - if (n1->type == ECMA119_FILE) { - ret1 = iso_file_src_cmp(n1->info.file, n2->info.file); - return ret1; - -#ifdef Libisofs_hardlink_matcheR - - } else if (n1->type == ECMA119_SYMLINK) { - IsoSymlink *t1, *t2; - - t1 = (IsoSymlink *) (n1->node); - t2 = (IsoSymlink *) (n2->node); - return (t1->fs_id < t2->fs_id ? -1 : t1->fs_id > t2->fs_id ? 1 : - t1->st_dev < t2->st_dev ? -1 : t1->st_dev > t2->st_dev ? 1 : - t1->st_ino < t2->st_ino ? -1 : t1->st_ino > t2->st_ino ? 1 : - t1->fs_id || t1->st_dev || t1->st_ino ? 0 : (v1 < v2 ? -1 : 1)); - - } else if (n1->type == ECMA119_SPECIAL) { - IsoSpecial *t1, *t2; - - t1 = (IsoSpecial *) (n1->node); - t2 = (IsoSpecial *) (n2->node); - return (t1->fs_id < t2->fs_id ? -1 : t1->fs_id > t2->fs_id ? 1 : - t1->st_dev < t2->st_dev ? -1 : t1->st_dev > t2->st_dev ? 1 : - t1->st_ino < t2->st_ino ? -1 : t1->st_ino > t2->st_ino ? 1 : - t1->fs_id || t1->st_dev || t1->st_ino ? 0 : (v1 < v2 ? -1 : 1)); - -#endif /* Libisofs_hardlink_matcheR */ - - } else { - return (v1 < v2 ? -1 : 1); /* case v1 == v2 is handled above */ - } - return 0; + ret = iso_node_cmp_flag(n1->node, n2->node, flag & (1 | 2)); + return ret; } +/* ts A90508 */ +static +int ecma119_node_cmp_hard(const void *v1, const void *v2) +{ + return ecma119_node_cmp_flag(v1, v2, 1); +} + +/* ts A90509 */ +static +int ecma119_node_cmp_nohard(const void *v1, const void *v2) +{ + return ecma119_node_cmp_flag(v1, v2, 1 | 2); +} + /* ts A90503 */ static int family_set_ino(Ecma119Image *img, Ecma119Node **nodes, size_t family_start, - size_t next_family, ino_t img_ino, int flag) + size_t next_family, ino_t img_ino, ino_t prev_ino, int flag) { size_t i; + if (img_ino != 0) { + /* Check whether this is the same img_ino as in the previous + family (e.g. by property divergence of imported hardlink). + */ + if (img_ino == prev_ino) + img_ino = 0; + } if (img_ino == 0) { img_ino = img_give_ino_number(img->image, 0); } @@ -982,7 +957,7 @@ int match_hardlinks(Ecma119Image *img, Ecma119Node *dir, int flag) Ecma119Node **nodes = NULL; unsigned int fs_id; dev_t dev_id; - ino_t img_ino = 0; + ino_t img_ino = 0, prev_ino = 0; ret = make_node_array(img, dir, nodes, nodes_size, &node_count, 2); if (ret < 0) @@ -995,27 +970,34 @@ int match_hardlinks(Ecma119Image *img, Ecma119Node *dir, int flag) if (ret < 0) goto ex; - /* Sort according to id tuples and IsoFileSrc identity. */ - qsort(nodes, node_count, sizeof(Ecma119Node *), ecma119_node_cmp); + /* Sort according to id tuples, IsoFileSrc identity, properties, xattr. */ + if (img->hardlinks) + qsort(nodes, node_count, sizeof(Ecma119Node *), ecma119_node_cmp_hard); + else + qsort(nodes, node_count, sizeof(Ecma119Node *), + ecma119_node_cmp_nohard); /* Hand out image inode numbers to all Ecma119Node.ino == 0 . Same sorting rank gets same inode number. + Split those image inode number families where the sort criterion + differs. */ iso_node_get_id(nodes[0]->node, &fs_id, &dev_id, &img_ino, 1); family_start = 0; for (i = 1; i < node_count; i++) { - if (ecma119_node_cmp(nodes + (i - 1), nodes + i) == 0) { + if (ecma119_node_cmp_hard(nodes + (i - 1), nodes + i) == 0) { /* Still in same ino family */ if (img_ino == 0) { /* Just in case any member knows its img_ino */ iso_node_get_id(nodes[0]->node, &fs_id, &dev_id, &img_ino, 1); } continue; } - family_set_ino(img, nodes, family_start, i, img_ino, 0); + family_set_ino(img, nodes, family_start, i, img_ino, prev_ino, 0); + prev_ino = img_ino; iso_node_get_id(nodes[i]->node, &fs_id, &dev_id, &img_ino, 1); family_start = i; } - family_set_ino(img, nodes, family_start, i, img_ino, 0); + family_set_ino(img, nodes, family_start, i, img_ino, prev_ino, 0); ret = ISO_SUCCESS; ex:; diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 74eb538..c32f42b 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1186,15 +1186,48 @@ int iso_write_opts_set_joliet(IsoWriteOpts *opts, int enable); */ int iso_write_opts_set_iso1999(IsoWriteOpts *opts, int enable); +/* ts A90508 */ +/** + * Control generation of non-unique inode numbers for the emerging image. + * Inode numbers get written as "file serial number" with PX entries as of + * RRIP-1.12. They may mark families of hardlinks. + * RRIP-1.10 prescribes a PX entry without file serial number. If not overriden + * by iso_write_opts_set_rrip_1_10_px_ino() there will be no file serial + * written into RRIP-1.10 images. + * + * Inode number generation does not affect IsoNode objects which imported their + * inode numbers from the old ISO image (see iso_read_opts_set_new_inos()) + * and which have not been altered since import. It rather applies to IsoNode + * objects which were newly added to the image, or to IsoNode which brought no + * inode number from the old image, or to IsoNode where certain properties + * have been altered since image import. + * + * If two IsoNode are found with same imported inode number but differing + * properties, then one of them will get assigned a new unique inode number. + * I.e. the hardlink relation between both IsoNode objects ends. + * + * @param enable + * 1 = Collect IsoNode objects which have identical data sources and + * properties. + * 0 = Generate unique inode numbers for all IsoNode objects which do not + * have a valid inode number from an imported ISO image. + * All other values are reserved. + * + * @since 0.6.20 + */ +int iso_write_opts_set_hardlinks(IsoWriteOpts *opts, int enable); + /** * Control writing of AAIP informations for ACL and xattr. * For importing ACL and xattr when inserting nodes from external filesystems * (e.g. the local POSIX filesystem) see iso_image_set_ignore_aclea(). * For loading of this information from images see iso_read_opts_set_no_aaip(). * - * @param enable 1 = write AAIP information from nodes into the image - * 0 = do not write AAIP information into the image - * All other values are reserved. + * @param enable + * 1 = write AAIP information from nodes into the image + * 0 = do not write AAIP information into the image + * All other values are reserved. + * * @since 0.6.14 */ int iso_write_opts_set_aaip(IsoWriteOpts *opts, int enable); @@ -1290,6 +1323,19 @@ int iso_write_opts_set_joliet_longer_paths(IsoWriteOpts *opts, int allow); */ int iso_write_opts_set_rrip_version_1_10(IsoWriteOpts *opts, int oldvers); +/* ts A90509 */ +/** + * Write field PX with file serial number (i.e. inode number) even if + * iso_write_opts_set_rrip_version_1_10(,1) is in effect. + * This clearly violates the RRIP-1.10 specs. But it is done by mkisofs since + * a while and no widespread protest is visible in the web. + * If this option is not enabled, then iso_write_opts_set_hardlinks() will + * only have an effect with iso_write_opts_set_rrip_version_1_10(,0). + * + * @since 0.6.20 + */ +int iso_write_opts_set_rrip_1_10_px_ino(IsoWriteOpts *opts, int enable); + /** * Write AAIP as extension according to SUSP 1.10 rather than SUSP 1.12. * I.e. without announcing it by an ER field and thus without the need diff --git a/libisofs/node.c b/libisofs/node.c index 68e2600..549ad74 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -2420,3 +2420,140 @@ int iso_node_set_unique_id(IsoNode *node, IsoImage *image, int flag) return ret; } +/* ts A90508 */ +/* + * @param flag + * bit0= compare stat properties and attributes + * bit1= treat all nodes with image ino == 0 as unique + */ +int iso_node_cmp_flag(IsoNode *n1, IsoNode *n2, int flag) +{ + int ret1, ret2; + unsigned int fs_id1, fs_id2; + dev_t dev_id1, dev_id2; + ino_t ino_id1, ino_id2; + IsoFile *f1 = NULL, *f2 = NULL; + IsoSymlink *l1 = NULL, *l2 = NULL; + IsoSpecial *s1 = NULL, *s2 = NULL; + void *x1, *x2; + + if (n1 == n2) + return 0; + + /* Imported or explicite ISO image node id has absolute priority */ + ret1 = (iso_node_get_id(n1, &fs_id1, &dev_id1, &ino_id1, 1) > 0); + ret2 = (iso_node_get_id(n2, &fs_id2, &dev_id2, &ino_id2, 1) > 0); + if (ret1 != ret2) + return (ret1 < ret2 ? -1 : 1); + if (ret1) { + /* fs_id and dev_id do not matter here. + Both nodes have explicit inode numbers of the emerging image. + */ + if (ino_id1 != ino_id2) + return (ino_id1 < ino_id2 ? -1 : 1); + goto inode_match; + } + + if (n1->type != n2->type) + return (n1->type < n2->type ? -1 : 1); + + if (n1->type == LIBISO_FILE) { + + f1 = (IsoFile *) n1; + f2 = (IsoFile *) n2; + ret1 = iso_stream_cmp_ino(f1->stream, f2->stream, 0); + if (ret1) + return ret1; + goto inode_match; + +#ifdef Libisofs_hardlink_matcheR + + } else if (n1->type == LIBISO_SYMLINK) { + + l1 = (IsoSymlink *) n1; + l2 = (IsoSymlink *) n2; + fs_id1 = l1->fs_id; + dev_id1 = l1->st_dev; + ino_id1 = l1->st_ino; + fs_id2 = l2->fs_id; + dev_id2 = l2->st_dev; + ino_id2 = l2->st_ino; + + } else if (n1->type == LIBISO_SPECIAL) { + + s1 = (IsoSpecial *) n1; + s2 = (IsoSpecial *) n2; + fs_id1 = s1->fs_id; + dev_id1 = s1->st_dev; + ino_id1 = s1->st_ino; + fs_id2 = s2->fs_id; + dev_id2 = s2->st_dev; + ino_id2 = s2->st_ino; + +#endif /* Libisofs_hardlink_matcheR */ + + } else { + return (n1 < n2 ? -1 : 1); /* case n1 == n2 is handled above */ + } + if (fs_id1 != fs_id2) + return (fs_id1 < fs_id2 ? -1 : 1); + if (dev_id1 != dev_id2) + return (dev_id1 < dev_id2 ? -1 : 1); + if (ino_id1 != ino_id2) + return (ino_id1 < ino_id2 ? -1 : 1); + if (fs_id1 == 0 && dev_id1 == 0 && ino_id1 == 0) + return (n1 < n2 ? -1 : 1); + +inode_match:; + if (flag & 2) { + iso_node_get_id(n1, &fs_id1, &dev_id1, &ino_id1, 1); + iso_node_get_id(n2, &fs_id2, &dev_id2, &ino_id2, 1); + if (ino_id1 == 0 || ino_id2 == 0) + return (n1 < n2 ? -1 : 1); + } + + if (!(flag & 1)) + return 0; + if (n1->type == LIBISO_SYMLINK) { + ret1 = strcmp(l1->dest, l2->dest); + if (ret1) + return ret1; + } else if (n1->type == LIBISO_SPECIAL) { + if (s1->dev != s2->dev) + return (s1->dev < s2->dev ? -1 : 1); + } + + if (n1->mode != n2->mode) + return (n1->mode < n2->mode ? -1 : 1); + if (n1->uid != n2->uid) + return (n1->uid < n2->uid ? -1 : 1); + if (n1->gid != n2->gid) + return (n1->gid < n2->gid ? -1 : 1); + if (n1->atime != n2->atime) + return (n1->atime < n2->atime ? -1 : 1); + if (n1->mtime != n2->mtime) + return (n1->mtime < n2->mtime ? -1 : 1); + if (n1->ctime != n2->ctime) + return (n1->ctime < n2->ctime ? -1 : 1); + + /* >>> compare xinfo */; + /* :( cannot compare general xinfo because data length is not known :( */ + + /* compare aa_string */ + ret1 = iso_node_get_xinfo(n1, aaip_xinfo_func, &x1); + ret2 = iso_node_get_xinfo(n2, aaip_xinfo_func, &x2); + if (ret1 != ret2) + return (ret1 < ret2 ? -1 : 1); + if (ret1 == 1) { + ret1 = aaip_count_bytes((unsigned char *) x1, 0); + ret2 = aaip_count_bytes((unsigned char *) x2, 0); + if (ret1 != ret2) + return (ret1 < ret2 ? -1 : 1); + ret1 = memcmp(x1, x2, ret1); + if (ret1) + return ret1; + } + + return 0; +} + diff --git a/libisofs/node.h b/libisofs/node.h index 72a0dd2..09ddeaa 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -447,4 +447,13 @@ int iso_node_set_unique_id(IsoNode *node, IsoImage *image, int flag); */ int iso_node_set_ino(IsoNode *node, ino_t ino, int flag); +/* ts A90508 */ +/* + * @param flag + * bit0= compare stat properties and attributes + * bit1= treat all nodes with image ino == 0 as unique + * (those with 0,0,0 are treated as unique anyway) + */ +int iso_node_cmp_flag(IsoNode *n1, IsoNode *n2, int flag); + #endif /*LIBISO_NODE_H_*/ diff --git a/libisofs/rockridge.c b/libisofs/rockridge.c index f3b5189..02de358 100644 --- a/libisofs/rockridge.c +++ b/libisofs/rockridge.c @@ -102,7 +102,7 @@ int rrip_add_PX(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) PX[0] = 'P'; PX[1] = 'X'; - if (!t->rrip_version_1_10) { + if (t->rrip_1_10_px_ino || !t->rrip_version_1_10 ) { PX[2] = 44; } else { PX[2] = 36; @@ -112,7 +112,7 @@ int rrip_add_PX(Ecma119Image *t, Ecma119Node *n, struct susp_info *susp) iso_bb(&PX[12], n->nlink, 4); iso_bb(&PX[20], px_get_uid(t, n), 4); iso_bb(&PX[28], px_get_gid(t, n), 4); - if (!t->rrip_version_1_10) { + if (t->rrip_1_10_px_ino || !t->rrip_version_1_10) { iso_bb(&PX[36], n->ino, 4); } @@ -1144,7 +1144,7 @@ size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t space, #endif /* PX and TF, we are sure they always fit in SUA */ - if (!t->rrip_version_1_10) { + if (t->rrip_1_10_px_ino || !t->rrip_version_1_10) { su_size += 44 + 26; } else { su_size += 36 + 26;