mirror of https://github.com/mpv-player/mpv
stream_libarchive: stop reading on ARCHIVE_FATAL
According to https://github.com/libarchive/libarchive/pull/773#issuecomment-334892291 we're not allowed to "continue reading" (post above) or performing "more operations" (comments in archive.h header), whatever that means. Assume closing and freeing the archive is still ok. Since the codec already includes logic for closing and reopening the archive for seeking in unseekable archives, this probably isn't too bad. Untested due to lack of crashing sample (I lost my original test case, and as recently user-provided one didn't crash).
This commit is contained in:
parent
49e925f830
commit
1199c1e38a
|
@ -126,12 +126,30 @@ static int switch_cb(struct archive *arch, void *oldpriv, void *newpriv)
|
||||||
return open_cb(arch, newpriv);
|
return open_cb(arch, newpriv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mp_archive_free(struct mp_archive *mpa)
|
static void mp_archive_close(struct mp_archive *mpa)
|
||||||
{
|
{
|
||||||
if (mpa && mpa->arch) {
|
if (mpa && mpa->arch) {
|
||||||
archive_read_close(mpa->arch);
|
archive_read_close(mpa->arch);
|
||||||
archive_read_free(mpa->arch);
|
archive_read_free(mpa->arch);
|
||||||
|
mpa->arch = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supposedly we're not allowed to continue reading on FATAL returns. Otherwise
|
||||||
|
// crashes and other UB is possible. Assume calling the close/free functions is
|
||||||
|
// still ok. Return true if it was fatal and the archive was closed.
|
||||||
|
static bool mp_archive_check_fatal(struct mp_archive *mpa, int r)
|
||||||
|
{
|
||||||
|
if (r > ARCHIVE_FATAL)
|
||||||
|
return false;
|
||||||
|
MP_FATAL(mpa, "fatal error received - cllsing archive\n");
|
||||||
|
mp_archive_close(mpa);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mp_archive_free(struct mp_archive *mpa)
|
||||||
|
{
|
||||||
|
mp_archive_close(mpa);
|
||||||
talloc_free(mpa);
|
talloc_free(mpa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +292,9 @@ bool mp_archive_next_entry(struct mp_archive *mpa)
|
||||||
talloc_free(mpa->entry_filename);
|
talloc_free(mpa->entry_filename);
|
||||||
mpa->entry_filename = NULL;
|
mpa->entry_filename = NULL;
|
||||||
|
|
||||||
|
if (!mpa->arch)
|
||||||
|
return false;
|
||||||
|
|
||||||
while (!mp_cancel_test(mpa->primary_src->cancel)) {
|
while (!mp_cancel_test(mpa->primary_src->cancel)) {
|
||||||
struct archive_entry *entry;
|
struct archive_entry *entry;
|
||||||
int r = archive_read_next_header(mpa->arch, &entry);
|
int r = archive_read_next_header(mpa->arch, &entry);
|
||||||
|
@ -283,6 +304,7 @@ bool mp_archive_next_entry(struct mp_archive *mpa)
|
||||||
MP_ERR(mpa, "%s\n", archive_error_string(mpa->arch));
|
MP_ERR(mpa, "%s\n", archive_error_string(mpa->arch));
|
||||||
if (r < ARCHIVE_WARN) {
|
if (r < ARCHIVE_WARN) {
|
||||||
MP_FATAL(mpa, "could not read archive entry\n");
|
MP_FATAL(mpa, "could not read archive entry\n");
|
||||||
|
mp_archive_check_fatal(mpa, r);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (archive_entry_filetype(entry) != AE_IFREG)
|
if (archive_entry_filetype(entry) != AE_IFREG)
|
||||||
|
@ -341,8 +363,13 @@ static int archive_entry_fill_buffer(stream_t *s, char *buffer, int max_len)
|
||||||
if (!p->mpa)
|
if (!p->mpa)
|
||||||
return 0;
|
return 0;
|
||||||
int r = archive_read_data(p->mpa->arch, buffer, max_len);
|
int r = archive_read_data(p->mpa->arch, buffer, max_len);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
MP_ERR(s, "%s\n", archive_error_string(p->mpa->arch));
|
MP_ERR(s, "%s\n", archive_error_string(p->mpa->arch));
|
||||||
|
if (mp_archive_check_fatal(p->mpa, r)) {
|
||||||
|
mp_archive_free(p->mpa);
|
||||||
|
p->mpa = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,8 +378,14 @@ static int archive_entry_seek(stream_t *s, int64_t newpos)
|
||||||
struct priv *p = s->priv;
|
struct priv *p = s->priv;
|
||||||
if (!p->mpa)
|
if (!p->mpa)
|
||||||
return -1;
|
return -1;
|
||||||
if (archive_seek_data(p->mpa->arch, newpos, SEEK_SET) >= 0)
|
int r = archive_seek_data(p->mpa->arch, newpos, SEEK_SET);
|
||||||
|
if (r >= 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
if (mp_archive_check_fatal(p->mpa, r)) {
|
||||||
|
mp_archive_free(p->mpa);
|
||||||
|
p->mpa = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
// libarchive can't seek in most formats.
|
// libarchive can't seek in most formats.
|
||||||
if (newpos < s->pos) {
|
if (newpos < s->pos) {
|
||||||
// Hack seeking backwards into working by reopening the archive and
|
// Hack seeking backwards into working by reopening the archive and
|
||||||
|
@ -371,9 +404,13 @@ static int archive_entry_seek(stream_t *s, int64_t newpos)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
int size = MPMIN(newpos - s->pos, sizeof(buffer));
|
int size = MPMIN(newpos - s->pos, sizeof(buffer));
|
||||||
int r = archive_read_data(p->mpa->arch, buffer, size);
|
r = archive_read_data(p->mpa->arch, buffer, size);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
MP_ERR(s, "%s\n", archive_error_string(p->mpa->arch));
|
MP_ERR(s, "%s\n", archive_error_string(p->mpa->arch));
|
||||||
|
if (mp_archive_check_fatal(p->mpa, r)) {
|
||||||
|
mp_archive_free(p->mpa);
|
||||||
|
p->mpa = NULL;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
s->pos += r;
|
s->pos += r;
|
||||||
|
|
Loading…
Reference in New Issue