From e826e5f176f21cd18b3bbc22887a266835ada57c Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 29 Jun 2008 12:32:32 +0000 Subject: Added client and server side support for 32-bit solids. New R1Q2 and Q2PRO minor protocol versions, 1905 and 1014. Use environment variables for game and server features negotiation. Relax restrictions on quake paths when searching inside pak files. Made OSS subsystem cvar names consistent with core sound system conventions. Misc latched cvar handling changes. --- source/files.c | 2533 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 1307 insertions(+), 1226 deletions(-) (limited to 'source/files.c') diff --git a/source/files.c b/source/files.c index b6a8871..120d564 100644 --- a/source/files.c +++ b/source/files.c @@ -39,8 +39,8 @@ QUAKE FILESYSTEM ============================================================================= */ -#define MAX_FILES_IN_PK2 0x4000 -#define MAX_FILE_HANDLES 8 +#define MAX_FILES_IN_PK2 0x4000 +#define MAX_FILE_HANDLES 8 // macros for dealing portably with files at OS level #ifdef _WIN32 @@ -51,8 +51,8 @@ QUAKE FILESYSTEM #define FS_strncmp strncmp #endif -#define MAX_READ 0x40000 // read in blocks of 256k -#define MAX_WRITE 0x40000 // write in blocks of 256k +#define MAX_READ 0x40000 // read in blocks of 256k +#define MAX_WRITE 0x40000 // write in blocks of 256k // @@ -60,54 +60,54 @@ QUAKE FILESYSTEM // typedef struct packfile_s { - char *name; - size_t filepos; - size_t filelen; + char *name; + size_t filepos; + size_t filelen; - struct packfile_s *hashNext; + struct packfile_s *hashNext; } packfile_t; typedef struct pack_s { #if USE_ZLIB - unzFile zFile; + unzFile zFile; #endif - FILE *fp; - int numfiles; - packfile_t *files; - packfile_t **fileHash; - int hashSize; - char filename[1]; + FILE *fp; + int numfiles; + packfile_t *files; + packfile_t **fileHash; + int hashSize; + char filename[1]; } pack_t; typedef struct searchpath_s { - struct searchpath_s *next; + struct searchpath_s *next; int mode; - struct pack_s *pack; // only one of filename / pack will be used - char filename[1]; + struct pack_s *pack; // only one of filename / pack will be used + char filename[1]; } searchpath_t; typedef enum fsFileType_e { - FS_FREE, - FS_REAL, - FS_PAK, + FS_FREE, + FS_REAL, + FS_PAK, #if USE_ZLIB - FS_PK2, - FS_GZIP, + FS_PK2, + FS_GZIP, #endif - FS_BAD + FS_BAD } fsFileType_t; typedef struct fsFile_s { - char fullpath[MAX_OSPATH]; - fsFileType_t type; - unsigned mode; - FILE *fp; + char fullpath[MAX_OSPATH]; + fsFileType_t type; + unsigned mode; + FILE *fp; #if USE_ZLIB - void *zfp; + void *zfp; #endif - packfile_t *pak; - qboolean unique; - size_t length; + packfile_t *pak; + qboolean unique; + size_t length; } fsFile_t; typedef struct fsLink_s { @@ -118,26 +118,26 @@ typedef struct fsLink_s { } fsLink_t; // these point to user home directory -static char fs_gamedir[MAX_OSPATH]; -//static char fs_basedir[MAX_OSPATH]; +static char fs_gamedir[MAX_OSPATH]; +//static char fs_basedir[MAX_OSPATH]; -static cvar_t *fs_debug; -static cvar_t *fs_restrict_mask; +static cvar_t *fs_debug; +static cvar_t *fs_restrict_mask; -static searchpath_t *fs_searchpaths; -static searchpath_t *fs_base_searchpaths; +static searchpath_t *fs_searchpaths; +static searchpath_t *fs_base_searchpaths; static fsLink_t *fs_links; -static fsFile_t fs_files[MAX_FILE_HANDLES]; +static fsFile_t fs_files[MAX_FILE_HANDLES]; -static qboolean fs_fileFromPak; +static qboolean fs_fileFromPak; static int fs_count_read, fs_count_strcmp, fs_count_open; -cvar_t *fs_game; +cvar_t *fs_game; -fsAPI_t fs; +fsAPI_t fs; /* @@ -157,24 +157,74 @@ This is a precacution against having a malicious server instruct clients to writ */ +/* +================ +FS_pathcmp + +Portably compares quake paths +================ +*/ +static int FS_pathcmp( const char *s1, const char *s2 ) { + int c1, c2; + + do { + c1 = *s1++; + c2 = *s2++; + + if( c1 != c2 ) { + c1 = c1 == '\\' ? '/' : Q_tolower( c1 ); + c2 = c2 == '\\' ? '/' : Q_tolower( c2 ); + if( c1 < c2 ) + return -1; + if( c1 > c2 ) + return 1; /* strings not equal */ + } + } while( c1 ); + + return 0; /* strings are equal */ +} + +static int FS_pathcmpn( const char *s1, const char *s2, size_t n ) { + int c1, c2; + + do { + c1 = *s1++; + c2 = *s2++; + + if( !n-- ) + return 0; /* strings are equal until end point */ + + if( c1 != c2 ) { + c1 = c1 == '\\' ? '/' : Q_tolower( c1 ); + c2 = c2 == '\\' ? '/' : Q_tolower( c2 ); + if( c1 < c2 ) + return -1; + if( c1 > c2 ) + return 1; /* strings not equal */ + } + } while( c1 ); + + return 0; /* strings are equal */ +} + /* ================ FS_DPrintf ================ */ static void FS_DPrintf( char *format, ... ) { - va_list argptr; - char string[MAXPRINTMSG]; + va_list argptr; + char string[MAXPRINTMSG]; - if( !fs_debug || !fs_debug->integer ) { - return; - } + if( !fs_debug || !fs_debug->integer ) { + return; + } - va_start( argptr, format ); - Q_vsnprintf( string, sizeof( string ), format, argptr ); - va_end( argptr ); + va_start( argptr, format ); + Q_vsnprintf( string, sizeof( string ), format, argptr ); + va_end( argptr ); - Com_Printf( S_COLOR_CYAN "%s", string ); + Com_Printf( S_COLOR_CYAN "%s", string ); } /* @@ -183,21 +233,21 @@ FS_AllocHandle ================ */ static fsFile_t *FS_AllocHandle( fileHandle_t *f ) { - fsFile_t *file; - int i; + fsFile_t *file; + int i; - for( i = 0, file = fs_files; i < MAX_FILE_HANDLES; i++, file++ ) { - if( file->type == FS_FREE ) { - break; - } - } + for( i = 0, file = fs_files; i < MAX_FILE_HANDLES; i++, file++ ) { + if( file->type == FS_FREE ) { + break; + } + } - if( i == MAX_FILE_HANDLES ) { - Com_Error( ERR_FATAL, "%s: none free", __func__ ); - } + if( i == MAX_FILE_HANDLES ) { + Com_Error( ERR_FATAL, "%s: none free", __func__ ); + } - *f = i + 1; - return file; + *f = i + 1; + return file; } /* @@ -206,22 +256,22 @@ FS_FileForHandle ================ */ static fsFile_t *FS_FileForHandle( fileHandle_t f ) { - fsFile_t *file; + fsFile_t *file; - if( f <= 0 || f >= MAX_FILE_HANDLES + 1 ) { - Com_Error( ERR_FATAL, "%s: invalid handle: %i", __func__, f ); - } + if( f <= 0 || f >= MAX_FILE_HANDLES + 1 ) { + Com_Error( ERR_FATAL, "%s: invalid handle: %i", __func__, f ); + } - file = &fs_files[f - 1]; - if( file->type == FS_FREE ) { - Com_Error( ERR_FATAL, "%s: free handle: %i", __func__, f ); - } + file = &fs_files[f - 1]; + if( file->type == FS_FREE ) { + Com_Error( ERR_FATAL, "%s: free handle: %i", __func__, f ); + } - if( file->type < FS_FREE || file->type >= FS_BAD ) { - Com_Error( ERR_FATAL, "%s: invalid file type: %i", __func__, file->type ); - } + if( file->type < FS_FREE || file->type >= FS_BAD ) { + Com_Error( ERR_FATAL, "%s: invalid file type: %i", __func__, file->type ); + } - return file; + return file; } /* @@ -230,42 +280,42 @@ FS_ValidatePath ================ */ static qboolean FS_ValidatePath( const char *s ) { - const char *start; - - // check for leading slash - // check for empty path - if( *s == '/' || *s == '\\' /*|| *s == 0*/ ) { - return qfalse; - } - - start = s; - while( *s ) { - // check for ".." - if( *s == '.' && s[1] == '.' ) { - return qfalse; - } - if( *s == '/' || *s == '\\' ) { - // check for two slashes in a row - // check for trailing slash - if( ( s[1] == '/' || s[1] == '\\' || s[1] == 0 ) ) { - return qfalse; - } - } - if( *s == ':' ) { - // check for "X:\" - if( s[1] == '\\' || s[1] == '/' ) { - return qfalse; - } - } - s++; - } + const char *start; + + // check for leading slash + // check for empty path + if( *s == '/' || *s == '\\' /*|| *s == 0*/ ) { + return qfalse; + } + + start = s; + while( *s ) { + // check for ".." + if( *s == '.' && s[1] == '.' ) { + return qfalse; + } + if( *s == '/' || *s == '\\' ) { + // check for two slashes in a row + // check for trailing slash + if( ( s[1] == '/' || s[1] == '\\' || s[1] == 0 ) ) { + return qfalse; + } + } + if( *s == ':' ) { + // check for "X:\" + if( s[1] == '\\' || s[1] == '/' ) { + return qfalse; + } + } + s++; + } // check length - if( s - start > MAX_OSPATH ) { - return qfalse; - } + if( s - start > MAX_OSPATH ) { + return qfalse; + } - return qtrue; + return qtrue; } /* @@ -274,17 +324,17 @@ FS_ReplaceSeparators ================ */ char *FS_ReplaceSeparators( char *s, int separator ) { - char *p; + char *p; - p = s; - while( *p ) { - if( *p == '/' || *p == '\\' ) { - *p = separator; - } - p++; - } + p = s; + while( *p ) { + if( *p == '/' || *p == '\\' ) { + *p = separator; + } + p++; + } - return s; + return s; } @@ -298,32 +348,32 @@ Returns compressed length for GZIP files. ================ */ size_t FS_GetFileLength( fileHandle_t f ) { - fsFile_t *file = FS_FileForHandle( f ); + fsFile_t *file = FS_FileForHandle( f ); fsFileInfo_t info; - switch( file->type ) { - case FS_REAL: + switch( file->type ) { + case FS_REAL: if( !Sys_GetFileInfo( file->fp, &info ) ) { return INVALID_LENGTH; } - return info.size; - case FS_PAK: - return file->length; + return info.size; + case FS_PAK: + return file->length; #if USE_ZLIB - case FS_PK2: - return file->length; - case FS_GZIP: + case FS_PK2: + return file->length; + case FS_GZIP: return INVALID_LENGTH; #endif default: - Com_Error( ERR_FATAL, "%s: bad file type", __func__ ); - } + Com_Error( ERR_FATAL, "%s: bad file type", __func__ ); + } return INVALID_LENGTH; } const char *FS_GetFileFullPath( fileHandle_t f ) { - return ( FS_FileForHandle( f ) )->fullpath; + return ( FS_FileForHandle( f ) )->fullpath; } /* @@ -335,29 +385,29 @@ Expects a fully qualified quake path (i.e. with / separators). ============ */ void FS_CreatePath( const char *path ) { - char buffer[MAX_OSPATH]; - char *ofs; + char buffer[MAX_OSPATH]; + char *ofs; - Q_strncpyz( buffer, path, sizeof( buffer ) ); + Q_strncpyz( buffer, path, sizeof( buffer ) ); - FS_DPrintf( "%s: %s\n", __func__, buffer ); - - for( ofs = buffer + 1; *ofs; ofs++ ) { - if( *ofs == '/' ) { - // create the directory - *ofs = 0; - Sys_Mkdir( buffer ); - *ofs = '/'; - } - } + FS_DPrintf( "%s: %s\n", __func__, buffer ); + + for( ofs = buffer + 1; *ofs; ofs++ ) { + if( *ofs == '/' ) { + // create the directory + *ofs = 0; + Q_mkdir( buffer ); + *ofs = '/'; + } + } } qboolean FS_FilterFile( fileHandle_t f ) { #if USE_ZLIB - fsFile_t *file = FS_FileForHandle( f ); + fsFile_t *file = FS_FileForHandle( f ); int mode; char *modeStr; - void *zfp; + void *zfp; switch( file->type ) { case FS_GZIP: @@ -368,17 +418,17 @@ qboolean FS_FilterFile( fileHandle_t f ) { return qfalse; } - mode = file->mode & FS_MODE_MASK; - switch( mode ) { - case FS_MODE_READ: + mode = file->mode & FS_MODE_MASK; + switch( mode ) { + case FS_MODE_READ: modeStr = "rb"; break; - case FS_MODE_WRITE: - modeStr = "wb"; - break; - default: + case FS_MODE_WRITE: + modeStr = "wb"; + break; + default: return qfalse; - } + } fseek( file->fp, 0, SEEK_SET ); zfp = gzdopen( fileno( file->fp ), modeStr ); @@ -401,43 +451,43 @@ FS_FCloseFile ============== */ void FS_FCloseFile( fileHandle_t f ) { - fsFile_t *file = FS_FileForHandle( f ); - - FS_DPrintf( "%s: %s\n", __func__, file->fullpath ); - - switch( file->type ) { - case FS_REAL: - fclose( file->fp ); - break; - case FS_PAK: - if( file->unique ) { - fclose( file->fp ); - } - break; + fsFile_t *file = FS_FileForHandle( f ); + + FS_DPrintf( "%s: %s\n", __func__, file->fullpath ); + + switch( file->type ) { + case FS_REAL: + fclose( file->fp ); + break; + case FS_PAK: + if( file->unique ) { + fclose( file->fp ); + } + break; #if USE_ZLIB - case FS_GZIP: - gzclose( file->zfp ); - break; - case FS_PK2: - unzCloseCurrentFile( file->zfp ); - if( file->unique ) { - unzClose( file->zfp ); - } - break; + case FS_GZIP: + gzclose( file->zfp ); + break; + case FS_PK2: + unzCloseCurrentFile( file->zfp ); + if( file->unique ) { + unzClose( file->zfp ); + } + break; #endif - default: - break; - } + default: + break; + } - // don't clear name and mode, in case + // don't clear name and mode, in case // this handle will be reopened later - file->type = FS_FREE; - file->fp = NULL; + file->type = FS_FREE; + file->fp = NULL; #if USE_ZLIB - file->zfp = NULL; + file->zfp = NULL; #endif - file->pak = NULL; - file->unique = qfalse; + file->pak = NULL; + file->unique = qfalse; } /* @@ -446,49 +496,54 @@ FS_FOpenFileWrite ============ */ static size_t FS_FOpenFileWrite( fsFile_t *file, const char *name ) { - FILE *fp; - char *modeStr; - unsigned mode; + FILE *fp; + char *modeStr; + unsigned mode; - if( ( file->mode & FS_PATH_MASK ) == FS_PATH_BASE ) { + if( !FS_ValidatePath( name ) ) { + FS_DPrintf( "%s: refusing invalid path: %s\n", __func__, name ); + return INVALID_LENGTH; + } + + if( ( file->mode & FS_PATH_MASK ) == FS_PATH_BASE ) { if( sys_homedir->string[0] ) { - Q_concat( file->fullpath, sizeof( file->fullpath ), - sys_homedir->string, "/" BASEGAME "/", name, NULL ); + Q_concat( file->fullpath, sizeof( file->fullpath ), + sys_homedir->string, "/" BASEGAME "/", name, NULL ); } else { - Q_concat( file->fullpath, sizeof( file->fullpath ), - sys_basedir->string, "/" BASEGAME "/", name, NULL ); - } - } else { - Q_concat( file->fullpath, sizeof( file->fullpath ), - fs_gamedir, "/", name, NULL ); - } - - mode = file->mode & FS_MODE_MASK; - switch( mode ) { - case FS_MODE_APPEND: - modeStr = "ab"; - break; - case FS_MODE_WRITE: - modeStr = "wb"; - break; - case FS_MODE_RDWR: - modeStr = "r+b"; - break; - default: - Com_Error( ERR_FATAL, "%s: %s: invalid mode mask", + Q_concat( file->fullpath, sizeof( file->fullpath ), + sys_basedir->string, "/" BASEGAME "/", name, NULL ); + } + } else { + Q_concat( file->fullpath, sizeof( file->fullpath ), + fs_gamedir, "/", name, NULL ); + } + + mode = file->mode & FS_MODE_MASK; + switch( mode ) { + case FS_MODE_APPEND: + modeStr = "ab"; + break; + case FS_MODE_WRITE: + modeStr = "wb"; + break; + case FS_MODE_RDWR: + modeStr = "r+b"; + break; + default: + Com_Error( ERR_FATAL, "%s: %s: invalid mode mask", __func__, file->fullpath ); - modeStr = NULL; - break; - } + modeStr = NULL; + break; + } - FS_CreatePath( file->fullpath ); + FS_CreatePath( file->fullpath ); - fp = fopen( file->fullpath, modeStr ); - if( !fp ) { - FS_DPrintf( "%s: %s: fopen(%s): %s\n", - __func__, file->fullpath, modeStr, strerror( errno ) ); - return INVALID_LENGTH; - } + fp = fopen( file->fullpath, modeStr ); + if( !fp ) { + FS_DPrintf( "%s: %s: fopen(%s): %s\n", + __func__, file->fullpath, modeStr, strerror( errno ) ); + return INVALID_LENGTH; + } #ifdef __unix__ if( !Sys_GetFileInfo( fp, NULL ) ) { @@ -499,22 +554,88 @@ static size_t FS_FOpenFileWrite( fsFile_t *file, const char *name ) { } #endif - FS_DPrintf( "%s: %s: succeeded\n", __func__, file->fullpath ); + FS_DPrintf( "%s: %s: succeeded\n", __func__, file->fullpath ); + + file->fp = fp; + file->type = FS_REAL; + file->length = 0; + file->unique = qtrue; + + if( mode == FS_MODE_WRITE ) { + return 0; + } + + if( mode == FS_MODE_RDWR ) { + fseek( fp, 0, SEEK_END ); + } + + return ( size_t )ftell( fp ); +} + +static size_t FS_FOpenFromPak( fsFile_t *file, pack_t *pak, packfile_t *entry, qboolean unique ) { + // found it! + fs_fileFromPak = qtrue; + + Q_concat( file->fullpath, sizeof( file->fullpath ), + pak->filename, "/", entry->name, NULL ); + + // open a new file on the pakfile +#if USE_ZLIB + if( pak->zFile ) { + void *zfp; + + if( unique ) { + zfp = unzReOpen( pak->filename, pak->zFile ); + if( !zfp ) { + Com_Error( ERR_FATAL, "%s: couldn't reopen %s", + __func__, pak->filename ); + } + } else { + zfp = pak->zFile; + } + if( unzSetCurrentFileInfoPosition( zfp, entry->filepos ) == -1 ) { + Com_Error( ERR_FATAL, "%s: couldn't seek into %s", + __func__, pak->filename ); + } + if( unzOpenCurrentFile( zfp ) != UNZ_OK ) { + Com_Error( ERR_FATAL, "%s: couldn't open curfile from %s", + __func__, pak->filename ); + } + + file->zfp = zfp; + file->type = FS_PK2; + } else +#endif + { + FILE *fp; + + if( unique ) { + fp = fopen( pak->filename, "rb" ); + if( !fp ) { + Com_Error( ERR_FATAL, "%s: couldn't reopen %s", + __func__, pak->filename ); + } + } else { + fp = pak->fp; + } + + if( fseek( fp, entry->filepos, SEEK_SET ) == -1 ) { + Com_Error( ERR_FATAL, "%s: couldn't seek into %s", + __func__, pak->filename ); + } + + file->fp = fp; + file->type = FS_PAK; + } - file->fp = fp; - file->type = FS_REAL; - file->length = 0; - file->unique = qtrue; + file->pak = entry; + file->length = entry->filelen; + file->unique = unique; - if( mode == FS_MODE_WRITE ) { - return 0; - } + FS_DPrintf( "%s: %s/%s: succeeded\n", + __func__, pak->filename, entry->name ); - if( mode == FS_MODE_RDWR ) { - fseek( fp, 0, SEEK_END ); - } - - return ( size_t )ftell( fp ); + return file->length; } /* @@ -530,105 +651,65 @@ a seperate file. */ static size_t FS_FOpenFileRead( fsFile_t *file, const char *name, qboolean unique ) { searchpath_t *search; - pack_t *pak; - unsigned hash; - packfile_t *entry; - FILE *fp; + pack_t *pak; + unsigned hash; + packfile_t *entry; + FILE *fp; fsFileInfo_t info; + int valid = -1; - fs_fileFromPak = qfalse; + fs_fileFromPak = qfalse; fs_count_read++; // // search through the path, one element at a time // - hash = Com_HashPath( name, 0 ); - - for( search = fs_searchpaths; search; search = search->next ) { - if( file->mode & FS_PATH_MASK ) { - if( ( file->mode & search->mode & FS_PATH_MASK ) == 0 ) { - continue; - } - } - - // is the element a pak file? - if( search->pack ) { - if( ( file->mode & FS_TYPE_MASK ) == FS_TYPE_REAL ) { - continue; - } - // look through all the pak file elements - pak = search->pack; - entry = pak->fileHash[ hash & ( pak->hashSize - 1 ) ]; - for( ; entry; entry = entry->hashNext ) { - fs_count_strcmp++; - if( !Q_stricmp( entry->name, name ) ) { - // found it! - fs_fileFromPak = qtrue; - - Q_concat( file->fullpath, sizeof( file->fullpath ), pak->filename, "/", entry->name, NULL ); + hash = Com_HashPath( name, 0 ); - // open a new file on the pakfile -#if USE_ZLIB - if( pak->zFile ) { - void *zfp; - - if( unique ) { - zfp = unzReOpen( pak->filename, pak->zFile ); - if( !zfp ) { - Com_Error( ERR_FATAL, "%s: %s: unzReOpen failed", __func__, pak->filename ); - } - } else { - zfp = pak->zFile; - } - if( unzSetCurrentFileInfoPosition( zfp, entry->filepos ) == -1 ) { - Com_Error( ERR_FATAL, "%s: %s/%s: unzSetCurrentFileInfoPosition failed", __func__, pak->filename, entry->name ); - } - if( unzOpenCurrentFile( zfp ) != UNZ_OK ) { - Com_Error( ERR_FATAL, "%s: %s/%s: unzReOpen failed", __func__, pak->filename, entry->name ); - } - - file->zfp = zfp; - file->type = FS_PK2; - } else -#endif - { - if( unique ) { - fp = fopen( pak->filename, "rb" ); - if( !fp ) { - Com_Error( ERR_FATAL, "%s: couldn't reopen %s", __func__, pak->filename ); - } - } else { - fp = pak->fp; - } - - fseek( fp, entry->filepos, SEEK_SET ); - - file->fp = fp; - file->type = FS_PAK; - } - - file->pak = entry; - file->length = entry->filelen; - file->unique = unique; - - FS_DPrintf( "%s: %s/%s: succeeded\n", __func__, pak->filename, entry->name ); - - return file->length; - } - } - } else { - if( ( file->mode & FS_TYPE_MASK ) == FS_TYPE_PAK ) { - continue; - } - // check a file in the directory tree - Q_concat( file->fullpath, sizeof( file->fullpath ), - search->filename, "/", name, NULL ); + for( search = fs_searchpaths; search; search = search->next ) { + if( file->mode & FS_PATH_MASK ) { + if( ( file->mode & search->mode & FS_PATH_MASK ) == 0 ) { + continue; + } + } + + // is the element a pak file? + if( search->pack ) { + if( ( file->mode & FS_TYPE_MASK ) == FS_TYPE_REAL ) { + continue; + } + // look through all the pak file elements + pak = search->pack; + entry = pak->fileHash[ hash & ( pak->hashSize - 1 ) ]; + for( ; entry; entry = entry->hashNext ) { + fs_count_strcmp++; + if( !FS_pathcmp( entry->name, name ) ) { + return FS_FOpenFromPak( file, pak, entry, unique ); + } + } + } else { + if( ( file->mode & FS_TYPE_MASK ) == FS_TYPE_PAK ) { + continue; + } + if( valid == -1 ) { + if( !FS_ValidatePath( name ) ) { + FS_DPrintf( "%s: refusing invalid path: %s\n", + __func__, name ); + valid = 0; + } + } + if( valid == 0 ) { + continue; + } + // check a file in the directory tree + Q_concat( file->fullpath, sizeof( file->fullpath ), + search->filename, "/", name, NULL ); fs_count_open++; - fp = fopen( file->fullpath, "rb" ); - if( !fp ) { - continue; - } + fp = fopen( file->fullpath, "rb" ); + if( !fp ) { + continue; + } if( !Sys_GetFileInfo( fp, &info ) ) { FS_DPrintf( "%s: %s: couldn't get info\n", @@ -637,20 +718,20 @@ static size_t FS_FOpenFileRead( fsFile_t *file, const char *name, qboolean uniqu continue; } - file->fp = fp; - file->type = FS_REAL; - file->unique = qtrue; - file->length = info.size; + file->fp = fp; + file->type = FS_REAL; + file->unique = qtrue; + file->length = info.size; - FS_DPrintf( "%s: %s: succeeded\n", __func__, file->fullpath ); + FS_DPrintf( "%s: %s: succeeded\n", __func__, file->fullpath ); - return file->length; - } - } - - FS_DPrintf( "%s: %s: not found\n", __func__, name ); - - return INVALID_LENGTH; + return file->length; + } + } + + FS_DPrintf( "%s: %s: not found\n", __func__, name ); + + return INVALID_LENGTH; } /* @@ -659,7 +740,7 @@ FS_LastFileFromPak ================= */ qboolean FS_LastFileFromPak( void ) { - return fs_fileFromPak; + return fs_fileFromPak; } @@ -671,51 +752,51 @@ Properly handles partial reads ================= */ size_t FS_Read( void *buffer, size_t len, fileHandle_t hFile ) { - size_t block, remaining = len, read = 0; - byte *buf = (byte *)buffer; - fsFile_t *file = FS_FileForHandle( hFile ); - - // read in chunks for progress bar - while( remaining ) { - block = remaining; - if( block > MAX_READ ) - block = MAX_READ; - switch( file->type ) { - case FS_REAL: - case FS_PAK: - read = fread( buf, 1, block, file->fp ); - break; + size_t block, remaining = len, read = 0; + byte *buf = (byte *)buffer; + fsFile_t *file = FS_FileForHandle( hFile ); + + // read in chunks for progress bar + while( remaining ) { + block = remaining; + if( block > MAX_READ ) + block = MAX_READ; + switch( file->type ) { + case FS_REAL: + case FS_PAK: + read = fread( buf, 1, block, file->fp ); + break; #if USE_ZLIB - case FS_GZIP: - read = gzread( file->zfp, buf, block ); - break; - case FS_PK2: - read = unzReadCurrentFile( file->zfp, buf, block ); - break; + case FS_GZIP: + read = gzread( file->zfp, buf, block ); + break; + case FS_PK2: + read = unzReadCurrentFile( file->zfp, buf, block ); + break; #endif - default: - break; - } - if( read == 0 ) { - return len - remaining; - } - if( read > block ) { - Com_Error( ERR_FATAL, "FS_Read: %"PRIz" bytes read", read ); + default: + break; + } + if( read == 0 ) { + return len - remaining; + } + if( read > block ) { + Com_Error( ERR_FATAL, "FS_Read: %"PRIz" bytes read", read ); } - remaining -= read; - buf += read; - } + remaining -= read; + buf += read; + } - return len; + return len; } size_t FS_ReadLine( fileHandle_t f, char *buffer, int size ) { - fsFile_t *file = FS_FileForHandle( f ); + fsFile_t *file = FS_FileForHandle( f ); char *s; size_t len; - if( file->type != FS_REAL ) { + if( file->type != FS_REAL ) { return 0; } do { @@ -731,7 +812,7 @@ size_t FS_ReadLine( fileHandle_t f, char *buffer, int size ) { } void FS_Flush( fileHandle_t f ) { - fsFile_t *file = FS_FileForHandle( f ); + fsFile_t *file = FS_FileForHandle( f ); switch( file->type ) { case FS_REAL: @@ -755,55 +836,55 @@ Properly handles partial writes ================= */ size_t FS_Write( const void *buffer, size_t len, fileHandle_t hFile ) { - size_t block, remaining = len, write = 0; - byte *buf = (byte *)buffer; - fsFile_t *file = FS_FileForHandle( hFile ); - - // read in chunks for progress bar - while( remaining ) { - block = remaining; - if( block > MAX_WRITE ) - block = MAX_WRITE; - switch( file->type ) { - case FS_REAL: - write = fwrite( buf, 1, block, file->fp ); - break; + size_t block, remaining = len, write = 0; + byte *buf = (byte *)buffer; + fsFile_t *file = FS_FileForHandle( hFile ); + + // read in chunks for progress bar + while( remaining ) { + block = remaining; + if( block > MAX_WRITE ) + block = MAX_WRITE; + switch( file->type ) { + case FS_REAL: + write = fwrite( buf, 1, block, file->fp ); + break; #if USE_ZLIB - case FS_GZIP: - write = gzwrite( file->zfp, buf, block ); - break; + case FS_GZIP: + write = gzwrite( file->zfp, buf, block ); + break; #endif - default: - Com_Error( ERR_FATAL, "FS_Write: illegal file type" ); - break; - } - if( write == 0 ) { - return len - remaining; - } - if( write > block ) { - Com_Error( ERR_FATAL, "FS_Write: %"PRIz" bytes written", write ); - } - - remaining -= write; - buf += write; - } - - if( ( file->mode & FS_FLUSH_MASK ) == FS_FLUSH_SYNC ) { - switch( file->type ) { - case FS_REAL: - fflush( file->fp ); - break; + default: + Com_Error( ERR_FATAL, "FS_Write: illegal file type" ); + break; + } + if( write == 0 ) { + return len - remaining; + } + if( write > block ) { + Com_Error( ERR_FATAL, "FS_Write: %"PRIz" bytes written", write ); + } + + remaining -= write; + buf += write; + } + + if( ( file->mode & FS_FLUSH_MASK ) == FS_FLUSH_SYNC ) { + switch( file->type ) { + case FS_REAL: + fflush( file->fp ); + break; #if USE_ZLIB - case FS_GZIP: - gzflush( file->zfp, Z_SYNC_FLUSH ); - break; + case FS_GZIP: + gzflush( file->zfp, Z_SYNC_FLUSH ); + break; #endif - default: - break; - } - } + default: + break; + } + } - return len; + return len; } static char *FS_ExpandLinks( const char *filename ) { @@ -816,7 +897,7 @@ static char *FS_ExpandLinks( const char *filename ) { if( l->namelen > length ) { continue; } - if( !Q_stricmpn( l->name, filename, l->namelen ) ) { + if( !FS_pathcmpn( l->name, filename, l->namelen ) ) { if( l->targlen + length - l->namelen >= MAX_OSPATH ) { FS_DPrintf( "%s: %s: MAX_OSPATH exceeded\n", __func__, filename ); return ( char * )filename; @@ -838,19 +919,19 @@ FS_FOpenFile ============ */ size_t FS_FOpenFile( const char *name, fileHandle_t *f, int mode ) { - fsFile_t *file; - fileHandle_t hFile; - size_t ret = INVALID_LENGTH; + fsFile_t *file; + fileHandle_t hFile; + size_t ret = INVALID_LENGTH; - if( !name || !f ) { - Com_Error( ERR_FATAL, "FS_FOpenFile: NULL" ); - } + if( !name || !f ) { + Com_Error( ERR_FATAL, "%s: NULL", __func__ ); + } - *f = 0; + *f = 0; - if( !fs_searchpaths ) { - return ret; // not yet initialized - } + if( !fs_searchpaths ) { + return ret; // not yet initialized + } if( *name == '/' ) { name++; @@ -860,36 +941,31 @@ size_t FS_FOpenFile( const char *name, fileHandle_t *f, int mode ) { name = FS_ExpandLinks( name ); } - if( !FS_ValidatePath( name ) ) { - FS_DPrintf( "FS_FOpenFile: refusing invalid path: %s\n", name ); - return ret; - } + // allocate new file handle + file = FS_AllocHandle( &hFile ); + file->mode = mode; - // allocate new file handle - file = FS_AllocHandle( &hFile ); - file->mode = mode; - - mode &= FS_MODE_MASK; - switch( mode ) { - case FS_MODE_READ: - ret = FS_FOpenFileRead( file, name, qtrue ); - break; - case FS_MODE_WRITE: - case FS_MODE_APPEND: - case FS_MODE_RDWR: - ret = FS_FOpenFileWrite( file, name ); - break; - default: - Com_Error( ERR_FATAL, "FS_FOpenFile: illegal mode: %u", mode ); - break; - } + mode &= FS_MODE_MASK; + switch( mode ) { + case FS_MODE_READ: + ret = FS_FOpenFileRead( file, name, qtrue ); + break; + case FS_MODE_WRITE: + case FS_MODE_APPEND: + case FS_MODE_RDWR: + ret = FS_FOpenFileWrite( file, name ); + break; + default: + Com_Error( ERR_FATAL, "%s: illegal mode: %u", __func__, mode ); + break; + } - // if succeeded, store file handle - if( ret != -1 ) { - *f = hFile; - } + // if succeeded, store file handle + if( ret != -1 ) { + *f = hFile; + } - return ret; + return ret; } @@ -899,30 +975,30 @@ FS_Tell ============ */ int FS_Tell( fileHandle_t f ) { - fsFile_t *file = FS_FileForHandle( f ); - int length; - - switch( file->type ) { - case FS_REAL: - length = ftell( file->fp ); - break; - case FS_PAK: - length = ftell( file->fp ) - file->pak->filepos; - break; + fsFile_t *file = FS_FileForHandle( f ); + int length; + + switch( file->type ) { + case FS_REAL: + length = ftell( file->fp ); + break; + case FS_PAK: + length = ftell( file->fp ) - file->pak->filepos; + break; #if USE_ZLIB - case FS_GZIP: - length = gztell( file->zfp ); - break; - case FS_PK2: - length = unztell( file->zfp ); - break; + case FS_GZIP: + length = gztell( file->zfp ); + break; + case FS_PK2: + length = unztell( file->zfp ); + break; #endif - default: - length = -1; - break; - } + default: + length = -1; + break; + } - return length; + return length; } /* @@ -931,33 +1007,33 @@ FS_RawTell ============ */ int FS_RawTell( fileHandle_t f ) { - fsFile_t *file = FS_FileForHandle( f ); - int length; - - switch( file->type ) { - case FS_REAL: - length = ftell( file->fp ); - break; - case FS_PAK: - length = ftell( file->fp ) - file->pak->filepos; - break; + fsFile_t *file = FS_FileForHandle( f ); + int length; + + switch( file->type ) { + case FS_REAL: + length = ftell( file->fp ); + break; + case FS_PAK: + length = ftell( file->fp ) - file->pak->filepos; + break; #if USE_ZLIB - case FS_GZIP: - length = ftell( file->fp ); - break; - case FS_PK2: - length = unztell( file->zfp ); - break; + case FS_GZIP: + length = ftell( file->fp ); + break; + case FS_PK2: + length = unztell( file->zfp ); + break; #endif - default: - length = -1; - break; - } + default: + length = -1; + break; + } - return length; + return length; } -#define MAX_LOAD_BUFFER 0x100000 // 1 MiB +#define MAX_LOAD_BUFFER 0x100000 // 1 MiB // static buffer for small, stacked file loads and temp allocations // the last allocation may be easily undone @@ -980,22 +1056,22 @@ a null buffer will just return the file length without loading ============ */ size_t FS_LoadFileEx( const char *path, void **buffer, int flags, memtag_t tag ) { - fsFile_t *file; - fileHandle_t f; - byte *buf; - size_t len; + fsFile_t *file; + fileHandle_t f; + byte *buf; + size_t len; - if( !path ) { - Com_Error( ERR_FATAL, "FS_LoadFile: NULL" ); - } + if( !path ) { + Com_Error( ERR_FATAL, "%s: NULL", __func__ ); + } - if( buffer ) { - *buffer = NULL; - } + if( buffer ) { + *buffer = NULL; + } - if( !fs_searchpaths ) { - return INVALID_LENGTH; // not yet initialized - } + if( !fs_searchpaths ) { + return INVALID_LENGTH; // not yet initialized + } if( *path == '/' ) { path++; @@ -1003,23 +1079,18 @@ size_t FS_LoadFileEx( const char *path, void **buffer, int flags, memtag_t tag ) path = FS_ExpandLinks( path ); - if( !FS_ValidatePath( path ) ) { - FS_DPrintf( "FS_LoadFile: refusing invalid path: %s\n", path ); - return INVALID_LENGTH; - } + // allocate new file handle + file = FS_AllocHandle( &f ); + flags &= ~FS_MODE_MASK; + file->mode = flags | FS_MODE_READ; - // allocate new file handle - file = FS_AllocHandle( &f ); - flags &= ~FS_MODE_MASK; - file->mode = flags | FS_MODE_READ; - - // look for it in the filesystem or pack files - len = FS_FOpenFileRead( file, path, qfalse ); - if( len == INVALID_LENGTH ) { - return len; - } + // look for it in the filesystem or pack files + len = FS_FOpenFileRead( file, path, qfalse ); + if( len == INVALID_LENGTH ) { + return len; + } - if( buffer ) { + if( buffer ) { #if USE_ZLIB if( file->type == FS_GZIP ) { len = INVALID_LENGTH; // unknown length @@ -1035,7 +1106,7 @@ size_t FS_LoadFileEx( const char *path, void **buffer, int flags, memtag_t tag ) *buffer = buf; buf[len] = 0; } else { - Com_EPrintf( "FS_LoadFile: error reading file: %s\n", path ); + Com_EPrintf( "%s: error reading file: %s\n", __func__, path ); if( tag == TAG_FREE ) { FS_FreeFile( buf ); } else { @@ -1044,15 +1115,15 @@ size_t FS_LoadFileEx( const char *path, void **buffer, int flags, memtag_t tag ) len = INVALID_LENGTH; } } - } + } - FS_FCloseFile( f ); + FS_FCloseFile( f ); - return len; + return len; } size_t FS_LoadFile( const char *path, void **buffer ) { - return FS_LoadFileEx( path, buffer, 0, TAG_FREE ); + return FS_LoadFileEx( path, buffer, 0, TAG_FREE ); } void *FS_AllocTempMem( size_t length ) { @@ -1069,7 +1140,7 @@ void *FS_AllocTempMem( size_t length ) { } else { // Com_Printf(S_COLOR_MAGENTA"alloc %d\n",length); buf = FS_Malloc( length ); - loadCount++; + loadCount++; } return buf; } @@ -1080,24 +1151,24 @@ FS_FreeFile ============= */ void FS_FreeFile( void *buffer ) { - if( !buffer ) { - Com_Error( ERR_FATAL, "FS_FreeFile: NULL" ); - } - if( ( byte * )buffer >= loadBuffer && ( byte * )buffer < loadBuffer + MAX_LOAD_BUFFER ) { - if( loadStack == 0 ) { - Com_Error( ERR_FATAL, "FS_FreeFile: loadStack is zero" ); - } - loadStack--; - if( loadStack == 0 ) { - loadInuse = 0; + if( !buffer ) { + Com_Error( ERR_FATAL, "%s: NULL", __func__ ); + } + if( ( byte * )buffer >= loadBuffer && ( byte * )buffer < loadBuffer + MAX_LOAD_BUFFER ) { + if( loadStack == 0 ) { + Com_Error( ERR_FATAL, "%s: empty load stack", __func__ ); + } + loadStack--; + if( loadStack == 0 ) { + loadInuse = 0; // Com_Printf(S_COLOR_MAGENTA"clear\n"); - } else if( buffer == loadLast ) { + } else if( buffer == loadLast ) { loadInuse = loadSaved; // Com_Printf(S_COLOR_MAGENTA"partial\n"); } - } else { - Z_Free( buffer ); - } + } else { + Z_Free( buffer ); + } } /* @@ -1106,43 +1177,41 @@ FS_CopyFile ============= */ qboolean FS_CopyFile( const char *src, const char *dst ) { - fileHandle_t hSrc, hDst; - byte buffer[MAX_READ]; - size_t len, size; + fileHandle_t hSrc, hDst; + byte buffer[MAX_READ]; + size_t len, size; - FS_DPrintf( "FS_CopyFile( '%s', '%s' )\n", src, dst ); - - size = FS_FOpenFile( src, &hSrc, FS_MODE_READ ); - if( !hSrc ) { - return qfalse; - } + size = FS_FOpenFile( src, &hSrc, FS_MODE_READ ); + if( !hSrc ) { + return qfalse; + } - FS_FOpenFile( dst, &hDst, FS_MODE_WRITE ); - if( !hDst ) { - FS_FCloseFile( hSrc ); - return qfalse; - } + FS_FOpenFile( dst, &hDst, FS_MODE_WRITE ); + if( !hDst ) { + FS_FCloseFile( hSrc ); + return qfalse; + } - while( size ) { - len = size; - if( len > sizeof( buffer ) ) { - len = sizeof( buffer ); - } - if( !( len = FS_Read( buffer, len, hSrc ) ) ) { - break; - } - FS_Write( buffer, len, hDst ); - size -= len; - } + while( size ) { + len = size; + if( len > sizeof( buffer ) ) { + len = sizeof( buffer ); + } + if( !( len = FS_Read( buffer, len, hSrc ) ) ) { + break; + } + FS_Write( buffer, len, hDst ); + size -= len; + } - FS_FCloseFile( hSrc ); - FS_FCloseFile( hDst ); + FS_FCloseFile( hSrc ); + FS_FCloseFile( hDst ); - if( size ) { - return qfalse; - } + if( size ) { + return qfalse; + } - return qtrue; + return qtrue; } /* @@ -1151,25 +1220,25 @@ FS_RemoveFile ================ */ qboolean FS_RemoveFile( const char *filename ) { - char path[MAX_OSPATH]; + char path[MAX_OSPATH]; if( *filename == '/' ) { filename++; } - if( !FS_ValidatePath( filename ) ) { - FS_DPrintf( "FS_RemoveFile: refusing invalid path: %s\n", filename ); - return qfalse; - } + if( !FS_ValidatePath( filename ) ) { + FS_DPrintf( "%s: refusing invalid path: %s\n", __func__, filename ); + return qfalse; + } - Q_concat( path, sizeof( path ), fs_gamedir, "/", filename, NULL ); - //FS_ConvertToSysPath( path ); + Q_concat( path, sizeof( path ), fs_gamedir, "/", filename, NULL ); + //FS_ConvertToSysPath( path ); - if( !Sys_RemoveFile( path ) ) { - return qfalse; - } + if( Q_unlink( path ) ) { + return qfalse; + } - return qtrue; + return qtrue; } /* @@ -1178,8 +1247,8 @@ FS_RemoveFile ================ */ qboolean FS_RenameFile( const char *from, const char *to ) { - char frompath[MAX_OSPATH]; - char topath[MAX_OSPATH]; + char frompath[MAX_OSPATH]; + char topath[MAX_OSPATH]; if( *from == '/' ) { from++; @@ -1188,20 +1257,22 @@ qboolean FS_RenameFile( const char *from, const char *to ) { to++; } - if( !FS_ValidatePath( from ) || !FS_ValidatePath( to ) ) { - FS_DPrintf( "FS_RenameFile: refusing invalid path: %s to %s\n", from, to ); - return qfalse; - } + if( !FS_ValidatePath( from ) || !FS_ValidatePath( to ) ) { + FS_DPrintf( "%s: refusing invalid path: %s to %s\n", + __func__, from, to ); + return qfalse; + } - Q_concat( frompath, sizeof( frompath ), fs_gamedir, "/", from, NULL ); - Q_concat( topath, sizeof( topath ), fs_gamedir, "/", to, NULL ); + Q_concat( frompath, sizeof( frompath ), fs_gamedir, "/", from, NULL ); + Q_concat( topath, sizeof( topath ), fs_gamedir, "/", to, NULL ); - if( !Sys_RenameFile( frompath, topath ) ) { - FS_DPrintf( "FS_RenameFile: rename failed: %s to %s\n", frompath, topath ); - return qfalse; - } + if( rename( frompath, topath ) ) { + FS_DPrintf( "%s: rename failed: %s to %s\n", + __func__, frompath, topath ); + return qfalse; + } - return qtrue; + return qtrue; } /* @@ -1210,15 +1281,15 @@ FS_FPrintf ================ */ void FS_FPrintf( fileHandle_t f, const char *format, ... ) { - va_list argptr; - char string[MAXPRINTMSG]; - size_t len; + va_list argptr; + char string[MAXPRINTMSG]; + size_t len; - va_start( argptr, format ); - len = Q_vsnprintf( string, sizeof( string ), format, argptr ); - va_end( argptr ); + va_start( argptr, format ); + len = Q_vsnprintf( string, sizeof( string ), format, argptr ); + va_end( argptr ); - FS_Write( string, len, f ); + FS_Write( string, len, f ); } /* @@ -1232,114 +1303,114 @@ of the list so they override previous pack files. ================= */ static pack_t *FS_LoadPakFile( const char *packfile ) { - dpackheader_t header; - int i; - packfile_t *file; - dpackfile_t *dfile; - int numpackfiles; - char *names; - size_t namesLength; - pack_t *pack; - FILE *packhandle; - dpackfile_t info[MAX_FILES_IN_PACK]; - int hashSize; - unsigned hash; - size_t len; - - packhandle = fopen( packfile, "rb" ); - if( !packhandle ) { - Com_WPrintf( "Couldn't open %s\n", packfile ); - return NULL; - } - - if( fread( &header, 1, sizeof( header ), packhandle ) != sizeof( header ) ) { - Com_WPrintf( "Reading header failed on %s\n", packfile ); - goto fail; - } - - if( LittleLong( header.ident ) != IDPAKHEADER ) { - Com_WPrintf( "%s is not a 'PACK' file\n", packfile ); - goto fail; - } - - header.dirlen = LittleLong( header.dirlen ); - if( header.dirlen % sizeof( dpackfile_t ) ) { - Com_WPrintf( "%s has bad directory length\n", packfile ); - goto fail; - } - - numpackfiles = header.dirlen / sizeof( dpackfile_t ); - if( numpackfiles < 1 ) { - Com_WPrintf( "%s has bad number of files: %i\n", packfile, numpackfiles ); - goto fail; - } - if( numpackfiles > MAX_FILES_IN_PACK ) { - Com_WPrintf( "%s has too many files: %i > %i\n", packfile, numpackfiles, MAX_FILES_IN_PACK ); - goto fail; - } - - header.dirofs = LittleLong( header.dirofs ); - if( fseek( packhandle, header.dirofs, SEEK_SET ) ) { - Com_WPrintf( "Seeking to directory failed on %s\n", packfile ); - goto fail; - } - if( fread( info, 1, header.dirlen, packhandle ) != header.dirlen ) { - Com_WPrintf( "Reading directory failed on %s\n", packfile ); - goto fail; - } - - namesLength = 0; - for( i = 0, dfile = info; i < numpackfiles; i++, dfile++ ) { - dfile->name[sizeof( dfile->name ) - 1] = 0; - namesLength += strlen( dfile->name ) + 1; - } - - hashSize = Q_CeilPowerOfTwo( numpackfiles ); - if( hashSize > 32 ) { - hashSize >>= 1; - } - - len = strlen( packfile ); - len = ( len + 3 ) & ~3; - pack = FS_Malloc( sizeof( pack_t ) + - numpackfiles * sizeof( packfile_t ) + - hashSize * sizeof( packfile_t * ) + - namesLength + len ); - strcpy( pack->filename, packfile ); - pack->fp = packhandle; + dpackheader_t header; + int i; + packfile_t *file; + dpackfile_t *dfile; + int numpackfiles; + char *names; + size_t namesLength; + pack_t *pack; + FILE *packhandle; + dpackfile_t info[MAX_FILES_IN_PACK]; + int hashSize; + unsigned hash; + size_t len; + + packhandle = fopen( packfile, "rb" ); + if( !packhandle ) { + Com_WPrintf( "Couldn't open %s\n", packfile ); + return NULL; + } + + if( fread( &header, 1, sizeof( header ), packhandle ) != sizeof( header ) ) { + Com_WPrintf( "Reading header failed on %s\n", packfile ); + goto fail; + } + + if( LittleLong( header.ident ) != IDPAKHEADER ) { + Com_WPrintf( "%s is not a 'PACK' file\n", packfile ); + goto fail; + } + + header.dirlen = LittleLong( header.dirlen ); + if( header.dirlen % sizeof( dpackfile_t ) ) { + Com_WPrintf( "%s has bad directory length\n", packfile ); + goto fail; + } + + numpackfiles = header.dirlen / sizeof( dpackfile_t ); + if( numpackfiles < 1 ) { + Com_WPrintf( "%s has bad number of files: %i\n", packfile, numpackfiles ); + goto fail; + } + if( numpackfiles > MAX_FILES_IN_PACK ) { + Com_WPrintf( "%s has too many files: %i > %i\n", packfile, numpackfiles, MAX_FILES_IN_PACK ); + goto fail; + } + + header.dirofs = LittleLong( header.dirofs ); + if( fseek( packhandle, header.dirofs, SEEK_SET ) ) { + Com_WPrintf( "Seeking to directory failed on %s\n", packfile ); + goto fail; + } + if( fread( info, 1, header.dirlen, packhandle ) != header.dirlen ) { + Com_WPrintf( "Reading directory failed on %s\n", packfile ); + goto fail; + } + + namesLength = 0; + for( i = 0, dfile = info; i < numpackfiles; i++, dfile++ ) { + dfile->name[sizeof( dfile->name ) - 1] = 0; + namesLength += strlen( dfile->name ) + 1; + } + + hashSize = Q_CeilPowerOfTwo( numpackfiles ); + if( hashSize > 32 ) { + hashSize >>= 1; + } + + len = strlen( packfile ); + len = ( len + 3 ) & ~3; + pack = FS_Malloc( sizeof( pack_t ) + + numpackfiles * sizeof( packfile_t ) + + hashSize * sizeof( packfile_t * ) + + namesLength + len ); + strcpy( pack->filename, packfile ); + pack->fp = packhandle; #if USE_ZLIB - pack->zFile = NULL; + pack->zFile = NULL; #endif - pack->numfiles = numpackfiles; - pack->hashSize = hashSize; - pack->files = ( packfile_t * )( ( byte * )pack + sizeof( pack_t ) + len ); - pack->fileHash = ( packfile_t ** )( pack->files + numpackfiles ); - names = ( char * )( pack->fileHash + hashSize ); - memset( pack->fileHash, 0, hashSize * sizeof( packfile_t * ) ); + pack->numfiles = numpackfiles; + pack->hashSize = hashSize; + pack->files = ( packfile_t * )( ( byte * )pack + sizeof( pack_t ) + len ); + pack->fileHash = ( packfile_t ** )( pack->files + numpackfiles ); + names = ( char * )( pack->fileHash + hashSize ); + memset( pack->fileHash, 0, hashSize * sizeof( packfile_t * ) ); // parse the directory - for( i = 0, file = pack->files, dfile = info; i < pack->numfiles; i++, file++, dfile++ ) { - len = strlen( dfile->name ) + 1; + for( i = 0, file = pack->files, dfile = info; i < pack->numfiles; i++, file++, dfile++ ) { + len = strlen( dfile->name ) + 1; - file->name = memcpy( names, dfile->name, len ); - names += len; + file->name = memcpy( names, dfile->name, len ); + names += len; - file->filepos = LittleLong( dfile->filepos ); - file->filelen = LittleLong( dfile->filelen ); + file->filepos = LittleLong( dfile->filepos ); + file->filelen = LittleLong( dfile->filelen ); - hash = Com_HashPath( file->name, hashSize ); - file->hashNext = pack->fileHash[hash]; - pack->fileHash[hash] = file; - } + hash = Com_HashPath( file->name, hashSize ); + file->hashNext = pack->fileHash[hash]; + pack->fileHash[hash] = file; + } - FS_DPrintf( "%s: %d files, %d hash table entries\n", - packfile, numpackfiles, hashSize ); + FS_DPrintf( "%s: %d files, %d hash table entries\n", + packfile, numpackfiles, hashSize ); - return pack; + return pack; fail: - fclose( packhandle ); - return NULL; + fclose( packhandle ); + return NULL; } #if USE_ZLIB @@ -1349,110 +1420,110 @@ FS_LoadZipFile ================= */ static pack_t *FS_LoadZipFile( const char *packfile ) { - int i; - packfile_t *file; - char *names; - int numFiles; - pack_t *pack; - unzFile zFile; - unz_global_info zGlobalInfo; - unz_file_info zInfo; - char name[MAX_QPATH]; - size_t namesLength; - int hashSize; - unsigned hash; - size_t len; - - zFile = unzOpen( packfile ); - if( !zFile ) { - Com_WPrintf( "unzOpen() failed on %s\n", packfile ); - return NULL; - } - - if( unzGetGlobalInfo( zFile, &zGlobalInfo ) != UNZ_OK ) { - Com_WPrintf( "unzGetGlobalInfo() failed on %s\n", packfile ); - goto fail; - } - - numFiles = zGlobalInfo.number_entry; - if( numFiles > MAX_FILES_IN_PK2 ) { - Com_WPrintf( "%s has too many files, %i > %i\n", packfile, numFiles, MAX_FILES_IN_PK2 ); - goto fail; - } - - if( unzGoToFirstFile( zFile ) != UNZ_OK ) { - Com_WPrintf( "unzGoToFirstFile() failed on %s\n", packfile ); - goto fail; - } - - namesLength = 0; - for( i = 0; i < numFiles; i++ ) { - if( unzGetCurrentFileInfo( zFile, &zInfo, name, sizeof( name ), NULL, 0, NULL, 0 ) != UNZ_OK ) { - Com_WPrintf( "unzGetCurrentFileInfo() failed on %s\n", packfile ); - goto fail; - } - - namesLength += strlen( name ) + 1; - - if( i != numFiles - 1 && unzGoToNextFile( zFile ) != UNZ_OK ) { - Com_WPrintf( "unzGoToNextFile() failed on %s\n", packfile ); - - } - } - - hashSize = Q_CeilPowerOfTwo( numFiles ); - if( hashSize > 32 ) { - hashSize >>= 1; - } - - len = strlen( packfile ); - len = ( len + 3 ) & ~3; - pack = FS_Malloc( sizeof( pack_t ) + - numFiles * sizeof( packfile_t ) + - hashSize * sizeof( packfile_t * ) + - namesLength + len ); - strcpy( pack->filename, packfile ); - pack->zFile = zFile; - pack->fp = NULL; - pack->numfiles = numFiles; - pack->hashSize = hashSize; - pack->files = ( packfile_t * )( ( byte * )pack + sizeof( pack_t ) + len ); - pack->fileHash = ( packfile_t ** )( pack->files + numFiles ); - names = ( char * )( pack->fileHash + hashSize ); - memset( pack->fileHash, 0, hashSize * sizeof( packfile_t * ) ); + int i; + packfile_t *file; + char *names; + int numFiles; + pack_t *pack; + unzFile zFile; + unz_global_info zGlobalInfo; + unz_file_info zInfo; + char name[MAX_QPATH]; + size_t namesLength; + int hashSize; + unsigned hash; + size_t len; + + zFile = unzOpen( packfile ); + if( !zFile ) { + Com_WPrintf( "unzOpen() failed on %s\n", packfile ); + return NULL; + } + + if( unzGetGlobalInfo( zFile, &zGlobalInfo ) != UNZ_OK ) { + Com_WPrintf( "unzGetGlobalInfo() failed on %s\n", packfile ); + goto fail; + } + + numFiles = zGlobalInfo.number_entry; + if( numFiles > MAX_FILES_IN_PK2 ) { + Com_WPrintf( "%s has too many files, %i > %i\n", packfile, numFiles, MAX_FILES_IN_PK2 ); + goto fail; + } + + if( unzGoToFirstFile( zFile ) != UNZ_OK ) { + Com_WPrintf( "unzGoToFirstFile() failed on %s\n", packfile ); + goto fail; + } + + namesLength = 0; + for( i = 0; i < numFiles; i++ ) { + if( unzGetCurrentFileInfo( zFile, &zInfo, name, sizeof( name ), NULL, 0, NULL, 0 ) != UNZ_OK ) { + Com_WPrintf( "unzGetCurrentFileInfo() failed on %s\n", packfile ); + goto fail; + } + + namesLength += strlen( name ) + 1; + + if( i != numFiles - 1 && unzGoToNextFile( zFile ) != UNZ_OK ) { + Com_WPrintf( "unzGoToNextFile() failed on %s\n", packfile ); + + } + } + + hashSize = Q_CeilPowerOfTwo( numFiles ); + if( hashSize > 32 ) { + hashSize >>= 1; + } + + len = strlen( packfile ); + len = ( len + 3 ) & ~3; + pack = FS_Malloc( sizeof( pack_t ) + + numFiles * sizeof( packfile_t ) + + hashSize * sizeof( packfile_t * ) + + namesLength + len ); + strcpy( pack->filename, packfile ); + pack->zFile = zFile; + pack->fp = NULL; + pack->numfiles = numFiles; + pack->hashSize = hashSize; + pack->files = ( packfile_t * )( ( byte * )pack + sizeof( pack_t ) + len ); + pack->fileHash = ( packfile_t ** )( pack->files + numFiles ); + names = ( char * )( pack->fileHash + hashSize ); + memset( pack->fileHash, 0, hashSize * sizeof( packfile_t * ) ); // parse the directory - unzGoToFirstFile( zFile ); + unzGoToFirstFile( zFile ); - for( i = 0, file = pack->files; i < numFiles; i++, file++ ) { - unzGetCurrentFileInfo( zFile, &zInfo, name, sizeof( name ), NULL, 0, NULL, 0 ); + for( i = 0, file = pack->files; i < numFiles; i++, file++ ) { + unzGetCurrentFileInfo( zFile, &zInfo, name, sizeof( name ), NULL, 0, NULL, 0 ); - len = strlen( name ) + 1; - file->name = names; + len = strlen( name ) + 1; + file->name = names; - strcpy( file->name, name ); - file->filepos = unzGetCurrentFileInfoPosition( zFile ); - file->filelen = zInfo.uncompressed_size; + strcpy( file->name, name ); + file->filepos = unzGetCurrentFileInfoPosition( zFile ); + file->filelen = zInfo.uncompressed_size; - hash = Com_HashPath( file->name, hashSize ); - file->hashNext = pack->fileHash[hash]; - pack->fileHash[hash] = file; + hash = Com_HashPath( file->name, hashSize ); + file->hashNext = pack->fileHash[hash]; + pack->fileHash[hash] = file; - names += len; - - if( i != numFiles - 1 ) { - unzGoToNextFile( zFile ); - } - } + names += len; + + if( i != numFiles - 1 ) { + unzGoToNextFile( zFile ); + } + } - FS_DPrintf( "%s: %d files, %d hash table entries\n", - packfile, numFiles, hashSize ); + FS_DPrintf( "%s: %d files, %d hash table entries\n", + packfile, numFiles, hashSize ); - return pack; + return pack; fail: - unzClose( zFile ); - return NULL; + unzClose( zFile ); + return NULL; } #endif @@ -1460,8 +1531,8 @@ fail: // sorted in numerical order, then the rest of the paks in // alphabetical order, e.g. pak0.pak, pak2.pak, pak17.pak, abc.pak... static int QDECL pakcmp( const void *p1, const void *p2 ) { - char *s1 = *( char ** )p1; - char *s2 = *( char ** )p2; + char *s1 = *( char ** )p1; + char *s2 = *( char ** )p2; if( !FS_strncmp( s1, "pak", 3 ) ) { if( !FS_strncmp( s2, "pak", 3 ) ) { @@ -1482,36 +1553,36 @@ static int QDECL pakcmp( const void *p1, const void *p2 ) { } alphacmp: - return FS_strcmp( s1, s2 ); + return FS_strcmp( s1, s2 ); } static void FS_LoadPackFiles( int mode, const char *extension, pack_t *(loadfunc)( const char * ) ) { - int i; - searchpath_t *search; - pack_t *pak; - void **list; - int numFiles; + int i; + searchpath_t *search; + pack_t *pak; + void **list; + int numFiles; char path[MAX_OSPATH]; - list = Sys_ListFiles( fs_gamedir, extension, FS_SEARCH_NOSORT, 0, &numFiles ); - if( !list ) { - return; - } - qsort( list, numFiles, sizeof( list[0] ), pakcmp ); - for( i = 0; i < numFiles; i++ ) { + list = Sys_ListFiles( fs_gamedir, extension, FS_SEARCH_NOSORT, 0, &numFiles ); + if( !list ) { + return; + } + qsort( list, numFiles, sizeof( list[0] ), pakcmp ); + for( i = 0; i < numFiles; i++ ) { Q_concat( path, sizeof( path ), fs_gamedir, "/", list[i], NULL ); - pak = (*loadfunc)( path ); - if( !pak ) - continue; - search = FS_Malloc( sizeof( searchpath_t ) ); + pak = (*loadfunc)( path ); + if( !pak ) + continue; + search = FS_Malloc( sizeof( searchpath_t ) ); search->mode = mode; - search->filename[0] = 0; - search->pack = pak; - search->next = fs_searchpaths; - fs_searchpaths = search; - } + search->filename[0] = 0; + search->pack = pak; + search->next = fs_searchpaths; + fs_searchpaths = search; + } - FS_FreeList( list ); + FS_FreeList( list ); } /* @@ -1524,43 +1595,43 @@ then loads and adds pak*.pak, then anything else in alphabethical order. */ static void q_printf( 2, 3 ) FS_AddGameDirectory( int mode, const char *fmt, ... ) { va_list argptr; - searchpath_t *search; - size_t len; + searchpath_t *search; + size_t len; va_start( argptr, fmt ); - len = Q_vsnprintf( fs_gamedir, sizeof( fs_gamedir ), fmt, argptr ); + len = Q_vsnprintf( fs_gamedir, sizeof( fs_gamedir ), fmt, argptr ); va_end( argptr ); #ifdef _WIN32 - FS_ReplaceSeparators( fs_gamedir, '/' ); + FS_ReplaceSeparators( fs_gamedir, '/' ); #endif - // - // add the directory to the search path - // - if( !( fs_restrict_mask->integer & 1 ) ) { - search = FS_Malloc( sizeof( searchpath_t ) + len ); + // + // add the directory to the search path + // + if( !( fs_restrict_mask->integer & 1 ) ) { + search = FS_Malloc( sizeof( searchpath_t ) + len ); search->mode = mode; - search->pack = NULL; - memcpy( search->filename, fs_gamedir, len + 1 ); - search->next = fs_searchpaths; - fs_searchpaths = search; - } - - // - // add any pak files in the format *.pak - // - if( !( fs_restrict_mask->integer & 2 ) ) { - FS_LoadPackFiles( mode, ".pak", FS_LoadPakFile ); - } + search->pack = NULL; + memcpy( search->filename, fs_gamedir, len + 1 ); + search->next = fs_searchpaths; + fs_searchpaths = search; + } + + // + // add any pak files in the format *.pak + // + if( !( fs_restrict_mask->integer & 2 ) ) { + FS_LoadPackFiles( mode, ".pak", FS_LoadPakFile ); + } #if USE_ZLIB - // - // add any zip files in the format *.pkz - // - if( !( fs_restrict_mask->integer & 4 ) ) { - FS_LoadPackFiles( mode, ".pkz", FS_LoadZipFile ); - } + // + // add any zip files in the format *.pkz + // + if( !( fs_restrict_mask->integer & 4 ) ) { + FS_LoadPackFiles( mode, ".pkz", FS_LoadZipFile ); + } #endif } @@ -1570,32 +1641,32 @@ FS_CopyInfo ================= */ fsFileInfo_t *FS_CopyInfo( const char *name, size_t size, time_t ctime, time_t mtime ) { - fsFileInfo_t *out; - size_t len; + fsFileInfo_t *out; + size_t len; - if( !name ) { - return NULL; - } + if( !name ) { + return NULL; + } - len = strlen( name ); - out = FS_Mallocz( sizeof( *out ) + len ); + len = strlen( name ); + out = FS_Mallocz( sizeof( *out ) + len ); out->size = size; out->ctime = ctime; out->mtime = mtime; - memcpy( out->name, name, len + 1 ); + memcpy( out->name, name, len + 1 ); - return out; + return out; } void **FS_CopyList( void **list, int count ) { void **out; int i; - out = FS_Malloc( sizeof( void * ) * ( count + 1 ) ); - for( i = 0; i < count; i++ ) { - out[i] = list[i]; - } - out[i] = NULL; + out = FS_Malloc( sizeof( void * ) * ( count + 1 ) ); + for( i = 0; i < count; i++ ) { + out[i] = list[i]; + } + out[i] = NULL; return out; } @@ -1615,48 +1686,48 @@ static qboolean FS_WildCmp_r( const char *filter, const char *string ) { continue; } - if( *filter != '?' && Q_toupper( *filter ) != Q_toupper( *string ) ) { + if( *filter != '?' && Q_toupper( *filter ) != Q_toupper( *string ) ) { return qfalse; } filter++; string++; } - return !*string; + return !*string; } #endif static int FS_WildCmp_r( const char *filter, const char *string ) { - switch( *filter ) { - case '\0': - case ';': - return !*string; + switch( *filter ) { + case '\0': + case ';': + return !*string; - case '*': - return FS_WildCmp_r( filter + 1, string ) || (*string && FS_WildCmp_r( filter, string + 1 )); + case '*': + return FS_WildCmp_r( filter + 1, string ) || (*string && FS_WildCmp_r( filter, string + 1 )); - case '?': - return *string && FS_WildCmp_r( filter + 1, string + 1 ); + case '?': + return *string && FS_WildCmp_r( filter + 1, string + 1 ); - default: - return ((*filter == *string) || (Q_toupper( *filter ) == Q_toupper( *string ))) && FS_WildCmp_r( filter + 1, string + 1 ); - } + default: + return ((*filter == *string) || (Q_toupper( *filter ) == Q_toupper( *string ))) && FS_WildCmp_r( filter + 1, string + 1 ); + } } qboolean FS_WildCmp( const char *filter, const char *string ) { - do { - if( FS_WildCmp_r( filter, string ) ) { - return qtrue; - } - filter = strchr( filter, ';' ); - if( filter ) filter++; - } while( filter ); + do { + if( FS_WildCmp_r( filter, string ) ) { + return qtrue; + } + filter = strchr( filter, ';' ); + if( filter ) filter++; + } while( filter ); - return qfalse; + return qfalse; } qboolean FS_ExtCmp( const char *ext, const char *name ) { - int c1, c2; + int c1, c2; const char *e, *n, *l; if( !name[0] || !ext[0] ) { @@ -1704,14 +1775,14 @@ static int infocmp( const void *p1, const void *p2 ) { fsFileInfo_t *n1 = *( fsFileInfo_t ** )p1; fsFileInfo_t *n2 = *( fsFileInfo_t ** )p2; - return Q_stricmp( n1->name, n2->name ); + return FS_pathcmp( n1->name, n2->name ); } static int alphacmp( const void *p1, const void *p2 ) { char *s1 = *( char ** )p1; char *s2 = *( char ** )p2; - return Q_stricmp( s1, s2 ); + return FS_pathcmp( s1, s2 ); } /* @@ -1724,49 +1795,46 @@ void **FS_ListFiles( const char *path, int flags, int *numFiles ) { - searchpath_t *search; - void *listedFiles[MAX_LISTED_FILES]; - int count, total; - char buffer[MAX_OSPATH]; - void **dirlist; - int dircount; - void **list; - int i; - size_t len, pathlen; - char *s; - - if( flags & FS_SEARCH_BYFILTER ) { - if( !extension ) { - Com_Error( ERR_FATAL, "FS_ListFiles: NULL filter" ); - } - } - - count = 0; - - if( numFiles ) { - *numFiles = 0; - } - - if( !path ) { - path = ""; + searchpath_t *search; + void *listedFiles[MAX_LISTED_FILES]; + int count, total; + char buffer[MAX_OSPATH]; + void **dirlist; + int dircount; + void **list; + int i; + size_t len, pathlen; + char *s; + int valid = -1; + + if( flags & FS_SEARCH_BYFILTER ) { + if( !extension ) { + Com_Error( ERR_FATAL, "FS_ListFiles: NULL filter" ); + } + } + + count = 0; + + if( numFiles ) { + *numFiles = 0; + } + + if( !path ) { + path = ""; pathlen = 0; - } else { + } else { if( *path == '/' ) { path++; } - if( !FS_ValidatePath( path ) ) { - FS_DPrintf( "%s: refusing invalid path: %s\n", __func__, path ); - return NULL; - } pathlen = strlen( path ); } for( search = fs_searchpaths; search; search = search->next ) { - if( flags & FS_PATH_MASK ) { - if( ( flags & search->mode & FS_PATH_MASK ) == 0 ) { - continue; - } - } + if( flags & FS_PATH_MASK ) { + if( ( flags & search->mode & FS_PATH_MASK ) == 0 ) { + continue; + } + } if( search->pack ) { if( ( flags & FS_TYPE_MASK ) == FS_TYPE_REAL ) { // don't search in paks @@ -1784,7 +1852,7 @@ void **FS_ListFiles( const char *path, // check path if( pathlen ) { - if( Q_stricmpn( s, path, pathlen ) ) { + if( FS_pathcmpn( s, path, pathlen ) ) { continue; } s += pathlen + 1; @@ -1815,7 +1883,7 @@ void **FS_ListFiles( const char *path, s = search->pack->files[i].name; // check path - if( pathlen && Q_stricmpn( s, path, pathlen ) ) { + if( pathlen && FS_pathcmpn( s, path, pathlen ) ) { continue; } @@ -1851,6 +1919,16 @@ void **FS_ListFiles( const char *path, if( len + pathlen + 1 >= MAX_OSPATH ) { continue; } + if( valid == -1 ) { + if( !FS_ValidatePath( path ) ) { + FS_DPrintf( "%s: refusing invalid path: %s\n", + __func__, path ); + valid = 0; + } + } + if( valid == 0 ) { + continue; + } memcpy( buffer, search->filename, len ); buffer[len++] = '/'; memcpy( buffer + len, path, pathlen + 1 ); @@ -1884,9 +1962,9 @@ void **FS_ListFiles( const char *path, } } - if( !count ) { - return NULL; - } + if( !count ) { + return NULL; + } if( flags & FS_SEARCH_EXTRAINFO ) { // TODO @@ -1899,8 +1977,7 @@ void **FS_ListFiles( const char *path, // remove duplicates total = 1; for( i = 1; i < count; i++ ) { - // FIXME: use Q_stricmp instead of FS_strcmp here? - if( !Q_stricmp( listedFiles[ i - 1 ], listedFiles[i] ) ) { + if( !FS_pathcmp( listedFiles[ i - 1 ], listedFiles[i] ) ) { Z_Free( listedFiles[ i - 1 ] ); listedFiles[i-1] = NULL; } else { @@ -1909,21 +1986,21 @@ void **FS_ListFiles( const char *path, } } - list = FS_Malloc( sizeof( void * ) * ( total + 1 ) ); + list = FS_Malloc( sizeof( void * ) * ( total + 1 ) ); - total = 0; - for( i = 0; i < count; i++ ) { - if( listedFiles[i] ) { - list[total++] = listedFiles[i]; - } - } - list[total] = NULL; + total = 0; + for( i = 0; i < count; i++ ) { + if( listedFiles[i] ) { + list[total++] = listedFiles[i]; + } + } + list[total] = NULL; - if( numFiles ) { - *numFiles = total; - } + if( numFiles ) { + *numFiles = total; + } - return list; + return list; } /* @@ -1932,13 +2009,13 @@ FS_FreeList ================= */ void FS_FreeList( void **list ) { - void **p = list; + void **p = list; - while( *p ) { - Z_Free( *p++ ); - } + while( *p ) { + Z_Free( *p++ ); + } - Z_Free( list ); + Z_Free( list ); } void FS_File_g( const char *path, const char *ext, int flags, genctx_t *ctx ) { @@ -1953,10 +2030,10 @@ void FS_File_g( const char *path, const char *ext, int flags, genctx_t *ctx ) { for( i = 0; i < numFiles; i++ ) { s = list[i]; - if( flags & 0x80000000 ) { - p = COM_FileExtension( s ); - *p = 0; - } + if( flags & 0x80000000 ) { + p = COM_FileExtension( s ); + *p = 0; + } if( ctx->count < ctx->size && !strncmp( s, ctx->partial, ctx->length ) ) { ctx->matches[ctx->count++] = s; } else { @@ -1976,16 +2053,16 @@ extract file from *.pak, *.pk2 or *.gz ================= */ static void FS_CopyFile_f( void ) { - if( Cmd_Argc() < 2 ) { - Com_Printf( "Usage: %s \n", Cmd_Argv( 0 ) ); - return; - } + if( Cmd_Argc() < 2 ) { + Com_Printf( "Usage: %s \n", Cmd_Argv( 0 ) ); + return; + } - if( FS_CopyFile( Cmd_Argv( 1 ), Cmd_Argv( 2 ) ) ) { - Com_Printf( "File copied successfully\n" ); - } else { - Com_Printf( "Failed to copy file\n" ); - } + if( FS_CopyFile( Cmd_Argv( 1 ), Cmd_Argv( 2 ) ) ) { + Com_Printf( "File copied successfully\n" ); + } else { + Com_Printf( "Failed to copy file\n" ); + } } /* @@ -1994,30 +2071,30 @@ FS_FDir_f ============ */ static void FS_FDir_f( void ) { - void **list; - int ndirs = 0; - int i; + void **list; + int ndirs = 0; + int i; char *filter; - if( Cmd_Argc() < 2 ) { - Com_Printf( "Usage: %s [fullPath]\n", Cmd_Argv( 0 ) ); - return; - } + if( Cmd_Argc() < 2 ) { + Com_Printf( "Usage: %s [fullPath]\n", Cmd_Argv( 0 ) ); + return; + } filter = Cmd_Argv( 1 ); - i = FS_SEARCH_BYFILTER; - if( Cmd_Argc() > 2 ) { - i |= FS_SEARCH_SAVEPATH; - } + i = FS_SEARCH_BYFILTER; + if( Cmd_Argc() > 2 ) { + i |= FS_SEARCH_SAVEPATH; + } - if( ( list = FS_ListFiles( NULL, filter, i, &ndirs ) ) != NULL ) { - for( i = 0; i < ndirs; i++ ) { - Com_Printf( "%s\n", ( char * )list[i] ); - } - FS_FreeList( list ); - } - Com_Printf( "%i files listed\n", ndirs ); + if( ( list = FS_ListFiles( NULL, filter, i, &ndirs ) ) != NULL ) { + for( i = 0; i < ndirs; i++ ) { + Com_Printf( "%s\n", ( char * )list[i] ); + } + FS_FreeList( list ); + } + Com_Printf( "%i files listed\n", ndirs ); } /* @@ -2026,28 +2103,28 @@ FS_Dir_f ============ */ static void FS_Dir_f( void ) { - void **list; - int ndirs = 0; - int i; + void **list; + int ndirs = 0; + int i; char *ext; - if( Cmd_Argc() < 2 ) { - Com_Printf( "Usage: %s [.extension]\n", Cmd_Argv( 0 ) ); - return; - } + if( Cmd_Argc() < 2 ) { + Com_Printf( "Usage: %s [.extension]\n", Cmd_Argv( 0 ) ); + return; + } if( Cmd_Argc() > 2 ) { ext = Cmd_Argv( 2 ); } else { ext = NULL; } list = FS_ListFiles( Cmd_Argv( 1 ), ext, 0, &ndirs ); - if( list ) { - for( i = 0; i < ndirs; i++ ) { - Com_Printf( "%s\n", ( char * )list[i] ); - } - FS_FreeList( list ); - } - Com_Printf( "%i files listed\n", ndirs ); + if( list ) { + for( i = 0; i < ndirs; i++ ) { + Com_Printf( "%s\n", ( char * )list[i] ); + } + FS_FreeList( list ); + } + Com_Printf( "%i files listed\n", ndirs ); } /* @@ -2066,10 +2143,10 @@ static void FS_WhereIs_f( void ) { fsFileInfo_t info; int total; - if( Cmd_Argc() < 2 ) { - Com_Printf( "Usage: %s [all]\n", Cmd_Argv( 0 ) ); - return; - } + if( Cmd_Argc() < 2 ) { + Com_Printf( "Usage: %s [all]\n", Cmd_Argv( 0 ) ); + return; + } Cmd_ArgvBuffer( 1, filename, sizeof( filename ) ); @@ -2082,16 +2159,16 @@ static void FS_WhereIs_f( void ) { total = 0; for( search = fs_searchpaths; search; search = search->next ) { - // is the element a pak file? - if( search->pack ) { - // look through all the pak file elements - pak = search->pack; - entry = pak->fileHash[ hash & ( pak->hashSize - 1 ) ]; - for( ; entry; entry = entry->hashNext ) { - if( !Q_stricmp( entry->name, path ) ) { + // is the element a pak file? + if( search->pack ) { + // look through all the pak file elements + pak = search->pack; + entry = pak->fileHash[ hash & ( pak->hashSize - 1 ) ]; + for( ; entry; entry = entry->hashNext ) { + if( !FS_pathcmp( entry->name, path ) ) { Com_Printf( "%s/%s (%"PRIz" bytes)\n", pak->filename, path, entry->filelen ); - if( Cmd_Argc() < 3 ) { + if( Cmd_Argc() < 3 ) { return; } total++; @@ -2100,7 +2177,7 @@ static void FS_WhereIs_f( void ) { } else { Q_concat( fullpath, sizeof( fullpath ), search->filename, "/", path, NULL ); - //FS_ConvertToSysPath( fullpath ); + //FS_ConvertToSysPath( fullpath ); if( Sys_GetPathInfo( fullpath, &info ) ) { Com_Printf( "%s/%s (%"PRIz" bytes)\n", search->filename, filename, info.size ); if( Cmd_Argc() < 3 ) { @@ -2125,39 +2202,39 @@ FS_Path_f ============ */ void FS_Path_f( void ) { - searchpath_t *s; - int numFilesInPAK = 0; + searchpath_t *s; + int numFilesInPAK = 0; #if USE_ZLIB - int numFilesInPK2 = 0; + int numFilesInPK2 = 0; #endif - Com_Printf( "Current search path:\n" ); - for( s = fs_searchpaths; s; s = s->next ) { - if( s->pack ) { + Com_Printf( "Current search path:\n" ); + for( s = fs_searchpaths; s; s = s->next ) { + if( s->pack ) { #if USE_ZLIB - if( s->pack->zFile ) { - numFilesInPK2 += s->pack->numfiles; - } else + if( s->pack->zFile ) { + numFilesInPK2 += s->pack->numfiles; + } else #endif { - numFilesInPAK += s->pack->numfiles; - } - } + numFilesInPAK += s->pack->numfiles; + } + } - if( s->pack ) - Com_Printf( "%s (%i files)\n", s->pack->filename, s->pack->numfiles ); - else - Com_Printf( "%s\n", s->filename ); - } + if( s->pack ) + Com_Printf( "%s (%i files)\n", s->pack->filename, s->pack->numfiles ); + else + Com_Printf( "%s\n", s->filename ); + } - if( !( fs_restrict_mask->integer & 2 ) ) { - Com_Printf( "%i files in PAK files\n", numFilesInPAK ); - } + if( numFilesInPAK ) { + Com_Printf( "%i files in PAK files\n", numFilesInPAK ); + } #if USE_ZLIB - if( !( fs_restrict_mask->integer & 4 ) ) { - Com_Printf( "%i files in PKZ files\n", numFilesInPK2 ); - } + if( numFilesInPK2 ) { + Com_Printf( "%i files in PKZ files\n", numFilesInPK2 ); + } #endif } @@ -2167,55 +2244,55 @@ FS_Stats_f ================ */ static void FS_Stats_f( void ) { - searchpath_t *path; - pack_t *pack, *maxpack = NULL; - packfile_t *file, *max = NULL; - int i; - int len, maxLen = 0; - int totalHashSize, totalLen; - - totalHashSize = totalLen = 0; - for( path = fs_searchpaths; path; path = path->next ) { - if( !( pack = path->pack ) ) { - continue; - } - for( i = 0; i < pack->hashSize; i++ ) { - if( !( file = pack->fileHash[i] ) ) { - continue; - } - len = 0; - for( ; file ; file = file->hashNext ) { - len++; - } - if( maxLen < len ) { - max = pack->fileHash[i]; - maxpack = pack; - maxLen = len; - } - totalLen += len; - totalHashSize++; - } - //totalHashSize += pack->hashSize; - } - - Com_Printf( "LoadFile counter: %d\n", loadCount ); - Com_Printf( "Static LoadFile counter: %d\n", loadCountStatic ); - Com_Printf( "Total calls to OpenFileRead: %d\n", fs_count_read ); - Com_Printf( "Total path comparsions: %d\n", fs_count_strcmp ); - Com_Printf( "Total calls to fopen: %d\n", fs_count_open ); - - if( !totalHashSize ) { - Com_Printf( "No stats to display\n" ); - return; - } - - Com_Printf( "Maximum hash bucket length is %d, average is %.2f\n", maxLen, ( float )totalLen / totalHashSize ); - if( max ) { - Com_Printf( "Dumping longest bucket (%s):\n", maxpack->filename ); - for( file = max; file ; file = file->hashNext ) { - Com_Printf( "%s\n", file->name ); - } - } + searchpath_t *path; + pack_t *pack, *maxpack = NULL; + packfile_t *file, *max = NULL; + int i; + int len, maxLen = 0; + int totalHashSize, totalLen; + + totalHashSize = totalLen = 0; + for( path = fs_searchpaths; path; path = path->next ) { + if( !( pack = path->pack ) ) { + continue; + } + for( i = 0; i < pack->hashSize; i++ ) { + if( !( file = pack->fileHash[i] ) ) { + continue; + } + len = 0; + for( ; file ; file = file->hashNext ) { + len++; + } + if( maxLen < len ) { + max = pack->fileHash[i]; + maxpack = pack; + maxLen = len; + } + totalLen += len; + totalHashSize++; + } + //totalHashSize += pack->hashSize; + } + + Com_Printf( "LoadFile counter: %d\n", loadCount ); + Com_Printf( "Static LoadFile counter: %d\n", loadCountStatic ); + Com_Printf( "Total calls to OpenFileRead: %d\n", fs_count_read ); + Com_Printf( "Total path comparsions: %d\n", fs_count_strcmp ); + Com_Printf( "Total calls to fopen: %d\n", fs_count_open ); + + if( !totalHashSize ) { + Com_Printf( "No stats to display\n" ); + return; + } + + Com_Printf( "Maximum hash bucket length is %d, average is %.2f\n", maxLen, ( float )totalLen / totalHashSize ); + if( max ) { + Com_Printf( "Dumping longest bucket (%s):\n", maxpack->filename ); + for( file = max; file ; file = file->hashNext ) { + Com_Printf( "%s\n", file->name ); + } + } } static void FS_Link_g( genctx_t *ctx ) { @@ -2273,7 +2350,7 @@ static void FS_UnLink_f( void ) { } for( l = fs_links, back = &fs_links; l; l = l->next ) { - if( !Q_stricmp( l->name, name ) ) { + if( !FS_pathcmp( l->name, name ) ) { break; } back = &l->next; @@ -2290,7 +2367,7 @@ static void FS_UnLink_f( void ) { static void FS_Link_f( void ) { int argc, count; - size_t length; + size_t length; fsLink_t *l; char *name, *target; @@ -2314,7 +2391,7 @@ static void FS_Link_f( void ) { name = Cmd_Argv( 1 ); for( l = fs_links; l; l = l->next ) { - if( !Q_stricmp( l->name, name ) ) { + if( !FS_pathcmp( l->name, name ) ) { break; } } @@ -2336,21 +2413,21 @@ static void FS_Link_f( void ) { } static void FS_FreeSearchPath( searchpath_t *path ) { - pack_t *pak; + pack_t *pak; - if( ( pak = path->pack ) != NULL ) { + if( ( pak = path->pack ) != NULL ) { #if USE_ZLIB - if( pak->zFile ) { - unzClose( pak->zFile ); - } else + if( pak->zFile ) { + unzClose( pak->zFile ); + } else #endif { - fclose( pak->fp ); - } - Z_Free( pak ); - } + fclose( pak->fp ); + } + Z_Free( pak ); + } - Z_Free( path ); + Z_Free( path ); } /* @@ -2359,24 +2436,24 @@ FS_Shutdown ================ */ void FS_Shutdown( qboolean total ) { - searchpath_t *path, *next; + searchpath_t *path, *next; fsLink_t *l, *nextLink; - fsFile_t *file; - int i; - - if( !fs_searchpaths ) { - return; - } - - if( total ) { - // close file handles - for( i = 0, file = fs_files; i < MAX_FILE_HANDLES; i++, file++ ) { - if( file->type != FS_FREE ) { - Com_WPrintf( "FS_Shutdown: closing handle %i: %s\n", + fsFile_t *file; + int i; + + if( !fs_searchpaths ) { + return; + } + + if( total ) { + // close file handles + for( i = 0, file = fs_files; i < MAX_FILE_HANDLES; i++, file++ ) { + if( file->type != FS_FREE ) { + Com_WPrintf( "FS_Shutdown: closing handle %i: %s\n", i + 1, file->fullpath ); - FS_FCloseFile( i + 1 ); - } - } + FS_FCloseFile( i + 1 ); + } + } // free symbolic links for( l = fs_links; l; l = nextLink ) { @@ -2386,27 +2463,27 @@ void FS_Shutdown( qboolean total ) { } fs_links = NULL; - } + } - // free search paths - for( path = fs_searchpaths; path; path = next ) { - next = path->next; - FS_FreeSearchPath( path ); - } + // free search paths + for( path = fs_searchpaths; path; path = next ) { + next = path->next; + FS_FreeSearchPath( path ); + } - fs_searchpaths = NULL; + fs_searchpaths = NULL; if( total ) { - Z_LeakTest( TAG_FILESYSTEM ); + Z_LeakTest( TAG_FILESYSTEM ); } - Cmd_RemoveCommand( "path" ); - Cmd_RemoveCommand( "fdir" ); - Cmd_RemoveCommand( "dir" ); - Cmd_RemoveCommand( "copyfile" ); - Cmd_RemoveCommand( "fs_stats" ); - Cmd_RemoveCommand( "link" ); - Cmd_RemoveCommand( "unlink" ); + Cmd_RemoveCommand( "path" ); + Cmd_RemoveCommand( "fdir" ); + Cmd_RemoveCommand( "dir" ); + Cmd_RemoveCommand( "copyfile" ); + Cmd_RemoveCommand( "fs_stats" ); + Cmd_RemoveCommand( "link" ); + Cmd_RemoveCommand( "unlink" ); } /* @@ -2416,14 +2493,14 @@ FS_DefaultGamedir */ static void FS_DefaultGamedir( void ) { if( sys_homedir->string[0] ) { - FS_AddGameDirectory( FS_PATH_BASE|FS_PATH_GAME, + FS_AddGameDirectory( FS_PATH_BASE|FS_PATH_GAME, "%s/"BASEGAME, sys_homedir->string ); } - Cvar_Set( "game", "" ); - Cvar_Set( "gamedir", "" ); + Cvar_Set( "game", "" ); + Cvar_Set( "gamedir", "" ); - Sys_Setenv( "QUAKE2_HOME", fs_gamedir ); + Q_setenv( "QUAKE2_GAME_PATH", fs_gamedir ); } @@ -2435,27 +2512,29 @@ Sets the gamedir and path to a different directory. ================ */ static void FS_SetupGamedir( void ) { - fs_game = Cvar_Get( "game", "", CVAR_LATCHED|CVAR_SERVERINFO ); + fs_game = Cvar_Get( "game", "", CVAR_FILES|CVAR_LATCH|CVAR_SERVERINFO ); - if( !fs_game->string[0] || !FS_strcmp( fs_game->string, BASEGAME ) ) { - FS_DefaultGamedir(); - return; - } + cvar_modified &= ~CVAR_FILES; - if( !FS_ValidatePath( fs_game->string ) || + if( !fs_game->string[0] || !FS_strcmp( fs_game->string, BASEGAME ) ) { + FS_DefaultGamedir(); + return; + } + + if( !FS_ValidatePath( fs_game->string ) || strchr( fs_game->string, '/' ) || - strchr( fs_game->string, '\\' ) ) - { - Com_WPrintf( "Gamedir should be a single filename, not a path.\n" ); - FS_DefaultGamedir(); - return; - } - - // this one is left for compatibility with server browsers, etc - Cvar_FullSet( "gamedir", fs_game->string, CVAR_ROM|CVAR_SERVERINFO, + strchr( fs_game->string, '\\' ) ) + { + Com_WPrintf( "Gamedir should be a single filename, not a path.\n" ); + FS_DefaultGamedir(); + return; + } + + // this one is left for compatibility with server browsers, etc + Cvar_FullSet( "gamedir", fs_game->string, CVAR_ROM|CVAR_SERVERINFO, CVAR_SET_DIRECT ); - FS_AddGameDirectory( FS_PATH_GAME, "%s/%s", sys_basedir->string, fs_game->string ); + FS_AddGameDirectory( FS_PATH_GAME, "%s/%s", sys_basedir->string, fs_game->string ); // home paths override system paths if( sys_homedir->string[0] ) { @@ -2463,21 +2542,21 @@ static void FS_SetupGamedir( void ) { FS_AddGameDirectory( FS_PATH_GAME, "%s/%s", sys_homedir->string, fs_game->string ); } - Sys_Setenv( "QUAKE2_HOME", fs_gamedir ); + Q_setenv( "QUAKE2_GAME_PATH", fs_gamedir ); } qboolean FS_SafeToRestart( void ) { - fsFile_t *file; - int i; + fsFile_t *file; + int i; - // make sure no files are opened for reading - for( i = 0, file = fs_files; i < MAX_FILE_HANDLES; i++, file++ ) { - if( file->type == FS_FREE ) { - continue; - } - if( file->mode == FS_MODE_READ ) { + // make sure no files are opened for reading + for( i = 0, file = fs_files; i < MAX_FILE_HANDLES; i++, file++ ) { + if( file->type == FS_FREE ) { + continue; + } + if( file->mode == FS_MODE_READ ) { return qfalse; - } + } } return qtrue; @@ -2489,49 +2568,49 @@ FS_Restart ================ */ void FS_Restart( void ) { - fsFile_t *file; - int i; - fileHandle_t temp; - searchpath_t *path, *next; - - Com_Printf( "---------- FS_Restart ----------\n" ); - - // temporary disable logfile - temp = com_logFile; - com_logFile = 0; - - // make sure no files are opened for reading - for( i = 0, file = fs_files; i < MAX_FILE_HANDLES; i++, file++ ) { - if( file->type == FS_FREE ) { - continue; - } - if( file->mode == FS_MODE_READ ) { - Com_Error( ERR_FATAL, "FS_Restart: closing handle %i: %s", + fsFile_t *file; + int i; + fileHandle_t temp; + searchpath_t *path, *next; + + Com_Printf( "---------- FS_Restart ----------\n" ); + + // temporary disable logfile + temp = com_logFile; + com_logFile = 0; + + // make sure no files are opened for reading + for( i = 0, file = fs_files; i < MAX_FILE_HANDLES; i++, file++ ) { + if( file->type == FS_FREE ) { + continue; + } + if( file->mode == FS_MODE_READ ) { + Com_Error( ERR_FATAL, "FS_Restart: closing handle %i: %s", i + 1, file->fullpath ); - } - } - - if( fs_restrict_mask->latched_string ) { - // perform full reset - FS_Shutdown( qfalse ); - FS_Init(); - } else { - // just change gamedir - for( path = fs_searchpaths; path != fs_base_searchpaths; path = next ) { - next = path->next; - FS_FreeSearchPath( path ); - } - - fs_searchpaths = fs_base_searchpaths; - - FS_SetupGamedir(); - FS_Path_f(); - } - - // re-enable logfile - com_logFile = temp; - - Com_Printf( "--------------------------------\n" ); + } + } + + if( fs_restrict_mask->latched_string ) { + // perform full reset + FS_Shutdown( qfalse ); + FS_Init(); + } else { + // just change gamedir + for( path = fs_searchpaths; path != fs_base_searchpaths; path = next ) { + next = path->next; + FS_FreeSearchPath( path ); + } + + fs_searchpaths = fs_base_searchpaths; + + FS_SetupGamedir(); + FS_Path_f(); + } + + // re-enable logfile + com_logFile = temp; + + Com_Printf( "--------------------------------\n" ); } /* @@ -2556,18 +2635,18 @@ FS_FillAPI ================ */ void FS_FillAPI( fsAPI_t *api ) { - api->LoadFile = FS_LoadFile; - api->LoadFileEx = FS_LoadFileEx; + api->LoadFile = FS_LoadFile; + api->LoadFileEx = FS_LoadFileEx; api->AllocTempMem = FS_AllocTempMem; - api->FreeFile = FS_FreeFile; - api->FOpenFile = FS_FOpenFile; - api->FCloseFile = FS_FCloseFile; - api->Tell = FS_Tell; - api->RawTell = FS_RawTell; - api->Read = FS_Read; - api->Write = FS_Write; - api->ListFiles = FS_ListFiles; - api->FreeList = FS_FreeList; + api->FreeFile = FS_FreeFile; + api->FOpenFile = FS_FOpenFile; + api->FCloseFile = FS_FCloseFile; + api->Tell = FS_Tell; + api->RawTell = FS_RawTell; + api->Read = FS_Read; + api->Write = FS_Write; + api->ListFiles = FS_ListFiles; + api->FreeList = FS_FreeList; api->FPrintf = FS_FPrintf; api->ReadLine = FS_ReadLine; } @@ -2581,7 +2660,7 @@ static const cmdreg_t c_fs[] = { { "whereis", FS_WhereIs_f }, { "link", FS_Link_f, FS_Link_c }, { "unlink", FS_UnLink_f, FS_Link_c }, - { "fs_restart", FS_Restart_f }, + { "fs_restart", FS_Restart_f }, { NULL } }; @@ -2592,39 +2671,39 @@ FS_Init ================ */ void FS_Init( void ) { - unsigned start, end; + unsigned start, end; - start = Sys_Milliseconds(); + start = Sys_Milliseconds(); - Com_Printf( "---------- FS_Init ----------\n" ); + Com_Printf( "---------- FS_Init ----------\n" ); Cmd_Register( c_fs ); - fs_debug = Cvar_Get( "fs_debug", "0", 0 ); - fs_restrict_mask = Cvar_Get( "fs_restrict_mask", "0", CVAR_NOSET ); + fs_debug = Cvar_Get( "fs_debug", "0", 0 ); + fs_restrict_mask = Cvar_Get( "fs_restrict_mask", "0", CVAR_NOSET ); - if( ( fs_restrict_mask->integer & 7 ) == 7 ) { - Com_WPrintf( "Invalid fs_restrict_mask value %d. " + if( ( fs_restrict_mask->integer & 7 ) == 7 ) { + Com_WPrintf( "Invalid fs_restrict_mask value %d. " "Falling back to default.\n", - fs_restrict_mask->integer ); - Cvar_Set( "fs_restrict_mask", "0" ); - } + fs_restrict_mask->integer ); + Cvar_Set( "fs_restrict_mask", "0" ); + } - // start up with baseq2 by default - FS_AddGameDirectory( FS_PATH_BASE|FS_PATH_GAME, "%s/"BASEGAME, sys_basedir->string ); + // start up with baseq2 by default + FS_AddGameDirectory( FS_PATH_BASE|FS_PATH_GAME, "%s/"BASEGAME, sys_basedir->string ); - fs_base_searchpaths = fs_searchpaths; + fs_base_searchpaths = fs_searchpaths; - // check for game override - FS_SetupGamedir(); + // check for game override + FS_SetupGamedir(); - FS_Path_f(); + FS_Path_f(); - FS_FillAPI( &fs ); - + FS_FillAPI( &fs ); + end = Sys_Milliseconds(); - Com_DPrintf( "%i msec to init filesystem\n", end - start ); - Com_Printf( "-----------------------------\n" ); + Com_DPrintf( "%i msec to init filesystem\n", end - start ); + Com_Printf( "-----------------------------\n" ); } /* @@ -2633,10 +2712,12 @@ FS_NeedRestart ================ */ qboolean FS_NeedRestart( void ) { - if( fs_game->latched_string || fs_restrict_mask->latched_string ) { - return qtrue; - } - - return qfalse; + if( cvar_modified & CVAR_FILES ) { + return qtrue; + } + if( fs_game->latched_string || fs_restrict_mask->latched_string ) { + return qtrue; + } + return qfalse; } -- cgit v1.2.3