summaryrefslogtreecommitdiffstats
path: root/contrib/file/src/cdf.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/file/src/cdf.c')
-rw-r--r--contrib/file/src/cdf.c125
1 files changed, 77 insertions, 48 deletions
diff --git a/contrib/file/src/cdf.c b/contrib/file/src/cdf.c
index c979b1d..cc587fc 100644
--- a/contrib/file/src/cdf.c
+++ b/contrib/file/src/cdf.c
@@ -35,7 +35,7 @@
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: cdf.c,v 1.76 2015/02/28 00:18:02 christos Exp $")
+FILE_RCSID("@(#)$File: cdf.c,v 1.80 2016/05/06 15:17:10 christos Exp $")
#endif
#include <assert.h>
@@ -267,13 +267,32 @@ cdf_unpack_dir(cdf_directory_t *d, char *buf)
}
static int
+cdf_zero_stream(cdf_stream_t *scn)
+{
+ scn->sst_len = 0;
+ scn->sst_dirlen = 0;
+ scn->sst_ss = 0;
+ free(scn->sst_tab);
+ scn->sst_tab = NULL;
+ return -1;
+}
+
+static size_t
+cdf_check_stream(const cdf_stream_t *sst, const cdf_header_t *h)
+{
+ size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
+ CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
+ assert(ss == sst->sst_ss);
+ return sst->sst_ss;
+}
+
+static int
cdf_check_stream_offset(const cdf_stream_t *sst, const cdf_header_t *h,
const void *p, size_t tail, int line)
{
const char *b = (const char *)sst->sst_tab;
const char *e = ((const char *)p) + tail;
- size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
- CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
+ size_t ss = cdf_check_stream(sst, h);
/*LINTED*/(void)&line;
if (e >= b && (size_t)(e - b) <= ss * sst->sst_len)
return 0;
@@ -290,10 +309,8 @@ cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len)
{
size_t siz = (size_t)off + len;
- if ((off_t)(off + len) != (off_t)siz) {
- errno = EINVAL;
- return -1;
- }
+ if ((off_t)(off + len) != (off_t)siz)
+ goto out;
if (info->i_buf != NULL && info->i_len >= siz) {
(void)memcpy(buf, &info->i_buf[off], len);
@@ -301,12 +318,15 @@ cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len)
}
if (info->i_fd == -1)
- return -1;
+ goto out;
if (pread(info->i_fd, buf, len, off) != (ssize_t)len)
return -1;
return (ssize_t)len;
+out:
+ errno = EINVAL;
+ return -1;
}
int
@@ -363,11 +383,14 @@ cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs,
DPRINTF(("Out of bounds read %" SIZE_T_FORMAT "u > %"
SIZE_T_FORMAT "u\n",
pos + len, CDF_SEC_SIZE(h) * sst->sst_len));
- return -1;
+ goto out;
}
(void)memcpy(((char *)buf) + offs,
((const char *)sst->sst_tab) + pos, len);
return len;
+out:
+ errno = EFTYPE;
+ return -1;
}
/*
@@ -421,8 +444,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
goto out;
if (j >= CDF_LOOP_LIMIT) {
DPRINTF(("Reading master sector loop limit"));
- errno = EFTYPE;
- goto out2;
+ goto out3;
}
if (cdf_read_sector(info, msa, 0, ss, h, mid) != (ssize_t)ss) {
DPRINTF(("Reading master sector %d", mid));
@@ -435,8 +457,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
if (i >= sat->sat_len) {
DPRINTF(("Out of bounds reading MSA %" SIZE_T_FORMAT
"u >= %" SIZE_T_FORMAT "u", i, sat->sat_len));
- errno = EFTYPE;
- goto out2;
+ goto out3;
}
if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
sec) != (ssize_t)ss) {
@@ -451,6 +472,8 @@ out:
sat->sat_len = i;
free(msa);
return 0;
+out3:
+ errno = EFTYPE;
out2:
free(msa);
out1:
@@ -476,23 +499,24 @@ cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size)
DPRINTF((" %d", sid));
if (j >= CDF_LOOP_LIMIT) {
DPRINTF(("Counting chain loop limit"));
- errno = EFTYPE;
- return (size_t)-1;
+ goto out;
}
if (sid >= maxsector) {
DPRINTF(("Sector %d >= %d\n", sid, maxsector));
- errno = EFTYPE;
- return (size_t)-1;
+ goto out;
}
sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
}
if (i == 0) {
DPRINTF((" none, sid: %d\n", sid));
- return (size_t)-1;
+ goto out;
}
DPRINTF(("\n"));
return i;
+out:
+ errno = EFTYPE;
+ return (size_t)-1;
}
int
@@ -501,27 +525,27 @@ cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
{
size_t ss = CDF_SEC_SIZE(h), i, j;
ssize_t nr;
+ scn->sst_tab = NULL;
scn->sst_len = cdf_count_chain(sat, sid, ss);
scn->sst_dirlen = len;
+ scn->sst_ss = ss;
if (scn->sst_len == (size_t)-1)
- return -1;
+ goto out;
scn->sst_tab = calloc(scn->sst_len, ss);
if (scn->sst_tab == NULL)
- return -1;
+ return cdf_zero_stream(scn);
for (j = i = 0; sid >= 0; i++, j++) {
if (j >= CDF_LOOP_LIMIT) {
DPRINTF(("Read long sector chain loop limit"));
- errno = EFTYPE;
goto out;
}
if (i >= scn->sst_len) {
DPRINTF(("Out of bounds reading long sector chain "
"%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i,
scn->sst_len));
- errno = EFTYPE;
goto out;
}
if ((nr = cdf_read_sector(info, scn->sst_tab, i * ss, ss, h,
@@ -537,8 +561,8 @@ cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
}
return 0;
out:
- free(scn->sst_tab);
- return -1;
+ errno = EFTYPE;
+ return cdf_zero_stream(scn);
}
int
@@ -547,27 +571,27 @@ cdf_read_short_sector_chain(const cdf_header_t *h,
cdf_secid_t sid, size_t len, cdf_stream_t *scn)
{
size_t ss = CDF_SHORT_SEC_SIZE(h), i, j;
- scn->sst_len = cdf_count_chain(ssat, sid, CDF_SEC_SIZE(h));
+ scn->sst_tab = NULL;
+ scn->sst_len = cdf_count_chain(ssat, sid, ss);
scn->sst_dirlen = len;
+ scn->sst_ss = ss;
if (sst->sst_tab == NULL || scn->sst_len == (size_t)-1)
- return -1;
+ goto out;
scn->sst_tab = calloc(scn->sst_len, ss);
if (scn->sst_tab == NULL)
- return -1;
+ return cdf_zero_stream(scn);
for (j = i = 0; sid >= 0; i++, j++) {
if (j >= CDF_LOOP_LIMIT) {
DPRINTF(("Read short sector chain loop limit"));
- errno = EFTYPE;
goto out;
}
if (i >= scn->sst_len) {
DPRINTF(("Out of bounds reading short sector chain "
"%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n",
i, scn->sst_len));
- errno = EFTYPE;
goto out;
}
if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h,
@@ -579,8 +603,8 @@ cdf_read_short_sector_chain(const cdf_header_t *h,
}
return 0;
out:
- free(scn->sst_tab);
- return -1;
+ errno = EFTYPE;
+ return cdf_zero_stream(scn);
}
int
@@ -625,7 +649,6 @@ cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h,
for (j = i = 0; i < ns; i++, j++) {
if (j >= CDF_LOOP_LIMIT) {
DPRINTF(("Read dir loop limit"));
- errno = EFTYPE;
goto out;
}
if (cdf_read_sector(info, buf, 0, ss, h, sid) != (ssize_t)ss) {
@@ -646,6 +669,7 @@ cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h,
out:
free(dir->dir_tab);
free(buf);
+ errno = EFTYPE;
return -1;
}
@@ -658,36 +682,37 @@ cdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h,
size_t ss = CDF_SEC_SIZE(h);
cdf_secid_t sid = h->h_secid_first_sector_in_short_sat;
+ ssat->sat_tab = NULL;
ssat->sat_len = cdf_count_chain(sat, sid, CDF_SEC_SIZE(h));
if (ssat->sat_len == (size_t)-1)
- return -1;
+ goto out;
ssat->sat_tab = CAST(cdf_secid_t *, calloc(ssat->sat_len, ss));
if (ssat->sat_tab == NULL)
- return -1;
+ goto out1;
for (j = i = 0; sid >= 0; i++, j++) {
if (j >= CDF_LOOP_LIMIT) {
DPRINTF(("Read short sat sector loop limit"));
- errno = EFTYPE;
goto out;
}
if (i >= ssat->sat_len) {
DPRINTF(("Out of bounds reading short sector chain "
"%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i,
ssat->sat_len));
- errno = EFTYPE;
goto out;
}
if (cdf_read_sector(info, ssat->sat_tab, i * ss, ss, h, sid) !=
(ssize_t)ss) {
DPRINTF(("Reading short sat sector %d", sid));
- goto out;
+ goto out1;
}
sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]);
}
return 0;
out:
+ errno = EFTYPE;
+out1:
free(ssat->sat_tab);
return -1;
}
@@ -715,13 +740,13 @@ cdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h,
if (d->d_stream_first_sector < 0)
goto out;
- return cdf_read_long_sector_chain(info, h, sat,
+ return cdf_read_long_sector_chain(info, h, sat,
d->d_stream_first_sector, d->d_size, scn);
out:
scn->sst_tab = NULL;
- scn->sst_len = 0;
- scn->sst_dirlen = 0;
- return 0;
+ (void)cdf_zero_stream(scn);
+ errno = EFTYPE;
+ return -1;
}
static int
@@ -750,8 +775,10 @@ cdf_read_user_stream(const cdf_info_t *info, const cdf_header_t *h,
const cdf_directory_t *d;
int i = cdf_find_stream(dir, name, CDF_DIR_TYPE_USER_STREAM);
- if (i <= 0)
+ if (i <= 0) {
+ memset(scn, 0, sizeof(*scn));
return -1;
+ }
d = &dir->dir_tab[i - 1];
return cdf_read_sector_chain(info, h, sat, ssat, sst,
@@ -824,7 +851,7 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h,
malloc(*maxcount * sizeof(*inp)));
}
if (inp == NULL)
- goto out;
+ goto out1;
*info = inp;
inp += *count;
*count += sh.sh_properties;
@@ -931,7 +958,7 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h,
inp = CAST(cdf_property_info_t *,
realloc(*info, *maxcount * sizeof(*inp)));
if (inp == NULL)
- goto out;
+ goto out1;
*info = inp;
inp = *info + nelem;
}
@@ -976,6 +1003,8 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h,
}
return 0;
out:
+ errno = EFTYPE;
+out1:
free(*info);
return -1;
}
@@ -1022,8 +1051,7 @@ int
cdf_unpack_catalog(const cdf_header_t *h, const cdf_stream_t *sst,
cdf_catalog_t **cat)
{
- size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
- CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
+ size_t ss = cdf_check_stream(sst, h);
const char *b = CAST(const char *, sst->sst_tab);
const char *eb = b + ss * sst->sst_len;
size_t nr, i, j, k;
@@ -1043,6 +1071,8 @@ cdf_unpack_catalog(const cdf_header_t *h, const cdf_stream_t *sst,
nr--;
*cat = CAST(cdf_catalog_t *,
malloc(sizeof(cdf_catalog_t) + nr * sizeof(*ce)));
+ if (*cat == NULL)
+ return -1;
ce = (*cat)->cat_e;
memset(ce, 0, nr * sizeof(*ce));
b = CAST(const char *, sst->sst_tab);
@@ -1245,8 +1275,7 @@ cdf_dump(const void *v, size_t len)
void
cdf_dump_stream(const cdf_header_t *h, const cdf_stream_t *sst)
{
- size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ?
- CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h);
+ size_t ss = sst->sst_ss;
cdf_dump(sst->sst_tab, ss * sst->sst_len);
}
OpenPOWER on IntegriCloud