#include "archive.h"
#include "archive_endian.h"
#include "archive_entry.h"
+#include "archive_entry_locale.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_string.h"
int64_t number;
int nlinks;
struct archive_string name; /* Pathname */
+ unsigned char *utf16be_name;
+ size_t utf16be_bytes;
char name_continues; /* Non-zero if name continues */
struct archive_string symlink;
char symlink_continues; /* Non-zero if link continues */
struct zisofs entry_zisofs;
struct content *entry_content;
struct archive_string_conv *sconv_utf16be;
+ unsigned char utf16be_path[240];
+ size_t utf16be_path_len;
+ unsigned char utf16be_previous_path[240];
+ size_t utf16be_previous_path_len;
};
static int archive_read_format_iso9660_bid(struct archive_read *);
static int archive_read_format_iso9660_read_header(struct archive_read *,
struct archive_entry *);
static const char *build_pathname(struct archive_string *, struct file_info *);
+static int build_pathname_utf16be(unsigned char *, size_t, size_t *,
+ struct file_info *);
#if DEBUG
static void dump_isodirrec(FILE *, const unsigned char *isodirrec);
#endif
if (r != ARCHIVE_OK)
return (r);
+ if (iso9660->seenJoliet) {
+ /*
+ * Convert UTF-16BE of a filename to local locale MBS
+ * and store the result into a filename field.
+ */
+ if (iso9660->sconv_utf16be == NULL) {
+ iso9660->sconv_utf16be =
+ archive_string_conversion_from_charset(
+ &(a->archive), "UTF-16BE", 1);
+ if (iso9660->sconv_utf16be == NULL)
+ /* Coundn't allocate memory */
+ return (ARCHIVE_FATAL);
+ }
+
+ iso9660->utf16be_path_len = 0;
+ if (build_pathname_utf16be(iso9660->utf16be_path,
+ sizeof(iso9660->utf16be_path),
+ &(iso9660->utf16be_path_len), file) != 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Pathname is too long(over 240 bytes)");
+ }
+
+ r = archive_entry_copy_pathname_l(entry,
+ iso9660->utf16be_path, iso9660->utf16be_path_len,
+ iso9660->sconv_utf16be);
+ if (r != 0) {
+ if (errno == ENOMEM) {
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory for Pathname");
+ return (ARCHIVE_FATAL);
+ }
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Pathname cannot be converted "
+ "from %s to current locale.",
+ archive_string_conversion_charset_name(
+ iso9660->sconv_utf16be));
+
+ rd_r = ARCHIVE_WARN;
+ }
+ } else {
+ archive_string_empty(&iso9660->pathname);
+ archive_entry_set_pathname(entry,
+ build_pathname(&iso9660->pathname, file));
+ }
+
iso9660->entry_bytes_remaining = file->size;
iso9660->entry_sparse_offset = 0; /* Offset for sparse-file-aware clients. */
if (file->offset + file->size > iso9660->volume_size) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "File is beyond end-of-media: %s", file->name.s);
+ "File is beyond end-of-media: %s",
+ archive_entry_pathname(entry));
iso9660->entry_bytes_remaining = 0;
iso9660->entry_sparse_offset = 0;
return (ARCHIVE_WARN);
/* N.B.: Rock Ridge supports 64-bit device numbers. */
archive_entry_set_rdev(entry, (dev_t)file->rdev);
archive_entry_set_size(entry, iso9660->entry_bytes_remaining);
- archive_string_empty(&iso9660->pathname);
- archive_entry_set_pathname(entry,
- build_pathname(&iso9660->pathname, file));
if (file->symlink.s != NULL)
archive_entry_copy_symlink(entry, file->symlink.s);
* original entry. */
if (file->number != -1 &&
file->number == iso9660->previous_number) {
- archive_entry_set_hardlink(entry,
- iso9660->previous_pathname.s);
+ if (iso9660->seenJoliet) {
+ r = archive_entry_copy_hardlink_l(entry,
+ iso9660->utf16be_previous_path,
+ iso9660->utf16be_previous_path_len,
+ iso9660->sconv_utf16be);
+ if (r != 0) {
+ if (errno == ENOMEM) {
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory for Linkname");
+ return (ARCHIVE_FATAL);
+ }
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Linkname cannot be converted "
+ "from %s to current locale.",
+ archive_string_conversion_charset_name(
+ iso9660->sconv_utf16be));
+ rd_r = ARCHIVE_WARN;
+ }
+ } else
+ archive_entry_set_hardlink(entry,
+ iso9660->previous_pathname.s);
archive_entry_unset_size(entry);
iso9660->entry_bytes_remaining = 0;
iso9660->entry_sparse_offset = 0;
}
iso9660->previous_number = file->number;
- archive_strcpy(&iso9660->previous_pathname, iso9660->pathname.s);
+ if (iso9660->seenJoliet) {
+ memcpy(iso9660->utf16be_previous_path, iso9660->utf16be_path,
+ iso9660->utf16be_path_len);
+ iso9660->utf16be_previous_path_len = iso9660->utf16be_path_len;
+ } else
+ archive_strcpy(
+ &iso9660->previous_pathname, iso9660->pathname.s);
/* Reset entry_bytes_remaining if the file is multi extent. */
iso9660->entry_content = file->contents.first;
}
/* Create a new file entry and copy data from the ISO dir record. */
- file = (struct file_info *)malloc(sizeof(*file));
+ file = (struct file_info *)calloc(1, sizeof(*file));
if (file == NULL) {
archive_set_error(&a->archive, ENOMEM,
"No memory for file entry");
return (NULL);
}
- memset(file, 0, sizeof(*file));
file->parent = parent;
file->offset = iso9660->logical_block_size * (uint64_t)location;
file->size = fsize;
if (name_len > 2 && p[name_len-2] == 0 && p[name_len-1] == '.')
name_len -= 2;
#endif
-
- /* Convert UTF-16BE of a filename to local locale MBS and store
- * the result into a filename field. */
- if (iso9660->sconv_utf16be == NULL) {
- iso9660->sconv_utf16be =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-16BE", 1);
- if (iso9660->sconv_utf16be == NULL)
- return (NULL);/* Coundn't allocate memory */
- }
- if (archive_strncpy_in_locale(&file->name,
- (const char *)p, name_len, iso9660->sconv_utf16be) != 0
- && errno == ENOMEM) {
+ if ((file->utf16be_name = malloc(name_len)) == NULL) {
archive_set_error(&a->archive, ENOMEM,
"No memory for file name");
return (NULL);
}
+ memcpy(file->utf16be_name, p, name_len);
+ file->utf16be_bytes = name_len;
} else {
/* Chop off trailing ';1' from files. */
if (name_len > 2 && p[name_len - 2] == ';' &&
archive_string_free(&file->name);
archive_string_free(&file->symlink);
+ free(file->utf16be_name);
con = file->contents.first;
while (con != NULL) {
connext = con->next;
return (as->s);
}
+static int
+build_pathname_utf16be(unsigned char *p, size_t max, size_t *len,
+ struct file_info *file)
+{
+ if (file->parent != NULL && file->parent->utf16be_bytes > 0) {
+ if (build_pathname_utf16be(p, max, len, file->parent) != 0)
+ return (-1);
+ p[*len] = 0;
+ p[*len + 1] = '/';
+ *len += 2;
+ }
+ if (file->utf16be_bytes == 0) {
+ if (*len + 2 > max)
+ return (-1);/* Path is too long! */
+ p[*len] = 0;
+ p[*len + 1] = '.';
+ *len += 2;
+ } else {
+ if (*len + file->utf16be_bytes > max)
+ return (-1);/* Path is too long! */
+ memcpy(p + *len, file->utf16be_name, file->utf16be_bytes);
+ *len += file->utf16be_bytes;
+ }
+ return (0);
+}
+
#if DEBUG
static void
dump_isodirrec(FILE *out, const unsigned char *isodirrec)