Skip to content

Commit

Permalink
Archivers can now specify whether an archive definitely was intended …
Browse files Browse the repository at this point in the history
…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."
  • Loading branch information
icculus committed Aug 14, 2017
1 parent 2a62153 commit 3078acd
Show file tree
Hide file tree
Showing 13 changed files with 95 additions and 42 deletions.
26 changes: 15 additions & 11 deletions src/physfs.c
Expand Up @@ -838,15 +838,15 @@ 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;

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));
Expand All @@ -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');
Expand All @@ -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 */

Expand Down
24 changes: 17 additions & 7 deletions src/physfs.h
Expand Up @@ -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).
Expand Down
11 changes: 10 additions & 1 deletion src/physfs_archiver_7z.c
Expand Up @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion src/physfs_archiver_dir.c
Expand Up @@ -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;
Expand All @@ -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);

Expand Down
5 changes: 4 additions & 1 deletion src/physfs_archiver_grp.c
Expand Up @@ -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;
Expand All @@ -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);

Expand Down
5 changes: 4 additions & 1 deletion src/physfs_archiver_hog.c
Expand Up @@ -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;
Expand All @@ -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);

Expand Down
17 changes: 10 additions & 7 deletions src/physfs_archiver_iso9660.c
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down
7 changes: 5 additions & 2 deletions src/physfs_archiver_mvl.c
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion src/physfs_archiver_qpak.c
Expand Up @@ -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;
Expand All @@ -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. */

Expand Down
5 changes: 4 additions & 1 deletion src/physfs_archiver_slb.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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 */

Expand Down
18 changes: 11 additions & 7 deletions src/physfs_archiver_vdf.c
Expand Up @@ -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];
Expand All @@ -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);
Expand All @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion src/physfs_archiver_wad.c
Expand Up @@ -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;
Expand All @@ -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);

Expand Down
5 changes: 4 additions & 1 deletion src/physfs_archiver_zip.c
Expand Up @@ -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;
Expand All @@ -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));
Expand Down

0 comments on commit 3078acd

Please sign in to comment.