From 7a3560035a33feb91c1d6abbe83acff45ef39049 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Thu, 17 Sep 2015 13:59:05 +0200 Subject: [PATCH] Rectified handling of oversized filenames by new API calls: iso_image_set_truncate_mode, iso_image_get_truncate_mode, iso_truncate_leaf_name, iso_image_set_node_name, iso_image_tree_clone, iso_image_add_new_dir, iso_image_add_new_file, iso_image_add_new_special, iso_image_add_new_symlink, iso_image_dir_get_node, iso_image_path_to_node, --- libisofs/builder.c | 17 +- libisofs/fs_image.c | 38 +++- libisofs/image.c | 45 +++++ libisofs/image.h | 22 +++ libisofs/libisofs.h | 416 ++++++++++++++++++++++++++++++++++++++---- libisofs/libisofs.ver | 11 ++ libisofs/messages.c | 2 + libisofs/node.c | 88 ++++++++- libisofs/node.h | 6 + libisofs/tree.c | 170 +++++++++++++++-- libisofs/util.c | 93 ++++++++++ libisofs/util.h | 2 + 12 files changed, 847 insertions(+), 63 deletions(-) diff --git a/libisofs/builder.c b/libisofs/builder.c index cb9b4d5..05b2224 100644 --- a/libisofs/builder.c +++ b/libisofs/builder.c @@ -21,6 +21,7 @@ #include "image.h" #include "aaip_0_2.h" #include "util.h" +#include "messages.h" #include #include @@ -72,8 +73,12 @@ int default_create_file(IsoNodeBuilder *builder, IsoImage *image, iso_file_source_ref(src); name = iso_file_source_get_name(src); - if (strlen(name) > LIBISOFS_NODE_NAME_MAX) - name[LIBISOFS_NODE_NAME_MAX] = 0; + if ((int) strlen(name) > image->truncate_length) { + ret = iso_truncate_rr_name(image->truncate_mode, + image->truncate_length, name, 0); + if (ret < 0) + return ret; + } ret = iso_node_new_file(name, stream, &node); if (ret < 0) { iso_stream_unref(stream); @@ -131,8 +136,12 @@ int default_create_node(IsoNodeBuilder *builder, IsoImage *image, } } - if (strlen(name) > LIBISOFS_NODE_NAME_MAX) - name[LIBISOFS_NODE_NAME_MAX] = 0; + if ((int) strlen(name) > image->truncate_length) { + ret = iso_truncate_rr_name(image->truncate_mode, + image->truncate_length, name, 0); + if (ret < 0) + goto ex; + } fs = iso_file_source_get_filesystem(src); new = NULL; diff --git a/libisofs/fs_image.c b/libisofs/fs_image.c index a10affe..1b98045 100644 --- a/libisofs/fs_image.c +++ b/libisofs/fs_image.c @@ -142,6 +142,14 @@ struct iso_read_opts */ int keep_import_src; + /** + * What to do in case of name longer than truncate_length: + * 0= throw FAILURE + * 1= truncate to truncate_length with MD5 of whole name at end + */ + int truncate_mode; + int truncate_length; + }; /** @@ -298,6 +306,8 @@ typedef struct /** * See struct iso_read_opts. */ + int truncate_mode; + int truncate_length; unsigned int ecma119_map : 2; /** Whether AAIP info shall be loaded if it is present. @@ -1415,7 +1425,7 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, struct ecma119_dir_record *record, IsoFileSource **src, int flag) { - int ret, ecma119_map; + int ret, ecma119_map, skip_nm = 0; struct stat atts; time_t recorded; _ImageFsData *fsdata; @@ -1610,11 +1620,15 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, "Invalid TF entry"); } } else if (SUSP_SIG(sue, 'N', 'M')) { + if (skip_nm) + continue; /* in NM error bailout mode */ + if (name != NULL && namecont == 0) { /* ups, RR standard violation */ ret = iso_rr_msg_submit(fsdata, 2, ISO_WRONG_RR_WARN, 0, "New NM entry found without previous" "CONTINUE flag. Ignored"); + skip_nm = 1; continue; } ret = read_rr_NM(sue, &name, &namecont); @@ -1622,6 +1636,14 @@ int iso_file_source_new_ifs(IsoImageFilesystem *fs, IsoFileSource *parent, /* notify and continue */ ret = iso_rr_msg_submit(fsdata, 3, ISO_WRONG_RR_WARN, ret, "Invalid NM entry"); + continue; + } + if (strlen(name) > 4095) { + /* Preliminarily truncate totally oversized name */ + ret = iso_rr_msg_submit(fsdata, 3, ISO_WRONG_RR_WARN, ret, + "Totally oversized NM list"); + skip_nm = 1; + continue; } #ifdef Libisofs_syslinux_tesT @@ -1965,6 +1987,15 @@ if (name != NULL && !namecont) { } } + if (name != NULL) { + if ((int) strlen(name) > fsdata->truncate_length) { + ret = iso_truncate_rr_name(fsdata->truncate_mode, + fsdata->truncate_length, name, 0); + if (ret < 0) + goto ex; + } + } + if (relocated_dir) { /* @@ -3060,6 +3091,8 @@ int iso_image_filesystem_new(IsoDataSource *src, struct iso_read_opts *opts, data->input_charset = strdup("ASCII"); } } + data->truncate_mode = opts->truncate_mode; + data->truncate_length = opts->truncate_length; data->ecma119_map = opts->ecma119_map; if (data->input_charset == NULL) { @@ -5670,7 +5703,8 @@ int iso_image_import(IsoImage *image, IsoDataSource *src, return ISO_NULL_POINTER; } - + opts->truncate_mode = image->truncate_mode; + opts->truncate_length = image->truncate_length; ret = iso_image_filesystem_new(src, opts, image->id, &fs); if (ret < 0) { return ret; diff --git a/libisofs/image.c b/libisofs/image.c index bf4f5a6..f80131d 100644 --- a/libisofs/image.c +++ b/libisofs/image.c @@ -188,6 +188,9 @@ int iso_image_new(const char *name, IsoImage **image) img->import_src = NULL; img->builder_ignore_acl = 1; img->builder_ignore_ea = 1; + img->truncate_mode = 1; + img->truncate_length = LIBISOFS_NODE_NAME_MAX; + img->truncate_buffer[0] = 0; img->inode_counter = 0; img->used_inodes = NULL; img->used_inodes_start = 0; @@ -1083,3 +1086,45 @@ int iso_image_get_alpha_boot(IsoImage *img, char **boot_loader_path) } +/* API */ +int iso_image_set_truncate_mode(IsoImage *img, int mode, int length) +{ + if (mode < 0 || mode > 1) + return ISO_WRONG_ARG_VALUE; + if (length < 64 || length > LIBISOFS_NODE_NAME_MAX) + return ISO_WRONG_ARG_VALUE; + img->truncate_mode = mode; + img->truncate_length = length; + return ISO_SUCCESS; +} + +/* API */ +int iso_image_get_truncate_mode(IsoImage *img, int *mode, int *length) +{ + *mode = img->truncate_mode; + *length = img->truncate_length; + return ISO_SUCCESS; +} + +/* Warning: Not thread-safe */ +int iso_image_truncate_name(IsoImage *image, const char *name, char **namept, + int flag) +{ + int ret; + + if (name == NULL) + return ISO_NULL_POINTER; + + if ((int) strlen(name) <= image->truncate_length) { + *namept = (char *) name; + return ISO_SUCCESS; + } + *namept = image->truncate_buffer; + if (name != image->truncate_buffer) + strncpy(image->truncate_buffer, name, 4095); + image->truncate_buffer[4095] = 0; + ret = iso_truncate_rr_name(image->truncate_mode, image->truncate_length, + image->truncate_buffer, 0); + return ret; +} + diff --git a/libisofs/image.h b/libisofs/image.h index fcf5aca..d23771a 100644 --- a/libisofs/image.h +++ b/libisofs/image.h @@ -160,6 +160,20 @@ struct Iso_Image /* TODO enum iso_replace_mode (*confirm_replace)(IsoFileSource *src, IsoNode *node); */ + + /** + * What to do in case of name longer than truncate_length: + * 0= throw FAILURE + * 1= truncate to truncate_length with MD5 of whole name at end + */ + int truncate_mode; + int truncate_length; + + /** + * This is a convenience buffer for name truncation during image + * manipulation where libisofs is not thread-safe anyway. + */ + char truncate_buffer[4096]; /** * When this is not NULL, it is a pointer to a function that will @@ -230,6 +244,14 @@ struct Iso_Image }; +/* Apply truncation mode to name, using image->truncate_buffer to perform + truncation if needed. + + Warning: Not thread-safe ! +*/ +int iso_image_truncate_name(IsoImage *image, const char *name, char **namept, + int flag); + /* Collect the bitmap of used inode numbers in the range of _ImageFsData.used_inodes_start + ISO_USED_INODE_RANGE diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 2ffbfd3..432ed09 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -3089,9 +3089,87 @@ int iso_image_attach_data(IsoImage *image, void *data, void (*give_up)(void*)); */ void *iso_image_get_attached_data(IsoImage *image); +/** + * Set the name truncation mode and the maximum name length for nodes from + * image importing, creation of new IsoNode objects, and name changing image + * manipulations. + * + * Truncated names are supposed to be nearly unique because they end by the MD5 + * of the first 4095 characters of the untruncated name. One should treat them + * as if they were the untruncated original names. + * + * For proper processing of truncated names it is necessary to use + * iso_image_set_node_name() instead of iso_node_set_name() + * iso_image_add_new_dir() iso_tree_add_new_dir() + * iso_image_add_new_file() iso_tree_add_new_file() + * iso_image_add_new_special() iso_tree_add_new_special() + * iso_image_add_new_symlink() iso_tree_add_new_symlink() + * iso_image_tree_clone() iso_tree_clone() + * iso_image_dir_get_node() iso_dir_get_node() + * iso_image_path_to_node() iso_tree_path_to_node() + * + * Beware of ambiguities if both, the full name and the truncated name, + * exist in the same directory. Best is to only set truncation parameters + * once with an ISO filesystem and to never change them later. + * + * @param image + * The image which shall be manipulated. + * @param mode + * 0= Do not truncate but throw error ISO_RR_NAME_TOO_LONG if a file name + * is longer than parameter length. + * 1= Truncate to length and overwrite the last 33 bytes of that length + * by a colon ':' and the hex representation of the MD5 of the first + * 4095 bytes of the whole oversized name. + * Potential incomplete UTF-8 characters will get their leading bytes + * replaced by '_'. + * Mode 1 is the default. + * @param length + * Maximum byte count of a file name. Permissible values are 64 to 255. + * Default is 255. + * @return + * ISO_SUCCESS or ISO_WRONG_ARG_VALUE + * + * @since 1.4.2 + */ +int iso_image_set_truncate_mode(IsoImage *img, int mode, int length); + +/** + * Inquire the current setting of iso_image_set_truncate_mode(). + * + * @param image + * The image which shall be inquired. + * @param mode + * Returns the mode value. + * @param length + * Returns the length value. + * @return + * ISO_SUCCESS or <0 = error + * + * @since 1.4.2 + */ +int iso_image_get_truncate_mode(IsoImage *img, int *mode, int *length); + +/** + * Immediately apply the given truncate mode and length to the given string. + * + * @param mode + * See iso_image_set_truncate_mode() + * @param length + * See iso_image_set_truncate_mode() + * @param name + * The string to be inspected and truncated if mode says so. + * @param flag + * Bitfield for control purposes. Unused yet. Submit 0. + * @return + * ISO_SUCCESS, ISO_WRONG_ARG_VALUE, ISO_RR_NAME_TOO_LONG + * + * @since 1.4.2 + */ +int iso_truncate_leaf_name(int mode, int length, char *name, int flag); + /** * Get the root directory of the image. - * No extra ref is added to it, so you musn't unref it. Use iso_node_ref() + * No extra ref is added to it, so you must not unref it. Use iso_node_ref() * if you want to get your own reference. * * @since 0.6.2 @@ -4632,10 +4710,36 @@ int iso_node_xinfo_make_clonable(iso_node_xinfo_func proc, int iso_node_xinfo_get_cloner(iso_node_xinfo_func proc, iso_node_xinfo_cloner *cloner, int flag); - /** * Set the name of a node. Note that if the node is already added to a dir * this can fail if dir already contains a node with the new name. + * The IsoImage context defines a maximum permissible name length and a mode + * how to react on oversized names. See iso_image_set_truncate_mode(). + * + * @param image + * The image object to which the node belongs or shall belong in future. + * @param node + * The node of which you want to change the name. One cannot change the + * name of the root directory. + * @param name + * The new name for the node. It may not be empty. If it is oversized + * then it will be handled according to iso_image_set_truncate_mode(). + * @param flag + * bit0= issue warning in case of truncation + * @return + * 1 on success, < 0 on error + * + * @since 1.4.2 + */ +int iso_image_set_node_name(IsoImage *image, IsoNode *node, const char *name, + int flag); + +/** + * *** Deprecated *** + * use iso_image_set_node_name() instead + * + * Set the name of a node without taking into respect name truncation mode of + * an IsoImage. * * @param node * The node whose name you want to change. Note that you can't change @@ -4651,6 +4755,7 @@ int iso_node_xinfo_get_cloner(iso_node_xinfo_func proc, */ int iso_node_set_name(IsoNode *node, const char *name); + /** * Get the name of a node. * The returned string belongs to the node and must not be modified nor @@ -4845,10 +4950,17 @@ int iso_dir_add_node(IsoDir *dir, IsoNode *child, /** * Locate a node inside a given dir. * + * The IsoImage context defines a maximum permissible name length and a mode + * how to react on oversized names. See iso_image_set_truncate_mode(). + * If the caller looks for an oversized name and image truncate mode is 1, + * then this call looks for the truncated name among the nodes of dir. + * + * @param image + * The image object to which dir belongs. * @param dir * The dir where to look for the node. * @param name - * The name of the node + * The name of the node. (Will not be changed if truncation happens.) * @param node * Location for a pointer to the node, it will filled with NULL if the dir * doesn't have a child with the given name. @@ -4856,6 +4968,33 @@ int iso_dir_add_node(IsoDir *dir, IsoNode *child, * iso_node_ref() to get your own reference to the node. * Note that you can pass NULL is the only thing you want to do is check * if a node with such name already exists on dir. + * @param flag + * Bitfield for control purposes. + * bit0= do not truncate name but lookup exactly as given. + * @return + * 1 node found + * 0 no name truncation was needed, name not found in dir + * 2 name truncation happened, truncated name not found in dir + * < 0 error, see iso_dir_get_node(). + * + * @since 1.4.2 + */ +int iso_image_dir_get_node(IsoImage *image, IsoDir *dir, + const char *name, IsoNode **node, int flag); + +/** + * *** Deprecated *** + * In most cases use iso_image_dir_get_node() instead. + * + * Locate a node inside a given dir without taking into respect name truncation + * mode of an IsoImage. + * + * @param dir + * The dir where to look for the node. + * @param name + * The name of the node + * @param node + * Location for a pointer to the node. See iso_image_get_node(). * @return * 1 node found, 0 child has no such node, < 0 error * Possible errors: @@ -5373,11 +5512,15 @@ int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag); * Add a new directory to the iso tree. Permissions, owner and hidden atts * are taken from parent, you can modify them later. * + * @param image + * The image object to which the new directory shall belong. * @param parent - * the dir where the new directory will be created + * The directory node where the new directory will be grafted in. * @param name - * name for the new dir. If a node with same name already exists on - * parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * Name for the new directory. If truncation mode is set to 1, + * an oversized name gets truncated before further processing. + * If a node with same name already exists on parent, this function + * fails with ISO_NODE_NAME_NOT_UNIQUE. * @param dir * place where to store a pointer to the newly created dir. No extra * ref is addded, so you will need to call iso_node_ref() if you really @@ -5389,6 +5532,33 @@ int iso_node_get_old_image_lba(IsoNode *node, uint32_t *lba, int flag); * ISO_NULL_POINTER, if parent or name are NULL * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists * ISO_OUT_OF_MEM + * ISO_RR_NAME_TOO_LONG + * + * @since 1.4.2 + */ +int iso_image_add_new_dir(IsoImage *image, IsoDir *parent, const char *name, + IsoDir **dir); + +/** + * *** Deprecated *** + * use iso_image_add_new_dir() instead + * + * Add a new directory to the iso tree without taking into respect name + * truncation mode of an IsoImage. + * For detailed description of parameters, see above iso_image_add_new_dir(). + * + * @param parent + * the dir where the new directory will be created + * @param name + * name for the new dir. + * @param dir + * place where to store a pointer to the newly created dir.i + * @return + * number of nodes in parent if success, < 0 otherwise + * Possible errors: + * ISO_NULL_POINTER, if parent or name are NULL + * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists + * ISO_OUT_OF_MEM * * @since 0.6.2 */ @@ -5399,11 +5569,15 @@ int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir); * owner and hidden atts are taken from parent. You can modify any of them * later. * - * @param parent - * the dir where the new file will be created + * @param image + * The image object to which the new file shall belong. + * @param parent + * The directory node where the new directory will be grafted in. * @param name - * name for the new file. If a node with same name already exists on - * parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * Name for the new file. If truncation mode is set to 1, + * an oversized name gets truncated before further processing. + * If a node with same name already exists on parent, this function + * fails with ISO_NODE_NAME_NOT_UNIQUE. * @param stream * IsoStream for the contents of the file. The reference will be taken * by the newly created file, you will need to take an extra ref to it @@ -5419,6 +5593,35 @@ int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir); * ISO_NULL_POINTER, if parent, name or dest are NULL * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists * ISO_OUT_OF_MEM + * ISO_RR_NAME_TOO_LONG + * + * @since 1.4.2 + */ +int iso_image_add_new_file(IsoImage *image, IsoDir *parent, const char *name, + IsoStream *stream, IsoFile **file); + +/** + * *** Deprecated *** + * use iso_image_add_new_file() instead + * + * Add a new regular file to the iso tree without taking into respect name + * truncation mode of an IsoImage. + * For detailed description of parameters, see above iso_image_add_new_file(). + * + * @param parent + * the dir where the new file will be created + * @param name + * name for the new file. + * @param stream + * IsoStream for the contents of the file. + * @param file + * place where to store a pointer to the newly created file. + * @return + * number of nodes in parent if success, < 0 otherwise + * Possible errors: + * ISO_NULL_POINTER, if parent, name or dest are NULL + * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists + * ISO_OUT_OF_MEM * * @since 0.6.4 */ @@ -5444,22 +5647,58 @@ int iso_tree_add_new_file(IsoDir *parent, const char *name, IsoStream *stream, int iso_memory_stream_new(unsigned char *buf, size_t size, IsoStream **stream); /** - * Add a new symlink to the directory tree. Permissions are set to 0777, + * Add a new symbolic link to the directory tree. Permissions are set to 0777, * owner and hidden atts are taken from parent. You can modify any of them * later. * + * @param image + * The image object to which the new directory shall belong. + * @param parent + * The directory node where the new symlink will be grafted in. + * @param name + * Name for the new symlink. If truncation mode is set to 1, + * an oversized name gets truncated before further processing. + * If a node with same name already exists on parent, this function + * fails with ISO_NODE_NAME_NOT_UNIQUE. + * @param dest + * The destination path of the link. The components of this path are + * not checked for being oversized. + * @param link + * Place where to store a pointer to the newly created link. No extra + * ref is addded, so you will need to call iso_node_ref() if you really + * need it. You can pass NULL in this parameter if you don't need the + * pointer + * @return + * number of nodes in parent if success, < 0 otherwise + * Possible errors: + * ISO_NULL_POINTER, if parent, name or dest are NULL + * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists + * ISO_OUT_OF_MEM + * ISO_RR_NAME_TOO_LONG + * + * @since 1.4.2 + */ +int iso_image_add_new_symlink(IsoImage *image, IsoDir *parent, + const char *name, const char *dest, + IsoSymlink **link); + +/** + * *** Deprecated *** + * use iso_image_add_new_symlink() instead + * + * Add a new symlink to the directory tree without taking into respect name + * truncation mode of an IsoImage. + * For detailed description of parameters, see above + * iso_image_add_new_isymlink(). + * * @param parent * the dir where the new symlink will be created * @param name - * name for the new symlink. If a node with same name already exists on - * parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * name for the new symlink. * @param dest * destination of the link * @param link - * place where to store a pointer to the newly created link. No extra - * ref is addded, so you will need to call iso_node_ref() if you really - * need it. You can pass NULL in this parameter if you don't need the - * pointer + * place where to store a pointer to the newly created link. * @return * number of nodes in parent if success, < 0 otherwise * Possible errors: @@ -5474,7 +5713,7 @@ int iso_tree_add_new_symlink(IsoDir *parent, const char *name, /** * Add a new special file to the directory tree. As far as libisofs concerns, - * an special file is a block device, a character device, a FIFO (named pipe) + * a special file is a block device, a character device, a FIFO (named pipe) * or a socket. You can choose the specific kind of file you want to add * by setting mode propertly (see man 2 stat). * @@ -5485,24 +5724,61 @@ int iso_tree_add_new_symlink(IsoDir *parent, const char *name, * Owner and hidden atts are taken from parent. You can modify any of them * later. * + * @param image + * The image object to which the new special file shall belong. * @param parent - * the dir where the new special file will be created + * The directory node where the new special file will be grafted in. * @param name - * name for the new special file. If a node with same name already exists - * on parent, this functions fails with ISO_NODE_NAME_NOT_UNIQUE. + * Name for the new special file. If truncation mode is set to 1, + * an oversized name gets truncated before further processing. + * If a node with same name already exists on parent, this function + * fails with ISO_NODE_NAME_NOT_UNIQUE. * @param mode - * file type and permissions for the new node. Note that you can't - * specify any kind of file here, only special types are allowed. i.e, - * S_IFSOCK, S_IFBLK, S_IFCHR and S_IFIFO are valid types; S_IFLNK, - * S_IFREG and S_IFDIR aren't. + * File type and permissions for the new node. Note that only the file + * types S_IFSOCK, S_IFBLK, S_IFCHR, and S_IFIFO are allowed. + * S_IFLNK, S_IFREG, or S_IFDIR are not. * @param dev - * device ID, equivalent to the st_rdev field in man 2 stat. + * Device ID, equivalent to the st_rdev field in man 2 stat. * @param special - * place where to store a pointer to the newly created special file. No + * Place where to store a pointer to the newly created special file. No * extra ref is addded, so you will need to call iso_node_ref() if you * really need it. You can pass NULL in this parameter if you don't need * the pointer. * @return + * Number of nodes in parent if success, < 0 otherwise + * Possible errors: + * ISO_NULL_POINTER, if parent, name or dest are NULL + * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists + * ISO_WRONG_ARG_VALUE if you select a incorrect mode + * ISO_OUT_OF_MEM + * ISO_RR_NAME_TOO_LONG + * + * @since 1.4.2 + */ +int iso_image_add_new_special(IsoImage *image, IsoDir *parent, + const char *name, mode_t mode, + dev_t dev, IsoSpecial **special); + +/** + * *** Deprecated *** + * use iso_image_add_new_special() instead + * + * Add a new special file to the directory tree without taking into respect name + * truncation mode of an IsoImage. + * For detailed description of parameters, see above + * iso_image_add_new_special(). + * + * @param parent + * the dir where the new special file will be created + * @param name + * name for the new special file. + * @param mode + * file type and permissions for the new node. + * @param dev + * device ID, equivalent to the st_rdev field in man 2 stat. + * @param special + * place where to store a pointer to the newly created special file. + * @return * number of nodes in parent if success, < 0 otherwise * Possible errors: * ISO_NULL_POINTER, if parent, name or dest are NULL @@ -5692,7 +5968,8 @@ void iso_tree_set_report_callback(IsoImage *image, * The directory in the image tree where the node will be added. * @param path * The absolute path of the file in the local filesystem. - * The node will have the same leaf name as the file on disk. + * The node will have the same leaf name as the file on disk, possibly + * truncated according to iso_image_set_truncate_mode(). * Its directory path depends on the parent node. * @param node * place where to store a pointer to the newly added file. No @@ -5705,6 +5982,7 @@ void iso_tree_set_report_callback(IsoImage *image, * ISO_NULL_POINTER, if image, parent or path are NULL * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists * ISO_OUT_OF_MEM + * ISO_RR_NAME_TOO_LONG * * @since 0.6.2 */ @@ -5723,7 +6001,8 @@ int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path, * @param parent * The directory in the image tree where the node will be added. * @param name - * The leaf name that the node will have on image. + * The leaf name that the node will have on image, possibly truncated + * according to iso_image_set_truncate_mode(). * Its directory path depends on the parent node. * @param path * The absolute path of the file in the local filesystem. @@ -5738,6 +6017,7 @@ int iso_tree_add_node(IsoImage *image, IsoDir *parent, const char *path, * ISO_NULL_POINTER, if image, parent or path are NULL * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists * ISO_OUT_OF_MEM + * ISO_RR_NAME_TOO_LONG * * @since 0.6.4 */ @@ -5754,7 +6034,8 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, * @param parent * The directory in the image tree where the node will be added. * @param name - * The leaf name that the node will have on image. + * The leaf name that the node will have on image, possibly truncated + * according to iso_image_set_truncate_mode(). * Its directory path depends on the parent node. * @param path * The absolute path of the file in the local filesystem. For now @@ -5775,6 +6056,7 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, * ISO_NULL_POINTER, if image, parent or path are NULL * ISO_NODE_NAME_NOT_UNIQUE, a node with same name already exists * ISO_OUT_OF_MEM + * ISO_RR_NAME_TOO_LONG * * @since 0.6.4 */ @@ -5809,6 +6091,42 @@ int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, * cloned if each of the iso_node_xinfo_func instances is associated to a * clone function. See iso_node_xinfo_make_clonable(). * All internally used classes of extended information are clonable. + * + * The IsoImage context defines a maximum permissible name length and a mode + * how to react on oversized names. See iso_image_set_truncate_mode(). + * + * @param image + * The image object to which the node belongs. + * @param node + * The node to be cloned. + * @param new_parent + * The existing directory node where to insert the cloned node. + * @param new_name + * The name for the cloned node. It must not yet exist in new_parent, + * unless it is a directory and node is a directory and flag bit0 is set. + * @param new_node + * Will return a pointer (without reference) to the newly created clone. + * @param flag + * Bitfield for control purposes. Submit any undefined bits as 0. + * bit0= Merge directories rather than returning ISO_NODE_NAME_NOT_UNIQUE. + * This will not allow to overwrite any existing node. + * Attributes of existing directories will not be overwritten. + * bit1= issue warning in case of new_name truncation + * @return + * <0 means error, 1 = new node created, + * 2 = if flag bit0 is set: new_node is a directory which already existed. + * + * @since 1.4.2 + */ +int iso_image_tree_clone(IsoImage *image, IsoNode *node, IsoDir *new_parent, + char *new_name, IsoNode **new_node, int flag); + +/** + * *** Deprecated *** + * use iso_image_tree_clone() instead + * + * Create a copy of the given node under a different path without taking + * into respect name truncation mode of an IsoImage. * * @param node * The node to be cloned. @@ -5857,17 +6175,48 @@ int iso_tree_clone(IsoNode *node, int iso_tree_add_dir_rec(IsoImage *image, IsoDir *parent, const char *dir); /** - * Locate a node by its absolute path on image. + * Locate a node by its absolute path in the image. + * The IsoImage context defines a maximum permissible name length and a mode + * how to react on oversized names. See iso_image_set_truncate_mode(). * * @param image * The image to which the node belongs. + * @param path + * File path beginning at the root directory of image. If truncation mode + * is set to 1, oversized path components will be truncated before lookup. * @param node - * Location for a pointer to the node, it will filled with NULL if the + * Location for a pointer to the node, it will be filled with NULL if the * given path does not exists on image. * The node will be owned by the image and shouldn't be unref(). Just call * iso_node_ref() to get your own reference to the node. * Note that you can pass NULL is the only thing you want to do is check * if a node with such path really exists. + * + * @return + * 1 node found + * 0 no truncation was needed, path not found in image + * 2 truncation happened, truncated path component not found in parent dir + * < 0 error, see iso_dir_get_node(). + * + * @since 1.4.2 + */ +int iso_image_path_to_node(IsoImage *image, const char *path, IsoNode **node); + +/** + * *** Deprecated *** + * In most cases use iso_image_path_to_node() instead + * + * Locate a node by its absolute path on image without taking into respect + * name truncation mode of the image. + * + * @param image + * The image to which the node belongs. + * @param path + * File path beginning at the root directory of image. No truncation will + * happen. + * @param node + * Location for a pointer to the node, it will be filled with NULL if the + * given path does not exists on image. See iso_image_path_to_node(). * @return * 1 found, 0 not found, < 0 error * @@ -8342,6 +8691,9 @@ int iso_conv_name_chars(IsoWriteOpts *opts, char *name, size_t name_len, (FAILURE, HIGH, -411) */ #define ISO_PATCH_OVERSIZED_BOOT 0xE830FE65 +/** File name had to be truncated and MD5 marked (WARNING, HIGH, -412) */ +#define ISO_RR_NAME_TRUNCATED 0xD030FE64 + /* Internal developer note: Place new error codes directly above this comment. diff --git a/libisofs/libisofs.ver b/libisofs/libisofs.ver index eb5a5e2..09f5b15 100644 --- a/libisofs/libisofs.ver +++ b/libisofs/libisofs.ver @@ -75,6 +75,10 @@ iso_hfsplus_xinfo_func; iso_hfsplus_xinfo_new; iso_image_add_boot_image; iso_image_add_mips_boot_file; +iso_image_add_new_dir; +iso_image_add_new_file; +iso_image_add_new_special; +iso_image_add_new_symlink; iso_image_attach_data; iso_image_create_burn_source; iso_image_filesystem_new; @@ -99,6 +103,7 @@ iso_image_get_bootcat; iso_image_get_boot_image; iso_image_get_copyright_file_id; iso_image_get_data_preparer_id; +iso_image_dir_get_node; iso_image_get_hppa_palo; iso_image_get_mips_boot_files; iso_image_get_msg_id; @@ -109,6 +114,7 @@ iso_image_get_session_md5; iso_image_get_sparc_core; iso_image_get_system_area; iso_image_get_system_id; +iso_image_get_truncate_mode; iso_image_get_volset_id; iso_image_get_volume_id; iso_image_give_up_mips_boot; @@ -116,6 +122,7 @@ iso_image_hfsplus_bless; iso_image_hfsplus_get_blessed; iso_image_import; iso_image_new; +iso_image_path_to_node; iso_image_ref; iso_image_remove_boot_image; iso_image_report_el_torito; @@ -132,11 +139,14 @@ iso_image_set_copyright_file_id; iso_image_set_data_preparer_id; iso_image_set_hppa_palo; iso_image_set_ignore_aclea; +iso_image_set_node_name; iso_image_set_publisher_id; iso_image_set_sparc_core; iso_image_set_system_id; +iso_image_set_truncate_mode; iso_image_set_volset_id; iso_image_set_volume_id; +iso_image_tree_clone; iso_image_unref; iso_image_update_sizes; iso_init; @@ -281,6 +291,7 @@ iso_tree_set_ignore_hidden; iso_tree_set_ignore_special; iso_tree_set_replace_mode; iso_tree_set_report_callback; +iso_truncate_leaf_name; iso_util_decode_md5_tag; iso_write_opts_attach_jte; iso_write_opts_detach_jte; diff --git a/libisofs/messages.c b/libisofs/messages.c index 18d0d40..b2bb0a7 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -535,6 +535,8 @@ const char *iso_error_to_msg(int errcode) return "May not write boot info into filtered stream of boot image"; case ISO_PATCH_OVERSIZED_BOOT: return "Boot image to large to buffer for writing boot info"; + case ISO_RR_NAME_TRUNCATED: + return "File name had to be truncated and MD5 marked"; default: return "Unknown error"; } diff --git a/libisofs/node.c b/libisofs/node.c index f5a83f1..47d9310 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -327,32 +327,50 @@ enum IsoNodeType iso_node_get_type(IsoNode *node) * Set the name of a node. * * @param name The name in UTF-8 encoding + * @param truncate_length (<64 = return on oversized name ) + * @param flag bit0= issue warning in case of truncation */ -int iso_node_set_name(IsoNode *node, const char *name) +int iso_node_set_name_trunc(IsoNode *node, const char *in_name, + int truncate_length, int flag) { - char *new; + char *new, *name, *trunc = NULL; int ret; if ((IsoNode*)node->parent == node) { /* you can't change name of the root node */ - return ISO_WRONG_ARG_VALUE; + ret = ISO_WRONG_ARG_VALUE; + goto ex; } + name = (char *) in_name; + if (truncate_length >= 64) { + trunc = strdup(name); + if (trunc == 0) { + ret = ISO_OUT_OF_MEM; + goto ex; + } + ret = iso_truncate_rr_name(1, truncate_length, trunc, !(flag & 1)); + if (ret < 0) + goto ex; + name = trunc; + } /* check if the name is valid */ ret = iso_node_is_valid_name(name); if (ret < 0) - return ret; + goto ex; if (node->parent != NULL) { /* check if parent already has a node with same name */ if (iso_dir_get_node(node->parent, name, NULL) == 1) { - return ISO_NODE_NAME_NOT_UNIQUE; + ret = ISO_NODE_NAME_NOT_UNIQUE; + goto ex; } } new = strdup(name); if (new == NULL) { - return ISO_OUT_OF_MEM; + ret = ISO_OUT_OF_MEM; + goto ex; } free(node->name); node->name = new; @@ -364,10 +382,29 @@ int iso_node_set_name(IsoNode *node, const char *name) iso_node_take(node); res = iso_dir_add_node(parent, node, 0); if (res < 0) { - return res; + ret = res; + goto ex; } } - return ISO_SUCCESS; + ret = ISO_SUCCESS; +ex: + if (trunc != NULL) + free(trunc); + return ret; +} + +int iso_node_set_name(IsoNode *node, const char *name) +{ + return iso_node_set_name_trunc(node, name, 0, 0); +} + +int iso_image_set_node_name(IsoImage *image, IsoNode *node, const char *name, + int flag) +{ + if (image->truncate_mode == 0) + if ((int) strlen(name) > image->truncate_length) + return ISO_RR_NAME_TOO_LONG; + return iso_node_set_name_trunc(node, name, image->truncate_length, flag); } /** @@ -610,6 +647,41 @@ int iso_dir_get_node(IsoDir *dir, const char *name, IsoNode **node) return 1; } +int iso_dir_get_node_trunc(IsoDir *dir, int truncate_length, + const char *name, IsoNode **node) +{ + int ret; + char *trunc = NULL; + + if ((int) strlen(name) <= truncate_length) { + ret = iso_dir_get_node(dir, name, node); + return ret; + } + trunc = strdup(name); + if (trunc == NULL) + return ISO_OUT_OF_MEM; + ret = iso_truncate_rr_name(1, truncate_length, trunc, 1); + if (ret < 0) + return ret; + ret = iso_dir_get_node(dir, trunc, node); + if (ret == 0) + return 2; + return ret; +} + +/* API */ +int iso_image_dir_get_node(IsoImage *image, IsoDir *dir, + const char *name, IsoNode **node, int flag) +{ + int ret; + + if (image->truncate_mode == 0 || (flag & 1)) + ret = iso_dir_get_node(dir, name, node); + else + ret = iso_dir_get_node_trunc(dir, image->truncate_length, name, node); + return ret; +} + /** * Get the number of children of a directory. * diff --git a/libisofs/node.h b/libisofs/node.h index 2cdac22..fedc1b5 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -543,4 +543,10 @@ int zisofs_zf_xinfo_func(void *data, int flag); int zisofs_zf_xinfo_cloner(void *old_data, void **new_data, int flag); +/* Performing search for possibly truncated node name. + */ +int iso_dir_get_node_trunc(IsoDir *dir, int truncate_length, + const char *name, IsoNode **node); + + #endif /*LIBISO_NODE_H_*/ diff --git a/libisofs/tree.c b/libisofs/tree.c index 639c4b6..9bc8a64 100644 --- a/libisofs/tree.c +++ b/libisofs/tree.c @@ -100,6 +100,19 @@ int iso_tree_add_new_dir(IsoDir *parent, const char *name, IsoDir **dir) return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER); } +int iso_image_add_new_dir(IsoImage *image, IsoDir *parent, const char *name, + IsoDir **dir) +{ + int ret; + char *namept; + + ret = iso_image_truncate_name(image, name, &namept, 0); + if (ret < 0) + return ret; + ret = iso_tree_add_new_dir(parent, namept, dir); + return ret; +} + /** * Add a new symlink to the directory tree. Permissions are set to 0777, * owner and hidden atts are taken from parent. You can modify any of them @@ -175,6 +188,20 @@ int iso_tree_add_new_symlink(IsoDir *parent, const char *name, return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER); } +int iso_image_add_new_symlink(IsoImage *image, IsoDir *parent, + const char *name, const char *dest, + IsoSymlink **link) +{ + int ret; + char *namept; + + ret = iso_image_truncate_name(image, name, &namept, 0); + if (ret < 0) + return ret; + ret = iso_tree_add_new_symlink(parent, namept, dest, link); + return ret; +} + /** * Add a new special file to the directory tree. As far as libisofs concerns, * an special file is a block device, a character device, a FIFO (named pipe) @@ -264,6 +291,20 @@ int iso_tree_add_new_special(IsoDir *parent, const char *name, mode_t mode, return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER); } +int iso_image_add_new_special(IsoImage *image, IsoDir *parent, + const char *name, mode_t mode, + dev_t dev, IsoSpecial **special) +{ + int ret; + char *namept; + + ret = iso_image_truncate_name(image, name, &namept, 0); + if (ret < 0) + return ret; + ret = iso_tree_add_new_special(parent, namept, mode, dev, special); + return ret; +} + /** * Add a new regular file to the iso tree. Permissions are set to 0444, * owner and hidden atts are taken from parent. You can modify any of them @@ -339,6 +380,19 @@ int iso_tree_add_new_file(IsoDir *parent, const char *name, IsoStream *stream, return iso_dir_insert(parent, (IsoNode*)node, pos, ISO_REPLACE_NEVER); } +int iso_image_add_new_file(IsoImage *image, IsoDir *parent, const char *name, + IsoStream *stream, IsoFile **file) +{ + int ret; + char *namept; + + ret = iso_image_truncate_name(image, name, &namept, 0); + if (ret < 0) + return ret; + ret = iso_tree_add_new_file(parent, namept, stream, file); + return ret; +} + /** * Set whether to follow or not symbolic links when added a file from a source * to IsoImage. @@ -503,7 +557,7 @@ int iso_tree_add_node_builder(IsoImage *image, IsoDir *parent, int result; IsoNode *new; IsoNode **pos; - char *name = NULL; + char *name = NULL, *namept; if (parent == NULL || src == NULL || builder == NULL) { result = ISO_NULL_POINTER; goto ex; @@ -514,14 +568,18 @@ int iso_tree_add_node_builder(IsoImage *image, IsoDir *parent, name = iso_file_source_get_name(src); + result = iso_image_truncate_name(image, name, &namept, 0); + if (result < 0) + return result; + /* find place where to insert */ - result = iso_dir_exists(parent, name, &pos); + result = iso_dir_exists(parent, namept, &pos); if (result) { /* a node with same name already exists */ result = ISO_NODE_NAME_NOT_UNIQUE; goto ex; } - result = builder->create_node(builder, image, src, name, &new); + result = builder->create_node(builder, image, src, namept, &new); if (result < 0) goto ex; @@ -568,6 +626,7 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, IsoFileSource *file; IsoNode *new; IsoNode **pos; + char *namept; if (image == NULL || parent == NULL || name == NULL || path == NULL) { return ISO_NULL_POINTER; @@ -577,8 +636,12 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, *node = NULL; } + result = iso_image_truncate_name(image, name, &namept, 0); + if (result < 0) + return result; + /* find place where to insert */ - result = iso_dir_exists(parent, name, &pos); + result = iso_dir_exists(parent, namept, &pos); if (result) { /* a node with same name already exists */ return ISO_NODE_NAME_NOT_UNIQUE; @@ -591,7 +654,7 @@ int iso_tree_add_new_node(IsoImage *image, IsoDir *parent, const char *name, } result = image->builder->create_node(image->builder, image, file, - (char *) name, &new); + namept, &new); /* free the file */ iso_file_source_unref(file); @@ -620,6 +683,7 @@ int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, IsoFile *new; IsoNode **pos; IsoStream *stream; + char *namept; if (image == NULL || parent == NULL || name == NULL || path == NULL) { return ISO_NULL_POINTER; @@ -629,8 +693,12 @@ int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, *node = NULL; } + result = iso_image_truncate_name(image, name, &namept, 0); + if (result < 0) + return result; + /* find place where to insert */ - result = iso_dir_exists(parent, name, &pos); + result = iso_dir_exists(parent, namept, &pos); if (result) { /* a node with same name already exists */ return ISO_NODE_NAME_NOT_UNIQUE; @@ -673,7 +741,7 @@ int iso_tree_add_new_cut_out_node(IsoImage *image, IsoDir *parent, iso_stream_unref(new->stream); new->stream = stream; - result = iso_node_set_name((IsoNode*)new, name); + result = iso_node_set_name((IsoNode*)new, namept); if (result < 0) { iso_node_unref((IsoNode*)new); return result; @@ -1106,7 +1174,10 @@ int iso_tree_add_dir_rec(IsoImage *image, IsoDir *parent, const char *dir) return result; } -int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node) +/* @param flag bit0= truncate according to image truncate mode and length +*/ +int iso_tree_path_to_node_flag(IsoImage *image, const char *path, + IsoNode **node, int flag) { int result; IsoNode *n; @@ -1140,7 +1211,12 @@ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node) } dir = (IsoDir *)n; - result = iso_dir_get_node(dir, component, &n); + if ((flag & 1) && image->truncate_mode == 1) { + result = iso_dir_get_node_trunc(dir, image->truncate_length, + component, &n); + } else { + result = iso_dir_get_node(dir, component, &n); + } if (result != 1) { n = NULL; break; @@ -1156,6 +1232,16 @@ int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node) return result; } +int iso_tree_path_to_node(IsoImage *image, const char *path, IsoNode **node) +{ + return iso_tree_path_to_node_flag(image, path, node, 0); +} + +int iso_image_path_to_node(IsoImage *image, const char *path, IsoNode **node) +{ + return iso_tree_path_to_node_flag(image, path, node, 1); +} + char *iso_tree_get_node_path(IsoNode *node) { char *path = NULL, *parent_path = NULL; @@ -1397,18 +1483,36 @@ int iso_tree_clone_special(IsoSpecial *node, return ISO_SUCCESS; } -/* API */ -int iso_tree_clone(IsoNode *node, - IsoDir *new_parent, char *new_name, IsoNode **new_node, - int flag) + +/* @param flag bit0= Merge directories rather than ISO_NODE_NAME_NOT_UNIQUE. + bit1= issue warning in case of truncation +*/ +int iso_tree_clone_trunc(IsoNode *node, IsoDir *new_parent, + char *new_name_in, IsoNode **new_node, + int truncate_length, int flag) { int ret = ISO_SUCCESS; + char *new_name, *trunc = NULL; + *new_node = NULL; + new_name = new_name_in; + if (truncate_length >= 64 && (int) strlen(new_name) > truncate_length) { + trunc = strdup(new_name); + if (trunc == 0) { + ret = ISO_OUT_OF_MEM; + goto ex; + } + ret = iso_truncate_rr_name(1, truncate_length, trunc, !(flag & 2)); + if (ret < 0) + goto ex; + new_name = trunc; + } if (iso_dir_get_node(new_parent, new_name, new_node) == 1) { if (! (node->type == LIBISO_DIR && (*new_node)->type == LIBISO_DIR && (flag & 1))) { *new_node = NULL; - return ISO_NODE_NAME_NOT_UNIQUE; + ret = ISO_NODE_NAME_NOT_UNIQUE; + goto ex; } } else flag &= ~1; @@ -1429,10 +1533,42 @@ int iso_tree_clone(IsoNode *node, ret = ISO_SUCCESS; /* API says they are silently ignored */ } if (ret < 0) - return ret; - if (flag & 1) - return 2; /* merged two directories, *new_node is not new */ + goto ex; + if (flag & 1) { + ret = 2; /* merged two directories, *new_node is not new */ + goto ex; + } ret = iso_tree_copy_node_attr(node, *new_node, 0); + +ex:; + if (trunc != NULL) + free(trunc); + return ret; +} + + +/* API */ +int iso_tree_clone(IsoNode *node, + IsoDir *new_parent, char *new_name, IsoNode **new_node, + int flag) +{ + return iso_tree_clone_trunc(node, new_parent, new_name, new_node, 0, + flag & 1); +} + + +/* API */ +int iso_image_tree_clone(IsoImage *image, IsoNode *node, IsoDir *new_parent, + char *new_name, IsoNode **new_node, int flag) +{ + int length, ret; + + if (image->truncate_mode == 0) + length = 0; + else + length = image->truncate_length; + ret = iso_tree_clone_trunc(node, new_parent, new_name, new_node, length, + flag & 3); return ret; } diff --git a/libisofs/util.c b/libisofs/util.c index 873b86a..53df38a 100644 --- a/libisofs/util.c +++ b/libisofs/util.c @@ -17,6 +17,7 @@ #include "libisofs.h" #include "messages.h" #include "joliet.h" +#include "node.h" #include "../version.h" #include @@ -2343,3 +2344,95 @@ off_t iso_scanf_io_size(char *text, int flag) ret += fac - 1; return ret; } + + +/* Find backward from idx the start byte of a possible UTF-8 character. + https://en.wikipedia.org/wiki/UTF-8#Description +*/ +static +int find_utf8_start(char *name, int idx, int flag) +{ + unsigned char *uname, uch; + int i; + + uname= (unsigned char *) name; + if ((uname[idx] & 0xc0) != 0x80) + return idx; /* not an UTF-8 tail byte */ + for (i = 0; i < 5; i++) { /* up to deprecated 6-byte codes */ + uch = uname[idx - 1 - i]; + if ((uch & 0xe0) == 0xc0 || (uch & 0xf0) == 0xe0 || + (uch & 0xf8) == 0xf0 || (uch & 0xfc) == 0xf8 || + (uch & 0xfe) == 0xfc) + return (idx - 1 - i); /* UTF-8 start byte found */ + if ((uch & 0xc0) != 0x80) + return idx; /* not an UTF-8 tail byte, so no UTF-8 */ + } + return idx; /* no UTF-8 start found */ +} + +/* @param flag bit0= do not issue warning message +*/ +int iso_truncate_rr_name(int truncate_mode, int truncate_length, + char *name, int flag) +{ + int neck, goal, ret, l, i; + static int hash_size = 32; + void *ctx = NULL; + char hashval[16]; + + l = strlen(name); + if (l <= truncate_length) + return ISO_SUCCESS; + if (truncate_mode == 0) + return ISO_RR_NAME_TOO_LONG; + + /* Compute hash */ + ret = iso_md5_start(&ctx); + if (ret < 0) + goto ex; + ret = iso_md5_compute(ctx, name, l > 4095 ? 4095 : l); + if (ret < 0) + goto ex; + ret = iso_md5_end(&ctx, hashval); + if (ret < 0) + goto ex; + + if (!(flag & 1)) + iso_msg_submit(-1, ISO_RR_NAME_TRUNCATED, 0, + "File name had to be truncated and MD5 marked: %s", name); + + /* Avoid to produce incomplete UTF-8 characters */ + goal = truncate_length - hash_size - 1; + neck = find_utf8_start(name, goal, 0); + for (; neck < goal; neck++) + name[neck] = '_'; + + /* Write colon and hash text over end of truncated name */ + name[goal] = ':'; + goal++; + for (i = 0; goal < truncate_length - 1 && i < hash_size / 2; goal += 2) { + sprintf(name + goal, "%2.2x", *((unsigned char *) (hashval + i))); + i++; + } + name[truncate_length] = 0; + + ret = ISO_SUCCESS; +ex:; + if (ctx != NULL) + iso_md5_end(&ctx, hashval); + return ret; +} + +/* API */ +int iso_truncate_leaf_name(int mode, int length, char *name, int flag) +{ + int ret; + + if (mode < 0 || mode > 1) + return ISO_WRONG_ARG_VALUE; + if (length < 64 || length > LIBISOFS_NODE_NAME_MAX) + return ISO_WRONG_ARG_VALUE; + ret = iso_truncate_rr_name(mode, length, name, 1); + return ret; +} + diff --git a/libisofs/util.h b/libisofs/util.h index 938d4ad..dfb165e 100644 --- a/libisofs/util.h +++ b/libisofs/util.h @@ -564,6 +564,8 @@ int iso_util_bin_to_hex(char *target, uint8_t *bytes, int num_bytes, int flag); int iso_util_hex_to_bin(char *hex, char *bin, int bin_size, int *bin_count, int flag); +int iso_truncate_rr_name(int truncate_mode, int truncate_length, + char *name, int flag); /* ------------------------------------------------------------------------- */