New API call iso_write_opts_set_untranslated_name_len()

This commit is contained in:
Thomas Schmitt 2010-12-22 14:21:00 +01:00
parent 3d427bdf70
commit 2649045dfe
8 changed files with 184 additions and 41 deletions

View File

@ -141,7 +141,7 @@ static int show_chunk_to_jte(Ecma119Image *target, char *buf, int count)
static
int need_version_number(Ecma119Image *t, Ecma119Node *n)
{
if (t->omit_version_numbers & 1) {
if ((t->omit_version_numbers & 1) || t->untranslated_name_len > 0) {
return 0;
}
if (n->type == ECMA119_DIR || n->type == ECMA119_PLACEHOLDER) {
@ -188,9 +188,9 @@ size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce)
/* size of "." and ".." entries */
len = 34 + 34;
if (t->rockridge) {
len += rrip_calc_len(t, dir, 1, 255 - 34, &ce_len);
len += rrip_calc_len(t, dir, 1, 34, &ce_len);
*ce += ce_len;
len += rrip_calc_len(t, dir, 2, 255 - 34, &ce_len);
len += rrip_calc_len(t, dir, 2, 34, &ce_len);
*ce += ce_len;
}
@ -203,7 +203,7 @@ size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce)
for (section = 0; section < nsections; ++section) {
size_t dirent_len = calc_dirent_len(t, child);
if (t->rockridge) {
dirent_len += rrip_calc_len(t, child, 0, 255 - dirent_len, &ce_len);
dirent_len += rrip_calc_len(t, child, 0, dirent_len, &ce_len);
*ce += ce_len;
}
remaining = BLOCK_SIZE - (len % BLOCK_SIZE);
@ -594,7 +594,7 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir, Ecma119Node *parent)
/* write the "." and ".." entries first */
if (t->rockridge) {
ret = rrip_get_susp_fields(t, dir, 1, 255 - 32, &info);
ret = rrip_get_susp_fields(t, dir, 1, 34, &info);
if (ret < 0) {
return ret;
}
@ -604,7 +604,7 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir, Ecma119Node *parent)
buf += len;
if (t->rockridge) {
ret = rrip_get_susp_fields(t, dir, 2, 255 - 32, &info);
ret = rrip_get_susp_fields(t, dir, 2, 34, &info);
if (ret < 0) {
return ret;
}
@ -630,7 +630,7 @@ int write_one_dir(Ecma119Image *t, Ecma119Node *dir, Ecma119Node *parent)
/* get the SUSP fields if rockridge is enabled */
if (t->rockridge) {
ret = rrip_get_susp_fields(t, child, 0, 255 - len, &info);
ret = rrip_get_susp_fields(t, child, 0, len, &info);
if (ret < 0) {
return ret;
}
@ -1575,6 +1575,7 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *opts, Ecma119Image **img)
target->hardlinks = opts->hardlinks;
target->aaip = opts->aaip;
target->always_gmt = opts->always_gmt;
target->untranslated_name_len = opts->untranslated_name_len;
target->omit_version_numbers = opts->omit_version_numbers
| opts->max_37_char_filenames;
target->allow_deep_paths = opts->allow_deep_paths;
@ -2363,6 +2364,7 @@ int iso_write_opts_new(IsoWriteOpts **opts, int profile)
wopts->appended_partitions[i] = NULL;
wopts->ascii_disc_label[0] = 0;
wopts->will_cancel = 0;
wopts->untranslated_name_len = 0;
*opts = wopts;
return ISO_SUCCESS;
@ -2451,6 +2453,22 @@ int iso_write_opts_set_aaip(IsoWriteOpts *opts, int enable)
return ISO_SUCCESS;
}
int iso_write_opts_set_untranslated_name_len(IsoWriteOpts *opts, int len)
{
if (opts == NULL) {
return ISO_NULL_POINTER;
}
if (len == -1)
opts->untranslated_name_len = ISO_UNTRANSLATED_NAMES_MAX;
else if(len == 0)
opts->untranslated_name_len = 0;
else if(len > ISO_UNTRANSLATED_NAMES_MAX || len < 0)
return ISO_WRONG_ARG_VALUE;
else
opts->untranslated_name_len = len;
return opts->untranslated_name_len;
}
int iso_write_opts_set_omit_version_numbers(IsoWriteOpts *opts, int omit)
{
if (opts == NULL) {

View File

@ -52,6 +52,17 @@
#define ISO_DISC_LABEL_SIZE 129
/* The maximum lenght of an specs violating ECMA-119 file identifier.
The theoretical limit is 254 - 34 - 28 (len of SUSP CE entry) = 192
Currently the practical limit is 254 - 34 - 96 (non-CE RR entries) - 28 (CE)
*/
#ifdef Libisofs_with_rrip_rR
#define ISO_UNTRANSLATED_NAMES_MAX 92
#else
#define ISO_UNTRANSLATED_NAMES_MAX 96
#endif
/**
* Holds the options for the image generation.
*/
@ -213,6 +224,21 @@ struct iso_write_opts {
unsigned int replace_uid :2;
unsigned int replace_gid :2;
/**
* Extra Caution: This option breaks any assumptions about names that
* are supported by ECMA-119 specifications.
* Omit any translation which would make a file name compliant to the
* ECMA-119 rules. This includes and exceeds omit_version_numbers,
* max_37_char_filenames, no_force_dots bit0, allow_lowercase.
* The maximum name length is given by this variable.
* There is a length limit of ISO_UNTRANSLATED_NAMES_MAX characters,
* because ECMA-119 allows 254 byte in a directory record, some
* of them are occupied by ECMA-119, some more are needed for SUSP CE,
* and some are fixely occupied by libisofs Rock Ridge code.
* The default value 0 disables this feature.
*/
unsigned int untranslated_name_len;
mode_t dir_mode; /** Mode to use on dirs when replace_dir_mode == 2. */
mode_t file_mode; /** Mode to use on files when replace_file_mode == 2. */
uid_t uid; /** uid to use when replace_uid == 2. */
@ -437,6 +463,8 @@ struct ecma119_image
unsigned int replace_dir_mode :1;
unsigned int replace_timestamps :1;
unsigned int untranslated_name_len;
uid_t uid;
gid_t gid;
mode_t file_mode;

View File

@ -12,6 +12,9 @@
#include "../config.h"
#endif
/* Must be before ecma119.h because of eventual Libisofs_with_rrip_rR */
#include "libisofs.h"
#include "ecma119_tree.h"
#include "ecma119.h"
#include "node.h"
@ -29,7 +32,7 @@
static
int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
{
int ret, relaxed;
int ret, relaxed, free_ascii_name= 0;
char *ascii_name;
char *isoname= NULL;
@ -38,9 +41,15 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
return ISO_SUCCESS;
}
ret = str2ascii(img->input_charset, iso->name, &ascii_name);
if (img->untranslated_name_len > 0) {
ascii_name = iso->name;
} else {
ret = str2ascii(img->input_charset, iso->name, &ascii_name);
free_ascii_name = 1;
}
if (ret < 0) {
iso_msg_submit(img->image->id, ret, 0, "Can't convert %s", iso->name);
iso_msg_submit(img->image->id, ret, 0,
"Cannot convert name '%s' to ASCII", iso->name);
return ret;
}
@ -50,7 +59,17 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
relaxed = (int)img->allow_lowercase;
}
if (iso->type == LIBISO_DIR) {
if (img->max_37_char_filenames) {
if (img->untranslated_name_len > 0) {
if (strlen(ascii_name) > img->untranslated_name_len) {
needs_transl:;
iso_msg_submit(img->image->id, ISO_NAME_NEEDS_TRANSL, 0,
"File name too long (%d > %d) for untranslated recording: '%s'",
strlen(ascii_name), img->untranslated_name_len,
ascii_name);
return ISO_NAME_NEEDS_TRANSL;
}
isoname = strdup(ascii_name);
} else if (img->max_37_char_filenames) {
isoname = iso_r_dirid(ascii_name, 37, relaxed);
} else if (img->iso_level == 1) {
if (relaxed) {
@ -66,7 +85,11 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
}
}
} else {
if (img->max_37_char_filenames) {
if (img->untranslated_name_len > 0) {
if (strlen(ascii_name) > img->untranslated_name_len)
goto needs_transl;
isoname = strdup(ascii_name);
} else if (img->max_37_char_filenames) {
isoname = iso_r_fileid(ascii_name, 36, relaxed,
(img->no_force_dots & 1) ? 0 : 1);
} else if (img->iso_level == 1) {
@ -85,7 +108,8 @@ int get_iso_name(Ecma119Image *img, IsoNode *iso, char **name)
}
}
}
free(ascii_name);
if (free_ascii_name)
free(ascii_name);
if (isoname != NULL) {
*name = isoname;
return ISO_SUCCESS;
@ -416,8 +440,6 @@ int create_tree(Ecma119Image *image, IsoNode *iso, Ecma119Node **tree,
!!hidden);
if (cret < 0) {
/* error */
if (!hidden)
ecma119_node_free(node);
ret = cret;
break;
} else if (cret == ISO_SUCCESS && !hidden) {
@ -537,6 +559,18 @@ int mangle_single_dir(Ecma119Image *img, Ecma119Node *dir, int max_file_len,
continue;
}
if (img->untranslated_name_len) {
/* This should not happen because no two IsoNode names should be
identical and only unaltered IsoNode names should be seen here.
Thus the Ema119Node names should be unique.
*/
iso_msg_submit(img->image->id, ISO_NAME_NEEDS_TRANSL, 0,
"ECMA-119 file name collision: '%s'",
children[i]->iso_name);
ret = ISO_NAME_NEEDS_TRANSL;
goto mangle_cleanup;
}
/*
* A max of 7 characters is good enought, it allows handling up to
* 9,999,999 files with same name. We can increment this to
@ -716,7 +750,9 @@ int mangle_tree(Ecma119Image *img, int recurse)
int max_file, max_dir;
Ecma119Node *root;
if (img->max_37_char_filenames) {
if (img->untranslated_name_len > 0) {
max_file = max_dir = img->untranslated_name_len;
} else if (img->max_37_char_filenames) {
max_file = max_dir = 37;
} else if (img->iso_level == 1) {
max_file = 12; /* 8 + 3 + 1 */

View File

@ -1344,6 +1344,34 @@ int iso_write_opts_set_hardlinks(IsoWriteOpts *opts, int enable);
*/
int iso_write_opts_set_aaip(IsoWriteOpts *opts, int enable);
/**
* Caution: This option breaks any assumptions about names that
* are supported by ECMA-119 specifications.
* Try to omit any translation which would make a file name compliant to the
* ECMA-119 rules. This includes and exceeds omit_version_numbers,
* max_37_char_filenames, no_force_dots bit0, allow_full_ascii. Further it
* prevents the conversion from local character set to ASCII.
* The maximum name length is given by this call. If a filename exceeds
* this length or cannot be recorded untranslated for other reasons, then
* image production is aborted with ISO_NAME_NEEDS_TRANSL.
* Currently the length limit is 96 characters, because an ECMA-119 directory
* record may at most have 254 bytes and up to 158 other bytes must fit into
* the record. Probably 96 more bytes can be made free for the name in future.
* @param opts
* The option set to be manipulated.
* @param len
* 0 = disable this feature and perform name translation according to
* other settings.
* >0 = Omit any translation. Eventually abort image production
* if a name is longer than the given value.
* -1 = Like >0. Allow maximum possible length (currently 96)
* @return >=0 success, <0 failure
* In case of >=0 the return value tells the effectively set len.
* E.g. 96 after using len == -1.
* @since 0.6.42
*/
int iso_write_opts_set_untranslated_name_len(IsoWriteOpts *opts, int len);
/**
* Omit the version number (";1") at the end of the ISO-9660 identifiers.
* This breaks ECMA-119 specification, but version numbers are usually not
@ -6422,6 +6450,9 @@ int iso_md5_match(char first_md5[16], char second_md5[16]);
/** Displacement offset leads outside 32 bit range (FAILURE, HIGH, -372) */
#define ISO_DISPLACE_ROLLOVER 0xE830FE8C
/** File name cannot be written into ECMA-119 untranslated
(FAILURE, HIGH, -373) */
#define ISO_NAME_NEEDS_TRANSL 0xE830FE8B
/* Internal developer note:

View File

@ -293,6 +293,7 @@ iso_write_opts_set_scdbackup_tag;
iso_write_opts_set_sort_files;
iso_write_opts_set_system_area;
iso_write_opts_set_tail_blocks;
iso_write_opts_set_untranslated_name_len;
iso_write_opts_set_will_cancel;
iso_zisofs_get_params;
iso_zisofs_get_refcounts;

View File

@ -361,6 +361,8 @@ const char *iso_error_to_msg(int errcode)
return "May not combine appended partition with non-MBR system area";
case ISO_DISPLACE_ROLLOVER:
return "Displacement offset leads outside 32 bit range";
case ISO_NAME_NEEDS_TRANSL:
return "File name cannot be written into ECMA-119 untranslated";
default:
return "Unknown error";
}

View File

@ -13,6 +13,9 @@
#include "../config.h"
#endif
#include <string.h>
#include <stdio.h>
#include "rockridge.h"
#include "node.h"
#include "ecma119_tree.h"
@ -22,7 +25,12 @@
#include "aaip_0_2.h"
#include "libisofs.h"
#include <string.h>
#ifdef Libisofs_with_rrip_rR
#define ISO_ROCKRIDGE_IN_DIR_REC 128
#else
#define ISO_ROCKRIDGE_IN_DIR_REC 124
#endif
static
@ -1104,27 +1112,30 @@ unannounced_ca:;
* @param type
* 0 normal entry, 1 "." entry for that node (it is a dir), 2 ".."
* for that node (i.e., it will refer to the parent)
* @param space
* Available space in the System Use Area for the directory record.
* @param used_up
* Already occupied space in the directory record.
* @param ce
* Will be filled with the space needed in a CE
* @return
* The size needed for the RR entries in the System Use Area
*/
size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t space,
size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t used_up,
size_t *ce)
{
size_t su_size;
size_t su_size, space;
int ret;
/* space min is 255 - 33 - 37 = 185
* At the same time, it is always an odd number, but we need to pad it
* propertly to ensure the length of a directory record is a even number
* (ECMA-119, 9.1.13). Thus, in fact the real space is always space - 1
*/
space--;
*ce = 0;
/* Directory record length must be even (ECMA-119, 9.1.13). Maximum is 254.
*/
space = 254 - used_up - (used_up % 2);
if (type < 0 || type > 2 || space < ISO_ROCKRIDGE_IN_DIR_REC) {
iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
"Unknown node type %d or short RR space %d < %d in directory record",
type, (int) space, ISO_ROCKRIDGE_IN_DIR_REC);
return ISO_ASSERT_FAILURE;
}
*ce = 0;
su_size = 0;
/* If AAIP enabled and announced by ER : account for 5 bytes of ES */;
@ -1268,8 +1279,8 @@ int add_aa_string(Ecma119Image *t, Ecma119Node *n, struct susp_info *info,
* @param type
* 0 normal entry, 1 "." entry for that node (it is a dir), 2 ".."
* for that node (i.e., it will refer to the parent)
* @param space
* Available space in the System Use Area for the directory record.
* @param used_up
* Already occupied space in the directory record.
* @param info
* Pointer to the struct susp_info where the entries will be stored.
* If some entries need to go to a Continuation Area, they will be added
@ -1279,7 +1290,7 @@ int add_aa_string(Ecma119Image *t, Ecma119Node *n, struct susp_info *info,
* 1 success, < 0 error
*/
int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type,
size_t space, struct susp_info *info)
size_t used_up, struct susp_info *info)
{
int ret;
size_t i;
@ -1291,13 +1302,20 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type,
size_t su_size_pd, ce_len_pd; /* predicted sizes of SUA and CA */
int ce_is_predicted = 0;
size_t aaip_sua_free= 0, aaip_len= 0;
size_t space;
if (t == NULL || n == NULL || info == NULL) {
return ISO_NULL_POINTER;
}
if (type < 0 || type > 2 || space < 185) {
/* space min is 255 - 33 - 37 = 185 */
return ISO_WRONG_ARG_VALUE;
/* Directory record length must be even (ECMA-119, 9.1.13). Maximum is 254.
*/
space = 254 - used_up - (used_up % 2);
if (type < 0 || type > 2 || space < ISO_ROCKRIDGE_IN_DIR_REC) {
iso_msg_submit(t->image->id, ISO_ASSERT_FAILURE, 0,
"Unknown node type %d or short RR space %d < %d in directory record",
type, (int) space, ISO_ROCKRIDGE_IN_DIR_REC);
return ISO_ASSERT_FAILURE;
}
if (type == 2 && n->parent != NULL) {
@ -1306,13 +1324,6 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type,
node = n;
}
/* space min is 255 - 33 - 37 = 185
* At the same time, it is always an odd number, but we need to pad it
* propertly to ensure the length of a directory record is a even number
* (ECMA-119, 9.1.13). Thus, in fact the real space is always space - 1
*/
space--;
/*
* SP must be the first entry for the "." record of the root directory
* (SUSP, 5.3)
@ -1384,6 +1395,16 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type,
}
}
/* <<< ts B01222 : For testing only */
if (info->suf_len + 28 > space) {
fprintf(stderr,
"libisofs_debug: Directory Record overflow. name='%s' , info->suf_len=%d > space=%d - 28\n",
node->iso_name, (int) info->suf_len, (int) space);
return ISO_ASSERT_FAILURE;
}
if (type == 0) {
size_t sua_free; /* free space in the SUA */
int nm_type = 0; /* 0 whole entry in SUA, 1 part in CE */

View File

@ -773,6 +773,8 @@ char *iso_r_dirid(const char *src, int size, int relaxed)
len = size;
}
dest = malloc(len + 1);
if (dest == NULL)
return NULL;
for (i = 0; i < len; i++) {
char c= src[i];
if (relaxed == 2) {
@ -1036,6 +1038,8 @@ uint16_t *ucsdup(const uint16_t *str)
size_t len = ucslen(str);
ret = malloc(2 * (len + 1));
if (ret == NULL)
return NULL;
if (ret != NULL) {
memcpy(ret, str, 2 * (len + 1));
}
@ -1460,6 +1464,8 @@ char *ucs2str(const char *buf, size_t len)
/* ensure enought space */
out = calloc(outbytes, 1);
if (out == NULL)
return NULL;
/* convert to local charset */
conv_ret = iso_iconv_open(&conv, iso_get_local_charset(0), "UCS-2BE", 0);