diff --git a/libisofs/ecma119.c b/libisofs/ecma119.c index e80418f..dde70b9 100644 --- a/libisofs/ecma119.c +++ b/libisofs/ecma119.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2007 Vreixo Formoso * Copyright (c) 2007 Mario Danic - * Copyright (c) 2009 - 2019 Thomas Schmitt + * Copyright (c) 2009 - 2023 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -205,17 +205,24 @@ size_t calc_dirent_len(Ecma119Image *t, Ecma119Node *n) * taking into account the continuation areas. */ static -size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce) +ssize_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce) { size_t i, len; + ssize_t ret; size_t ce_len = 0; /* size of "." and ".." entries */ len = 34 + 34; if (t->opts->rockridge) { - len += rrip_calc_len(t, dir, 1, 34, &ce_len, *ce); + ret = rrip_calc_len(t, dir, 1, 34, &ce_len, *ce); + if (ret < 0) + return ret; + len += ret; *ce += ce_len; - len += rrip_calc_len(t, dir, 2, 34, &ce_len, *ce); + ret = rrip_calc_len(t, dir, 2, 34, &ce_len, *ce); + if (ret < 0) + return ret; + len += ret; *ce += ce_len; } @@ -228,8 +235,10 @@ 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->opts->rockridge) { - dirent_len += rrip_calc_len(t, child, 0, dirent_len, &ce_len, - *ce); + ret = rrip_calc_len(t, child, 0, dirent_len, &ce_len, *ce); + if (ret < 0) + return ret; + dirent_len += ret; *ce += ce_len; } remaining = BLOCK_SIZE - (len % BLOCK_SIZE); @@ -255,14 +264,18 @@ size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce) } static -void calc_dir_pos(Ecma119Image *t, Ecma119Node *dir) +int calc_dir_pos(Ecma119Image *t, Ecma119Node *dir) { size_t i, len; + ssize_t ret; size_t ce_len = 0; t->ndirs++; dir->info.dir->block = t->curblock; - len = calc_dir_size(t, dir, &ce_len); + ret = calc_dir_size(t, dir, &ce_len); + if (ret < 0) + return (int) ret; + len = ret; t->curblock += DIV_UP(len, BLOCK_SIZE); if (t->opts->rockridge) { t->curblock += DIV_UP(ce_len, BLOCK_SIZE); @@ -270,9 +283,12 @@ void calc_dir_pos(Ecma119Image *t, Ecma119Node *dir) for (i = 0; i < dir->info.dir->nchildren; i++) { Ecma119Node *child = dir->info.dir->children[i]; if (child->type == ECMA119_DIR) { - calc_dir_pos(t, child); + ret = calc_dir_pos(t, child); + if (ret < 0) + return (int) ret; } } + return ISO_SUCCESS; } /** @@ -305,6 +321,7 @@ int ecma119_writer_compute_data_blocks(IsoImageWriter *writer) Ecma119Image *target; uint32_t path_table_size; size_t ndirs; + int ret; if (writer == NULL) { return ISO_ASSERT_FAILURE; @@ -315,7 +332,9 @@ int ecma119_writer_compute_data_blocks(IsoImageWriter *writer) /* compute position of directories */ iso_msg_debug(target->image->id, "Computing position of dir structure"); target->ndirs = 0; - calc_dir_pos(target, target->root); + ret = calc_dir_pos(target, target->root); + if (ret < 0) + return ret; /* compute length of pathlist */ iso_msg_debug(target->image->id, "Computing length of pathlist"); @@ -338,7 +357,9 @@ int ecma119_writer_compute_data_blocks(IsoImageWriter *writer) /* Take into respect the second directory tree */ ndirs = target->ndirs; target->ndirs = 0; - calc_dir_pos(target, target->partition_root); + ret = calc_dir_pos(target, target->partition_root); + if (ret < 0) + return ret; if (target->ndirs != ndirs) { iso_msg_submit(target->image->id, ISO_ASSERT_FAILURE, 0, "Number of directories differs in ECMA-119 partiton_tree"); @@ -2737,6 +2758,8 @@ int ecma119_image_new(IsoImage *src, IsoWriteOpts *in_opts, Ecma119Image **img) target->filesrc_start = 0; target->filesrc_blocks = 0; + target->curr_ce_entries = 0; + target->joliet_ucs2_failures = 0; /* If partitions get appended, then the backup GPT cannot be part of @@ -3611,6 +3634,8 @@ int iso_write_opts_new(IsoWriteOpts **opts, int profile) wopts->hfsp_block_size = 0; memset(wopts->gpt_disk_guid, 0, 16); wopts->gpt_disk_guid_mode = 0; + wopts->max_ce_entries = 31; /* Linux hates >= RR_MAX_CE_ENTRIES = 32 */ + wopts->max_ce_drop_attr = 2; /* If needed drop non-isofs fattr and ACL */ *opts = wopts; return ISO_SUCCESS; @@ -4403,6 +4428,17 @@ int iso_write_opts_set_gpt_guid(IsoWriteOpts *opts, uint8_t guid[16], int mode) return ISO_SUCCESS; } +int iso_write_opts_set_max_ce_entries(IsoWriteOpts *opts, uint32_t num, + int flag) +{ + if (num > 100000) + return ISO_TOO_MANY_CE; + if (num == 0) + num = 1; + opts->max_ce_entries = num; + opts->max_ce_drop_attr = flag & 15; + return ISO_SUCCESS; +} /* * @param flag diff --git a/libisofs/ecma119.h b/libisofs/ecma119.h index ada37b5..e4c361a 100644 --- a/libisofs/ecma119.h +++ b/libisofs/ecma119.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 - 2019 Thomas Schmitt + * Copyright (c) 2009 - 2023 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -543,6 +543,17 @@ struct iso_write_opts { */ uint8_t gpt_disk_guid[16]; int gpt_disk_guid_mode; + + /* Maximum number of CE entries per file */ + uint32_t max_ce_entries; + /* Whether to try dropping AAIP data on too many CE: + bit0-3 = Mode: + 0 = throw ISO_TOO_MANY_CE, without trying to drop anything + 1 = drop non-isofs fattr + 2 = drop ACL if dropping non-isofs fattr does not suffice + */ + int max_ce_drop_attr; + }; typedef struct ecma119_image Ecma119Image; @@ -913,6 +924,8 @@ struct ecma119_image uint32_t filesrc_start; uint32_t filesrc_blocks; + /* Number of CE entries in currently processed node */ + uint32_t curr_ce_entries; }; #define BP(a,b) [(b) - (a) + 1] diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index e4c3b2b..070c4f4 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -4,7 +4,7 @@ /* * Copyright (c) 2007-2008 Vreixo Formoso, Mario Danic - * Copyright (c) 2009-2022 Thomas Schmitt + * Copyright (c) 2009-2023 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -2684,6 +2684,39 @@ int iso_write_opts_set_efi_bootp(IsoWriteOpts *opts, char *image_path, int iso_write_opts_set_gpt_guid(IsoWriteOpts *opts, uint8_t guid[16], int mode); +/** + * Set the maximum number of SUSP CE entries and thus continuation areas. + * Each continuation area can hold at most 2048 bytes of SUSP data (Rock Ridge + * or AAIP). The first area can be smaller. There might be some waste at the + * end of each area. + * When the maximum number is exceeded during ISO filesystem production + * then possibly xattr and ACL get removed or error ISO_TOO_MANY_CE gets + * reported and filesystem production is prevented. + * + * Files with 32 or more CE entries do not show up in mounted filesystems on + * Linux. So the default setting is 31 with drop mode 2. If a higher limit is + * chosen and 31 gets surpassed, then a warning message gets reported. + * + * @param opts + * The option set to be manipulated. + * @param num + * The maximum number of CE entries per file. + * Not more than 100000 may be set here. + * 0 gets silently mapped to 1, because the root directory needs one CE. + * @param flag + * bit0-bit3 = Drop mode: What to do with AAIP data on too many CE: + * 0 = throw ISO_TOO_MANY_CE, without dropping anything + * 1 = permanently drop non-isofs fattr from IsoNode and + * retry filesystem production + * 2 = drop ACL if dropping non-isofs fattr does not suffice + * @return + * ISO_SUCCESS or ISO_TOO_MANY_CE + * + * @since 1.5.6 +*/ +int iso_write_opts_set_max_ce_entries(IsoWriteOpts *opts, uint32_t num, + int flag); + /** * Generate a pseudo-random GUID suitable for iso_write_opts_set_gpt_guid(). * @@ -9401,6 +9434,16 @@ int iso_conv_name_chars(IsoWriteOpts *opts, char *name, size_t name_len, /** Undefined IsoReadImageFeatures name (SORRY, HIGH, -426) */ #define ISO_UNDEF_READ_FEATURE 0xE030FE56 +/** Too many CE entries for single file (FAILURE,HIGH, -427) */ +#define ISO_TOO_MANY_CE 0xE830FE55 + +/** Too many CE entries for single file when mounted by Linux + (WARNING,HIGH, -428) */ +#define ISO_TOO_MANY_CE_FOR_LINUX 0xD030FE54 + +/** Too many CE entries for single file, omitting attributes + (WARNING,HIGH, -429) */ +#define ISO_CE_REMOVING_ATTR 0xD030FE53 /* Internal developer note: diff --git a/libisofs/libisofs.ver b/libisofs/libisofs.ver index 84d19f7..7216da6 100644 --- a/libisofs/libisofs.ver +++ b/libisofs/libisofs.ver @@ -350,6 +350,7 @@ iso_write_opts_set_joliet_long_names; iso_write_opts_set_joliet_longer_paths; iso_write_opts_set_joliet_utf16; iso_write_opts_set_max_37_char_filenames; +iso_write_opts_set_max_ce_entries; iso_write_opts_set_ms_block; iso_write_opts_set_no_force_dots; iso_write_opts_set_old_empty; diff --git a/libisofs/messages.c b/libisofs/messages.c index d556e8d..5d677ed 100644 --- a/libisofs/messages.c +++ b/libisofs/messages.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 - 2022 Thomas Schmitt + * Copyright (c) 2009 - 2023 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -567,6 +567,12 @@ const char *iso_error_to_msg(int errcode) return "Cannot obtain size of zisofs compressed stream"; case ISO_UNDEF_READ_FEATURE: return "Undefined IsoReadImageFeatures name"; + case ISO_TOO_MANY_CE: + return "Too many CE entries for single file"; + case ISO_TOO_MANY_CE_FOR_LINUX: + return "Too many CE entries for single file when mounted by Linux"; + case ISO_CE_REMOVING_ATTR: + return "Too many CE entries for single file, removing attributes"; default: return "Unknown error"; } diff --git a/libisofs/node.c b/libisofs/node.c index ae0f2bc..e1e653a 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 - 2020 Thomas Schmitt + * Copyright (c) 2009 - 2023 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -2046,13 +2046,60 @@ int iso_node_set_attrs(IsoNode *node, size_t num_attrs, char **names, } ret = 1; ex:; - /* Dispose eventual merged list */ + /* Dispose merged list if it was created */ iso_node_merge_xattr(node, num_attrs, names, value_lengths, values, &m_num, &m_names, &m_value_lengths, &m_values, 1 << 15); + /* Dispose ACL if saved */ + iso_node_get_acl_text(node, &a_acl, &d_acl, 1 << 15); return ret; } +/* @param flag + bit0= delete ACL, too +*/ +int iso_node_remove_fattr(IsoNode *node, int flag) +{ + int ret; + size_t num_attrs, *value_lengths = NULL, i, w; + char **names = NULL, **values = NULL; + + ret = iso_node_get_attrs(node, &num_attrs, &names, &value_lengths, &values, + flag & 1); + if (ret < 0) + goto ex; + + /* Delete variables of all namespaces except isofs */ + w = 0; + for (i = 0; i < num_attrs; i++) { + if (strncmp(names[i], "isofs.", 6) != 0) { + free(names[i]); + names[i] = NULL; + free(values[i]); + values[i] = NULL; + continue; + } + if (w != i) { + /* move i to w , nullify i */ + names[w] = names[i]; + names[i] = NULL; + values[w] = values[i]; + values[i] = NULL; + value_lengths[w] = value_lengths[i]; + } + w++; + } + num_attrs = w; + ret = iso_node_set_attrs(node, num_attrs, names, value_lengths, values, + (flag & 1) | 8); +ex:; + if (names != NULL) + iso_node_get_attrs(NULL, &num_attrs, &names, &value_lengths, &values, + 1 << 15); + return ret; +} + + static int iso_decode_acl(unsigned char *v_data, size_t v_len, size_t *consumed, char **text, size_t *text_fill, int flag) diff --git a/libisofs/node.h b/libisofs/node.h index 44f7ba5..abba621 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2007 Vreixo Formoso - * Copyright (c) 2009 - 2020 Thomas Schmitt + * Copyright (c) 2009 - 2023 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -422,6 +422,12 @@ int iso_aa_get_attrs(unsigned char *aa_string, size_t *num_attrs, int iso_aa_lookup_attr(unsigned char *aa_string, char *name, size_t *value_length, char **value, int flag); +/** + * Delete variables of all namespaces except isofs + * + * @param flag bit0= delete ACL, too +*/ +int iso_node_remove_fattr(IsoNode *node, int flag); /** * Function to identify and manage ZF parameters which do not stem from ZF diff --git a/libisofs/rockridge.c b/libisofs/rockridge.c index ab3553d..e0696b0 100644 --- a/libisofs/rockridge.c +++ b/libisofs/rockridge.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2007 Vreixo Formoso * Copyright (c) 2007 Mario Danic - * Copyright (c) 2009 - 2022 Thomas Schmitt + * Copyright (c) 2009 - 2023 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -618,13 +618,15 @@ int rrip_add_SL(Ecma119Image *t, struct susp_info *susp, uint8_t **comp, /* @param flag bit1= care about crossing block boundaries */ static -int susp_calc_add_to_ce(size_t *ce, size_t base_ce, int add, int flag) +int susp_calc_add_to_ce(Ecma119Image *t, size_t *ce, size_t base_ce, int add, + int flag) { if (flag & 2) { /* Account for inserted CE before size exceeds block size */ if ((*ce + base_ce + add + ISO_CE_ENTRY_SIZE - 1) / BLOCK_SIZE != (*ce + base_ce) / BLOCK_SIZE) { /* Insert CE and padding */ + t->curr_ce_entries++; *ce += ISO_CE_ENTRY_SIZE; if ((*ce + base_ce) % BLOCK_SIZE) *ce += BLOCK_SIZE - ((*ce + base_ce) % BLOCK_SIZE); @@ -658,12 +660,12 @@ int aaip_add_AL(Ecma119Image *t, struct susp_info *susp, es_extra = 5; if (*sua_free < num_data + es_extra || *ce_len > 0) { if (es_extra > 0) - susp_calc_add_to_ce(ce_len, ce_mem, es_extra, flag & 2); + susp_calc_add_to_ce(t, ce_len, ce_mem, es_extra, flag & 2); done = 0; for (aapt = *data; !done; aapt += aapt[2]) { done = !(aapt[4] & 1); len = aapt[2]; - susp_calc_add_to_ce(ce_len, ce_mem, len, flag & 2); + susp_calc_add_to_ce(t, ce_len, ce_mem, len, flag & 2); count += len; } } else { @@ -704,7 +706,7 @@ int aaip_add_AL(Ecma119Image *t, struct susp_info *susp, } else { ret = susp_append(t, susp, cpt); } - if (ret == -1) + if (ret < 0) return ret; } free(*data); @@ -1078,7 +1080,7 @@ int add_zf_field(Ecma119Image *t, Ecma119Node *n, struct susp_info *info, /* Account for field size */ if (*sua_free < 16 || *ce_len > 0) { - susp_calc_add_to_ce(ce_len, base_ce, 16, flag & 2); + susp_calc_add_to_ce(t, ce_len, base_ce, 16, flag & 2); } else { *sua_free -= 16; } @@ -1139,6 +1141,7 @@ int aaip_xinfo_cloner(void *old_data, void **new_data, int flag) * <0= error: * -1= not enough SUA space for 28 bytes of CE entry * -2= out of memory + * (int) ISO_TOO_MANY_CE */ static int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, @@ -1150,17 +1153,20 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, size_t num_aapt = 0, sua_free = 0; int ret; uint8_t *aapt; + uint32_t curr_ce_entries_mem; #ifdef Libisofs_ce_calc_debug_extrA if (n->node->name != NULL) - fprintf(stderr, "libburn_DEBUG: susp_calc_nm_sl_al : %.f %s \n", + fprintf(stderr, "libburn_DEBUG: susp_calc_nm_sl_al : %u %.f %s \n", + (unsigned int) t->curr_ce_entries, (double) base_ce, n->node->name); #endif /* Libisofs_ce_calc_debug_extrA */ su_mem = *su_size; ce_mem = *ce; + curr_ce_entries_mem = t->curr_ce_entries; if (*ce > 0 && !(flag & 1)) goto unannounced_ca; @@ -1175,10 +1181,11 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, } if (flag & 1) { - /* Account for 28 bytes of CE field */ - if (*su_size + 28 > space) - return -1; - *su_size += 28; + /* Account for 28 bytes of CE field */ + if (*su_size + 28 > space) + return -1; + *su_size += 28; + t->curr_ce_entries++; } /* NM entry */ @@ -1196,7 +1203,7 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, of the name will always fit into the directory entry.) */; - susp_calc_add_to_ce(ce, base_ce, 5 + namelen, flag & 2); + susp_calc_add_to_ce(t, ce, base_ce, 5 + namelen, flag & 2); *su_size = space; } if (n->type == ECMA119_SYMLINK) { @@ -1267,7 +1274,7 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, * and another SL entry */ /* Will fill up old SL and write it */ - susp_calc_add_to_ce(ce, base_ce, 255, flag & 2); + susp_calc_add_to_ce(t, ce, base_ce, 255, flag & 2); sl_len = 5 + (clen - fit); /* Start new SL */ } else { /* @@ -1276,15 +1283,16 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, * anything in this SL */ /* Will write non-full old SL */ - susp_calc_add_to_ce(ce, base_ce, sl_len, flag & 2); + susp_calc_add_to_ce(t, ce, base_ce, sl_len, + flag & 2); /* Will write another full SL */ - susp_calc_add_to_ce(ce, base_ce, 255, flag & 2); + susp_calc_add_to_ce(t, ce, base_ce, 255, flag & 2); sl_len = 5 + (clen - 250) + 2; /* Start new SL */ } } else { /* case 2, create a new SL entry */ /* Will write non-full old SL */ - susp_calc_add_to_ce(ce, base_ce, sl_len, flag & 2); + susp_calc_add_to_ce(t, ce, base_ce, sl_len, flag & 2); sl_len = 5 + clen; /* Start new SL */ } } else { @@ -1307,7 +1315,7 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, /* the whole SL fits into the SUA */ *su_size += sl_len; } else { - susp_calc_add_to_ce(ce, base_ce, sl_len, flag & 2); + susp_calc_add_to_ce(t, ce, base_ce, sl_len, flag & 2); } } @@ -1367,6 +1375,7 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, /* Crossed a block boundary */ *su_size = su_mem; *ce = ce_mem; + t->curr_ce_entries = curr_ce_entries_mem; return 0; } } @@ -1376,6 +1385,7 @@ int susp_calc_nm_sl_al(Ecma119Image *t, Ecma119Node *n, size_t space, unannounced_ca:; *su_size = su_mem; *ce = ce_mem; + t->curr_ce_entries = curr_ce_entries_mem; return 0; } @@ -1422,6 +1432,21 @@ int add_aa_string(Ecma119Image *t, Ecma119Node *n, struct susp_info *info, } +static +void iso_msg_too_many_ce(Ecma119Image *t, Ecma119Node *n, int err) +{ + if (n->node->name != NULL) { + iso_msg_submit(t->image->id, err, 0, + "Too many CE entries for file with name: %s", + n->node->name); + } else { + iso_msg_submit(t->image->id, err, 0, + "Too many CE entries for a single file", + n->node->name); + } +} + + /** * Compute the length needed for write all RR and SUSP entries for a given * node. @@ -1438,13 +1463,15 @@ int add_aa_string(Ecma119Image *t, Ecma119Node *n, struct susp_info *info, * @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 used_up, - size_t *ce, size_t base_ce) +ssize_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t used_up, + size_t *ce, size_t base_ce) { size_t su_size, space; - int ret; + int ret, retry = 0; size_t aaip_sua_free= 0, aaip_len= 0; +try_again: + /* Directory record length must be even (ECMA-119, 9.1.13). Maximum is 254. */ space = 254 - used_up - (used_up % 2); @@ -1457,6 +1484,7 @@ size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t used_up, *ce = 0; su_size = 0; + t->curr_ce_entries = 0; /* If AAIP enabled and announced by ER : account for 5 bytes of ES */; if (t->opts->aaip && !t->opts->aaip_susp_1_10) @@ -1506,9 +1534,18 @@ size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t used_up, if (ret == 0) /* Retry with CE but no block crossing */ ret = susp_calc_nm_sl_al(t, n, space, &su_size, ce, base_ce, 1); if (ret == 0) /* Retry with aligned CE and block hopping */ - ret = susp_calc_nm_sl_al(t, n, space, &su_size, ce, base_ce, 1 | 2); + ret = susp_calc_nm_sl_al(t, n, space, &su_size, ce, base_ce, + 1 | 2); if (ret == -2) return ISO_OUT_OF_MEM; + /* -1 should not occur. By tradition it would not cause return */ + if (ret < -2) { + if (n->node->name != NULL) + iso_msg_submit(t->image->id, ret, 0, + "SUSP planning failed for file with name: %s", + n->node->name); + return ret; + } } else { @@ -1524,6 +1561,7 @@ size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t used_up, * ER needs a Continuation Area, thus we also need a CE entry */ su_size += 7 + 28; /* SP + CE */ + t->curr_ce_entries++; /* ER of RRIP */ if (t->opts->rrip_version_1_10) { *ce = 237; @@ -1546,6 +1584,40 @@ size_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t used_up, } } + if (t->curr_ce_entries > t->opts->max_ce_entries) { + /* If permitted by API setting: Remove non-isofs-non-ACL fattr */ + retry++; + if (retry == 1) { + if ((t->opts->max_ce_drop_attr & 15) >= 1) { + ret = iso_node_remove_fattr(n->node, 0); + if (ret > 0) { + iso_msg_too_many_ce(t, n, ISO_CE_REMOVING_ATTR); + iso_msg_submit(t->image->id, ISO_CE_REMOVING_ATTR, 0, + "Removed non-isofs attributes"); + goto try_again; + } + } + } else if (retry == 2) { + if ((t->opts->max_ce_drop_attr & 15) >= 2) { + ret = iso_node_remove_fattr(n->node, 1); + if (ret > 0) { + iso_msg_submit(t->image->id, ISO_CE_REMOVING_ATTR, 0, + "Removed ACL"); + goto try_again; + } + } + } + iso_msg_too_many_ce(t, n, ISO_TOO_MANY_CE); + return (ssize_t) (int) ISO_TOO_MANY_CE; + } else if (t->curr_ce_entries >= 32) { + if (n->node->name != NULL) + iso_msg_submit(t->image->id, ISO_TOO_MANY_CE_FOR_LINUX, 0, + "SUSP planning risky for file with name: %s", + n->node->name); + iso_msg_submit(t->image->id, ISO_TOO_MANY_CE_FOR_LINUX, 0, + "Too many CE entries for single file when mounted by Linux"); + } + /* * The System Use field inside the directory record must be padded if * it is an odd number (ECMA-119, 9.1.13) @@ -1762,6 +1834,9 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type, ret = ISO_OUT_OF_MEM; goto add_susp_cleanup; } + /* -1 should not occur. By tradition it would not cause return */ + if (ret < -2) + goto add_susp_cleanup; /* NM entry */ if (5 + namelen <= sua_free) { @@ -2064,6 +2139,8 @@ int rrip_get_susp_fields(Ecma119Image *t, Ecma119Node *n, int type, /* Compute length of AAIP string of root node */ aaip_sua_free= 0; + /* (just to give t->curr_ce_entries a defined state) */ + t->curr_ce_entries = 0; ret = add_aa_string(t, n, NULL, &aaip_sua_free, &aaip_len, ce_mem, 1 | 2); if (ret < 0) diff --git a/libisofs/rockridge.h b/libisofs/rockridge.h index c2dbed4..5649eb7 100644 --- a/libisofs/rockridge.h +++ b/libisofs/rockridge.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2007 Vreixo Formoso * Copyright (c) 2007 Mario Danic - * Copyright (c) 2009 - 2020 Thomas Schmitt + * Copyright (c) 2009 - 2023 Thomas Schmitt * * This file is part of the libisofs project; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 @@ -203,8 +203,8 @@ struct susp_sys_user_entry * @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 *ce, size_t base_ce); +ssize_t rrip_calc_len(Ecma119Image *t, Ecma119Node *n, int type, size_t space, + size_t *ce, size_t base_ce); /** * Fill a struct susp_info with the RR/SUSP entries needed for a given