diff options
Diffstat (limited to 'source/files.c')
-rw-r--r-- | source/files.c | 2533 |
1 files changed, 1307 insertions, 1226 deletions
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; /* @@ -159,22 +159,72 @@ 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 <sourcePath> <destPath>\n", Cmd_Argv( 0 ) ); - return; - } + if( Cmd_Argc() < 2 ) { + Com_Printf( "Usage: %s <sourcePath> <destPath>\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 <filter> [fullPath]\n", Cmd_Argv( 0 ) ); - return; - } + if( Cmd_Argc() < 2 ) { + Com_Printf( "Usage: %s <filter> [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 <directory> [.extension]\n", Cmd_Argv( 0 ) ); - return; - } + if( Cmd_Argc() < 2 ) { + Com_Printf( "Usage: %s <directory> [.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 <path> [all]\n", Cmd_Argv( 0 ) ); - return; - } + if( Cmd_Argc() < 2 ) { + Com_Printf( "Usage: %s <path> [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; } |