summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-12-24 06:14:10 +0100
committerMartin Herkt <652892+lachs0r@users.noreply.github.com>2017-12-24 21:33:16 +0100
commitbf111f9c3cccf0a4aefb998558cce67f9b0d6d25 (patch)
tree4ebb8730857cf01611b8f7aceaf19cad4f3c1015
parent2a43060560a1c246943dccc77215542d6b507580 (diff)
downloadmpv-bf111f9c3cccf0a4aefb998558cce67f9b0d6d25.tar.bz2
mpv-bf111f9c3cccf0a4aefb998558cce67f9b0d6d25.tar.xz
stream_libarchive: fix seeking fallback
In commit 1199c1e3, we added checks to every libarchive API call to make sure the archive was closed on ARCHIVE_FATAL - otherwise, libarchive could endow us with free CVEs (such as it apparently happens when you continue reading a rar archive that uses features not yet supported by libarchive). This broke the fallback for seeking in unseekable archive formats. Of course libarchive won't tell us directly whether a format implementation has seek support or not - and OF COURSE it returns ARCHIVE_FATAL if it has no seek support. (The error string, which you can retrieve via API, is actually more detailed, and also claims it's an "internal error". I don't think so, libarchive.) Returning ARCHIVE_FATAL means we have to assume free CVEs are ahead, and we have to close the archive. Which breaks the fallback in a dumb way (we have no way of telling which of those cases happened anyway). Fix this by assuming that all seek errors are potentially due to lack of seek support. If the seek call fails, reopen the archive, and set a flag so the seek API is never tried again. (This means we can still skip ahead for forward seeks, which is more efficient than skipping from the start of the archive entry.) Also fix an old typo in an error message.
-rw-r--r--stream/stream_libarchive.c28
1 files changed, 14 insertions, 14 deletions
diff --git a/stream/stream_libarchive.c b/stream/stream_libarchive.c
index fdcc9c3ce2..2dddb45832 100644
--- a/stream/stream_libarchive.c
+++ b/stream/stream_libarchive.c
@@ -142,7 +142,7 @@ 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_FATAL(mpa, "fatal error received - closing archive\n");
mp_archive_close(mpa);
return true;
}
@@ -347,6 +347,7 @@ bool mp_archive_next_entry(struct mp_archive *mpa)
struct priv {
struct mp_archive *mpa;
+ bool broken_seek;
struct stream *src;
int64_t entry_size;
char *entry_name;
@@ -400,17 +401,16 @@ static int archive_entry_fill_buffer(stream_t *s, char *buffer, int max_len)
static int archive_entry_seek(stream_t *s, int64_t newpos)
{
struct priv *p = s->priv;
- if (!p->mpa)
- return -1;
- locale_t oldlocale = uselocale(p->mpa->locale);
- int r = archive_seek_data(p->mpa->arch, newpos, SEEK_SET);
- uselocale(oldlocale);
- if (r >= 0)
- return 1;
- if (mp_archive_check_fatal(p->mpa, r)) {
- mp_archive_free(p->mpa);
- p->mpa = NULL;
- return -1;
+ if (p->mpa && !p->broken_seek) {
+ locale_t oldlocale = uselocale(p->mpa->locale);
+ int r = archive_seek_data(p->mpa->arch, newpos, SEEK_SET);
+ uselocale(oldlocale);
+ if (r >= 0)
+ return 1;
+ MP_WARN(s, "possibly unsupported seeking - switching to reopening\n");
+ p->broken_seek = true;
+ if (reopen_archive(s) < STREAM_OK)
+ return -1;
}
// libarchive can't seek in most formats.
if (newpos < s->pos) {
@@ -430,8 +430,8 @@ static int archive_entry_seek(stream_t *s, int64_t newpos)
return -1;
int size = MPMIN(newpos - s->pos, sizeof(buffer));
- oldlocale = uselocale(p->mpa->locale);
- r = archive_read_data(p->mpa->arch, buffer, size);
+ locale_t oldlocale = uselocale(p->mpa->locale);
+ int r = archive_read_data(p->mpa->arch, buffer, size);
if (r < 0) {
MP_ERR(s, "%s\n", archive_error_string(p->mpa->arch));
uselocale(oldlocale);