Import bugfix for reading and extracting of FreeBSD ISO images with tar.
Upstream revision 3645 (merge of 3642): Change the mechanism handling a rr_moved directory, which is Rockridge extension that can exceed the limitation of a maximum directory depth of ISO 9660. - Stop reading all entries at a time. - Connect "CL" entry to "RE" entry dynamically, which "CL" and "RE" have information to rebuild a full directory tree. - Tweak some related tests since we use Headsort for re-ordering entries and it cannot make a steady order when the keies of the entries are the same. http://code.google.com/p/libarchive/issues/detail?id=168 Reviewed by: kientzle Approved by: re (kib) Obtained from: libarchive (release/2.8, svn rev 3645) MFC after: 3 days
This commit is contained in:
parent
82378711f9
commit
ee3cdf6b2e
@ -1,7 +1,7 @@
|
||||
/*-
|
||||
* Copyright (c) 2003-2007 Tim Kientzle
|
||||
* Copyright (c) 2009 Andreas Henriksson <andreas@fatal.se>
|
||||
* Copyright (c) 2009 Michihiro NAKAJIMA
|
||||
* Copyright (c) 2009-2011 Michihiro NAKAJIMA
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -261,13 +261,17 @@ struct file_info {
|
||||
struct file_info *use_next;
|
||||
struct file_info *parent;
|
||||
struct file_info *next;
|
||||
struct file_info *re_next;
|
||||
int subdirs;
|
||||
uint64_t key; /* Heap Key. */
|
||||
uint64_t offset; /* Offset on disk. */
|
||||
uint64_t size; /* File size in bytes. */
|
||||
uint32_t ce_offset; /* Offset of CE. */
|
||||
uint32_t ce_size; /* Size of CE. */
|
||||
char rr_moved; /* Flag to rr_moved. */
|
||||
char rr_moved_has_re_only;
|
||||
char re; /* Having RRIP "RE" extension. */
|
||||
char re_descendant;
|
||||
uint64_t cl_offset; /* Having RRIP "CL" extension. */
|
||||
int birthtime_is_set;
|
||||
time_t birthtime; /* File created time. */
|
||||
@ -294,7 +298,10 @@ struct file_info {
|
||||
struct content *first;
|
||||
struct content **last;
|
||||
} contents;
|
||||
char exposed;
|
||||
struct {
|
||||
struct file_info *first;
|
||||
struct file_info **last;
|
||||
} rede_files;
|
||||
};
|
||||
|
||||
struct heap_queue {
|
||||
@ -317,8 +324,6 @@ struct iso9660 {
|
||||
|
||||
unsigned char suspOffset;
|
||||
struct file_info *rr_moved;
|
||||
struct heap_queue re_dirs;
|
||||
struct heap_queue cl_files;
|
||||
struct read_ce_queue {
|
||||
struct read_ce_req {
|
||||
uint64_t offset;/* Offset of CE on disk. */
|
||||
@ -337,6 +342,10 @@ struct iso9660 {
|
||||
struct file_info *first;
|
||||
struct file_info **last;
|
||||
} cache_files;
|
||||
struct {
|
||||
struct file_info *first;
|
||||
struct file_info **last;
|
||||
} re_files;
|
||||
|
||||
uint64_t current_position;
|
||||
ssize_t logical_block_size;
|
||||
@ -377,7 +386,8 @@ static int isJolietSVD(struct iso9660 *, const unsigned char *);
|
||||
static int isSVD(struct iso9660 *, const unsigned char *);
|
||||
static int isEVD(struct iso9660 *, const unsigned char *);
|
||||
static int isPVD(struct iso9660 *, const unsigned char *);
|
||||
static struct file_info *next_cache_entry(struct iso9660 *iso9660);
|
||||
static int next_cache_entry(struct archive_read *, struct iso9660 *,
|
||||
struct file_info **);
|
||||
static int next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
|
||||
struct file_info **pfile);
|
||||
static struct file_info *
|
||||
@ -400,10 +410,12 @@ static void parse_rockridge_ZF1(struct file_info *,
|
||||
static void register_file(struct iso9660 *, struct file_info *);
|
||||
static void release_files(struct iso9660 *);
|
||||
static unsigned toi(const void *p, int n);
|
||||
static inline void re_add_entry(struct iso9660 *, struct file_info *);
|
||||
static inline struct file_info * re_get_entry(struct iso9660 *);
|
||||
static inline int rede_add_entry(struct file_info *);
|
||||
static inline struct file_info * rede_get_entry(struct file_info *);
|
||||
static inline void cache_add_entry(struct iso9660 *iso9660,
|
||||
struct file_info *file);
|
||||
static inline void cache_add_to_next_of_parent(struct iso9660 *iso9660,
|
||||
struct file_info *file);
|
||||
static inline struct file_info *cache_get_entry(struct iso9660 *iso9660);
|
||||
static void heap_add_entry(struct heap_queue *heap,
|
||||
struct file_info *file, uint64_t key);
|
||||
@ -430,6 +442,8 @@ archive_read_support_format_iso9660(struct archive *_a)
|
||||
iso9660->magic = ISO9660_MAGIC;
|
||||
iso9660->cache_files.first = NULL;
|
||||
iso9660->cache_files.last = &(iso9660->cache_files.first);
|
||||
iso9660->re_files.first = NULL;
|
||||
iso9660->re_files.last = &(iso9660->re_files.first);
|
||||
/* Enable to support Joliet extensions by default. */
|
||||
iso9660->opt_support_joliet = 1;
|
||||
/* Enable to support Rock Ridge extensions by default. */
|
||||
@ -975,42 +989,38 @@ read_children(struct archive_read *a, struct file_info *parent)
|
||||
child = parse_file_info(a, parent, p);
|
||||
if (child == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
if (child->cl_offset)
|
||||
heap_add_entry(&(iso9660->cl_files),
|
||||
child, child->cl_offset);
|
||||
else {
|
||||
if (child->multi_extent || multi != NULL) {
|
||||
struct content *con;
|
||||
if (child->cl_offset == 0 &&
|
||||
(child->multi_extent || multi != NULL)) {
|
||||
struct content *con;
|
||||
|
||||
if (multi == NULL) {
|
||||
multi = child;
|
||||
multi->contents.first = NULL;
|
||||
multi->contents.last =
|
||||
&(multi->contents.first);
|
||||
}
|
||||
con = malloc(sizeof(struct content));
|
||||
if (con == NULL) {
|
||||
archive_set_error(
|
||||
&a->archive, ENOMEM,
|
||||
"No memory for "
|
||||
"multi extent");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
con->offset = child->offset;
|
||||
con->size = child->size;
|
||||
con->next = NULL;
|
||||
*multi->contents.last = con;
|
||||
multi->contents.last = &(con->next);
|
||||
if (multi == child)
|
||||
add_entry(iso9660, child);
|
||||
else {
|
||||
multi->size += child->size;
|
||||
if (!child->multi_extent)
|
||||
multi = NULL;
|
||||
}
|
||||
} else
|
||||
if (multi == NULL) {
|
||||
multi = child;
|
||||
multi->contents.first = NULL;
|
||||
multi->contents.last =
|
||||
&(multi->contents.first);
|
||||
}
|
||||
con = malloc(sizeof(struct content));
|
||||
if (con == NULL) {
|
||||
archive_set_error(
|
||||
&a->archive, ENOMEM,
|
||||
"No memory for "
|
||||
"multi extent");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
con->offset = child->offset;
|
||||
con->size = child->size;
|
||||
con->next = NULL;
|
||||
*multi->contents.last = con;
|
||||
multi->contents.last = &(con->next);
|
||||
if (multi == child)
|
||||
add_entry(iso9660, child);
|
||||
}
|
||||
else {
|
||||
multi->size += child->size;
|
||||
if (!child->multi_extent)
|
||||
multi = NULL;
|
||||
}
|
||||
} else
|
||||
add_entry(iso9660, child);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1021,103 +1031,13 @@ read_children(struct archive_read *a, struct file_info *parent)
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
relocate_dir(struct iso9660 *iso9660, struct file_info *file)
|
||||
{
|
||||
struct file_info *re;
|
||||
|
||||
re = heap_get_entry(&(iso9660->re_dirs));
|
||||
while (re != NULL && re->offset < file->cl_offset) {
|
||||
/* This case is wrong pattern.
|
||||
* But dont't reject this directory entry to be robust. */
|
||||
cache_add_entry(iso9660, re);
|
||||
re = heap_get_entry(&(iso9660->re_dirs));
|
||||
}
|
||||
if (re == NULL)
|
||||
/* This case is wrong pattern. */
|
||||
return (0);
|
||||
if (re->offset == file->cl_offset) {
|
||||
re->parent->subdirs--;
|
||||
re->parent = file->parent;
|
||||
re->parent->subdirs++;
|
||||
cache_add_to_next_of_parent(iso9660, re);
|
||||
return (1);
|
||||
} else
|
||||
/* This case is wrong pattern. */
|
||||
heap_add_entry(&(iso9660->re_dirs), re, re->offset);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
read_entries(struct archive_read *a)
|
||||
{
|
||||
struct iso9660 *iso9660;
|
||||
struct file_info *file;
|
||||
int r;
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
|
||||
while ((file = next_entry(iso9660)) != NULL &&
|
||||
(file->mode & AE_IFMT) == AE_IFDIR) {
|
||||
r = read_children(a, file);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
|
||||
if (iso9660->seenRockridge &&
|
||||
file->parent != NULL &&
|
||||
file->parent->parent == NULL &&
|
||||
iso9660->rr_moved == NULL &&
|
||||
(strcmp(file->name.s, "rr_moved") == 0 ||
|
||||
strcmp(file->name.s, ".rr_moved") == 0)) {
|
||||
iso9660->rr_moved = file;
|
||||
} else if (file->re)
|
||||
heap_add_entry(&(iso9660->re_dirs), file,
|
||||
file->offset);
|
||||
else
|
||||
cache_add_entry(iso9660, file);
|
||||
}
|
||||
if (file != NULL)
|
||||
add_entry(iso9660, file);
|
||||
|
||||
if (iso9660->rr_moved != NULL) {
|
||||
/*
|
||||
* Relocate directory which rr_moved has.
|
||||
*/
|
||||
while ((file = heap_get_entry(&(iso9660->cl_files))) != NULL)
|
||||
relocate_dir(iso9660, file);
|
||||
|
||||
/* If rr_moved directory still has children,
|
||||
* Add rr_moved into pending_files to show
|
||||
*/
|
||||
if (iso9660->rr_moved->subdirs) {
|
||||
cache_add_entry(iso9660, iso9660->rr_moved);
|
||||
/* If entries which have "RE" extension are still
|
||||
* remaining(this case is unlikely except ISO image
|
||||
* is broken), the entries won't be exposed. */
|
||||
while ((file = heap_get_entry(&(iso9660->re_dirs))) != NULL)
|
||||
cache_add_entry(iso9660, file);
|
||||
} else
|
||||
iso9660->rr_moved->parent->subdirs--;
|
||||
} else {
|
||||
/*
|
||||
* In case ISO image is broken. If the name of rr_moved
|
||||
* directory has been changed by damage, subdirectories
|
||||
* of rr_moved entry won't be exposed.
|
||||
*/
|
||||
while ((file = heap_get_entry(&(iso9660->re_dirs))) != NULL)
|
||||
cache_add_entry(iso9660, file);
|
||||
}
|
||||
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_read_format_iso9660_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct iso9660 *iso9660;
|
||||
struct file_info *file;
|
||||
int r, rd_r;
|
||||
int r, rd_r = ARCHIVE_OK;
|
||||
|
||||
iso9660 = (struct iso9660 *)(a->format->data);
|
||||
|
||||
@ -1207,11 +1127,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
|
||||
a->archive.archive_format_name =
|
||||
"ISO9660 with Rockridge extensions";
|
||||
}
|
||||
rd_r = read_entries(a);
|
||||
if (rd_r == ARCHIVE_FATAL)
|
||||
return (ARCHIVE_FATAL);
|
||||
} else
|
||||
rd_r = ARCHIVE_OK;
|
||||
}
|
||||
|
||||
/* Get the next entry that appears after the current offset. */
|
||||
r = next_entry_seek(a, iso9660, &file);
|
||||
@ -1324,7 +1240,6 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
|
||||
/* Directory data has been read completely. */
|
||||
iso9660->entry_bytes_remaining = 0;
|
||||
iso9660->entry_sparse_offset = 0;
|
||||
file->exposed = 1;
|
||||
}
|
||||
|
||||
if (rd_r != ARCHIVE_OK)
|
||||
@ -1651,10 +1566,6 @@ archive_read_format_iso9660_cleanup(struct archive_read *a)
|
||||
archive_string_free(&iso9660->previous_pathname);
|
||||
if (iso9660->pending_files.files)
|
||||
free(iso9660->pending_files.files);
|
||||
if (iso9660->re_dirs.files)
|
||||
free(iso9660->re_dirs.files);
|
||||
if (iso9660->cl_files.files)
|
||||
free(iso9660->cl_files.files);
|
||||
#ifdef HAVE_ZLIB_H
|
||||
free(iso9660->entry_zisofs.uncompressed_buffer);
|
||||
free(iso9660->entry_zisofs.block_pointers);
|
||||
@ -1735,6 +1646,8 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
|
||||
file->size = fsize;
|
||||
file->mtime = isodate7(isodirrec + DR_date_offset);
|
||||
file->ctime = file->atime = file->mtime;
|
||||
file->rede_files.first = NULL;
|
||||
file->rede_files.last = &(file->rede_files.first);
|
||||
|
||||
p = isodirrec + DR_name_offset;
|
||||
/* Rockridge extensions (if any) follow name. Compute this
|
||||
@ -1873,9 +1786,40 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
|
||||
|
||||
file->nlinks = 1;/* Reset nlink. we'll calculate it later. */
|
||||
/* Tell file's parent how many children that parent has. */
|
||||
if (parent != NULL && (flags & 0x02) && file->cl_offset == 0)
|
||||
if (parent != NULL && (flags & 0x02))
|
||||
parent->subdirs++;
|
||||
|
||||
if (iso9660->seenRockridge) {
|
||||
if (parent != NULL && parent->parent == NULL &&
|
||||
(flags & 0x02) && iso9660->rr_moved == NULL &&
|
||||
(strcmp(file->name.s, "rr_moved") == 0 ||
|
||||
strcmp(file->name.s, ".rr_moved") == 0)) {
|
||||
iso9660->rr_moved = file;
|
||||
file->rr_moved = 1;
|
||||
file->rr_moved_has_re_only = 1;
|
||||
file->re = 0;
|
||||
parent->subdirs--;
|
||||
} else if (file->re) {
|
||||
/* This file's parent is not rr_moved, clear invalid
|
||||
* "RE" mark. */
|
||||
if (parent == NULL || parent->rr_moved == 0)
|
||||
file->re = 0;
|
||||
else if ((flags & 0x02) == 0) {
|
||||
file->rr_moved_has_re_only = 0;
|
||||
file->re = 0;
|
||||
}
|
||||
} else if (parent != NULL && parent->rr_moved)
|
||||
file->rr_moved_has_re_only = 0;
|
||||
else if (parent != NULL && (flags & 0x02) &&
|
||||
(parent->re || parent->re_descendant))
|
||||
file->re_descendant = 1;
|
||||
if (file->cl_offset != 0) {
|
||||
parent->subdirs++;
|
||||
/* To be appeared before other dirs. */
|
||||
file->offset = file->number = file->cl_offset;
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
/* DEBUGGING: Warn about attributes I don't yet fully support. */
|
||||
if ((flags & ~0x02) != 0) {
|
||||
@ -2489,10 +2433,12 @@ next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
|
||||
struct file_info **pfile)
|
||||
{
|
||||
struct file_info *file;
|
||||
int r;
|
||||
|
||||
*pfile = file = next_cache_entry(iso9660);
|
||||
if (file == NULL)
|
||||
return (ARCHIVE_EOF);
|
||||
r = next_cache_entry(a, iso9660, pfile);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
file = *pfile;
|
||||
|
||||
/* Don't waste time seeking for zero-length bodies. */
|
||||
if (file->size == 0)
|
||||
@ -2513,8 +2459,9 @@ next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static struct file_info *
|
||||
next_cache_entry(struct iso9660 *iso9660)
|
||||
static int
|
||||
next_cache_entry(struct archive_read *a, struct iso9660 *iso9660,
|
||||
struct file_info **pfile)
|
||||
{
|
||||
struct file_info *file;
|
||||
struct {
|
||||
@ -2526,21 +2473,128 @@ next_cache_entry(struct iso9660 *iso9660)
|
||||
|
||||
file = cache_get_entry(iso9660);
|
||||
if (file != NULL) {
|
||||
while (file->parent != NULL && !file->parent->exposed) {
|
||||
/* If file's parent is not exposed, it's moved
|
||||
* to next entry of its parent. */
|
||||
cache_add_to_next_of_parent(iso9660, file);
|
||||
file = cache_get_entry(iso9660);
|
||||
}
|
||||
return (file);
|
||||
*pfile = file;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
file = next_entry(iso9660);
|
||||
if (file == NULL)
|
||||
return (NULL);
|
||||
for (;;) {
|
||||
struct file_info *re, *d;
|
||||
|
||||
*pfile = file = next_entry(iso9660);
|
||||
if (file == NULL) {
|
||||
/*
|
||||
* If directory entries all which are descendant of
|
||||
* rr_moved are stil remaning, expose their.
|
||||
*/
|
||||
if (iso9660->re_files.first != NULL &&
|
||||
iso9660->rr_moved != NULL &&
|
||||
iso9660->rr_moved->rr_moved_has_re_only)
|
||||
/* Expose "rr_moved" entry. */
|
||||
cache_add_entry(iso9660, iso9660->rr_moved);
|
||||
while ((re = re_get_entry(iso9660)) != NULL) {
|
||||
/* Expose its descendant dirs. */
|
||||
while ((d = rede_get_entry(re)) != NULL)
|
||||
cache_add_entry(iso9660, d);
|
||||
}
|
||||
if (iso9660->cache_files.first != NULL)
|
||||
return (next_cache_entry(a, iso9660, pfile));
|
||||
return (ARCHIVE_EOF);
|
||||
}
|
||||
|
||||
if (file->cl_offset) {
|
||||
struct file_info *first_re = NULL;
|
||||
int nexted_re = 0;
|
||||
|
||||
/*
|
||||
* Find "RE" dir for the current file, which
|
||||
* has "CL" flag.
|
||||
*/
|
||||
while ((re = re_get_entry(iso9660))
|
||||
!= first_re) {
|
||||
if (first_re == NULL)
|
||||
first_re = re;
|
||||
if (re->offset == file->cl_offset) {
|
||||
re->parent->subdirs--;
|
||||
re->parent = file->parent;
|
||||
re->re = 0;
|
||||
if (re->parent->re_descendant) {
|
||||
nexted_re = 1;
|
||||
re->re_descendant = 1;
|
||||
if (rede_add_entry(re) < 0)
|
||||
goto fatal_rr;
|
||||
/* Move a list of descendants
|
||||
* to a new ancestor. */
|
||||
while ((d = rede_get_entry(
|
||||
re)) != NULL)
|
||||
if (rede_add_entry(d)
|
||||
< 0)
|
||||
goto fatal_rr;
|
||||
break;
|
||||
}
|
||||
/* Replace the current file
|
||||
* with "RE" dir */
|
||||
*pfile = file = re;
|
||||
/* Expose its descendant */
|
||||
while ((d = rede_get_entry(
|
||||
file)) != NULL)
|
||||
cache_add_entry(
|
||||
iso9660, d);
|
||||
break;
|
||||
} else
|
||||
re_add_entry(iso9660, re);
|
||||
}
|
||||
if (nexted_re) {
|
||||
/*
|
||||
* Do not expose this at this time
|
||||
* because we have not gotten its full-path
|
||||
* name yet.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
} else if ((file->mode & AE_IFMT) == AE_IFDIR) {
|
||||
int r;
|
||||
|
||||
/* Read file entries in this dir. */
|
||||
r = read_children(a, file);
|
||||
if (r != ARCHIVE_OK)
|
||||
return (r);
|
||||
|
||||
/*
|
||||
* Handle a special dir of Rockridge extensions,
|
||||
* "rr_moved".
|
||||
*/
|
||||
if (file->rr_moved) {
|
||||
/*
|
||||
* If this has only the subdirectories which
|
||||
* have "RE" flags, do not expose at this time.
|
||||
*/
|
||||
if (file->rr_moved_has_re_only)
|
||||
continue;
|
||||
/* Otherwise expose "rr_moved" entry. */
|
||||
} else if (file->re) {
|
||||
/*
|
||||
* Do not expose this at this time
|
||||
* because we have not gotten its full-path
|
||||
* name yet.
|
||||
*/
|
||||
re_add_entry(iso9660, file);
|
||||
continue;
|
||||
} else if (file->re_descendant) {
|
||||
/*
|
||||
* Do not expose this at this time
|
||||
* because we have not gotten its full-path
|
||||
* name yet.
|
||||
*/
|
||||
if (rede_add_entry(file) < 0)
|
||||
goto fatal_rr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((file->mode & AE_IFMT) != AE_IFREG || file->number == -1)
|
||||
return (file);
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
count = 0;
|
||||
number = file->number;
|
||||
@ -2573,8 +2627,10 @@ next_cache_entry(struct iso9660 *iso9660)
|
||||
file = next_entry(iso9660);
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return (file);
|
||||
if (count == 0) {
|
||||
*pfile = file;
|
||||
return ((file == NULL)?ARCHIVE_EOF:ARCHIVE_OK);
|
||||
}
|
||||
if (file->number == -1) {
|
||||
file->next = NULL;
|
||||
*empty_files.last = file;
|
||||
@ -2599,7 +2655,67 @@ next_cache_entry(struct iso9660 *iso9660)
|
||||
*iso9660->cache_files.last = empty_files.first;
|
||||
iso9660->cache_files.last = empty_files.last;
|
||||
}
|
||||
return (cache_get_entry(iso9660));
|
||||
*pfile = cache_get_entry(iso9660);
|
||||
return ((*pfile == NULL)?ARCHIVE_EOF:ARCHIVE_OK);
|
||||
|
||||
fatal_rr:
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Failed to connect 'CL' pointer to 'RE' rr_moved pointer of"
|
||||
"Rockridge extensions");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
static inline void
|
||||
re_add_entry(struct iso9660 *iso9660, struct file_info *file)
|
||||
{
|
||||
file->re_next = NULL;
|
||||
*iso9660->re_files.last = file;
|
||||
iso9660->re_files.last = &(file->re_next);
|
||||
}
|
||||
|
||||
static inline struct file_info *
|
||||
re_get_entry(struct iso9660 *iso9660)
|
||||
{
|
||||
struct file_info *file;
|
||||
|
||||
if ((file = iso9660->re_files.first) != NULL) {
|
||||
iso9660->re_files.first = file->re_next;
|
||||
if (iso9660->re_files.first == NULL)
|
||||
iso9660->re_files.last =
|
||||
&(iso9660->re_files.first);
|
||||
}
|
||||
return (file);
|
||||
}
|
||||
|
||||
static inline int
|
||||
rede_add_entry(struct file_info *file)
|
||||
{
|
||||
struct file_info *re;
|
||||
|
||||
re = file->parent;
|
||||
while (re != NULL && !re->re)
|
||||
re = re->parent;
|
||||
if (re == NULL)
|
||||
return (-1);
|
||||
|
||||
file->re_next = NULL;
|
||||
*re->rede_files.last = file;
|
||||
re->rede_files.last = &(file->re_next);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static inline struct file_info *
|
||||
rede_get_entry(struct file_info *re)
|
||||
{
|
||||
struct file_info *file;
|
||||
|
||||
if ((file = re->rede_files.first) != NULL) {
|
||||
re->rede_files.first = file->re_next;
|
||||
if (re->rede_files.first == NULL)
|
||||
re->rede_files.last =
|
||||
&(re->rede_files.first);
|
||||
}
|
||||
return (file);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -2610,15 +2726,6 @@ cache_add_entry(struct iso9660 *iso9660, struct file_info *file)
|
||||
iso9660->cache_files.last = &(file->next);
|
||||
}
|
||||
|
||||
static inline void
|
||||
cache_add_to_next_of_parent(struct iso9660 *iso9660, struct file_info *file)
|
||||
{
|
||||
file->next = file->parent->next;
|
||||
file->parent->next = file;
|
||||
if (iso9660->cache_files.last == &(file->parent->next))
|
||||
iso9660->cache_files.last = &(file->next);
|
||||
}
|
||||
|
||||
static inline struct file_info *
|
||||
cache_get_entry(struct iso9660 *iso9660)
|
||||
{
|
||||
|
37
lib/libarchive/test/test_read_format_iso_2.iso.Z.uu
Normal file
37
lib/libarchive/test/test_read_format_iso_2.iso.Z.uu
Normal file
@ -0,0 +1,37 @@
|
||||
$FreeBSD$
|
||||
|
||||
begin 644 test_read_format_iso_2.iso.Z
|
||||
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
|
||||
`
|
||||
end
|
@ -25,7 +25,8 @@
|
||||
#include "test.h"
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
DEFINE_TEST(test_read_format_iso_gz)
|
||||
static void
|
||||
test1(void)
|
||||
{
|
||||
struct archive_entry *ae;
|
||||
struct archive *a;
|
||||
@ -49,4 +50,50 @@ DEFINE_TEST(test_read_format_iso_gz)
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
|
||||
}
|
||||
|
||||
static
|
||||
void test2(void)
|
||||
{
|
||||
struct archive_entry *ae;
|
||||
struct archive *a;
|
||||
const char *name = "test_read_format_iso_2.iso.Z";
|
||||
|
||||
extract_reference_file(name);
|
||||
|
||||
assert((a = archive_read_new()) != NULL);
|
||||
assertEqualIntA(a, ARCHIVE_OK,
|
||||
archive_read_support_compression_all(a));
|
||||
assertEqualIntA(a, ARCHIVE_OK,
|
||||
archive_read_support_format_all(a));
|
||||
assertEqualIntA(a, ARCHIVE_OK,
|
||||
archive_read_open_filename(a, name, 512));
|
||||
assertEqualIntA(a, ARCHIVE_OK,
|
||||
archive_read_next_header(a, &ae));
|
||||
assertEqualString(".", archive_entry_pathname(ae));
|
||||
assertEqualIntA(a, ARCHIVE_OK,
|
||||
archive_read_next_header(a, &ae));
|
||||
assertEqualString("A", archive_entry_pathname(ae));
|
||||
assertEqualIntA(a, ARCHIVE_OK,
|
||||
archive_read_next_header(a, &ae));
|
||||
assertEqualString("A/B", archive_entry_pathname(ae));
|
||||
assertEqualIntA(a, ARCHIVE_OK,
|
||||
archive_read_next_header(a, &ae));
|
||||
assertEqualString("C", archive_entry_pathname(ae));
|
||||
assertEqualIntA(a, ARCHIVE_OK,
|
||||
archive_read_next_header(a, &ae));
|
||||
assertEqualString("C/D", archive_entry_pathname(ae));
|
||||
assertEqualIntA(a, ARCHIVE_EOF,
|
||||
archive_read_next_header(a, &ae));
|
||||
assertEqualInt(archive_compression(a),
|
||||
ARCHIVE_COMPRESSION_COMPRESS);
|
||||
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_ISO9660);
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
|
||||
}
|
||||
|
||||
DEFINE_TEST(test_read_format_iso_gz)
|
||||
{
|
||||
test1();
|
||||
test2();
|
||||
}
|
||||
|
||||
|
||||
|
@ -95,7 +95,7 @@ DEFINE_TEST(test_read_format_isojoliet_bz2)
|
||||
/* A regular file with two names ("hardlink" gets returned
|
||||
* first, so it's not marked as a hardlink). */
|
||||
assertEqualInt(0, archive_read_next_header(a, &ae));
|
||||
assertEqualString("long-joliet-file-name.textfile",
|
||||
assertEqualString("hardlink",
|
||||
archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assert(archive_entry_hardlink(ae) == NULL);
|
||||
@ -108,9 +108,10 @@ DEFINE_TEST(test_read_format_isojoliet_bz2)
|
||||
/* Second name for the same regular file (this happens to be
|
||||
* returned second, so does get marked as a hardlink). */
|
||||
assertEqualInt(0, archive_read_next_header(a, &ae));
|
||||
assertEqualString("hardlink", archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assertEqualString("long-joliet-file-name.textfile",
|
||||
archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assertEqualString("hardlink",
|
||||
archive_entry_hardlink(ae));
|
||||
assert(!archive_entry_size_is_set(ae));
|
||||
|
||||
|
@ -111,7 +111,7 @@ DEFINE_TEST(test_read_format_isojoliet_long)
|
||||
pathname[102] = '3';
|
||||
pathname[103] = '\0';
|
||||
assertEqualInt(0, archive_read_next_header(a, &ae));
|
||||
assertEqualString(pathname, archive_entry_pathname(ae));
|
||||
assertEqualString("hardlink", archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assert(archive_entry_hardlink(ae) == NULL);
|
||||
assertEqualInt(6, archive_entry_size(ae));
|
||||
@ -123,9 +123,9 @@ DEFINE_TEST(test_read_format_isojoliet_long)
|
||||
/* Second name for the same regular file (this happens to be
|
||||
* returned second, so does get marked as a hardlink). */
|
||||
assertEqualInt(0, archive_read_next_header(a, &ae));
|
||||
assertEqualString("hardlink", archive_entry_pathname(ae));
|
||||
assertEqualString(pathname, archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assertEqualString(pathname, archive_entry_hardlink(ae));
|
||||
assertEqualString("hardlink", archive_entry_hardlink(ae));
|
||||
assert(!archive_entry_size_is_set(ae));
|
||||
|
||||
/* End of archive. */
|
||||
|
@ -98,7 +98,7 @@ DEFINE_TEST(test_read_format_isojoliet_rr)
|
||||
/* A regular file with two names ("hardlink" gets returned
|
||||
* first, so it's not marked as a hardlink). */
|
||||
assertEqualInt(0, archive_read_next_header(a, &ae));
|
||||
assertEqualString("long-joliet-file-name.textfile",
|
||||
assertEqualString("hardlink",
|
||||
archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assert(archive_entry_hardlink(ae) == NULL);
|
||||
@ -120,9 +120,10 @@ DEFINE_TEST(test_read_format_isojoliet_rr)
|
||||
/* Second name for the same regular file (this happens to be
|
||||
* returned second, so does get marked as a hardlink). */
|
||||
assertEqualInt(0, archive_read_next_header(a, &ae));
|
||||
assertEqualString("hardlink", archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assertEqualString("long-joliet-file-name.textfile",
|
||||
archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assertEqualString("hardlink",
|
||||
archive_entry_hardlink(ae));
|
||||
assert(!archive_entry_size_is_set(ae));
|
||||
assertEqualInt(86401, archive_entry_mtime(ae));
|
||||
|
@ -97,9 +97,9 @@ DEFINE_TEST(test_read_format_isorr_bz2)
|
||||
assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
|
||||
assertEqualInt(1, archive_entry_uid(ae));
|
||||
assertEqualInt(2, archive_entry_gid(ae));
|
||||
} else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
|
||||
} else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
|
||||
/* A regular file. */
|
||||
assertEqualString("hardlink", archive_entry_pathname(ae));
|
||||
assertEqualString("file", archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assertEqualInt(12345684, archive_entry_size(ae));
|
||||
assertEqualInt(0,
|
||||
@ -111,16 +111,16 @@ DEFINE_TEST(test_read_format_isorr_bz2)
|
||||
assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
|
||||
assertEqualInt(1, archive_entry_uid(ae));
|
||||
assertEqualInt(2, archive_entry_gid(ae));
|
||||
} else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
|
||||
} else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
|
||||
/* A hardlink to the regular file. */
|
||||
/* Note: If "hardlink" gets returned before "file",
|
||||
* then "hardlink" will get returned as a regular file
|
||||
* and "file" will get returned as the hardlink.
|
||||
* This test should tolerate that, since it's a
|
||||
* perfectly permissible thing for libarchive to do. */
|
||||
assertEqualString("file", archive_entry_pathname(ae));
|
||||
assertEqualString("hardlink", archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assertEqualString("hardlink", archive_entry_hardlink(ae));
|
||||
assertEqualString("file", archive_entry_hardlink(ae));
|
||||
assertEqualInt(0, archive_entry_size_is_set(ae));
|
||||
assertEqualInt(0, archive_entry_size(ae));
|
||||
assertEqualInt(86401, archive_entry_mtime(ae));
|
||||
|
@ -98,9 +98,9 @@ DEFINE_TEST(test_read_format_isorr_new_bz2)
|
||||
assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
|
||||
assertEqualInt(1, archive_entry_uid(ae));
|
||||
assertEqualInt(2, archive_entry_gid(ae));
|
||||
} else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
|
||||
} else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
|
||||
/* A regular file. */
|
||||
assertEqualString("hardlink", archive_entry_pathname(ae));
|
||||
assertEqualString("file", archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assertEqualInt(12345684, archive_entry_size(ae));
|
||||
assertEqualInt(0,
|
||||
@ -112,16 +112,16 @@ DEFINE_TEST(test_read_format_isorr_new_bz2)
|
||||
assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
|
||||
assertEqualInt(1, archive_entry_uid(ae));
|
||||
assertEqualInt(2, archive_entry_gid(ae));
|
||||
} else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
|
||||
} else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
|
||||
/* A hardlink to the regular file. */
|
||||
/* Note: If "hardlink" gets returned before "file",
|
||||
* then "hardlink" will get returned as a regular file
|
||||
* and "file" will get returned as the hardlink.
|
||||
* This test should tolerate that, since it's a
|
||||
* perfectly permissible thing for libarchive to do. */
|
||||
assertEqualString("file", archive_entry_pathname(ae));
|
||||
assertEqualString("hardlink", archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assertEqualString("hardlink", archive_entry_hardlink(ae));
|
||||
assertEqualString("file", archive_entry_hardlink(ae));
|
||||
assertEqualInt(0, archive_entry_size_is_set(ae));
|
||||
assertEqualInt(0, archive_entry_size(ae));
|
||||
assertEqualInt(86401, archive_entry_mtime(ae));
|
||||
|
@ -96,10 +96,10 @@ DEFINE_TEST(test_read_format_isozisofs_bz2)
|
||||
assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
|
||||
assertEqualInt(1, archive_entry_uid(ae));
|
||||
assertEqualInt(2, archive_entry_gid(ae));
|
||||
} else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
|
||||
} else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
|
||||
int r;
|
||||
/* A regular file. */
|
||||
assertEqualString("hardlink", archive_entry_pathname(ae));
|
||||
assertEqualString("file", archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assertEqualInt(12345684, archive_entry_size(ae));
|
||||
r = archive_read_data_block(a, &p, &size, &offset);
|
||||
@ -111,23 +111,23 @@ DEFINE_TEST(test_read_format_isozisofs_bz2)
|
||||
assertEqualMem(p, "hello\n", 6);
|
||||
}
|
||||
assertEqualInt(86401, archive_entry_mtime(ae));
|
||||
assertEqualInt(86401, archive_entry_atime(ae));
|
||||
assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
|
||||
assertEqualInt(1, archive_entry_uid(ae));
|
||||
assertEqualInt(2, archive_entry_gid(ae));
|
||||
} else if (strcmp("file", archive_entry_pathname(ae)) == 0) {
|
||||
} else if (strcmp("hardlink", archive_entry_pathname(ae)) == 0) {
|
||||
/* A hardlink to the regular file. */
|
||||
/* Note: If "hardlink" gets returned before "file",
|
||||
* then "hardlink" will get returned as a regular file
|
||||
* and "file" will get returned as the hardlink.
|
||||
* This test should tolerate that, since it's a
|
||||
* perfectly permissible thing for libarchive to do. */
|
||||
assertEqualString("file", archive_entry_pathname(ae));
|
||||
assertEqualString("hardlink", archive_entry_pathname(ae));
|
||||
assertEqualInt(AE_IFREG, archive_entry_filetype(ae));
|
||||
assertEqualString("hardlink", archive_entry_hardlink(ae));
|
||||
assertEqualString("file", archive_entry_hardlink(ae));
|
||||
assertEqualInt(0, archive_entry_size_is_set(ae));
|
||||
assertEqualInt(0, archive_entry_size(ae));
|
||||
assertEqualInt(86401, archive_entry_mtime(ae));
|
||||
assertEqualInt(86401, archive_entry_atime(ae));
|
||||
assertEqualInt(2, archive_entry_stat(ae)->st_nlink);
|
||||
assertEqualInt(1, archive_entry_uid(ae));
|
||||
assertEqualInt(2, archive_entry_gid(ae));
|
||||
|
Loading…
Reference in New Issue
Block a user