Unbreak libarchive on arm. Two parts of libarchive relied on a
traditional shortcut of defining on-disk layouts using structures of character arrays. Unfortunately, as recently discussed on cvs-all@, this usage is not actually sanctioned by the standards and specifically fails on GCC/arm (unless your data structures happen to be "naturally aligned"). The new code defines offsets/sizes for data fields and accesses them using explicit pointer arithmetic, instead of casting to a structure and accessing structure fields. In particular, the new code is now clean with WARNS=6 on arm. MFC after: 14 days
This commit is contained in:
parent
548d785ec5
commit
43baed1581
@ -21,12 +21,7 @@ CFLAGS+= -DPACKAGE_NAME=\"lib${LIB}\"
|
||||
CFLAGS+= -DPACKAGE_VERSION=\"${VERSION}\"
|
||||
CFLAGS+= -I${.OBJDIR}
|
||||
|
||||
# FreeBSD/arm has some limitations.
|
||||
.if ${MACHINE_ARCH} == "arm"
|
||||
WARNS?= 3
|
||||
.else
|
||||
WARNS?= 6
|
||||
.endif
|
||||
|
||||
# Headers to be installed in /usr/include
|
||||
INCS= archive.h archive_entry.h
|
||||
|
@ -80,56 +80,98 @@ __FBSDID("$FreeBSD$");
|
||||
* CDs with a single pass through the data, as required by libarchive.
|
||||
*/
|
||||
|
||||
/* Structure of on-disk PVD. */
|
||||
struct iso9660_primary_volume_descriptor {
|
||||
unsigned char type[1];
|
||||
char id[5];
|
||||
unsigned char version[1];
|
||||
char reserved1[1];
|
||||
char system_id[32];
|
||||
char volume_id[32];
|
||||
char reserved2[8];
|
||||
char volume_space_size[8];
|
||||
char reserved3[32];
|
||||
char volume_set_size[4];
|
||||
char volume_sequence_number[4];
|
||||
char logical_block_size[4];
|
||||
char path_table_size[8];
|
||||
char type_1_path_table[4];
|
||||
char opt_type_1_path_table[4];
|
||||
char type_m_path_table[4];
|
||||
char opt_type_m_path_table[4];
|
||||
char root_directory_record[34];
|
||||
char volume_set_id[128];
|
||||
char publisher_id[128];
|
||||
char preparer_id[128];
|
||||
char application_id[128];
|
||||
char copyright_file_id[37];
|
||||
char abstract_file_id[37];
|
||||
char bibliographic_file_id[37];
|
||||
char creation_date[17];
|
||||
char modification_date[17];
|
||||
char expiration_date[17];
|
||||
char effective_date[17];
|
||||
char file_structure_version[1];
|
||||
char reserved4[1];
|
||||
char application_data[512];
|
||||
};
|
||||
/* Structure of on-disk primary volume descriptor. */
|
||||
#define PVD_type_offset 0
|
||||
#define PVD_type_size 1
|
||||
#define PVD_id_offset (PVD_type_offset + PVD_type_size)
|
||||
#define PVD_id_size 5
|
||||
#define PVD_version_offset (PVD_id_offset + PVD_id_size)
|
||||
#define PVD_version_size 1
|
||||
#define PVD_reserved1_offset (PVD_version_offset + PVD_version_size)
|
||||
#define PVD_reserved1_size 1
|
||||
#define PVD_system_id_offset (PVD_reserved1_offset + PVD_reserved1_size)
|
||||
#define PVD_system_id_size 32
|
||||
#define PVD_volume_id_offset (PVD_system_id_offset + PVD_system_id_size)
|
||||
#define PVD_volume_id_size 32
|
||||
#define PVD_reserved2_offset (PVD_volume_id_offset + PVD_volume_id_size)
|
||||
#define PVD_reserved2_size 8
|
||||
#define PVD_volume_space_size_offset (PVD_reserved2_offset + PVD_reserved2_size)
|
||||
#define PVD_volume_space_size_size 8
|
||||
#define PVD_reserved3_offset (PVD_volume_space_size_offset + PVD_volume_space_size_size)
|
||||
#define PVD_reserved3_size 32
|
||||
#define PVD_volume_set_size_offset (PVD_reserved3_offset + PVD_reserved3_size)
|
||||
#define PVD_volume_set_size_size 4
|
||||
#define PVD_volume_sequence_number_offset (PVD_volume_set_size_offset + PVD_volume_set_size_size)
|
||||
#define PVD_volume_sequence_number_size 4
|
||||
#define PVD_logical_block_size_offset (PVD_volume_sequence_number_offset + PVD_volume_sequence_number_size)
|
||||
#define PVD_logical_block_size_size 4
|
||||
#define PVD_path_table_size_offset (PVD_logical_block_size_offset + PVD_logical_block_size_size)
|
||||
#define PVD_path_table_size_size 8
|
||||
#define PVD_type_1_path_table_offset (PVD_path_table_size_offset + PVD_path_table_size_size)
|
||||
#define PVD_type_1_path_table_size 4
|
||||
#define PVD_opt_type_1_path_table_offset (PVD_type_1_path_table_offset + PVD_type_1_path_table_size)
|
||||
#define PVD_opt_type_1_path_table_size 4
|
||||
#define PVD_type_m_path_table_offset (PVD_opt_type_1_path_table_offset + PVD_opt_type_1_path_table_size)
|
||||
#define PVD_type_m_path_table_size 4
|
||||
#define PVD_opt_type_m_path_table_offset (PVD_type_m_path_table_offset + PVD_type_m_path_table_size)
|
||||
#define PVD_opt_type_m_path_table_size 4
|
||||
#define PVD_root_directory_record_offset (PVD_opt_type_m_path_table_offset + PVD_opt_type_m_path_table_size)
|
||||
#define PVD_root_directory_record_size 34
|
||||
#define PVD_volume_set_id_offset (PVD_root_directory_record_offset + PVD_root_directory_record_size)
|
||||
#define PVD_volume_set_id_size 128
|
||||
#define PVD_publisher_id_offset (PVD_volume_set_id_offset + PVD_volume_set_id_size)
|
||||
#define PVD_publisher_id_size 128
|
||||
#define PVD_preparer_id_offset (PVD_publisher_id_offset + PVD_publisher_id_size)
|
||||
#define PVD_preparer_id_size 128
|
||||
#define PVD_application_id_offset (PVD_preparer_id_offset + PVD_preparer_id_size)
|
||||
#define PVD_application_id_size 128
|
||||
#define PVD_copyright_file_id_offset (PVD_application_id_offset + PVD_application_id_size)
|
||||
#define PVD_copyright_file_id_size 37
|
||||
#define PVD_abstract_file_id_offset (PVD_copyright_file_id_offset + PVD_copyright_file_id_size)
|
||||
#define PVD_abstract_file_id_size 37
|
||||
#define PVD_bibliographic_file_id_offset (PVD_abstract_file_id_offset + PVD_abstract_file_id_size)
|
||||
#define PVD_bibliographic_file_id_size 37
|
||||
#define PVD_creation_date_offset (PVD_bibliographic_file_id_offset + PVD_bibliographic_file_id_size)
|
||||
#define PVD_creation_date_size 17
|
||||
#define PVD_modification_date_offset (PVD_creation_date_offset + PVD_creation_date_size)
|
||||
#define PVD_modification_date_size 17
|
||||
#define PVD_expiration_date_offset (PVD_modification_date_offset + PVD_modification_date_size)
|
||||
#define PVD_expiration_date_size 17
|
||||
#define PVD_effective_date_offset (PVD_expiration_date_offset + PVD_expiration_date_size)
|
||||
#define PVD_effective_date_size 17
|
||||
#define PVD_file_structure_version_offset (PVD_effective_date_offset + PVD_effective_date_size)
|
||||
#define PVD_file_structure_version_size 1
|
||||
#define PVD_reserved4_offset (PVD_file_structure_version_offset + PVD_file_structure_version_size)
|
||||
#define PVD_reserved4_size 1
|
||||
#define PVD_application_data_offset (PVD_reserved4_offset + PVD_reserved4_size)
|
||||
#define PVD_application_data_size 512
|
||||
|
||||
/* Structure of an on-disk directory record. */
|
||||
struct iso9660_directory_record {
|
||||
unsigned char length[1];
|
||||
unsigned char ext_attr_length[1];
|
||||
unsigned char extent[8];
|
||||
unsigned char size[8];
|
||||
char date[7];
|
||||
unsigned char flags[1];
|
||||
unsigned char file_unit_size[1];
|
||||
unsigned char interleave[1];
|
||||
unsigned char volume_sequence_number[4];
|
||||
unsigned char name_len[1];
|
||||
char name[1];
|
||||
};
|
||||
/* Note: ISO9660 stores each multi-byte integer twice, once in
|
||||
* each byte order. The sizes here are the size of just one
|
||||
* of the two integers. (This is why the offset of a field isn't
|
||||
* the same as the offset+size of the previous field.) */
|
||||
#define DR_length_offset 0
|
||||
#define DR_length_size 1
|
||||
#define DR_ext_attr_length_offset 1
|
||||
#define DR_ext_attr_length_size 1
|
||||
#define DR_extent_offset 2
|
||||
#define DR_extent_size 4
|
||||
#define DR_size_offset 10
|
||||
#define DR_size_size 4
|
||||
#define DR_date_offset 18
|
||||
#define DR_date_size 7
|
||||
#define DR_flags_offset 25
|
||||
#define DR_flags_size 1
|
||||
#define DR_file_unit_size_offset 26
|
||||
#define DR_file_unit_size_size 1
|
||||
#define DR_interleave_offset 27
|
||||
#define DR_interleave_size 1
|
||||
#define DR_volume_sequence_number_offset 28
|
||||
#define DR_volume_sequence_number_size 2
|
||||
#define DR_name_len_offset 32
|
||||
#define DR_name_len_size 1
|
||||
#define DR_name_offset 33
|
||||
|
||||
/*
|
||||
* Our private data.
|
||||
@ -188,18 +230,17 @@ static int archive_read_format_iso9660_read_data(struct archive *,
|
||||
static int archive_read_format_iso9660_read_header(struct archive *,
|
||||
struct archive_entry *);
|
||||
static const char *build_pathname(struct archive_string *, struct file_info *);
|
||||
static void dump_isodirrec(FILE *, const struct iso9660_directory_record *);
|
||||
static void dump_isodirrec(FILE *, const unsigned char *isodirrec);
|
||||
static time_t time_from_tm(struct tm *);
|
||||
static time_t isodate17(const void *);
|
||||
static time_t isodate7(const void *);
|
||||
static int isPVD(struct iso9660 *, const char *);
|
||||
static time_t isodate17(const unsigned char *);
|
||||
static time_t isodate7(const unsigned char *);
|
||||
static int isPVD(struct iso9660 *, const unsigned char *);
|
||||
static struct file_info *next_entry(struct iso9660 *);
|
||||
static int next_entry_seek(struct archive *a, struct iso9660 *iso9660,
|
||||
struct file_info **pfile);
|
||||
static struct file_info *
|
||||
parse_file_info(struct iso9660 *iso9660,
|
||||
struct file_info *parent,
|
||||
const struct iso9660_directory_record *isodirrec);
|
||||
struct file_info *parent, const unsigned char *isodirrec);
|
||||
static void parse_rockridge(struct iso9660 *iso9660,
|
||||
struct file_info *file, const unsigned char *start,
|
||||
const unsigned char *end);
|
||||
@ -279,9 +320,8 @@ archive_read_format_iso9660_bid(struct archive *a)
|
||||
}
|
||||
|
||||
static int
|
||||
isPVD(struct iso9660 *iso9660, const char *h)
|
||||
isPVD(struct iso9660 *iso9660, const unsigned char *h)
|
||||
{
|
||||
const struct iso9660_primary_volume_descriptor *voldesc;
|
||||
struct file_info *file;
|
||||
|
||||
if (h[0] != 1)
|
||||
@ -289,13 +329,10 @@ isPVD(struct iso9660 *iso9660, const char *h)
|
||||
if (memcmp(h+1, "CD001", 5) != 0)
|
||||
return (0);
|
||||
|
||||
|
||||
voldesc = (const struct iso9660_primary_volume_descriptor *)h;
|
||||
iso9660->logical_block_size = toi(&voldesc->logical_block_size, 2);
|
||||
iso9660->logical_block_size = toi(h + PVD_logical_block_size_offset, 2);
|
||||
|
||||
/* Store the root directory in the pending list. */
|
||||
file = parse_file_info(iso9660, NULL,
|
||||
(struct iso9660_directory_record *)&voldesc->root_directory_record);
|
||||
file = parse_file_info(iso9660, NULL, h + PVD_root_directory_record_offset);
|
||||
add_entry(iso9660, file);
|
||||
return (48);
|
||||
}
|
||||
@ -395,19 +432,17 @@ archive_read_format_iso9660_read_header(struct archive *a,
|
||||
for (p = (const unsigned char *)block;
|
||||
*p != 0 && p < (const unsigned char *)block + bytes_read;
|
||||
p += *p) {
|
||||
const struct iso9660_directory_record *dr
|
||||
= (const struct iso9660_directory_record *)p;
|
||||
struct file_info *child;
|
||||
|
||||
/* Skip '.' entry. */
|
||||
if (dr->name_len[0] == 1
|
||||
&& dr->name[0] == '\0')
|
||||
if (*(p + DR_name_len_offset) == 1
|
||||
&& *(p + DR_name_offset) == '\0')
|
||||
continue;
|
||||
/* Skip '..' entry. */
|
||||
if (dr->name_len[0] == 1
|
||||
&& dr->name[0] == '\001')
|
||||
if (*(p + DR_name_len_offset) == 1
|
||||
&& *(p + DR_name_offset) == '\001')
|
||||
continue;
|
||||
child = parse_file_info(iso9660, file, dr);
|
||||
child = parse_file_info(iso9660, file, p);
|
||||
add_entry(iso9660, child);
|
||||
if (iso9660->seenRockridge) {
|
||||
a->archive_format =
|
||||
@ -477,9 +512,11 @@ archive_read_format_iso9660_cleanup(struct archive *a)
|
||||
*/
|
||||
static struct file_info *
|
||||
parse_file_info(struct iso9660 *iso9660, struct file_info *parent,
|
||||
const struct iso9660_directory_record *isodirrec)
|
||||
const unsigned char *isodirrec)
|
||||
{
|
||||
struct file_info *file;
|
||||
size_t name_len;
|
||||
int flags;
|
||||
|
||||
/* TODO: Sanity check that name_len doesn't exceed length, etc. */
|
||||
|
||||
@ -491,19 +528,21 @@ parse_file_info(struct iso9660 *iso9660, struct file_info *parent,
|
||||
file->parent = parent;
|
||||
if (parent != NULL)
|
||||
parent->refcount++;
|
||||
file->offset = toi(isodirrec->extent, 4)
|
||||
file->offset = toi(isodirrec + DR_extent_offset, DR_extent_size)
|
||||
* iso9660->logical_block_size;
|
||||
file->size = toi(isodirrec->size, 4);
|
||||
file->mtime = isodate7(isodirrec->date);
|
||||
file->size = toi(isodirrec + DR_size_offset, DR_size_size);
|
||||
file->mtime = isodate7(isodirrec + DR_date_offset);
|
||||
file->ctime = file->atime = file->mtime;
|
||||
file->name = (char *)malloc(isodirrec->name_len[0] + 1);
|
||||
name_len = (size_t)*(const unsigned char *)(isodirrec + DR_name_len_offset);
|
||||
file->name = (char *)malloc(name_len + 1);
|
||||
if (file->name == NULL) {
|
||||
free(file);
|
||||
return (NULL);
|
||||
}
|
||||
memcpy(file->name, isodirrec->name, isodirrec->name_len[0]);
|
||||
file->name[(int)isodirrec->name_len[0]] = '\0';
|
||||
if (isodirrec->flags[0] & 0x02)
|
||||
memcpy(file->name, isodirrec + DR_name_offset, name_len);
|
||||
file->name[name_len] = '\0';
|
||||
flags = *(isodirrec + DR_flags_offset);
|
||||
if (flags & 0x02)
|
||||
file->mode = S_IFDIR | 0700;
|
||||
else
|
||||
file->mode = S_IFREG | 0400;
|
||||
@ -512,33 +551,33 @@ parse_file_info(struct iso9660 *iso9660, struct file_info *parent,
|
||||
{
|
||||
const unsigned char *rr_start, *rr_end;
|
||||
rr_end = (const unsigned char *)isodirrec
|
||||
+ isodirrec->length[0];
|
||||
rr_start = (const unsigned char *)isodirrec->name
|
||||
+ isodirrec->name_len[0];
|
||||
if ((isodirrec->name_len[0] & 1) == 0)
|
||||
+ *(isodirrec + DR_length_offset);
|
||||
rr_start = (const unsigned char *)(isodirrec + DR_name_offset
|
||||
+ name_len);
|
||||
if ((name_len & 1) == 0)
|
||||
rr_start++;
|
||||
rr_start += iso9660->suspOffset;
|
||||
parse_rockridge(iso9660, file, rr_start, rr_end);
|
||||
}
|
||||
|
||||
/* DEBUGGING: Warn about attributes I don't yet fully support. */
|
||||
if ((isodirrec->flags[0] & ~0x02) != 0) {
|
||||
if ((flags & ~0x02) != 0) {
|
||||
fprintf(stderr, "\n ** Unrecognized flag: ");
|
||||
dump_isodirrec(stderr, isodirrec);
|
||||
fprintf(stderr, "\n");
|
||||
} else if (toi(isodirrec->volume_sequence_number, 2) != 1) {
|
||||
} else if (toi(isodirrec + DR_volume_sequence_number_offset, 2) != 1) {
|
||||
fprintf(stderr, "\n ** Unrecognized sequence number: ");
|
||||
dump_isodirrec(stderr, isodirrec);
|
||||
fprintf(stderr, "\n");
|
||||
} else if (isodirrec->file_unit_size[0] != 0) {
|
||||
} else if (*(isodirrec + DR_file_unit_size_offset) != 0) {
|
||||
fprintf(stderr, "\n ** Unexpected file unit size: ");
|
||||
dump_isodirrec(stderr, isodirrec);
|
||||
fprintf(stderr, "\n");
|
||||
} else if (isodirrec->interleave[0] != 0) {
|
||||
} else if (*(isodirrec + DR_interleave_offset) != 0) {
|
||||
fprintf(stderr, "\n ** Unexpected interleave: ");
|
||||
dump_isodirrec(stderr, isodirrec);
|
||||
fprintf(stderr, "\n");
|
||||
} else if (isodirrec->ext_attr_length[0] != 0) {
|
||||
} else if (*(isodirrec + DR_ext_attr_length_offset) != 0) {
|
||||
fprintf(stderr, "\n ** Unexpected extended attribute length: ");
|
||||
dump_isodirrec(stderr, isodirrec);
|
||||
fprintf(stderr, "\n");
|
||||
@ -959,10 +998,9 @@ toi(const void *p, int n)
|
||||
}
|
||||
|
||||
static time_t
|
||||
isodate7(const void *p)
|
||||
isodate7(const unsigned char *v)
|
||||
{
|
||||
struct tm tm;
|
||||
const unsigned char *v = (const unsigned char *)p;
|
||||
int offset;
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
tm.tm_year = v[0];
|
||||
@ -971,8 +1009,8 @@ isodate7(const void *p)
|
||||
tm.tm_hour = v[3];
|
||||
tm.tm_min = v[4];
|
||||
tm.tm_sec = v[5];
|
||||
/* v[6] is the timezone offset, in 1/4-hour increments. */
|
||||
offset = ((const signed char *)p)[6];
|
||||
/* v[6] is the signed timezone offset, in 1/4-hour increments. */
|
||||
offset = ((const signed char *)v)[6];
|
||||
if (offset > -48 && offset < 52) {
|
||||
tm.tm_hour -= offset / 4;
|
||||
tm.tm_min -= (offset % 4) * 15;
|
||||
@ -981,10 +1019,9 @@ isodate7(const void *p)
|
||||
}
|
||||
|
||||
static time_t
|
||||
isodate17(const void *p)
|
||||
isodate17(const unsigned char *v)
|
||||
{
|
||||
struct tm tm;
|
||||
const unsigned char *v = (const unsigned char *)p;
|
||||
int offset;
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
tm.tm_year = (v[0] - '0') * 1000 + (v[1] - '0') * 100
|
||||
@ -995,8 +1032,8 @@ isodate17(const void *p)
|
||||
tm.tm_hour = (v[8] - '0') * 10 + (v[9] - '0');
|
||||
tm.tm_min = (v[10] - '0') * 10 + (v[11] - '0');
|
||||
tm.tm_sec = (v[12] - '0') * 10 + (v[13] - '0');
|
||||
/* v[16] is the timezone offset, in 1/4-hour increments. */
|
||||
offset = ((const signed char *)p)[16];
|
||||
/* v[16] is the signed timezone offset, in 1/4-hour increments. */
|
||||
offset = ((const signed char *)v)[16];
|
||||
if (offset > -48 && offset < 52) {
|
||||
tm.tm_hour -= offset / 4;
|
||||
tm.tm_min -= (offset % 4) * 15;
|
||||
@ -1020,7 +1057,7 @@ time_from_tm(struct tm *t)
|
||||
* mktime() function is a close match, except that it uses
|
||||
* local timezone instead of GMT. Close enough for now.
|
||||
* Note that it is not possible to emulate timegm() using
|
||||
* standard interfaces:
|
||||
* completely standard interfaces:
|
||||
* * ANSI C90 does not even guarantee that time_t is
|
||||
* an arithmetic type, so time adjustments can only be
|
||||
* done by manipulating struct tm elements. You cannot
|
||||
@ -1034,6 +1071,10 @@ time_from_tm(struct tm *t)
|
||||
* * POSIX does not promise that the epoch begins in 1970,
|
||||
* so you can't write a portable timegm() function from
|
||||
* scratch.
|
||||
* In practice, of course, mktime() is a reasonable approximation
|
||||
* and most POSIX systems do use seconds since 1970, so you
|
||||
* can roll your own and have it work on all but a few pretty
|
||||
* whacky systems.
|
||||
*/
|
||||
time_t result = mktime(t);
|
||||
/* TODO: Find a way to improve this approximation to timegm(). */
|
||||
@ -1056,16 +1097,26 @@ build_pathname(struct archive_string *as, struct file_info *file)
|
||||
}
|
||||
|
||||
static void
|
||||
dump_isodirrec(FILE *out, const struct iso9660_directory_record *isodirrec)
|
||||
dump_isodirrec(FILE *out, const unsigned char *isodirrec)
|
||||
{
|
||||
fprintf(out, " l %d,", isodirrec->length[0]);
|
||||
fprintf(out, " a %d,", isodirrec->ext_attr_length[0]);
|
||||
fprintf(out, " ext 0x%x,", toi(isodirrec->extent, 4));
|
||||
fprintf(out, " s %d,", toi(isodirrec->size, 4));
|
||||
fprintf(out, " f 0x%02x,", isodirrec->flags[0]);
|
||||
fprintf(out, " u %d,", isodirrec->file_unit_size[0]);
|
||||
fprintf(out, " ilv %d,", isodirrec->interleave[0]);
|
||||
fprintf(out, " seq %d,", toi(isodirrec->volume_sequence_number,2));
|
||||
fprintf(out, " nl %d:", isodirrec->name_len[0]);
|
||||
fprintf(out, " `%.*s'", isodirrec->name_len[0], isodirrec->name);
|
||||
fprintf(out, " l %d,",
|
||||
toi(isodirrec + DR_length_offset, DR_length_size));
|
||||
fprintf(out, " a %d,",
|
||||
toi(isodirrec + DR_ext_attr_length_offset, DR_ext_attr_length_size));
|
||||
fprintf(out, " ext 0x%x,",
|
||||
toi(isodirrec + DR_extent_offset, DR_extent_size));
|
||||
fprintf(out, " s %d,",
|
||||
toi(isodirrec + DR_size_offset, DR_extent_size));
|
||||
fprintf(out, " f 0x%02x,",
|
||||
toi(isodirrec + DR_flags_offset, DR_flags_size));
|
||||
fprintf(out, " u %d,",
|
||||
toi(isodirrec + DR_file_unit_size_offset, DR_file_unit_size_size));
|
||||
fprintf(out, " ilv %d,",
|
||||
toi(isodirrec + DR_interleave_offset, DR_interleave_size));
|
||||
fprintf(out, " seq %d,",
|
||||
toi(isodirrec + DR_volume_sequence_number_offset, DR_volume_sequence_number_size));
|
||||
fprintf(out, " nl %d:",
|
||||
toi(isodirrec + DR_name_len_offset, DR_name_len_size));
|
||||
fprintf(out, " `%.*s'",
|
||||
toi(isodirrec + DR_name_len_offset, DR_name_len_size), isodirrec + DR_name_offset);
|
||||
}
|
||||
|
@ -61,56 +61,94 @@ struct ustar {
|
||||
/*
|
||||
* Define structure of POSIX 'ustar' tar header.
|
||||
*/
|
||||
struct archive_entry_header_ustar {
|
||||
char name[100];
|
||||
char mode[6];
|
||||
char mode_padding[2];
|
||||
char uid[6];
|
||||
char uid_padding[2];
|
||||
char gid[6];
|
||||
char gid_padding[2];
|
||||
char size[11];
|
||||
char size_padding[1];
|
||||
char mtime[11];
|
||||
char mtime_padding[1];
|
||||
char checksum[8];
|
||||
char typeflag[1];
|
||||
char linkname[100];
|
||||
char magic[6]; /* For POSIX: "ustar\0" */
|
||||
char version[2]; /* For POSIX: "00" */
|
||||
char uname[32];
|
||||
char gname[32];
|
||||
char rdevmajor[6];
|
||||
char rdevmajor_padding[2];
|
||||
char rdevminor[6];
|
||||
char rdevminor_padding[2];
|
||||
char prefix[155];
|
||||
char padding[12];
|
||||
};
|
||||
#define USTAR_name_offset 0
|
||||
#define USTAR_name_size 100
|
||||
#define USTAR_mode_offset 100
|
||||
#define USTAR_mode_size 6
|
||||
#define USTAR_mode_max_size 8
|
||||
#define USTAR_uid_offset 108
|
||||
#define USTAR_uid_size 6
|
||||
#define USTAR_uid_max_size 8
|
||||
#define USTAR_gid_offset 116
|
||||
#define USTAR_gid_size 6
|
||||
#define USTAR_gid_max_size 8
|
||||
#define USTAR_size_offset 124
|
||||
#define USTAR_size_size 11
|
||||
#define USTAR_size_max_size 12
|
||||
#define USTAR_mtime_offset 136
|
||||
#define USTAR_mtime_size 11
|
||||
#define USTAR_mtime_max_size 11
|
||||
#define USTAR_checksum_offset 148
|
||||
#define USTAR_checksum_size 8
|
||||
#define USTAR_typeflag_offset 156
|
||||
#define USTAR_typeflag_size 1
|
||||
#define USTAR_linkname_offset 157
|
||||
#define USTAR_linkname_size 100
|
||||
#define USTAR_magic_offset 257
|
||||
#define USTAR_magic_size 6
|
||||
#define USTAR_version_offset 263
|
||||
#define USTAR_version_size 2
|
||||
#define USTAR_uname_offset 265
|
||||
#define USTAR_uname_size 32
|
||||
#define USTAR_gname_offset 297
|
||||
#define USTAR_gname_size 32
|
||||
#define USTAR_rdevmajor_offset 329
|
||||
#define USTAR_rdevmajor_size 6
|
||||
#define USTAR_rdevmajor_max_size 8
|
||||
#define USTAR_rdevminor_offset 337
|
||||
#define USTAR_rdevminor_size 6
|
||||
#define USTAR_rdevminor_max_size 8
|
||||
#define USTAR_prefix_offset 345
|
||||
#define USTAR_prefix_size 155
|
||||
#define USTAR_padding_offset 500
|
||||
#define USTAR_padding_size 12
|
||||
|
||||
/*
|
||||
* A filled-in copy of the header for initialization.
|
||||
*/
|
||||
static const struct archive_entry_header_ustar template_header = {
|
||||
{ "" }, /* name */
|
||||
{ '0','0','0','0','0','0' }, { ' ', '\0' }, /* mode, space-null term.*/
|
||||
{ '0','0','0','0','0','0' }, { ' ', '\0' }, /* uid, space-null term. */
|
||||
{ '0','0','0','0','0','0' }, { ' ', '\0' }, /* gid, space-null term. */
|
||||
{ '0','0','0','0','0','0','0','0','0','0','0' }, { ' ' },
|
||||
/* size, space termination. */
|
||||
{ '0','0','0','0','0','0','0','0','0','0','0' }, { ' ' },
|
||||
/* mtime, space termination. */
|
||||
{ ' ',' ',' ',' ',' ',' ',' ',' ' }, /* Initial checksum value. */
|
||||
{ '0' }, /* default: regular file */
|
||||
{ "" }, /* linkname */
|
||||
{ 'u','s','t','a','r' }, /* magic */
|
||||
{ '0', '0' }, /* version */
|
||||
{ "" }, /* uname */
|
||||
{ "" }, /* gname */
|
||||
{ '0','0','0','0','0','0' }, { ' ', '\0' }, /* rdevmajor, space-null */
|
||||
{ '0','0','0','0','0','0' }, { ' ', '\0' }, /* rdevminor, space-null */
|
||||
{ "" }, /* prefix */
|
||||
{ "" } /* padding */
|
||||
static const char template_header[] = {
|
||||
/* name: 100 bytes */
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,
|
||||
/* Mode, space-null termination: 8 bytes */
|
||||
'0','0','0','0','0','0', ' ','\0',
|
||||
/* uid, space-null termination: 8 bytes */
|
||||
'0','0','0','0','0','0', ' ','\0',
|
||||
/* gid, space-null termination: 8 bytes */
|
||||
'0','0','0','0','0','0', ' ','\0',
|
||||
/* size, space termation: 12 bytes */
|
||||
'0','0','0','0','0','0','0','0','0','0','0', ' ',
|
||||
/* mtime, space termation: 12 bytes */
|
||||
'0','0','0','0','0','0','0','0','0','0','0', ' ',
|
||||
/* Initial checksum value: 8 spaces */
|
||||
' ',' ',' ',' ',' ',' ',' ',' ',
|
||||
/* Typeflag: 1 byte */
|
||||
'0', /* '0' = regular file */
|
||||
/* Linkname: 100 bytes */
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,
|
||||
/* Magic: 6 bytes, Version: 2 bytes */
|
||||
'u','s','t','a','r','\0', '0','0',
|
||||
/* Uname: 32 bytes */
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
/* Gname: 32 bytes */
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
/* rdevmajor + space/null padding: 8 bytes */
|
||||
'0','0','0','0','0','0', ' ','\0',
|
||||
/* rdevminor + space/null padding: 8 bytes */
|
||||
'0','0','0','0','0','0', ' ','\0',
|
||||
/* Prefix: 155 bytes */
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,
|
||||
/* Padding: 12 bytes */
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0
|
||||
};
|
||||
|
||||
static ssize_t archive_write_ustar_data(struct archive *a, const void *buff,
|
||||
@ -136,6 +174,12 @@ archive_write_set_format_ustar(struct archive *a)
|
||||
if (a->format_finish != NULL)
|
||||
(a->format_finish)(a);
|
||||
|
||||
/* Basic internal sanity test. */
|
||||
if (sizeof(template_header) != 512) {
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC, "Internal: template_header wrong size: %d should be 512", sizeof(template_header));
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
ustar = (struct ustar *)malloc(sizeof(*ustar));
|
||||
if (ustar == NULL) {
|
||||
archive_set_error(a, ENOMEM, "Can't allocate ustar data");
|
||||
@ -193,11 +237,10 @@ archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
|
||||
* This is exported so that other 'tar' formats can use it.
|
||||
*/
|
||||
int
|
||||
__archive_write_format_header_ustar(struct archive *a, char buff[512],
|
||||
__archive_write_format_header_ustar(struct archive *a, char h[512],
|
||||
struct archive_entry *entry, int tartype, int strict)
|
||||
{
|
||||
unsigned int checksum;
|
||||
struct archive_entry_header_ustar *h;
|
||||
int i, ret;
|
||||
size_t copy_length;
|
||||
const char *p, *pp;
|
||||
@ -211,9 +254,7 @@ __archive_write_format_header_ustar(struct archive *a, char buff[512],
|
||||
* signature, various end-of-field markers and other required
|
||||
* elements.
|
||||
*/
|
||||
memcpy(buff, &template_header, 512);
|
||||
|
||||
h = (struct archive_entry_header_ustar *)buff;
|
||||
memcpy(h, &template_header, 512);
|
||||
|
||||
/*
|
||||
* Because the block is already null-filled, and strings
|
||||
@ -222,11 +263,11 @@ __archive_write_format_header_ustar(struct archive *a, char buff[512],
|
||||
*/
|
||||
|
||||
pp = archive_entry_pathname(entry);
|
||||
if (strlen(pp) <= sizeof(h->name))
|
||||
memcpy(h->name, pp, strlen(pp));
|
||||
if (strlen(pp) <= USTAR_name_size)
|
||||
memcpy(h + USTAR_name_offset, pp, strlen(pp));
|
||||
else {
|
||||
/* Store in two pieces, splitting at a '/'. */
|
||||
p = strchr(pp + strlen(pp) - sizeof(h->name) - 1, '/');
|
||||
p = strchr(pp + strlen(pp) - USTAR_name_size - 1, '/');
|
||||
/*
|
||||
* If there is no path separator, or the prefix or
|
||||
* remaining name are too large, return an error.
|
||||
@ -235,14 +276,14 @@ __archive_write_format_header_ustar(struct archive *a, char buff[512],
|
||||
archive_set_error(a, ENAMETOOLONG,
|
||||
"Pathname too long");
|
||||
ret = ARCHIVE_WARN;
|
||||
} else if (p > pp + sizeof(h->prefix)) {
|
||||
} else if (p > pp + USTAR_prefix_size) {
|
||||
archive_set_error(a, ENAMETOOLONG,
|
||||
"Pathname too long");
|
||||
ret = ARCHIVE_WARN;
|
||||
} else {
|
||||
/* Copy prefix and remainder to appropriate places */
|
||||
memcpy(h->prefix, pp, p - pp);
|
||||
memcpy(h->name, p + 1, pp + strlen(pp) - p - 1);
|
||||
memcpy(h + USTAR_prefix_offset, pp, p - pp);
|
||||
memcpy(h + USTAR_name_offset, p + 1, pp + strlen(pp) - p - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,77 +294,77 @@ __archive_write_format_header_ustar(struct archive *a, char buff[512],
|
||||
p = archive_entry_symlink(entry);
|
||||
if (p != NULL && p[0] != '\0') {
|
||||
copy_length = strlen(p);
|
||||
if (copy_length > sizeof(h->linkname)) {
|
||||
if (copy_length > USTAR_linkname_size) {
|
||||
archive_set_error(a, ENAMETOOLONG,
|
||||
"Link contents too long");
|
||||
ret = ARCHIVE_WARN;
|
||||
copy_length = sizeof(h->linkname);
|
||||
copy_length = USTAR_linkname_size;
|
||||
}
|
||||
memcpy(h->linkname, p, copy_length);
|
||||
memcpy(h + USTAR_linkname_offset, p, copy_length);
|
||||
}
|
||||
|
||||
p = archive_entry_uname(entry);
|
||||
if (p != NULL && p[0] != '\0') {
|
||||
copy_length = strlen(p);
|
||||
if (copy_length > sizeof(h->uname)) {
|
||||
if (copy_length > USTAR_uname_size) {
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"Username too long");
|
||||
ret = ARCHIVE_WARN;
|
||||
copy_length = sizeof(h->uname);
|
||||
copy_length = USTAR_uname_size;
|
||||
}
|
||||
memcpy(h->uname, p, copy_length);
|
||||
memcpy(h + USTAR_uname_offset, p, copy_length);
|
||||
}
|
||||
|
||||
p = archive_entry_gname(entry);
|
||||
if (p != NULL && p[0] != '\0') {
|
||||
copy_length = strlen(p);
|
||||
if (strlen(p) > sizeof(h->gname)) {
|
||||
if (strlen(p) > USTAR_gname_size) {
|
||||
archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
||||
"Group name too long");
|
||||
ret = ARCHIVE_WARN;
|
||||
copy_length = sizeof(h->gname);
|
||||
copy_length = USTAR_gname_size;
|
||||
}
|
||||
memcpy(h->gname, p, copy_length);
|
||||
memcpy(h + USTAR_gname_offset, p, copy_length);
|
||||
}
|
||||
|
||||
st = archive_entry_stat(entry);
|
||||
|
||||
if (format_number(st->st_mode & 07777, h->mode, sizeof(h->mode), 8, strict)) {
|
||||
if (format_number(st->st_mode & 07777, h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) {
|
||||
archive_set_error(a, ERANGE, "Numeric mode too large");
|
||||
ret = ARCHIVE_WARN;
|
||||
}
|
||||
|
||||
if (format_number(st->st_uid, h->uid, sizeof(h->uid), 8, strict)) {
|
||||
if (format_number(st->st_uid, h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) {
|
||||
archive_set_error(a, ERANGE, "Numeric user ID too large");
|
||||
ret = ARCHIVE_WARN;
|
||||
}
|
||||
|
||||
if (format_number(st->st_gid, h->gid, sizeof(h->gid), 8, strict)) {
|
||||
if (format_number(st->st_gid, h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) {
|
||||
archive_set_error(a, ERANGE, "Numeric group ID too large");
|
||||
ret = ARCHIVE_WARN;
|
||||
}
|
||||
|
||||
if (format_number(st->st_size, h->size, sizeof(h->size), 12, strict)) {
|
||||
if (format_number(st->st_size, h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) {
|
||||
archive_set_error(a, ERANGE, "File size out of range");
|
||||
ret = ARCHIVE_WARN;
|
||||
}
|
||||
|
||||
if (format_number(st->st_mtime, h->mtime, sizeof(h->mtime), 12, strict)) {
|
||||
if (format_number(st->st_mtime, h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) {
|
||||
archive_set_error(a, ERANGE,
|
||||
"File modification time too large");
|
||||
ret = ARCHIVE_WARN;
|
||||
}
|
||||
|
||||
if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
|
||||
if (format_number(major(st->st_rdev), h->rdevmajor,
|
||||
sizeof(h->rdevmajor), 8, strict)) {
|
||||
if (format_number(major(st->st_rdev), h + USTAR_rdevmajor_offset,
|
||||
USTAR_rdevmajor_size, USTAR_rdevmajor_max_size, strict)) {
|
||||
archive_set_error(a, ERANGE,
|
||||
"Major device number too large");
|
||||
ret = ARCHIVE_WARN;
|
||||
}
|
||||
|
||||
if (format_number(minor(st->st_rdev), h->rdevminor,
|
||||
sizeof(h->rdevminor), 8, strict)) {
|
||||
if (format_number(minor(st->st_rdev), h + USTAR_rdevminor_offset,
|
||||
USTAR_rdevminor_size, USTAR_rdevminor_max_size, strict)) {
|
||||
archive_set_error(a, ERANGE,
|
||||
"Minor device number too large");
|
||||
ret = ARCHIVE_WARN;
|
||||
@ -331,17 +372,17 @@ __archive_write_format_header_ustar(struct archive *a, char buff[512],
|
||||
}
|
||||
|
||||
if (tartype >= 0) {
|
||||
h->typeflag[0] = tartype;
|
||||
h[USTAR_typeflag_offset] = tartype;
|
||||
} else if (mytartype >= 0) {
|
||||
h->typeflag[0] = mytartype;
|
||||
h[USTAR_typeflag_offset] = mytartype;
|
||||
} else {
|
||||
switch (st->st_mode & S_IFMT) {
|
||||
case S_IFREG: h->typeflag[0] = '0' ; break;
|
||||
case S_IFLNK: h->typeflag[0] = '2' ; break;
|
||||
case S_IFCHR: h->typeflag[0] = '3' ; break;
|
||||
case S_IFBLK: h->typeflag[0] = '4' ; break;
|
||||
case S_IFDIR: h->typeflag[0] = '5' ; break;
|
||||
case S_IFIFO: h->typeflag[0] = '6' ; break;
|
||||
case S_IFREG: h[USTAR_typeflag_offset] = '0' ; break;
|
||||
case S_IFLNK: h[USTAR_typeflag_offset] = '2' ; break;
|
||||
case S_IFCHR: h[USTAR_typeflag_offset] = '3' ; break;
|
||||
case S_IFBLK: h[USTAR_typeflag_offset] = '4' ; break;
|
||||
case S_IFDIR: h[USTAR_typeflag_offset] = '5' ; break;
|
||||
case S_IFIFO: h[USTAR_typeflag_offset] = '6' ; break;
|
||||
case S_IFSOCK:
|
||||
archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"tar format cannot archive socket");
|
||||
@ -357,10 +398,10 @@ __archive_write_format_header_ustar(struct archive *a, char buff[512],
|
||||
|
||||
checksum = 0;
|
||||
for (i = 0; i < 512; i++)
|
||||
checksum += 255 & (unsigned int)buff[i];
|
||||
h->checksum[6] = '\0'; /* Can't be pre-set in the template. */
|
||||
/* h->checksum[7] = ' '; */ /* This is pre-set in the template. */
|
||||
format_octal(checksum, h->checksum, 6);
|
||||
checksum += 255 & (unsigned int)h[i];
|
||||
h[USTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */
|
||||
/* h[USTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */
|
||||
format_octal(checksum, h + USTAR_checksum_offset, 6);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user