Archivers can now specify whether an archive definitely was intended for them.

So if a zip file goes to the zip archiver but is corrupted, the system can now
know not to bother trying other archivers once the zip archiver has had a shot
at it, and just as important: it can report the real error from that archiver
instead of a generic "unsupported."
This commit is contained in:
Ryan C. Gordon 2017-08-14 02:28:00 -04:00
parent 2a6215394b
commit 3078acd1eb
13 changed files with 95 additions and 42 deletions

View File

@ -838,7 +838,7 @@ static const char *find_filename_extension(const char *fname)
static DirHandle *tryOpenDir(PHYSFS_Io *io, const PHYSFS_Archiver *funcs,
const char *d, int forWriting)
const char *d, int forWriting, int *_claimed)
{
DirHandle *retval = NULL;
void *opaque = NULL;
@ -846,7 +846,7 @@ static DirHandle *tryOpenDir(PHYSFS_Io *io, const PHYSFS_Archiver *funcs,
if (io != NULL)
BAIL_IF_ERRPASS(!io->seek(io, 0), NULL);
opaque = funcs->openArchive(io, d, forWriting);
opaque = funcs->openArchive(io, d, forWriting, _claimed);
if (opaque != NULL)
{
retval = (DirHandle *) allocator.Malloc(sizeof (DirHandle));
@ -871,14 +871,16 @@ static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting)
PHYSFS_Archiver **i;
const char *ext;
int created_io = 0;
int claimed = 0;
PHYSFS_ErrorCode errcode;
assert((io != NULL) || (d != NULL));
if (io == NULL)
{
/* DIR gets first shot (unlike the rest, it doesn't deal with files). */
retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting);
if (retval != NULL)
retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting, &claimed);
if (retval || claimed)
return retval;
io = __PHYSFS_createNativeIo(d, forWriting ? 'w' : 'r');
@ -890,30 +892,32 @@ static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting)
if (ext != NULL)
{
/* Look for archivers with matching file extensions first... */
for (i = archivers; (*i != NULL) && (retval == NULL); i++)
for (i = archivers; (*i != NULL) && (retval == NULL) && !claimed; i++)
{
if (PHYSFS_utf8stricmp(ext, (*i)->info.extension) == 0)
retval = tryOpenDir(io, *i, d, forWriting);
retval = tryOpenDir(io, *i, d, forWriting, &claimed);
} /* for */
/* failing an exact file extension match, try all the others... */
for (i = archivers; (*i != NULL) && (retval == NULL); i++)
for (i = archivers; (*i != NULL) && (retval == NULL) && !claimed; i++)
{
if (PHYSFS_utf8stricmp(ext, (*i)->info.extension) != 0)
retval = tryOpenDir(io, *i, d, forWriting);
retval = tryOpenDir(io, *i, d, forWriting, &claimed);
} /* for */
} /* if */
else /* no extension? Try them all. */
{
for (i = archivers; (*i != NULL) && (retval == NULL); i++)
retval = tryOpenDir(io, *i, d, forWriting);
for (i = archivers; (*i != NULL) && (retval == NULL) && !claimed; i++)
retval = tryOpenDir(io, *i, d, forWriting, &claimed);
} /* else */
errcode = currentErrorCode();
if ((!retval) && (created_io))
io->destroy(io);
BAIL_IF(!retval, PHYSFS_ERR_UNSUPPORTED, NULL);
BAIL_IF(!retval, claimed ? errcode : PHYSFS_ERR_UNSUPPORTED, NULL);
return retval;
} /* openDirectory */

View File

@ -3492,20 +3492,30 @@ typedef struct PHYSFS_Archiver
/**
* \brief Open an archive provided by (io).
*
* This is where resources are allocated and data is parsed when mounting an archive.
* (name) is a filename associated with (io), but doesn't necessarily
* This is where resources are allocated and data is parsed when mounting
* an archive.
* (name) is a filename associated with (io), but doesn't necessarily
* map to anything, let alone a real filename. This possibly-
* meaningless name is in platform-dependent notation.
* (forWrite) is non-zero if this is to be used for
* the write directory, and zero if this is to be used for an
* element of the search path.
* Return NULL on failure. We ignore any error code you set here;
* when PHYSFS_mount() returns, the error will be PHYSFS_ERR_UNSUPPORTED
* (no Archivers could handle this data). // !!! FIXME-3.0: yeah?
* Returns non-NULL on success. The pointer returned will be
* (claimed) should be set to 1 if this is definitely an archive your
* archiver implementation can handle, even if it fails. We use to
* decide if we should stop trying other archivers if you fail to open
* it. For example: the .zip archiver will set this to 1 for something
* that's got a .zip file signature, even if it failed because the file
* was also truncated. No sense in trying other archivers here, we
* already tried to handle it with the appropriate implementation!.
* Return NULL on failure and set (claimed) appropriately. If no archiver
* opened the archive or set (claimed), PHYSFS_mount() will report
* PHYSFS_ERR_UNSUPPORTED. Otherwise, it will report the error from the
* archiver that claimed the data through (claimed).
* Return non-NULL on success. The pointer returned will be
* passed as the "opaque" parameter for later calls.
*/
void *(*openArchive)(PHYSFS_Io *io, const char *name, int forWrite);
void *(*openArchive)(PHYSFS_Io *io, const char *name,
int forWrite, int *claimed);
/**
* \brief List all files in (dirname).

View File

@ -210,14 +210,23 @@ static void SZIP_closeArchive(void *opaque)
} /* SZIP_closeArchive */
static void *SZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
static void *SZIP_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed)
{
static const PHYSFS_uint8 wantedsig[] = { '7','z',0xBC,0xAF,0x27,0x1C };
SZIPLookToRead stream;
ISzAlloc *alloc = &SZIP_SzAlloc;
SZIPinfo *info = NULL;
SRes rc;
PHYSFS_uint8 sig[6];
PHYSFS_sint64 pos;
BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
pos = io->tell(io);
BAIL_IF_ERRPASS(pos == -1, NULL);
BAIL_IF_ERRPASS(io->read(io, sig, 6) != 6, NULL);
*claimed = (memcmp(sig, wantedsig, 6) == 0);
BAIL_IF_ERRPASS(!io->seek(io, pos), NULL);
info = (SZIPinfo *) allocator.Malloc(sizeof (SZIPinfo));
BAIL_IF(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);

View File

@ -37,7 +37,8 @@ static char *cvtToDependent(const char *prepend, const char *path,
static void *DIR_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
static void *DIR_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed)
{
PHYSFS_Stat st;
const char dirsep = __PHYSFS_platformDirSeparator;
@ -50,6 +51,7 @@ static void *DIR_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
if (st.filetype != PHYSFS_FILETYPE_DIRECTORY)
BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
*claimed = 1;
retval = allocator.Malloc(namelen + seplen + 1);
BAIL_IF(retval == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);

View File

@ -56,7 +56,8 @@ static int grpLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
} /* grpLoadEntries */
static void *GRP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
static void *GRP_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed)
{
PHYSFS_uint8 buf[12];
PHYSFS_uint32 count = 0;
@ -70,6 +71,8 @@ static void *GRP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
if (memcmp(buf, "KenSilverman", sizeof (buf)) != 0)
BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
*claimed = 1;
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL);
count = PHYSFS_swapULE32(count);

View File

@ -61,7 +61,8 @@ static int hogLoadEntries(PHYSFS_Io *io, void *arc)
} /* hogLoadEntries */
static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
static void *HOG_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed)
{
PHYSFS_uint8 buf[3];
void *unpkarc = NULL;
@ -71,6 +72,8 @@ static void *HOG_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, 3), NULL);
BAIL_IF(memcmp(buf, "DHF", 3) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
*claimed = 1;
unpkarc = UNPK_openArchive(io);
BAIL_IF_ERRPASS(!unpkarc, NULL);

View File

@ -215,11 +215,11 @@ static int iso9660LoadEntries(PHYSFS_Io *io, const int joliet,
static int parseVolumeDescriptor(PHYSFS_Io *io, PHYSFS_uint64 *_rootpos,
PHYSFS_uint64 *_rootlen, int *_joliet)
PHYSFS_uint64 *_rootlen, int *_joliet,
int *_claimed)
{
PHYSFS_uint64 pos = 32768; /* start at the Primary Volume Descriptor */
int found = 0;
int first = 1;
int done = 0;
*_joliet = 0;
@ -242,13 +242,13 @@ static int parseVolumeDescriptor(PHYSFS_Io *io, PHYSFS_uint64 *_rootpos,
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &type, 1), 0);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &identifier, 5), 0);
if (memcmp(identifier, "CD001", 5) != 0)
if (memcmp(identifier, "CD001", 5) != 0) /* maybe not an iso? */
{
BAIL_IF(first, PHYSFS_ERR_UNSUPPORTED, 0); /* maybe not an iso? */
BAIL_IF(!*_claimed, PHYSFS_ERR_UNSUPPORTED, 0);
continue; /* just skip this one */
} /* if */
first = 0; /* okay, this is probably an iso. */
*_claimed = 1; /* okay, this is probably an iso. */
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &version, 1), 0); /* version */
BAIL_IF(version != 1, PHYSFS_ERR_UNSUPPORTED, 0);
@ -320,7 +320,8 @@ static int parseVolumeDescriptor(PHYSFS_Io *io, PHYSFS_uint64 *_rootpos,
} /* parseVolumeDescriptor */
static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename, int forWriting)
static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename,
int forWriting, int *claimed)
{
PHYSFS_uint64 rootpos = 0;
PHYSFS_uint64 len = 0;
@ -330,7 +331,9 @@ static void *ISO9660_openArchive(PHYSFS_Io *io, const char *filename, int forWri
assert(io != NULL); /* shouldn't ever happen. */
BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
BAIL_IF_ERRPASS(!parseVolumeDescriptor(io, &rootpos, &len, &joliet), NULL);
if (!parseVolumeDescriptor(io, &rootpos, &len, &joliet, claimed))
return NULL;
unpkarc = UNPK_openArchive(io);
BAIL_IF_ERRPASS(!unpkarc, NULL);

View File

@ -53,7 +53,8 @@ static int mvlLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
} /* mvlLoadEntries */
static void *MVL_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
static void *MVL_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed)
{
PHYSFS_uint8 buf[4];
PHYSFS_uint32 count = 0;
@ -63,8 +64,10 @@ static void *MVL_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, buf, 4), NULL);
BAIL_IF(memcmp(buf, "DMVL", 4) != 0, PHYSFS_ERR_UNSUPPORTED, NULL);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL);
*claimed = 1;
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof(count)), NULL);
count = PHYSFS_swapULE32(count);
unpkarc = UNPK_openArchive(io);

View File

@ -56,7 +56,8 @@ static int qpakLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
} /* qpakLoadEntries */
static void *QPAK_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
static void *QPAK_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed)
{
PHYSFS_uint32 val = 0;
PHYSFS_uint32 pos = 0;
@ -71,6 +72,8 @@ static void *QPAK_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
if (PHYSFS_swapULE32(val) != QPAK_SIG)
BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
*claimed = 1;
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &val, 4), NULL);
pos = PHYSFS_swapULE32(val); /* directory table offset. */

View File

@ -59,7 +59,8 @@ static int slbLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
} /* slbLoadEntries */
static void *SLB_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
static void *SLB_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed)
{
PHYSFS_uint32 version;
PHYSFS_uint32 count;
@ -102,6 +103,8 @@ static void *SLB_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
return NULL;
} /* if */
*claimed = 1; /* oh well. */
return unpkarc;
} /* SLB_openArchive */

View File

@ -91,7 +91,8 @@ static int vdfLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count,
} /* vdfLoadEntries */
static void *VDF_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
static void *VDF_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed)
{
PHYSFS_uint8 ignore[16];
PHYSFS_uint8 sig[VDF_SIGNATURE_LENGTH];
@ -106,6 +107,15 @@ static void *VDF_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
BAIL_IF_ERRPASS(!io->seek(io, VDF_COMMENT_LENGTH), NULL);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, sig, sizeof (sig)), NULL);
if ((memcmp(sig, VDF_SIGNATURE_G1, VDF_SIGNATURE_LENGTH) != 0) &&
(memcmp(sig, VDF_SIGNATURE_G2, VDF_SIGNATURE_LENGTH) != 0))
{
BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
} /* if */
*claimed = 1;
BAIL_IF_ERRPASS(!readui32(io, &count), NULL);
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, ignore, 4), NULL); /* numFiles */
BAIL_IF_ERRPASS(!readui32(io, &timestamp), NULL);
@ -115,12 +125,6 @@ static void *VDF_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
BAIL_IF(version != 0x50, PHYSFS_ERR_UNSUPPORTED, NULL);
if ((memcmp(sig, VDF_SIGNATURE_G1, VDF_SIGNATURE_LENGTH) != 0) &&
(memcmp(sig, VDF_SIGNATURE_G2, VDF_SIGNATURE_LENGTH) != 0))
{
BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
} /* if */
BAIL_IF_ERRPASS(!io->seek(io, rootCatOffset), NULL);
unpkarc = UNPK_openArchive(io);

View File

@ -70,7 +70,8 @@ static int wadLoadEntries(PHYSFS_Io *io, const PHYSFS_uint32 count, void *arc)
} /* wadLoadEntries */
static void *WAD_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
static void *WAD_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed)
{
PHYSFS_uint8 buf[4];
PHYSFS_uint32 count;
@ -84,6 +85,8 @@ static void *WAD_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
if ((memcmp(buf, "IWAD", 4) != 0) && (memcmp(buf, "PWAD", 4) != 0))
BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
*claimed = 1;
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &count, sizeof (count)), NULL);
count = PHYSFS_swapULE32(count);

View File

@ -1451,7 +1451,8 @@ static void ZIP_closeArchive(void *opaque)
} /* ZIP_closeArchive */
static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
static void *ZIP_openArchive(PHYSFS_Io *io, const char *name,
int forWriting, int *claimed)
{
ZIPinfo *info = NULL;
ZIPentry *root = NULL;
@ -1464,6 +1465,8 @@ static void *ZIP_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
BAIL_IF(forWriting, PHYSFS_ERR_READ_ONLY, NULL);
BAIL_IF_ERRPASS(!isZip(io), NULL);
*claimed = 1;
info = (ZIPinfo *) allocator.Malloc(sizeof (ZIPinfo));
BAIL_IF(!info, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
memset(info, '\0', sizeof (ZIPinfo));