93
84
should be exactly the same executables as release versions, but with different data that
94
85
automatically restricts where game media can come from to prevent add-ons from working.
96
After the paths are initialized, quake will look for the product.txt file. If not
97
found and verified, the game will run in restricted mode. In restricted mode, only
98
files contained in demoq3/pak0.pk3 will be available for loading, and only if the zip header is
99
verified to not have been modified. A single exception is made for q3config.cfg. Files
100
can still be written out in restricted mode, so screenshots and demos are allowed.
101
Restricted mode can be tested by setting "+set fs_restrict 1" on the command line, even
102
if there is a valid product.txt under the basepath or cdpath.
104
If not running in restricted mode, and a file is not found in any local filesystem,
105
an attempt will be made to download it and save it under the base path.
107
If the "fs_copyfiles" cvar is set to 1, then every time a file is sourced from the cd
108
path, it will be copied over to the base path. This is a development aid to help build
109
test releases and to copy working sets over slow network links.
111
87
File search order: when FS_FOpenFileRead gets called it will go through the fs_searchpaths
112
88
structure and stop on the first successful hit. fs_searchpaths is built with successive
113
89
calls to FS_AddGameDirectory
708
688
fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
709
689
fsh[f].handleSync = qfalse;
710
if (!fsh[f].handleFiles.file.o)
712
// NOTE TTimo on non *nix systems, fs_homepath == fs_basepath, might want to avoid
713
if (Q_stricmp(fs_homepath->string,fs_basepath->string))
716
ospath = FS_BuildOSPath( fs_basepath->string, filename, "" );
717
ospath[strlen(ospath)-1] = '\0';
719
if ( fs_debug->integer )
721
Com_Printf( "FS_SV_FOpenFileRead (fs_basepath): %s\n", ospath );
724
fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
725
fsh[f].handleSync = qfalse;
727
if ( !fsh[f].handleFiles.file.o )
734
if (!fsh[f].handleFiles.file.o) {
736
ospath = FS_BuildOSPath( fs_cdpath->string, filename, "" );
737
ospath[strlen(ospath)-1] = '\0';
739
if (fs_debug->integer)
741
Com_Printf( "FS_SV_FOpenFileRead (fs_cdpath) : %s\n", ospath );
744
fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
745
fsh[f].handleSync = qfalse;
747
if( !fsh[f].handleFiles.file.o ) {
690
if (!fsh[f].handleFiles.file.o)
692
// If fs_homepath == fs_basepath, don't bother
693
if (Q_stricmp(fs_homepath->string,fs_basepath->string))
696
ospath = FS_BuildOSPath( fs_basepath->string, filename, "" );
697
ospath[strlen(ospath)-1] = '\0';
699
if ( fs_debug->integer )
701
Com_Printf( "FS_SV_FOpenFileRead (fs_basepath): %s\n", ospath );
704
fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
705
fsh[f].handleSync = qfalse;
708
if ( !fsh[f].handleFiles.file.o )
754
716
return FS_filelength(f);
2084
2013
static unsigned int Sys_CountFileList(char **list)
2099
static char** Sys_ConcatenateFileLists( char **list0, char **list1, char **list2 )
2028
static char** Sys_ConcatenateFileLists( char **list0, char **list1 )
2101
int totalLength = 0;
2102
char** cat = NULL, **dst, **src;
2104
totalLength += Sys_CountFileList(list0);
2105
totalLength += Sys_CountFileList(list1);
2106
totalLength += Sys_CountFileList(list2);
2108
/* Create new list. */
2109
dst = cat = Z_Malloc( ( totalLength + 1 ) * sizeof( char* ) );
2111
/* Copy over lists. */
2114
for (src = list0; *src; src++, dst++)
2119
for (src = list1; *src; src++, dst++)
2124
for (src = list2; *src; src++, dst++)
2128
// Terminate the list
2131
// Free our old lists.
2132
// NOTE: not freeing their content, it's been merged in dst and still being used
2133
if (list0) Z_Free( list0 );
2134
if (list1) Z_Free( list1 );
2135
if (list2) Z_Free( list2 );
2030
int totalLength = 0;
2031
char** cat = NULL, **dst, **src;
2033
totalLength += Sys_CountFileList(list0);
2034
totalLength += Sys_CountFileList(list1);
2036
/* Create new list. */
2037
dst = cat = Z_Malloc( ( totalLength + 1 ) * sizeof( char* ) );
2039
/* Copy over lists. */
2042
for (src = list0; *src; src++, dst++)
2047
for (src = list1; *src; src++, dst++)
2051
// Terminate the list
2054
// Free our old lists.
2055
// NOTE: not freeing their content, it's been merged in dst and still being used
2056
if (list0) Z_Free( list0 );
2057
if (list1) Z_Free( list1 );
2147
2069
================
2149
2071
int FS_GetModList( char *listbuf, int bufsize ) {
2150
int nMods, i, j, nTotal, nLen, nPaks, nPotential, nDescLen;
2151
char **pFiles = NULL;
2152
char **pPaks = NULL;
2154
char descPath[MAX_OSPATH];
2155
fileHandle_t descHandle;
2158
char **pFiles0 = NULL;
2159
char **pFiles1 = NULL;
2160
char **pFiles2 = NULL;
2161
qboolean bDrop = qfalse;
2164
nMods = nPotential = nTotal = 0;
2166
pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue );
2167
pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue );
2168
pFiles2 = Sys_ListFiles( fs_cdpath->string, NULL, NULL, &dummy, qtrue );
2169
// we searched for mods in the three paths
2170
// it is likely that we have duplicate names now, which we will cleanup below
2171
pFiles = Sys_ConcatenateFileLists( pFiles0, pFiles1, pFiles2 );
2172
nPotential = Sys_CountFileList(pFiles);
2174
for ( i = 0 ; i < nPotential ; i++ ) {
2176
// NOTE: cleaner would involve more changes
2177
// ignore duplicate mod directories
2182
if (Q_stricmp(pFiles[j],name)==0) {
2183
// this one can be dropped
2192
// we drop "baseq3" "." and ".."
2193
if (Q_stricmp(name, BASEGAME) && Q_stricmpn(name, ".", 1)) {
2194
// now we need to find some .pk3 files to validate the mod
2195
// NOTE TTimo: (actually I'm not sure why .. what if it's a mod under developement with no .pk3?)
2196
// we didn't keep the information when we merged the directory names, as to what OS Path it was found under
2197
// so it could be in base path, cd path or home path
2198
// we will try each three of them here (yes, it's a bit messy)
2199
path = FS_BuildOSPath( fs_basepath->string, name, "" );
2201
pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, qfalse);
2202
Sys_FreeFileList( pPaks ); // we only use Sys_ListFiles to check wether .pk3 files are present
2204
/* Try on cd path */
2206
path = FS_BuildOSPath( fs_cdpath->string, name, "" );
2208
pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
2209
Sys_FreeFileList( pPaks );
2212
/* try on home path */
2215
path = FS_BuildOSPath( fs_homepath->string, name, "" );
2217
pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
2218
Sys_FreeFileList( pPaks );
2222
nLen = strlen(name) + 1;
2223
// nLen is the length of the mod path
2224
// we need to see if there is a description available
2226
strcpy(descPath, name);
2227
strcat(descPath, "/description.txt");
2228
nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle );
2229
if ( nDescLen > 0 && descHandle) {
2231
file = FS_FileForHandle(descHandle);
2232
Com_Memset( descPath, 0, sizeof( descPath ) );
2233
nDescLen = fread(descPath, 1, 48, file);
2234
if (nDescLen >= 0) {
2235
descPath[nDescLen] = '\0';
2237
FS_FCloseFile(descHandle);
2239
strcpy(descPath, name);
2241
nDescLen = strlen(descPath) + 1;
2243
if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) {
2244
strcpy(listbuf, name);
2246
strcpy(listbuf, descPath);
2247
listbuf += nDescLen;
2248
nTotal += nLen + nDescLen;
2257
Sys_FreeFileList( pFiles );
2072
int nMods, i, j, nTotal, nLen, nPaks, nPotential, nDescLen;
2073
char **pFiles = NULL;
2074
char **pPaks = NULL;
2076
char descPath[MAX_OSPATH];
2077
fileHandle_t descHandle;
2080
char **pFiles0 = NULL;
2081
char **pFiles1 = NULL;
2082
qboolean bDrop = qfalse;
2085
nMods = nPotential = nTotal = 0;
2087
pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue );
2088
pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue );
2089
// we searched for mods in the three paths
2090
// it is likely that we have duplicate names now, which we will cleanup below
2091
pFiles = Sys_ConcatenateFileLists( pFiles0, pFiles1 );
2092
nPotential = Sys_CountFileList(pFiles);
2094
for ( i = 0 ; i < nPotential ; i++ ) {
2096
// NOTE: cleaner would involve more changes
2097
// ignore duplicate mod directories
2102
if (Q_stricmp(pFiles[j],name)==0) {
2103
// this one can be dropped
2112
// we drop "baseq3" "." and ".."
2113
if (Q_stricmp(name, BASEGAME) && Q_stricmpn(name, ".", 1)) {
2114
// now we need to find some .pk3 files to validate the mod
2115
// NOTE TTimo: (actually I'm not sure why .. what if it's a mod under developement with no .pk3?)
2116
// we didn't keep the information when we merged the directory names, as to what OS Path it was found under
2117
// so it could be in base path, cd path or home path
2118
// we will try each three of them here (yes, it's a bit messy)
2119
path = FS_BuildOSPath( fs_basepath->string, name, "" );
2121
pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, qfalse);
2122
Sys_FreeFileList( pPaks ); // we only use Sys_ListFiles to check wether .pk3 files are present
2124
/* try on home path */
2127
path = FS_BuildOSPath( fs_homepath->string, name, "" );
2129
pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
2130
Sys_FreeFileList( pPaks );
2134
nLen = strlen(name) + 1;
2135
// nLen is the length of the mod path
2136
// we need to see if there is a description available
2138
strcpy(descPath, name);
2139
strcat(descPath, "/description.txt");
2140
nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle );
2141
if ( nDescLen > 0 && descHandle) {
2143
file = FS_FileForHandle(descHandle);
2144
Com_Memset( descPath, 0, sizeof( descPath ) );
2145
nDescLen = fread(descPath, 1, 48, file);
2146
if (nDescLen >= 0) {
2147
descPath[nDescLen] = '\0';
2149
FS_FCloseFile(descHandle);
2151
strcpy(descPath, name);
2153
nDescLen = strlen(descPath) + 1;
2155
if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) {
2156
strcpy(listbuf, name);
2158
strcpy(listbuf, descPath);
2159
listbuf += nDescLen;
2160
nTotal += nLen + nDescLen;
2169
Sys_FreeFileList( pFiles );
2647
2555
if ( !havepak && fs_serverReferencedPakNames[i] && *fs_serverReferencedPakNames[i] ) {
2648
2556
// Don't got it
2652
// We need this to make sure we won't hit the end of the buffer or the server could
2653
// overwrite non-pk3 files on clients by writing so much crap into neededpaks that
2654
// Q_strcat cuts off the .pk3 extension.
2656
origpos += strlen(origpos);
2659
Q_strcat( neededpaks, len, "@");
2660
Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
2661
Q_strcat( neededpaks, len, ".pk3" );
2664
Q_strcat( neededpaks, len, "@");
2665
// Do we have one with the same name?
2666
if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
2669
// We already have one called this, we need to download it to another name
2670
// Make something up with the checksum in it
2671
Com_sprintf( st, sizeof( st ), "%s.%08x.pk3", fs_serverReferencedPakNames[i], fs_serverReferencedPaks[i] );
2672
Q_strcat( neededpaks, len, st );
2675
Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
2676
Q_strcat( neededpaks, len, ".pk3" );
2679
// Find out whether it might have overflowed the buffer and don't add this file to the
2680
// list if that is the case.
2681
if(strlen(origpos) + (origpos - neededpaks) >= len - 1)
2689
Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
2690
Q_strcat( neededpaks, len, ".pk3" );
2691
// Do we have one with the same name?
2692
if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
2694
Q_strcat( neededpaks, len, " (local file exists with wrong checksum)");
2696
Q_strcat( neededpaks, len, "\n");
2560
// We need this to make sure we won't hit the end of the buffer or the server could
2561
// overwrite non-pk3 files on clients by writing so much crap into neededpaks that
2562
// Q_strcat cuts off the .pk3 extension.
2564
origpos += strlen(origpos);
2567
Q_strcat( neededpaks, len, "@");
2568
Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
2569
Q_strcat( neededpaks, len, ".pk3" );
2572
Q_strcat( neededpaks, len, "@");
2573
// Do we have one with the same name?
2574
if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
2577
// We already have one called this, we need to download it to another name
2578
// Make something up with the checksum in it
2579
Com_sprintf( st, sizeof( st ), "%s.%08x.pk3", fs_serverReferencedPakNames[i], fs_serverReferencedPaks[i] );
2580
Q_strcat( neededpaks, len, st );
2584
Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
2585
Q_strcat( neededpaks, len, ".pk3" );
2588
// Find out whether it might have overflowed the buffer and don't add this file to the
2589
// list if that is the case.
2590
if(strlen(origpos) + (origpos - neededpaks) >= len - 1)
2598
Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
2599
Q_strcat( neededpaks, len, ".pk3" );
2600
// Do we have one with the same name?
2601
if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
2603
Q_strcat( neededpaks, len, " (local file exists with wrong checksum)");
2605
Q_strcat( neededpaks, len, "\n");
2801
2710
================
2803
static void FS_Startup( const char *gameName ) {
2804
const char *homePath;
2712
static void FS_Startup( const char *gameName )
2714
const char *homePath;
2807
2717
Com_Printf( "----- FS_Startup -----\n" );
2809
2719
fs_debug = Cvar_Get( "fs_debug", "0", 0 );
2810
fs_copyfiles = Cvar_Get( "fs_copyfiles", "0", CVAR_INIT );
2811
fs_cdpath = Cvar_Get ("fs_cdpath", Sys_DefaultCDPath(), CVAR_INIT );
2812
2720
fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT );
2813
2721
fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_INIT );
2814
homePath = Sys_DefaultHomePath();
2815
if (!homePath || !homePath[0]) {
2722
homePath = Sys_DefaultHomePath();
2723
if (!homePath || !homePath[0]) {
2816
2724
homePath = fs_basepath->string;
2818
2726
fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT );
2819
2727
fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
2820
fs_restrict = Cvar_Get ("fs_restrict", "", CVAR_INIT );
2822
2729
// add search path elements in reverse priority order
2823
if (fs_cdpath->string[0]) {
2824
FS_AddGameDirectory( fs_cdpath->string, gameName );
2826
2730
if (fs_basepath->string[0]) {
2827
2731
FS_AddGameDirectory( fs_basepath->string, gameName );
2829
// fs_homepath is somewhat particular to *nix systems, only add if relevant
2830
// NOTE: same filtering below for mods and basegame
2831
if (fs_basepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {
2733
// fs_homepath is somewhat particular to *nix systems, only add if relevant
2736
fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT );
2737
// Make MacOSX also include the base path included with the .app bundle
2738
if (fs_apppath->string[0])
2739
FS_AddGameDirectory(fs_apppath->string, gameName);
2742
// NOTE: same filtering below for mods and basegame
2743
if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {
2832
2744
FS_AddGameDirectory ( fs_homepath->string, gameName );
2835
2747
// check for additional base game so mods can be based upon other mods
2836
2748
if ( fs_basegame->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_basegame->string, gameName ) ) {
2837
if (fs_cdpath->string[0]) {
2838
FS_AddGameDirectory(fs_cdpath->string, fs_basegame->string);
2840
2749
if (fs_basepath->string[0]) {
2841
2750
FS_AddGameDirectory(fs_basepath->string, fs_basegame->string);
3339
3255
// we have to specially handle this, because normal command
3340
3256
// line variable sets don't happen until after the filesystem
3341
3257
// has already been initialized
3342
Com_StartupVariable( "fs_cdpath" );
3343
3258
Com_StartupVariable( "fs_basepath" );
3344
3259
Com_StartupVariable( "fs_homepath" );
3345
3260
Com_StartupVariable( "fs_game" );
3346
Com_StartupVariable( "fs_copyfiles" );
3347
Com_StartupVariable( "fs_restrict" );
3349
3262
// try to start up normally
3350
3263
FS_Startup( BASEGAME );
3354
3267
// if we can't find default.cfg, assume that the paths are
3355
3268
// busted and error out now, rather than getting an unreadable
3356
3269
// graphics screen when the font fails to load
3357
3270
if ( FS_ReadFile( "default.cfg", NULL ) <= 0 ) {
3358
3271
Com_Error( ERR_FATAL, "Couldn't load default.cfg" );
3359
// bk001208 - SafeMode see below, FIXME?
3362
3274
Q_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase));
3363
3275
Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame));
3365
// bk001208 - SafeMode see below, FIXME?