Skip to content

Commit

Permalink
filesystem: load on-disk archives like PAK and PK3 through VFS (disk-…
Browse files Browse the repository at this point in the history
…only for now)

* Track from which archive the file has been opened and provide needed functions for it
  • Loading branch information
a1batross committed Jun 27, 2024
1 parent 64aa476 commit ec107df
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 135 deletions.
1 change: 1 addition & 0 deletions filesystem/android.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ static file_t *FS_OpenFile_AndroidAssets( searchpath_t *search, const char *file

file->position = 0;
file->ungetc = EOF;
file->searchpath = search;

AAsset_close( assets );

Expand Down
6 changes: 5 additions & 1 deletion filesystem/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,10 +457,14 @@ static int FS_FileTime_DIR( searchpath_t *search, const char *filename )

static file_t *FS_OpenFile_DIR( searchpath_t *search, const char *filename, const char *mode, int pack_ind )
{
file_t *f;
char path[MAX_SYSPATH];

Q_snprintf( path, sizeof( path ), "%s%s", search->filename, filename );
return FS_SysOpen( path, mode );
f = FS_SysOpen( path, mode );
f->searchpath = search;

return f;
}

void FS_InitDirectorySearchpath( searchpath_t *search, const char *path, int flags )
Expand Down
38 changes: 28 additions & 10 deletions filesystem/filesystem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1162,13 +1162,13 @@ void FS_AddGameHierarchy( const char *dir, uint flags )
if( COM_CheckStringEmpty( fs_rodir ) )
{
// append new flags to rodir, except FS_GAMEDIR_PATH and FS_CUSTOM_PATH
uint newFlags = FS_NOWRITE_PATH | (flags & (~FS_GAMEDIR_PATH|FS_CUSTOM_PATH));
uint new_flags = FS_NOWRITE_PATH | (flags & (~FS_GAMEDIR_PATH|FS_CUSTOM_PATH));
if( isGameDir )
newFlags |= FS_GAMERODIR_PATH;
SetBits( new_flags, FS_GAMERODIR_PATH );

FS_AllowDirectPaths( true );
Q_snprintf( buf, sizeof( buf ), "%s/%s/", fs_rodir, dir );
FS_AddGameDirectory( buf, newFlags );
FS_AddGameDirectory( buf, new_flags );
FS_AllowDirectPaths( false );
}

Expand Down Expand Up @@ -1226,7 +1226,7 @@ void FS_LoadGameInfo( const char *rootfolder )
int i;

// lock uplevel of gamedir for read\write
fs_ext_path = false;
FS_AllowDirectPaths( false );

if( rootfolder ) Q_strncpy( fs_gamedir, rootfolder, sizeof( fs_gamedir ));
Con_Reportf( "%s( %s )\n", __func__, fs_gamedir );
Expand Down Expand Up @@ -1312,7 +1312,7 @@ static qboolean FS_FindLibrary( const char *dllname, qboolean directpath, fs_dll
if( !COM_CheckString( dllname ))
return false;

fs_ext_path = directpath;
FS_AllowDirectPaths( directpath );

// HACKHACK remove relative path to game folder
if( !Q_strnicmp( dllname, "..", 2 ))
Expand Down Expand Up @@ -1344,7 +1344,7 @@ static qboolean FS_FindLibrary( const char *dllname, qboolean directpath, fs_dll
}
else if( !directpath )
{
fs_ext_path = false;
FS_AllowDirectPaths( false );

// trying check also 'bin' folder for indirect paths
search = FS_FindFile( dllname, &index, fixedname, sizeof( fixedname ), false );
Expand Down Expand Up @@ -1389,7 +1389,7 @@ static qboolean FS_FindLibrary( const char *dllname, qboolean directpath, fs_dll
dllInfo->custom_loader = false;
}
}
fs_ext_path = false; // always reset direct paths
FS_AllowDirectPaths( false ); // always reset direct paths

return true;
}
Expand Down Expand Up @@ -1704,7 +1704,7 @@ file_t *FS_SysOpen( const char *filepath, const char *mode )
return NULL;
}


file->searchpath = NULL;
file->real_length = lseek( file->handle, 0, SEEK_END );

// uncomment do disable write
Expand All @@ -1730,16 +1730,23 @@ static int FS_DuplicateHandle( const char *filename, int handle, fs_offset_t pos
}
*/

file_t *FS_OpenHandle( const char *syspath, int handle, fs_offset_t offset, fs_offset_t len )
file_t *FS_OpenHandle( searchpath_t *searchpath, int handle, fs_offset_t offset, fs_offset_t len )
{
file_t *file = (file_t *)Mem_Calloc( fs_mempool, sizeof( file_t ));
#ifndef XASH_REDUCE_FD
#ifdef HAVE_DUP
file->handle = dup( handle );
#else
file->handle = open( syspath, O_RDONLY|O_BINARY );
file->handle = open( searchpath->filename, O_RDONLY|O_BINARY );
#endif

if( file->handle < 0 )
{
Con_Printf( S_ERROR "%s: couldn't create fd for %s:0x%lx: %s\n", __func__, searchpath->filename, (long)offset, strerror( errno ));
Mem_Free( file );
return NULL;
}

if( lseek( file->handle, offset, SEEK_SET ) == -1 )
{
Mem_Free( file );
Expand All @@ -1757,6 +1764,7 @@ file_t *FS_OpenHandle( const char *syspath, int handle, fs_offset_t offset, fs_o
file->offset = offset;
file->position = 0;
file->ungetc = EOF;
file->searchpath = searchpath;

return file;
}
Expand Down Expand Up @@ -2333,6 +2341,8 @@ int FS_Gets( file_t *file, char *string, size_t bufsize )
FS_Seek
Move the position index in a file
NOTE: when porting code, check return value!
NOTE: it's not compatible with lseek!
====================
*/
int FS_Seek( file_t *file, fs_offset_t offset, int whence )
Expand Down Expand Up @@ -2913,6 +2923,14 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
return search;
}

static const char *FS_ArchivePath( file_t *f )
{
if( f->searchpath )
return f->searchpath->filename;

return "plain";
}

void FS_InitMemory( void )
{
fs_mempool = Mem_AllocPool( "FileSystem Pool" );
Expand Down
5 changes: 2 additions & 3 deletions filesystem/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,8 @@ typedef struct fs_api_t
qboolean (*SysFileExists)( const char *path );
const char *(*GetDiskPath)( const char *name, qboolean gamedironly );

// reserved
void (*Unused0)( void );
void *(*MountArchive_Fullpath)( const char *path, int flags );
const char *(*ArchivePath)( file_t *f ); // returns path to archive from which file was opened or "plain"
void *(*MountArchive_Fullpath)( const char *path, int flags ); // mounts the archive by path, if supported

qboolean (*GetFullDiskPath)( char *buffer, size_t size, const char *name, qboolean gamedironly );

Expand Down
38 changes: 19 additions & 19 deletions filesystem/filesystem_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,30 @@ extern "C"
{
#endif

typedef struct searchpath_s searchpath_t;
typedef struct dir_s dir_t;
typedef struct zip_s zip_t;
typedef struct pack_s pack_t;
typedef struct wfile_s wfile_t;
#if XASH_ANDROID
typedef struct android_assets_s android_assets_t;
// typedef struct android_saf_s android_saf_t;
#endif

#define FILE_BUFF_SIZE (2048)
#define FILE_BUFF_SIZE (2048)

struct file_s
{
int handle; // file descriptor
int ungetc; // single stored character from ungetc, cleared to EOF when read
fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode)
fs_offset_t position; // current position in the file
fs_offset_t offset; // offset into the package (0 if external file)
time_t filetime; // pak, wad or real filetime
// contents buffer
fs_offset_t buff_ind, buff_len; // buffer current index and length
byte buff[FILE_BUFF_SIZE]; // intermediate buffer
int handle; // file descriptor
int ungetc; // single stored character from ungetc, cleared to EOF when read
time_t filetime; // pak, wad or real filetime
searchpath_t *searchpath;
fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode)
fs_offset_t position; // current position in the file
fs_offset_t offset; // offset into the package (0 if external file)

// contents buffer
fs_offset_t buff_ind; // buffer current index
fs_offset_t buff_len; // buffer current length
byte buff[FILE_BUFF_SIZE]; // intermediate buffer

#ifdef XASH_REDUCE_FD
const char *backup_path;
fs_offset_t backup_position;
Expand Down Expand Up @@ -80,19 +82,17 @@ typedef struct stringlist_s

typedef struct searchpath_s
{
string filename;
searchpathtype_t type;
int flags;
string filename;
searchpathtype_t type;
int flags;

union
{
dir_t *dir;
pack_t *pack;
wfile_t *wad;
zip_t *zip;
#if XASH_ANDROID
android_assets_t *assets;
#endif
};

struct searchpath_s *next;
Expand Down Expand Up @@ -211,7 +211,7 @@ qboolean FS_SysFileOrFolderExists( const char *path );
file_t *FS_OpenReadFile( const char *filename, const char *mode, qboolean gamedironly );

int FS_SysFileTime( const char *filename );
file_t *FS_OpenHandle( const char *syspath, int handle, fs_offset_t offset, fs_offset_t len );
file_t *FS_OpenHandle( searchpath_t *search, int handle, fs_offset_t offset, fs_offset_t len );
file_t *FS_SysOpen( const char *filepath, const char *mode );
searchpath_t *FS_FindFile( const char *name, int *index, char *fixedname, size_t len, qboolean gamedironly );
qboolean FS_FullPathToRelativePath( char *dst, const char *src, size_t size );
Expand Down
40 changes: 21 additions & 19 deletions filesystem/pak.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@ typedef struct

struct pack_s
{
int handle;
file_t *handle;
int numfiles;
time_t filetime; // common for all packed files
dpackfile_t files[1]; // flexible
};

Expand Down Expand Up @@ -99,35 +98,37 @@ of the list so they override previous pack files.
static pack_t *FS_LoadPackPAK( const char *packfile, int *error )
{
dpackheader_t header;
int packhandle;
file_t *packhandle;
int numpackfiles;
pack_t *pack;
fs_size_t c;

packhandle = open( packfile, O_RDONLY|O_BINARY );
// TODO: use FS_Open to allow PK3 to be included into other archives
// Currently, it doesn't work with rodir due to FS_FindFile logic
packhandle = FS_SysOpen( packfile, "rb" );

if( packhandle < 0 )
if( packhandle == NULL )
{
Con_Reportf( "%s couldn't open: %s\n", packfile, strerror( errno ));
if( error ) *error = PAK_LOAD_COULDNT_OPEN;
return NULL;
}

c = read( packhandle, (void *)&header, sizeof( header ));
c = FS_Read( packhandle, (void *)&header, sizeof( header ));

if( c != sizeof( header ) || header.ident != IDPACKV1HEADER )
{
Con_Reportf( "%s is not a packfile. Ignored.\n", packfile );
if( error ) *error = PAK_LOAD_BAD_HEADER;
close( packhandle );
FS_Close( packhandle );
return NULL;
}

if( header.dirlen % sizeof( dpackfile_t ))
{
Con_Reportf( S_ERROR "%s has an invalid directory size. Ignored.\n", packfile );
if( error ) *error = PAK_LOAD_BAD_FOLDERS;
close( packhandle );
FS_Close( packhandle );
return NULL;
}

Expand All @@ -137,34 +138,33 @@ static pack_t *FS_LoadPackPAK( const char *packfile, int *error )
{
Con_Reportf( S_ERROR "%s has too many files ( %i ). Ignored.\n", packfile, numpackfiles );
if( error ) *error = PAK_LOAD_TOO_MANY_FILES;
close( packhandle );
FS_Close( packhandle );
return NULL;
}

if( numpackfiles <= 0 )
{
Con_Reportf( "%s has no files. Ignored.\n", packfile );
if( error ) *error = PAK_LOAD_NO_FILES;
close( packhandle );
FS_Close( packhandle );
return NULL;
}

pack = (pack_t *)Mem_Calloc( fs_mempool, sizeof( pack_t ) + sizeof( dpackfile_t ) * ( numpackfiles - 1 ));
lseek( packhandle, header.dirofs, SEEK_SET );
FS_Seek( packhandle, header.dirofs, SEEK_SET );

if( header.dirlen != read( packhandle, (void *)pack->files, header.dirlen ))
if( header.dirlen != FS_Read( packhandle, (void *)pack->files, header.dirlen ))
{
Con_Reportf( "%s is an incomplete PAK, not loading\n", packfile );
if( error )
*error = PAK_LOAD_CORRUPTED;
close( packhandle );
FS_Close( packhandle );
Mem_Free( pack );
return NULL;
}

// TODO: validate directory?

pack->filetime = FS_SysFileTime( packfile );
pack->handle = packhandle;
pack->numfiles = numpackfiles;
qsort( pack->files, pack->numfiles, sizeof( pack->files[0] ), FS_SortPak );
Expand Down Expand Up @@ -194,7 +194,7 @@ static file_t *FS_OpenFile_PAK( searchpath_t *search, const char *filename, cons

pfile = &search->pack->files[pack_ind];

return FS_OpenHandle( search->filename, search->pack->handle, pfile->filepos, pfile->filelen );
return FS_OpenHandle( search, search->pack->handle->handle, pfile->filepos, pfile->filelen );
}

/*
Expand Down Expand Up @@ -288,7 +288,7 @@ FS_FileTime_PAK
*/
static int FS_FileTime_PAK( searchpath_t *search, const char *filename )
{
return search->pack->filetime;
return search->pack->handle->filetime;
}

/*
Expand All @@ -299,7 +299,9 @@ FS_PrintInfo_PAK
*/
static void FS_PrintInfo_PAK( searchpath_t *search, char *dst, size_t size )
{
Q_snprintf( dst, size, "%s (%i files)", search->filename, search->pack->numfiles );
if( search->pack->handle->searchpath )
Q_snprintf( dst, size, "%s (%i files)" S_CYAN " from %s" S_DEFAULT, search->filename, search->pack->numfiles, search->pack->handle->searchpath->filename );
else Q_snprintf( dst, size, "%s (%i files)", search->filename, search->pack->numfiles );
}

/*
Expand All @@ -310,8 +312,8 @@ FS_Close_PAK
*/
static void FS_Close_PAK( searchpath_t *search )
{
if( search->pack->handle >= 0 )
close( search->pack->handle );
if( search->pack->handle != NULL )
FS_Close( search->pack->handle );
Mem_Free( search->pack );
}

Expand Down
4 changes: 3 additions & 1 deletion filesystem/wad.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,9 @@ FS_PrintInfo_WAD
*/
static void FS_PrintInfo_WAD( searchpath_t *search, char *dst, size_t size )
{
Q_snprintf( dst, size, "%s (%i files)", search->filename, search->wad->numlumps );
if( search->wad->handle->searchpath )
Q_snprintf( dst, size, "%s (%i files)" S_CYAN " from %s" S_DEFAULT, search->filename, search->wad->numlumps, search->wad->handle->searchpath->filename );
else Q_snprintf( dst, size, "%s (%i files)", search->filename, search->wad->numlumps );
}

/*
Expand Down
Loading

0 comments on commit ec107df

Please sign in to comment.