diff --git a/src/ecma119.c b/src/ecma119.c index 908b771..45b1f27 100644 --- a/src/ecma119.c +++ b/src/ecma119.c @@ -15,6 +15,7 @@ #include "image.h" #include "writer.h" #include "messages.h" +#include "rockridge.h" #include "util.h" #include "libburn/libburn.h" @@ -60,18 +61,41 @@ size_t calc_dirent_len(Ecma119Image *t, Ecma119Node *n) /** * Computes the total size of all directory entries of a single dir, * acording to ECMA-119 6.8.1.1 + * + * This also take into account the size needed for RR entries and + * SUSP continuation areas (SUSP, 5.1). + * + * @param ce + * Will be filled with the size needed for Continuation Areas + * @return + * The size needed for all dir entries of the given dir, without + * taking into account the continuation areas. */ static -size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir) +size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir, size_t *ce) { size_t i, len; + size_t ce_len = 0; /* size of "." and ".." entries */ - len = 34 + 34; + len += 34 + 34; + if (t->rockridge) { + len += rrip_calc_len(t, dir, 1, 255 - 34, &ce_len); + *ce += ce_len; + len += rrip_calc_len(t, dir, 2, 255 - 34, &ce_len); + *ce += ce_len; + } + for (i = 0; i < dir->info.dir.nchildren; ++i) { + size_t remaining; Ecma119Node *child = dir->info.dir.children[i]; size_t dirent_len = calc_dirent_len(t, child); - size_t remaining = BLOCK_SIZE - (len % BLOCK_SIZE); + if (t->rockridge) { + dirent_len += rrip_calc_len(t, child, 0, 255 - dirent_len, + &ce_len); + *ce += ce_len; + } + remaining = BLOCK_SIZE - (len % BLOCK_SIZE); if (dirent_len > remaining) { /* child directory entry doesn't fit on block */ len += remaining + dirent_len; @@ -79,6 +103,8 @@ size_t calc_dir_size(Ecma119Image *t, Ecma119Node *dir) len += dirent_len; } } + /* cache the len */ + dir->info.dir.len = len; return len; } @@ -86,11 +112,15 @@ static void calc_dir_pos(Ecma119Image *t, Ecma119Node *dir) { size_t i, len; + size_t ce_len = 0; t->ndirs++; dir->info.dir.block = t->curblock; - len = calc_dir_size(t, dir); + len = calc_dir_size(t, dir, &ce_len); t->curblock += div_up(len, BLOCK_SIZE); + if (t->rockridge) { + t->curblock += div_up(ce_len, BLOCK_SIZE); + } for (i = 0; i < dir->info.dir.nchildren; i++) { Ecma119Node *child = dir->info.dir.children[i]; if (child->type == ECMA119_DIR) { @@ -189,7 +219,8 @@ void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id, } if (node->type == ECMA119_DIR) { - len = calc_dir_size(t, node); + /* use the cached length */ + len = node->info.dir.len; block = node->info.dir.block; } else if (node->type == ECMA119_FILE) { len = iso_file_src_get_size(node->info.file); diff --git a/src/ecma119_tree.h b/src/ecma119_tree.h index 12a55ba..57150e4 100644 --- a/src/ecma119_tree.h +++ b/src/ecma119_tree.h @@ -30,6 +30,15 @@ struct ecma119_dir_info { size_t nchildren; Ecma119Node **children; + /* + * Size of the dir, i.e., sum of the lengths of all directory records. + * It is computed by calc_dir_size() [ecma119.c]. + * Note that this don't include the length of any SUSP Continuation + * Area needed by the dir, but it includes the size of the SUSP entries + * than fit in the directory records System Use Field. + */ + size_t len; + /** * Real parent if the dir has been reallocated. NULL otherwise. */