diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index b2c0c6f..f7ea2b2 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1650,6 +1650,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img) target->allow_full_ascii = opts->allow_full_ascii; target->relaxed_vol_atts = opts->relaxed_vol_atts; target->joliet_longer_paths = opts->joliet_longer_paths; + target->joliet_long_names = opts->joliet_long_names; 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; @@ -2641,6 +2642,15 @@ int iso_write_opts_set_joliet_longer_paths(IsoWriteOpts *opts, int allow) return ISO_SUCCESS; } +int iso_write_opts_set_joliet_long_names(IsoWriteOpts *opts, int allow) +{ + if (opts == NULL) { + return ISO_NULL_POINTER; + } + opts->joliet_long_names = allow ? 1 : 0; + return ISO_SUCCESS; +} + int iso_write_opts_set_rrip_version_1_10(IsoWriteOpts *opts, int oldvers) { if (opts == NULL) { diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index eb2768f..3e59cf7 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -161,6 +161,11 @@ struct iso_write_opts { */ unsigned int joliet_longer_paths :1; + /** + * Allow Joliet names up to 103 characters rather than 64. + */ + unsigned int joliet_long_names :1; + /** * Write Rock Ridge info as of specification RRIP-1.10 rather than * RRIP-1.12: signature "RRIP_1991A" rather than "IEEE_1282", @@ -459,6 +464,9 @@ struct ecma119_image /** Allow paths on Joliet tree to be larger than 240 bytes */ unsigned int joliet_longer_paths :1; + /** Allow Joliet names up to 103 characters rather than 64 */ + unsigned int joliet_long_names :1; + /** Write old fashioned RRIP-1.10 rather than RRIP-1.12 */ unsigned int rrip_version_1_10 :1; diff --git a/libisofs/joliet.c b/libisofs/joliet.c index 6a6c4d9..3d03768 100644 --- a/libisofs/joliet.c +++ b/libisofs/joliet.c @@ -19,6 +19,7 @@ #include "filesrc.h" #include "eltorito.h" #include "libisofs.h" +#include "util.h" #include @@ -42,12 +43,11 @@ int get_joliet_name(Ecma119Image *t, IsoNode *iso, uint16_t **name) iso_msg_debug(t->image->id, "Can't convert %s", iso->name); return ret; } - - /* TODO #00022 : support relaxed constraints in joliet filenames */ if (iso->type == LIBISO_DIR) { - jname = iso_j_dir_id(ucs_name); + jname = iso_j_dir_id(ucs_name, t->joliet_long_names << 1); } else { - jname = iso_j_file_id(ucs_name, !!(t->no_force_dots & 2)); + jname = iso_j_file_id(ucs_name, + (t->joliet_long_names << 1) | !!(t->no_force_dots & 2)); } free(ucs_name); if (jname != NULL) { @@ -303,8 +303,15 @@ int joliet_create_mangled_name(uint16_t *dest, uint16_t *src, int digits, int ret, pos; uint16_t *ucsnumber; char fmt[16]; - char nstr[72]; /* The only caller of this function allocates dest with 66 - elements and limits digits to < 8 */ + char nstr[72]; + /* was: The only caller of this function allocates dest + with 66 elements and limits digits to < 8 + But this does not match the usage of nstr which has to take + the decimal representation of an int. + */ + + if (digits >= 8) + return ISO_ASSERT_FAILURE; sprintf(fmt, "%%0%dd", digits); sprintf(nstr, fmt, number); @@ -337,7 +344,7 @@ static int mangle_single_dir(Ecma119Image *t, JolietNode *dir) { int ret; - int i, nchildren; + int i, nchildren, maxchar = 64; JolietNode **children; IsoHTable *table; int need_sort = 0; @@ -345,6 +352,9 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir) nchildren = dir->info.dir->nchildren; children = dir->info.dir->children; + if (t->joliet_long_names) + maxchar = 103; + /* a hash table will temporary hold the names, for fast searching */ ret = iso_htable_create((nchildren * 100) / 80, iso_str_hash, (compare_function_t)ucscmp, &table); @@ -361,7 +371,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir) for (i = 0; i < nchildren; ++i) { uint16_t *name, *ext; - uint16_t full_name[66]; + uint16_t full_name[LIBISO_JOLIET_NAME_MAX]; int max; /* computed max len for name, without extension */ int j = i; int digits = 1; /* characters to change per name */ @@ -380,7 +390,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir) * A max of 7 characters is good enought, it allows handling up to * 9,999,999 files with same name. */ - /* Important: joliet_create_mangled_name() relies on digits < 72 */ + /* Important: joliet_create_mangled_name() relies on digits < 8 */ while (digits < 8) { int ok, k; @@ -403,7 +413,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir) ext = dot + 1; extlen = ucslen(ext); - max = 65 - extlen - 1 - digits; + max = maxchar + 1 - extlen - 1 - digits; if (max <= 0) { /* this can happen if extension is too long */ if (extlen + max > 3) { @@ -413,7 +423,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir) */ extlen = extlen + max - 1; ext[extlen] = 0; - max = 66 - extlen - 1 - digits; + max = maxchar + 2 - extlen - 1 - digits; } else { /* * error, we don't support extensions < 3 @@ -430,10 +440,10 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir) } else { /* Directory, or file without extension */ if (children[i]->type == JOLIET_DIR) { - max = 65 - digits; + max = maxchar + 1 - digits; dot = NULL; /* dots have no meaning in dirs */ } else { - max = 65 - digits; + max = maxchar + 1 - digits; } name = full_name; if (max < ucslen(name)) { @@ -446,7 +456,7 @@ int mangle_single_dir(Ecma119Image *t, JolietNode *dir) ok = 1; /* change name of each file */ for (k = i; k <= j; ++k) { - uint16_t tmp[66]; + uint16_t tmp[LIBISO_JOLIET_NAME_MAX]; while (1) { ret = joliet_create_mangled_name(tmp, name, digits, change, ext); diff --git a/libisofs/joliet.h b/libisofs/joliet.h index d0cd9fe..2079ae2 100644 --- a/libisofs/joliet.h +++ b/libisofs/joliet.h @@ -18,6 +18,10 @@ #include "libisofs.h" #include "ecma119.h" +/* was formerly 66 = 64 + 2. Now 105 = 103 + 2. +*/ +#define LIBISO_JOLIET_NAME_MAX 105 + enum joliet_node_type { JOLIET_FILE, JOLIET_DIR diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 7cbf61a..4dfbfb6 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1585,6 +1585,15 @@ int iso_write_opts_set_relaxed_vol_atts(IsoWriteOpts *opts, int allow); */ int iso_write_opts_set_joliet_longer_paths(IsoWriteOpts *opts, int allow); +/** + * Allow leaf names in the Joliet tree to have up to 103 characters. + * Normal limit is 64. + * This breaks Joliet specification. Use with caution. + * + * @since 1.0.6 + */ +int iso_write_opts_set_joliet_long_names(IsoWriteOpts *opts, int allow); + /** * Write Rock Ridge info as of specification RRIP-1.10 rather than RRIP-1.12: * signature "RRIP_1991A" rather than "IEEE_1282", field PX without file diff --git a/libisofs/libisofs.ver b/libisofs/libisofs.ver index 3392fee..095990e 100644 --- a/libisofs/libisofs.ver +++ b/libisofs/libisofs.ver @@ -282,6 +282,7 @@ iso_write_opts_set_hardlinks; iso_write_opts_set_iso1999; iso_write_opts_set_iso_level; iso_write_opts_set_joliet; +iso_write_opts_set_joliet_long_names; iso_write_opts_set_joliet_longer_paths; iso_write_opts_set_max_37_char_filenames; iso_write_opts_set_ms_block; diff --git a/libisofs/util.c b/libisofs/util.c index dc04f63..7d880bf 100644 --- a/libisofs/util.c +++ b/libisofs/util.c @@ -16,6 +16,7 @@ #include "util.h" #include "libisofs.h" #include "messages.h" +#include "joliet.h" #include "../version.h" #include @@ -916,16 +917,20 @@ ex:; /* bit0= no_force_dots + bit1= allow 103 characters rather than 64 */ uint16_t *iso_j_file_id(const uint16_t *src, int flag) { uint16_t *dot; - size_t lname, lext, lnname, lnext, pos, i; - uint16_t dest[66]; /* 66 = 64 (name + ext) + 1 (.) + 1 (\0) */ + size_t lname, lext, lnname, lnext, pos, i, maxchar = 64; + uint16_t dest[LIBISO_JOLIET_NAME_MAX]; + /* was: 66 = 64 (name + ext) + 1 (.) + 1 (\0) */ if (src == NULL) { return NULL; } + if (flag & 2) + maxchar = 103; dot = ucsrchr(src, '.'); @@ -937,14 +942,15 @@ uint16_t *iso_j_file_id(const uint16_t *src, int flag) */ if (dot == NULL || cmp_ucsbe(dot + 1, '\0') == 0) { lname = ucslen(src); - lnname = (lname > 64) ? 64 : lname; + lnname = (lname > maxchar) ? maxchar : lname; lext = lnext = 0; } else { lext = ucslen(dot + 1); lname = ucslen(src) - lext - 1; - lnext = (ucslen(src) > 65 && lext > 3) ? (lname < 61 ? 64 - lname : 3) + lnext = (ucslen(src) > maxchar + 1 && lext > 3) + ? (lname < maxchar - 3 ? maxchar - lname : 3) : lext; - lnname = (ucslen(src) > 65) ? 64 - lnext : lname; + lnname = (ucslen(src) > maxchar + 1) ? maxchar - lnext : lname; } if (lnname == 0 && lnext == 0) { @@ -986,18 +992,22 @@ is_done:; return ucsdup(dest); } -uint16_t *iso_j_dir_id(const uint16_t *src) +/* @param flag bit1= allow 103 characters rather than 64 +*/ +uint16_t *iso_j_dir_id(const uint16_t *src, int flag) { - size_t len, i; - uint16_t dest[65]; /* 65 = 64 + 1 (\0) */ + size_t len, i, maxchar = 64; + uint16_t dest[LIBISO_JOLIET_NAME_MAX]; /* was: 65 = 64 + 1 (\0) */ if (src == NULL) { return NULL; } + if (flag & 2) + maxchar = 103; len = ucslen(src); - if (len > 64) { - len = 64; + if (len > maxchar) { + len = maxchar; } for (i = 0; i < len; i++) { uint16_t c = src[i]; diff --git a/libisofs/util.h b/libisofs/util.h index 5f13db8..c0a1aa1 100644 --- a/libisofs/util.h +++ b/libisofs/util.h @@ -153,13 +153,15 @@ char *iso_r_fileid(const char *src, size_t len, int relaxed, int forcedot); /** * Create a Joliet file identifier that consists of name and extension. The - * combined name and extension length will not exceed 128 bytes, and the - * name and extension will be separated (.). All characters consist of - * 2 bytes and the resulting string is NULL-terminated by a 2-byte NULL. + * combined name and extension length will normally not exceed 64 characters + * (= 128 bytes). The name and the extension will be separated (.). + * All characters consist of 2 bytes and the resulting string is + * NULL-terminated by a 2-byte NULL. * * Note that version number and (;1) is not appended. * @param flag * bit0= no_force_dots + * bit1= allow 103 characters rather than 64 * @return * NULL if the original name and extension both are of length 0. */ @@ -171,10 +173,12 @@ uint16_t *iso_j_file_id(const uint16_t *src, int flag); * and the name and extension will be separated (.). All characters consist of * 2 bytes and the resulting string is NULL-terminated by a 2-byte NULL. * + * @param flag + * bit1= allow 103 characters rather than 64 * @return * NULL if the original name and extension both are of length 0. */ -uint16_t *iso_j_dir_id(const uint16_t *src); +uint16_t *iso_j_dir_id(const uint16_t *src, int flag); /** * Like strlen, but for Joliet strings.