|
|
|
/*
|
|
|
|
* Copyright (c) 2007 Vreixo Formoso
|
|
|
|
* Copyright (c) 2007 Mario Danic
|
|
|
|
* Copyright (c) 2009 - 2019 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
|
|
|
|
* or later as published by the Free Software Foundation.
|
|
|
|
* See COPYING file for details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "../config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
Use the copy of the struct burn_source definition in libisofs.h
|
|
|
|
*/
|
|
|
|
#define LIBISOFS_WITHOUT_LIBBURN yes
|
|
|
|
#include "libisofs.h"
|
|
|
|
|
|
|
|
#include "ecma119.h"
|
|
|
|
#include "joliet.h"
|
|
|
|
#include "hfsplus.h"
|
|
|
|
#include "iso1999.h"
|
|
|
|
#include "eltorito.h"
|
|
|
|
#include "ecma119_tree.h"
|
|
|
|
#include "filesrc.h"
|
|
|
|
#include "image.h"
|
|
|
|
#include "writer.h"
|
|
|
|
#include "messages.h"
|
|
|
|
#include "rockridge.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "system_area.h"
|
|
|
|
#include "md5.h"
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <locale.h>
|
|
|
|
#include <langinfo.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#ifdef Xorriso_standalonE
|
|
|
|
|
|
|
|
#ifdef Xorriso_with_libjtE
|
|
|
|
#include "../libjte/libjte.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
#ifdef Libisofs_with_libjtE
|
|
|
|
#include <libjte/libjte.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* ! Xorriso_standalonE */
|
|
|
|
|
|
|
|
|
|
|
|
int iso_write_opts_clone(IsoWriteOpts *in, IsoWriteOpts **out, int flag);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO #00011 : guard against bad path table usage with more than 65535 dirs
|
|
|
|
* image with more than 65535 directories have path_table related problems
|
|
|
|
* due to 16 bits parent id. Note that this problem only affects to folders
|
|
|
|
* that are parent of another folder.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static
|
|
|
|
void ecma119_image_free(Ecma119Image *t)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (t == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (t->refcount > 1) {
|
|
|
|
t->refcount--;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t->root != NULL)
|
|
|
|
ecma119_node_free(t->root);
|
|
|
|
if (t->opts != NULL)
|
|
|
|
iso_write_opts_free(t->opts);
|
|
|
|
if (t->image != NULL)
|
|
|
|
iso_image_unref(t->image);
|
|
|
|
if (t->files != NULL)
|
|
|
|
iso_rbtree_destroy(t->files, iso_file_src_free);
|
|
|
|
if (t->ecma119_hidden_list != NULL)
|
|
|
|
iso_filesrc_list_destroy(&(t->ecma119_hidden_list));
|
|
|
|
if (t->buffer != NULL)
|
|
|
|
iso_ring_buffer_free(t->buffer);
|
|
|
|
|
|
|
|
for (i = 0; i < t->nwriters; ++i) {
|
|
|
|
IsoImageWriter *writer = t->writers[i];
|
|
|
|
writer->free_data(writer);
|
|
|
|
free(writer);
|
|
|
|
}
|
|
|
|
if (t->input_charset != NULL)
|
|
|
|
free(t->input_charset);
|
|
|
|
if (t->output_charset != NULL)
|
|
|
|
free(t->output_charset);
|
|
|
|
if (t->bootsrc != NULL)
|
|
|
|
free(t->bootsrc);
|
|
|
|
if (t->boot_appended_idx != NULL)
|
|
|
|
free(t->boot_appended_idx);
|
|
|
|
if (t->boot_intvl_start != NULL)
|
|
|
|
free(t->boot_intvl_start);
|
|
|
|
if (t->boot_intvl_size != NULL)
|
|
|
|
free(t->boot_intvl_size);
|
|
|
|
if (t->system_area_data != NULL)
|
|
|
|
free(t->system_area_data);
|
|
|
|
if (t->checksum_ctx != NULL) { /* dispose checksum context */
|
|
|
|
char md5[16];
|
|
|
|
iso_md5_end(&(t->checksum_ctx), md5);
|
|
|
|
}
|
|
|
|
if (t->checksum_buffer != NULL)
|
|
|
|
free(t->checksum_buffer);
|
|
|
|
if (t->writers != NULL)
|
|
|
|
free(t->writers);
|
|
|
|
if (t->partition_root != NULL)
|
|
|
|
ecma119_node_free(t->partition_root);
|
|
|
|
for (i = 0; i < ISO_HFSPLUS_BLESS_MAX; i++)
|
|
|
|
if (t->hfsplus_blessed[i] != NULL)
|
|
|
|
iso_node_unref(t->hfsplus_blessed[i]);
|
|
|
|
for (i = 0; (int) i < t->apm_req_count; i++)
|
|
|
|
if (t->apm_req[i] != NULL)
|
|
|
|
free(t->apm_req[i]);
|
|
|
|
for (i = 0; (int) i < t->mbr_req_count; i++)
|
|
|
|
if (t->mbr_req[i] != NULL)
|
|
|
|
free(t->mbr_req[i]);
|
|
|
|
for (i = 0; (int) i < t->gpt_req_count; i++)
|
|
|
|
if (t->gpt_req[i] != NULL)
|
|
|
|
free(t->gpt_req[i]);
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int show_chunk_to_jte(Ecma119Image *target, char *buf, int count)
|
|
|
|
{
|
|
|
|
|
|
|
|
#ifdef Libisofs_with_libjtE
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (target->opts->libjte_handle == NULL)
|
|
|
|
return ISO_SUCCESS;
|
|
|
|
ret = libjte_show_data_chunk(target->opts->libjte_handle, buf, count, 1);
|
|
|
|
if (ret <= 0) {
|
|
|
|
iso_libjte_forward_msgs(target->opts->libjte_handle,
|
|
|
|
target->image->id, ISO_LIBJTE_FILE_FAILED, 0);
|
|
|
|
return ISO_LIBJTE_FILE_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* Libisofs_with_libjtE */
|
|
|
|
|
|
|
|
return ISO_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if we should add version number ";" to the given node name.
|
|
|
|
*/
|
|
|
|
static
|
|
|
|
int need_version_number(IsoWriteOpts *opts, enum ecma119_node_type node_type)
|
|
|
|
{
|
|
|
|
if ((opts->omit_version_numbers & 1) ||
|
|
|
|
opts->max_37_char_filenames || opts->untranslated_name_len > 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (node_type == ECMA119_DIR || node_type == ECMA119_PLACEHOLDER) {
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compute the size of a directory entry for a single node
|
|
|
|
*/
|
|
|
|
static
|
|
|
|
size_t calc_dirent_len(Ecma119Image *t, Ecma119Node *n)
|
|
|
|
{
|
|
|
|
int ret = n->iso_name ? strlen(n->iso_name) + 33 : 34;
|
|
|
|
if (need_version_number(t->opts, n->type)) {
|
|
|
|
ret += 2; /* take into account version numbers */
|
|
|
|
}
|
|
|
|
if (ret % 2)
|
|
|
|
ret++;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Computes the total size of all directory entries of a single dir,
|
|
|
|
* according 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 *ce)
|
|
|
|
{
|
|
|
|
size_t i, len;
|
|
|
|
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);
|
|
|
|
*ce += ce_len;
|
|
|
|
len += rrip_calc_len(t, dir, 2, 34, &ce_len, *ce);
|
|
|
|
*ce += ce_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < dir->info.dir->nchildren; ++i) {
|
|
|
|
size_t remaining;
|
|
|
|
int section, nsections;
|
|
|
|
Ecma119Node *child = dir->info.dir->children[i];
|
|
|
|
|
|
|
|
nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1;
|
|
|
|
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);
|
|
|
|
*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;
|
|
|
|
} else {
|
|
|
|
len += dirent_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The size of a dir is always a multiple of block size, as we must add
|
|
|
|
* the size of the unused space after the last directory record
|
|
|
|
* (ECMA-119, 6.8.1.3)
|
|
|
|
*/
|
|
|
|
len = ROUND_UP(len, BLOCK_SIZE);
|
|
|
|
|
|
|
|
/* cache the len */
|
|
|
|
dir->info.dir->len = len;
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
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, &ce_len);
|
|
|
|
t->curblock += DIV_UP(len, BLOCK_SIZE);
|
|
|
|
if (t->opts->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) {
|
|
|
|
calc_dir_pos(t, child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compute the length of the path table, in bytes.
|
|
|
|
*/
|
|
|
|
static
|
|
|
|
uint32_t calc_path_table_size(Ecma119Node *dir)
|
|
|
|
{
|
|
|
|
uint32_t size;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
/* size of path table for this entry */
|
|
|
|
size = 8;
|
|
|
|
size += dir->iso_name ? strlen(dir->iso_name) : 1;
|
|
|
|
size += (size % 2);
|
|
|
|
|
|
|
|
/* and recurse */
|
|
|
|
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
|
|
|
Ecma119Node *child = dir->info.dir->children[i];
|
|
|
|
if (child->type == ECMA119_DIR) {
|
|
|
|
size += calc_path_table_size(child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
int ecma119_writer_compute_data_blocks(IsoImageWriter *writer)
|
|
|
|
{
|
|
|
|
Ecma119Image *target;
|
|
|
|
uint32_t path_table_size;
|
|
|
|
size_t ndirs;
|
|
|
|
|
|
|
|
if (writer == NULL) {
|
|
|
|
return ISO_ASSERT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
target = writer->target;
|
|
|
|
|
|
|
|
/* compute position of directories */
|
|
|
|
iso_msg_debug(target->image->id, "Computing position of dir structure");
|
|
|
|
target->ndirs = 0;
|
|
|
|
calc_dir_pos(target, target->root);
|
|
|
|
|
|
|
|
/* compute length of pathlist */
|
|
|
|
iso_msg_debug(target->image->id, "Computing length of pathlist");
|
|
|
|
path_table_size = calc_path_table_size(target->root);
|
|
|
|
|
|
|
|
/* compute location for path tables */
|
|
|
|
target->l_path_table_pos = target->curblock;
|
|
|
|
target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
|
|
|
|
target->m_path_table_pos = target->curblock;
|
|
|
|
target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
|
|
|
|
target->path_table_size = path_table_size;
|
|
|
|
|
|
|
|
if (target->opts->md5_session_checksum) {
|
|
|
|
/* Account for first tree checksum tag */
|
|
|
|
target->checksum_tree_tag_pos = target->curblock;
|
|
|
|
target->curblock++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target->opts->partition_offset > 0) {
|
|
|
|
/* Take into respect the second directory tree */
|
|
|
|
ndirs = target->ndirs;
|
|
|
|
target->ndirs = 0;
|
|
|
|
calc_dir_pos(target, target->partition_root);
|
|
|
|
if (target->ndirs != ndirs) {
|
|
|
|
iso_msg_submit(target->image->id, ISO_ASSERT_FAILURE, 0,
|
|
|
|
"Number of directories differs in ECMA-119 partiton_tree");
|
|
|
|
return ISO_ASSERT_FAILURE;
|
|
|
|
}
|
|
|
|
/* Take into respect the second set of path tables */
|
|
|
|
path_table_size = calc_path_table_size(target->partition_root);
|
|
|
|
target->partition_l_table_pos = target->curblock;
|
|
|
|
target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
|
|
|
|
target->partition_m_table_pos = target->curblock;
|
|
|
|
target->curblock += DIV_UP(path_table_size, BLOCK_SIZE);
|
|
|
|
|
|
|
|
/* >>> TWINTREE: >>> For now, checksum tags are only for the
|
|
|
|
image start and not for the partition */;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
target->tree_end_block = target->curblock;
|
|
|
|
|
|
|
|
return ISO_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write a single directory record (ECMA-119, 9.1)
|
|
|
|
*
|
|
|
|
* @param file_id
|
|
|
|
* if >= 0, we use it instead of the filename (for "." and ".." entries).
|
|
|
|
* @param len_fi
|
|
|
|
* Computed length of the file identifier. Total size of the directory
|
|
|
|
* entry will be len + 33 + padding if needed (ECMA-119, 9.1.12)
|
|
|
|
* @param info
|
|
|
|
* SUSP entries for the given directory record. It will be NULL for the
|
|
|
|
* root directory record in the PVD (ECMA-119, 8.4.18) (in order to
|
|
|
|
* distinguish it from the "." entry in the root directory)
|
|
|
|
*/
|
|
|
|
static
|
|
|
|
void write_one_dir_record(Ecma119Image *t, Ecma119Node *node, int file_id,
|
|
|
|
uint8_t *buf, size_t len_fi, struct susp_info *info,
|
|
|
|
int extent)
|
|
|
|
{
|
|
|
|
uint32_t len;
|
|
|
|
uint32_t block;
|
|
|
|
uint8_t len_dr; /*< size of dir entry without SUSP fields */
|
|
|
|
int multi_extend = 0;
|
|
|
|
uint8_t *name = (file_id >= 0) ? (uint8_t*)&file_id
|
|
|
|
: (uint8_t*)node->iso_name;
|
|
|
|
|
|
|
|
struct ecma119_dir_record *rec = (struct ecma119_dir_record*)buf;
|
|
|
|
IsoNode *iso;
|
|
|
|
|
|
|
|
len_dr = 33 + len_fi + ((len_fi % 2) ? 0 : 1);
|
|
|
|
|
|
|
|
memcpy(rec->file_id, name, len_fi);
|
|
|
|
|
|
|
|
if (need_version_number(t->opts, node->type)) {
|
|
|
|
len_dr += 2;
|
|
|
|
rec->file_id[len_fi++] = ';';
|
|
|
|
rec->file_id[len_fi++] = '1';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->type == ECMA119_DIR) {
|
|
|
|
/* use the cached length */
|
|
|
|
len = node->info.dir->len;
|
|
|
|
block = node->info.dir->block;
|
|
|
|
} else if (node->type == ECMA119_FILE) {
|
|
|
|
block = node->info.file->sections[extent].block;
|
|
|
|
len = node->info.file->sections[extent].size;
|
|
|
|
multi_extend = (node->info.file->nsections - 1 == extent) ? 0 : 1;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* for nodes other than files and dirs, we set len to 0, and
|
|
|
|
* the content block address to a dummy value.
|
|
|
|
*/
|
|
|
|
len = 0;
|
|
|
|
if (! t->opts->old_empty)
|
|
|
|
block = t->empty_file_block;
|
|
|
|
else
|
|
|
|
block = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For ".." entry we need to write the parent info!
|
|
|
|
*/
|
|
|
|
if (file_id == 1 && node->parent)
|
|
|
|
node = node->parent;
|
|
|
|
|
|
|
|
rec->len_dr[0] = len_dr + (info != NULL ? info->suf_len : 0);
|
|
|
|
iso_bb(rec->block, block - t->eff_partition_offset, 4);
|
|
|
|
iso_bb(rec->length, len, 4);
|
|
|
|
if (t->opts->dir_rec_mtime & 1) {
|
|
|
|
iso= node->node;
|
|
|
|
iso_datetime_7(rec->recording_time,
|
|
|
|
t->replace_timestamps ? t->timestamp : iso->mtime,
|
|
|
|
t->opts->always_gmt);
|
|
|
|
} else {
|
|
|
|
iso_datetime_7(rec->recording_time, t->now, t->opts->always_gmt);
|
|
|
|
}
|
|
|
|
rec->flags[0] = ((node->type == ECMA119_DIR) ? 2 : 0) | (multi_extend ? 0x80 : 0);
|
|
|
|
iso_bb(rec->vol_seq_number, (uint32_t) 1, 2);
|
|
|
|
rec->len_fi[0] = len_fi;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* and finally write the SUSP fields.
|
|
|
|
*/
|
|
|
|
if (info != NULL) {
|
|
|
|
rrip_write_susp_fields(t, info, buf + len_dr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
char *get_relaxed_vol_id(Ecma119Image *t, const char *name)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
if (name == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (strcmp(t->input_charset, t->output_charset)) {
|
|
|
|
/* charset conversion needed */
|
|
|
|
char *str;
|
|
|
|
ret = strconv(name, t->input_charset, t->output_charset, &str);
|
|
|
|
if (ret == ISO_SUCCESS) {
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
iso_msg_submit(t->image->id, ISO_FILENAME_WRONG_CHARSET, ret,
|
|
|
|
"Charset conversion error. Cannot convert from %s to %s",
|
|
|
|
t->input_charset, t->output_charset);
|
|
|
|
}
|
|
|
|
return strdup(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the timestamps of Primary, Supplementary, or Enhanced Volume Descriptor.
|
|
|
|
*/
|
|
|
|
void ecma119_set_voldescr_times(IsoImageWriter *writer,
|
|
|
|
struct ecma119_pri_vol_desc *vol)
|
|
|
|
{
|
|
|
|
Ecma119Image *t = writer->target;
|
|
|
|
IsoWriteOpts *o;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
o = t->opts;
|
|
|
|
if (o->vol_uuid[0]) {
|
|
|
|
for(i = 0; i < 16; i++)
|
|
|
|
if(o->vol_uuid[i] < '0' || o->vol_uuid[i] > '9')
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
vol->vol_creation_time[i] = o->vol_uuid[i];
|
|
|
|
for(; i < 16; i++)
|
|
|
|
vol->vol_creation_time[i] = '1';
|
|
|
|
vol->vol_creation_time[16] = 0;
|
|
|
|
} else if (o->vol_creation_time > 0)
|
|
|
|
iso_datetime_17(vol->vol_creation_time, o->vol_creation_time,
|
|
|
|
o->always_gmt);
|
|
|
|
else
|
|
|
|
iso_datetime_17(vol->vol_creation_time, t->now, o->always_gmt);
|
|
|
|
|
|
|
|
if (o->vol_uuid[0]) {
|
|
|
|
for(i = 0; i < 16; i++)
|
|
|
|
if(o->vol_uuid[i] < '0' || o->vol_uuid[i] > '9')
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
vol->vol_modification_time[i] = o->vol_uuid[i];
|
|
|
|
for(; i < 16; i++)
|
|
|
|
vol->vol_modification_time[i] = '1';
|
|
|
|
vol->vol_modification_time[16] = 0;
|
|
|
|
} else if (o->vol_modification_time > 0)
|
|
|
|
iso_datetime_17(vol->vol_modification_time, o->vol_modification_time,
|
|
|
|
o->always_gmt);
|
|
|
|
else
|
|
|
|
iso_datetime_17(vol->vol_modification_time, t->now, o->always_gmt);
|
|
|
|
|
|
|
|
if (o->vol_expiration_time > 0) {
|
|
|
|
iso_datetime_17(vol->vol_expiration_time, o->vol_expiration_time,
|
|
|
|
o->always_gmt);
|
|
|
|
} else {
|
|
|
|
for(i = 0; i < 16; i++)
|
|
|
|
vol->vol_expiration_time[i] = '0';
|
|
|
|
vol->vol_expiration_time[16] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (o->vol_effective_time > 0) {
|
|
|
|
iso_datetime_17(vol->vol_effective_time, o->vol_effective_time,
|
|
|
|
o->always_gmt);
|
|
|
|
} else {
|
|
|
|
for(i = 0; i < 16; i++)
|
|
|
|
vol->vol_effective_time[i] = '0';
|
|
|
|
vol->vol_effective_time[16] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write the Primary Volume Descriptor (ECMA-119, 8.4)
|
|
|
|
*/
|
|
|
|
static
|
|
|
|
int ecma119_writer_write_vol_desc(IsoImageWriter *writer)
|
|
|
|
{
|
|
|
|
IsoImage *image;
|
|
|
|
Ecma119Image *t;
|
|
|
|
struct ecma119_pri_vol_desc vol;
|
|
|
|
char *vol_id, *pub_id, *data_id, *volset_id;
|
|
|
|
char *system_id, *application_id, *copyright_file_id;
|
|
|
|
char *abstract_file_id, *biblio_file_id;
|
|
|
|
|
|
|
|
if (writer == NULL) {
|
|
|
|
return ISO_ASSERT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
t = writer->target;
|
|
|
|
image = t->image;
|
|
|
|
|
|
|
|
iso_msg_debug(image->id, "Write Primary Volume Descriptor");
|
|
|
|
|
|
|
|
memset(&vol, 0, sizeof(struct ecma119_pri_vol_desc));
|
|
|
|
|
|
|
|
if (t->opts->relaxed_vol_atts) {
|
|
|
|
vol_id = get_relaxed_vol_id(t, image->volume_id);
|
|
|
|
volset_id = get_relaxed_vol_id(t, image->volset_id);
|
|
|
|
} else {
|
|
|
|
str2d_char(t->input_charset, image->volume_id, &vol_id);
|
|
|
|
str2d_char(t->input_charset, image->volset_id, &volset_id);
|
|
|
|
}
|
|
|
|
str2a_char(t->input_charset, image->publisher_id, &pub_id);
|
|
|
|
str2a_char(t->input_charset, image->data_preparer_id, &data_id);
|
|
|
|
str2a_char(t->input_charset, image->system_id, &system_id);
|
|
|
|
str2a_char(t->input_charset, image->application_id, &application_id);
|
|
|
|
str2d_char(t->input_charset, image->copyright_file_id, ©right_file_id);
|
|
|
|
str2d_char(t->input_charset, image->abstract_file_id, &abstract_file_id);
|
|
|
|
str2d_char(t->input_charset, image->biblio_file_id, &biblio_file_id);
|
|
|
|
|
|
|
|
vol.vol_desc_type[0] = 1;
|
|
|
|
memcpy(vol.std_identifier, "CD001", 5);
|
|
|
|
vol.vol_desc_version[0] = 1;
|
|
|
|
strncpy_pad((char*)vol.system_id, system_id, 32);
|
|
|
|
strncpy_pad((char*)vol.volume_id, vol_id, 32);
|
|
|
|
if (t->pvd_size_is_total_size && t->eff_partition_offset <= 0) {
|
|
|
|
iso_bb(vol.vol_space_size, t->total_size / 2048, 4);
|
|
|
|
} else {
|
|
|
|
iso_bb(vol.vol_space_size,
|
|
|
|
t->vol_space_size - t->eff_partition_offset, 4);
|
|
|
|
}
|
|
|
|
iso_bb(vol.vol_set_size, (uint32_t) 1, 2);
|
|
|
|
iso_bb(vol.vol_seq_number, (uint32_t) 1, 2);
|
|
|
|
iso_bb(vol.block_size, (uint32_t) BLOCK_SIZE, 2);
|
|
|
|
iso_bb(vol.path_table_size, t->path_table_size, 4);
|
|
|
|
|
|
|
|
if (t->eff_partition_offset > 0) {
|
|
|
|
/* Point to second tables and second root */
|
|
|
|
iso_lsb(vol.l_path_table_pos,
|
|
|
|
t->partition_l_table_pos - t->eff_partition_offset, 4);
|
|
|
|
iso_msb(vol.m_path_table_pos,
|
|
|
|
t->partition_m_table_pos - t->eff_partition_offset, 4);
|
|
|
|
write_one_dir_record(t, t->partition_root, 0,
|
|
|
|
vol.root_dir_record, 1, NULL, 0);
|
|
|
|
} else {
|
|
|
|
iso_lsb(vol.l_path_table_pos, t->l_path_table_pos, 4);
|
|
|
|
iso_msb(vol.m_path_table_pos, t->m_path_table_pos, 4);
|
|
|
|
write_one_dir_record(t, t->root, 0, vol.root_dir_record, 1, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
strncpy_pad((char*)vol.vol_set_id, volset_id, 128);
|
|
|
|
strncpy_pad((char*)vol.publisher_id, pub_id, 128);
|
|
|
|
strncpy_pad((char*)vol.data_prep_id, data_id, 128);
|
|
|
|
|
|
|
|
strncpy_pad((char*)vol.application_id, application_id, 128);
|
|
|
|
strncpy_pad((char*)vol.copyright_file_id, copyright_file_id, 37);
|
|
|
|
strncpy_pad((char*)vol.abstract_file_id, abstract_file_id, 37);
|
|
|
|
strncpy_pad((char*)vol.bibliographic_file_id, biblio_file_id, 37);
|
|
|
|
|
|
|
|
ecma119_set_voldescr_times(writer, &vol);
|
|
|
|
vol.file_structure_version[0] = 1;
|
|
|
|
|
|
|
|
memcpy(vol.app_use, image->application_use, 512);
|
|
|
|
|
|
|
|
free(vol_id);
|
|
|
|
free(volset_id);
|
|
|
|
free(pub_id);
|
|
|
|
free(data_id);
|
|
|
|
free(system_id);
|
|
|
|
free(application_id);
|
|
|
|
free(copyright_file_id);
|
|
|
|
free(abstract_file_id);
|
|
|
|
free(biblio_file_id);
|
|
|
|
|
|
|
|
/* Finally write the Volume Descriptor */
|
|
|
|
return iso_write(t, &vol, sizeof(struct ecma119_pri_vol_desc));
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
int write_one_dir(Ecma119Image *t, Ecma119Node *dir, Ecma119Node *parent)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
uint8_t *buffer = NULL;
|
|
|
|
size_t i;
|
|
|
|
size_t fi_len, len;
|
|
|
|
struct susp_info info;
|
|
|
|
|
|
|
|
/* buf will point to current write position on buffer */
|
|
|
|
uint8_t *buf;
|
|
|
|
|
|
|
|
LIBISO_ALLOC_MEM(buffer, uint8_t, BLOCK_SIZE);
|
|
|
|
buf = buffer;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* set susp_info to 0's, this way code for both plain ECMA-119 and
|
|
|
|
* RR is very similar
|
|
|
|
*/
|
|
|
|
memset(&info, 0, sizeof(struct susp_info));
|
|
|
|
if (t->opts->rockridge) {
|
|
|
|
/* initialize the ce_block, it might be needed */
|
|
|
|
info.ce_block = dir->info.dir->block + DIV_UP(dir->info.dir->len,
|
|
|
|
BLOCK_SIZE);
|
|
|
|
info.ce_susp_fields = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* write the "." and ".." entries first */
|
|
|
|
if (t->opts->rockridge) {
|
|
|
|
ret = rrip_get_susp_fields(t, dir, 1, 34, &info);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto ex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
len = 34 + info.suf_len;
|
|
|
|
write_one_dir_record(t, dir, 0, buf, 1, &info, 0);
|
|
|
|
buf += len;
|
|
|
|
|
|
|
|
if (t->opts->rockridge) {
|
|
|
|
ret = rrip_get_susp_fields(t, dir, 2, 34, &info);
|
|
|
|
if (ret < 0) {
|
|
|
|
goto ex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
len = 34 + info.suf_len;
|
|
|
|
write_one_dir_record(t, parent, 1, buf, 1, &info, 0);
|
|
|
|
buf += len;
|
|
|
|
|
|
|
|
for (i = 0; i < dir->info.dir->nchildren; i++) {
|
|
|
|
int section, nsections;
|
|
|
|
Ecma119Node *child = dir->info.dir->children[i];
|
|
|
|
|
|
|
|
fi_len = strlen(child->iso_name);
|
|
|
|
|
|
|
|
nsections = (child->type == ECMA119_FILE) ? child->info.file->nsections : 1;
|
|
|
|
for (section = 0; section < nsections; ++section) {
|
|
|
|
|
|
|
|
/* compute len of directory entry */
|
|
|
|
len = fi_len + 33 + ((fi_len % 2) ? 0 : 1);
|
|
|
|
if (need_version_number(t->opts, child->type)) {
|
|