00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "../game/q_shared.h"
00033 #include "qcommon.h"
00034 #include "unzip.h"
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 #define DEMOGAME "demota"
00200
00201
00202
00203 #define DEMO_PAK_CHECKSUM 437558517u
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213 #define MAX_ZPATH 256
00214 #define MAX_SEARCH_PATHS 4096
00215 #define MAX_FILEHASH_SIZE 1024
00216
00217 typedef struct fileInPack_s {
00218 char *name;
00219 unsigned long pos;
00220 struct fileInPack_s* next;
00221 } fileInPack_t;
00222
00223 typedef struct {
00224 char pakFilename[MAX_OSPATH];
00225 char pakBasename[MAX_OSPATH];
00226 char pakGamename[MAX_OSPATH];
00227 unzFile handle;
00228 int checksum;
00229 int pure_checksum;
00230 int numfiles;
00231 int referenced;
00232 int hashSize;
00233 fileInPack_t* *hashTable;
00234 fileInPack_t* buildBuffer;
00235 } pack_t;
00236
00237 typedef struct {
00238 char path[MAX_OSPATH];
00239 char gamedir[MAX_OSPATH];
00240 } directory_t;
00241
00242 typedef struct searchpath_s {
00243 struct searchpath_s *next;
00244
00245 pack_t *pack;
00246 directory_t *dir;
00247 } searchpath_t;
00248
00249 static char fs_gamedir[MAX_OSPATH];
00250 static cvar_t *fs_debug;
00251 static cvar_t *fs_homepath;
00252 static cvar_t *fs_basepath;
00253 static cvar_t *fs_basegame;
00254 static cvar_t *fs_cdpath;
00255 static cvar_t *fs_copyfiles;
00256 static cvar_t *fs_gamedirvar;
00257 static cvar_t *fs_restrict;
00258 static searchpath_t *fs_searchpaths;
00259 static int fs_readCount;
00260 static int fs_loadCount;
00261 static int fs_loadStack;
00262 static int fs_packFiles;
00263
00264 static int fs_fakeChkSum;
00265 static int fs_checksumFeed;
00266
00267 typedef union qfile_gus {
00268 FILE* o;
00269 unzFile z;
00270 } qfile_gut;
00271
00272 typedef struct qfile_us {
00273 qfile_gut file;
00274 qboolean unique;
00275 } qfile_ut;
00276
00277 typedef struct {
00278 qfile_ut handleFiles;
00279 qboolean handleSync;
00280 int baseOffset;
00281 int fileSize;
00282 int zipFilePos;
00283 qboolean zipFile;
00284 qboolean streamed;
00285 char name[MAX_ZPATH];
00286 } fileHandleData_t;
00287
00288 static fileHandleData_t fsh[MAX_FILE_HANDLES];
00289
00290
00291
00292 static qboolean fs_reordered;
00293
00294
00295 static int fs_numServerPaks;
00296 static int fs_serverPaks[MAX_SEARCH_PATHS];
00297 static char *fs_serverPakNames[MAX_SEARCH_PATHS];
00298
00299
00300
00301 static int fs_numServerReferencedPaks;
00302 static int fs_serverReferencedPaks[MAX_SEARCH_PATHS];
00303 static char *fs_serverReferencedPakNames[MAX_SEARCH_PATHS];
00304
00305
00306 char lastValidBase[MAX_OSPATH];
00307 char lastValidGame[MAX_OSPATH];
00308
00309
00310 static byte fs_scrambledProductId[152] = {
00311 220, 129, 255, 108, 244, 163, 171, 55, 133, 65, 199, 36, 140, 222, 53, 99, 65, 171, 175, 232, 236, 193, 210, 250, 169, 104, 231, 231, 21, 201, 170, 208, 135, 175, 130, 136, 85, 215, 71, 23, 96, 32, 96, 83, 44, 240, 219, 138, 184, 215, 73, 27, 196, 247, 55, 139, 148, 68, 78, 203, 213, 238, 139, 23, 45, 205, 118, 186, 236, 230, 231, 107, 212, 1, 10, 98, 30, 20, 116, 180, 216, 248, 166, 35, 45, 22, 215, 229, 35, 116, 250, 167, 117, 3, 57, 55, 201, 229, 218, 222, 128, 12, 141, 149, 32, 110, 168, 215, 184, 53, 31, 147, 62, 12, 138, 67, 132, 54, 125, 6, 221, 148, 140, 4, 21, 44, 198, 3, 126, 12, 100, 236, 61, 42, 44, 251, 15, 135, 14, 134, 89, 92, 177, 246, 152, 106, 124, 78, 118, 80, 28, 42
00312 };
00313
00314 #ifdef FS_MISSING
00315 FILE* missingFiles = NULL;
00316 #endif
00317
00318
00319
00320
00321
00322
00323
00324 qboolean FS_Initialized() {
00325 return (fs_searchpaths != NULL);
00326 }
00327
00328
00329
00330
00331
00332
00333 qboolean FS_PakIsPure( pack_t *pack ) {
00334 int i;
00335
00336 if ( fs_numServerPaks ) {
00337 for ( i = 0 ; i < fs_numServerPaks ; i++ ) {
00338
00339
00340
00341 if ( pack->checksum == fs_serverPaks[i] ) {
00342 return qtrue;
00343 }
00344 }
00345 return qfalse;
00346 }
00347 return qtrue;
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357 int FS_LoadStack()
00358 {
00359 return fs_loadStack;
00360 }
00361
00362
00363
00364
00365
00366
00367 static long FS_HashFileName( const char *fname, int hashSize ) {
00368 int i;
00369 long hash;
00370 char letter;
00371
00372 hash = 0;
00373 i = 0;
00374 while (fname[i] != '\0') {
00375 letter = tolower(fname[i]);
00376 if (letter =='.') break;
00377 if (letter =='\\') letter = '/';
00378 if (letter == PATH_SEP) letter = '/';
00379 hash+=(long)(letter)*(i+119);
00380 i++;
00381 }
00382 hash = (hash ^ (hash >> 10) ^ (hash >> 20));
00383 hash &= (hashSize-1);
00384 return hash;
00385 }
00386
00387 static fileHandle_t FS_HandleForFile(void) {
00388 int i;
00389
00390 for ( i = 1 ; i < MAX_FILE_HANDLES ; i++ ) {
00391 if ( fsh[i].handleFiles.file.o == NULL ) {
00392 return i;
00393 }
00394 }
00395 Com_Error( ERR_DROP, "FS_HandleForFile: none free" );
00396 return 0;
00397 }
00398
00399 static FILE *FS_FileForHandle( fileHandle_t f ) {
00400 if ( f < 0 || f > MAX_FILE_HANDLES ) {
00401 Com_Error( ERR_DROP, "FS_FileForHandle: out of reange" );
00402 }
00403 if (fsh[f].zipFile == qtrue) {
00404 Com_Error( ERR_DROP, "FS_FileForHandle: can't get FILE on zip file" );
00405 }
00406 if ( ! fsh[f].handleFiles.file.o ) {
00407 Com_Error( ERR_DROP, "FS_FileForHandle: NULL" );
00408 }
00409
00410 return fsh[f].handleFiles.file.o;
00411 }
00412
00413 void FS_ForceFlush( fileHandle_t f ) {
00414 FILE *file;
00415
00416 file = FS_FileForHandle(f);
00417 setvbuf( file, NULL, _IONBF, 0 );
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 int FS_filelength( fileHandle_t f ) {
00430 int pos;
00431 int end;
00432 FILE* h;
00433
00434 h = FS_FileForHandle(f);
00435 pos = ftell (h);
00436 fseek (h, 0, SEEK_END);
00437 end = ftell (h);
00438 fseek (h, pos, SEEK_SET);
00439
00440 return end;
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450 static void FS_ReplaceSeparators( char *path ) {
00451 char *s;
00452
00453 for ( s = path ; *s ; s++ ) {
00454 if ( *s == '/' || *s == '\\' ) {
00455 *s = PATH_SEP;
00456 }
00457 }
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467 char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ) {
00468 char temp[MAX_OSPATH];
00469 static char ospath[2][MAX_OSPATH];
00470 static int toggle;
00471
00472 toggle ^= 1;
00473
00474 if( !game || !game[0] ) {
00475 game = fs_gamedir;
00476 }
00477
00478 Com_sprintf( temp, sizeof(temp), "/%s/%s", game, qpath );
00479 FS_ReplaceSeparators( temp );
00480 Com_sprintf( ospath[toggle], sizeof( ospath[0] ), "%s%s", base, temp );
00481
00482 return ospath[toggle];
00483 }
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493 static qboolean FS_CreatePath (char *OSPath) {
00494 char *ofs;
00495
00496
00497
00498 if ( strstr( OSPath, ".." ) || strstr( OSPath, "::" ) ) {
00499 Com_Printf( "WARNING: refusing to create relative path \"%s\"\n", OSPath );
00500 return qtrue;
00501 }
00502
00503 for (ofs = OSPath+1 ; *ofs ; ofs++) {
00504 if (*ofs == PATH_SEP) {
00505
00506 *ofs = 0;
00507 Sys_Mkdir (OSPath);
00508 *ofs = PATH_SEP;
00509 }
00510 }
00511 return qfalse;
00512 }
00513
00514
00515
00516
00517
00518
00519
00520
00521 static void FS_CopyFile( char *fromOSPath, char *toOSPath ) {
00522 FILE *f;
00523 int len;
00524 byte *buf;
00525
00526 Com_Printf( "copy %s to %s\n", fromOSPath, toOSPath );
00527
00528 if (strstr(fromOSPath, "journal.dat") || strstr(fromOSPath, "journaldata.dat")) {
00529 Com_Printf( "Ignoring journal files\n");
00530 return;
00531 }
00532
00533 f = fopen( fromOSPath, "rb" );
00534 if ( !f ) {
00535 return;
00536 }
00537 fseek (f, 0, SEEK_END);
00538 len = ftell (f);
00539 fseek (f, 0, SEEK_SET);
00540
00541
00542
00543 buf = malloc( len );
00544 if (fread( buf, 1, len, f ) != len)
00545 Com_Error( ERR_FATAL, "Short read in FS_Copyfiles()\n" );
00546 fclose( f );
00547
00548 if( FS_CreatePath( toOSPath ) ) {
00549 return;
00550 }
00551
00552 f = fopen( toOSPath, "wb" );
00553 if ( !f ) {
00554 return;
00555 }
00556 if (fwrite( buf, 1, len, f ) != len)
00557 Com_Error( ERR_FATAL, "Short write in FS_Copyfiles()\n" );
00558 fclose( f );
00559 free( buf );
00560 }
00561
00562
00563
00564
00565
00566
00567
00568 static void FS_Remove( const char *osPath ) {
00569 remove( osPath );
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582 qboolean FS_FileExists( const char *file )
00583 {
00584 FILE *f;
00585 char *testpath;
00586
00587 testpath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, file );
00588
00589 f = fopen( testpath, "rb" );
00590 if (f) {
00591 fclose( f );
00592 return qtrue;
00593 }
00594 return qfalse;
00595 }
00596
00597
00598
00599
00600
00601
00602
00603
00604 qboolean FS_SV_FileExists( const char *file )
00605 {
00606 FILE *f;
00607 char *testpath;
00608
00609 testpath = FS_BuildOSPath( fs_homepath->string, file, "");
00610 testpath[strlen(testpath)-1] = '\0';
00611
00612 f = fopen( testpath, "rb" );
00613 if (f) {
00614 fclose( f );
00615 return qtrue;
00616 }
00617 return qfalse;
00618 }
00619
00620
00621
00622
00623
00624
00625
00626
00627 fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) {
00628 char *ospath;
00629 fileHandle_t f;
00630
00631 if ( !fs_searchpaths ) {
00632 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
00633 }
00634
00635 ospath = FS_BuildOSPath( fs_homepath->string, filename, "" );
00636 ospath[strlen(ospath)-1] = '\0';
00637
00638 f = FS_HandleForFile();
00639 fsh[f].zipFile = qfalse;
00640
00641 if ( fs_debug->integer ) {
00642 Com_Printf( "FS_SV_FOpenFileWrite: %s\n", ospath );
00643 }
00644
00645 if( FS_CreatePath( ospath ) ) {
00646 return 0;
00647 }
00648
00649 Com_DPrintf( "writing to: %s\n", ospath );
00650 fsh[f].handleFiles.file.o = fopen( ospath, "wb" );
00651
00652 Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );
00653
00654 fsh[f].handleSync = qfalse;
00655 if (!fsh[f].handleFiles.file.o) {
00656 f = 0;
00657 }
00658 return f;
00659 }
00660
00661
00662
00663
00664
00665
00666
00667
00668 int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ) {
00669 char *ospath;
00670 fileHandle_t f = 0;
00671
00672 if ( !fs_searchpaths ) {
00673 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
00674 }
00675
00676 f = FS_HandleForFile();
00677 fsh[f].zipFile = qfalse;
00678
00679 Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );
00680
00681
00682 S_ClearSoundBuffer();
00683
00684
00685 ospath = FS_BuildOSPath( fs_homepath->string, filename, "" );
00686
00687 ospath[strlen(ospath)-1] = '\0';
00688
00689 if ( fs_debug->integer ) {
00690 Com_Printf( "FS_SV_FOpenFileRead (fs_homepath): %s\n", ospath );
00691 }
00692
00693 fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
00694 fsh[f].handleSync = qfalse;
00695 if (!fsh[f].handleFiles.file.o)
00696 {
00697
00698 if (Q_stricmp(fs_homepath->string,fs_basepath->string))
00699 {
00700
00701 ospath = FS_BuildOSPath( fs_basepath->string, filename, "" );
00702 ospath[strlen(ospath)-1] = '\0';
00703
00704 if ( fs_debug->integer )
00705 {
00706 Com_Printf( "FS_SV_FOpenFileRead (fs_basepath): %s\n", ospath );
00707 }
00708
00709 fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
00710 fsh[f].handleSync = qfalse;
00711
00712 if ( !fsh[f].handleFiles.file.o )
00713 {
00714 f = 0;
00715 }
00716 }
00717 }
00718
00719 if (!fsh[f].handleFiles.file.o) {
00720
00721 ospath = FS_BuildOSPath( fs_cdpath->string, filename, "" );
00722 ospath[strlen(ospath)-1] = '\0';
00723
00724 if (fs_debug->integer)
00725 {
00726 Com_Printf( "FS_SV_FOpenFileRead (fs_cdpath) : %s\n", ospath );
00727 }
00728
00729 fsh[f].handleFiles.file.o = fopen( ospath, "rb" );
00730 fsh[f].handleSync = qfalse;
00731
00732 if( !fsh[f].handleFiles.file.o ) {
00733 f = 0;
00734 }
00735 }
00736
00737 *fp = f;
00738 if (f) {
00739 return FS_filelength(f);
00740 }
00741 return 0;
00742 }
00743
00744
00745
00746
00747
00748
00749
00750
00751 void FS_SV_Rename( const char *from, const char *to ) {
00752 char *from_ospath, *to_ospath;
00753
00754 if ( !fs_searchpaths ) {
00755 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
00756 }
00757
00758
00759 S_ClearSoundBuffer();
00760
00761 from_ospath = FS_BuildOSPath( fs_homepath->string, from, "" );
00762 to_ospath = FS_BuildOSPath( fs_homepath->string, to, "" );
00763 from_ospath[strlen(from_ospath)-1] = '\0';
00764 to_ospath[strlen(to_ospath)-1] = '\0';
00765
00766 if ( fs_debug->integer ) {
00767 Com_Printf( "FS_SV_Rename: %s --> %s\n", from_ospath, to_ospath );
00768 }
00769
00770 if (rename( from_ospath, to_ospath )) {
00771
00772 FS_CopyFile ( from_ospath, to_ospath );
00773 FS_Remove ( from_ospath );
00774 }
00775 }
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785 void FS_Rename( const char *from, const char *to ) {
00786 char *from_ospath, *to_ospath;
00787
00788 if ( !fs_searchpaths ) {
00789 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
00790 }
00791
00792
00793 S_ClearSoundBuffer();
00794
00795 from_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, from );
00796 to_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, to );
00797
00798 if ( fs_debug->integer ) {
00799 Com_Printf( "FS_Rename: %s --> %s\n", from_ospath, to_ospath );
00800 }
00801
00802 if (rename( from_ospath, to_ospath )) {
00803
00804 FS_CopyFile ( from_ospath, to_ospath );
00805 FS_Remove ( from_ospath );
00806 }
00807 }
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 void FS_FCloseFile( fileHandle_t f ) {
00820 if ( !fs_searchpaths ) {
00821 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
00822 }
00823
00824 if (fsh[f].streamed) {
00825 Sys_EndStreamedFile(f);
00826 }
00827 if (fsh[f].zipFile == qtrue) {
00828 unzCloseCurrentFile( fsh[f].handleFiles.file.z );
00829 if ( fsh[f].handleFiles.unique ) {
00830 unzClose( fsh[f].handleFiles.file.z );
00831 }
00832 Com_Memset( &fsh[f], 0, sizeof( fsh[f] ) );
00833 return;
00834 }
00835
00836
00837 if (fsh[f].handleFiles.file.o) {
00838 fclose (fsh[f].handleFiles.file.o);
00839 }
00840 Com_Memset( &fsh[f], 0, sizeof( fsh[f] ) );
00841 }
00842
00843
00844
00845
00846
00847
00848
00849 fileHandle_t FS_FOpenFileWrite( const char *filename ) {
00850 char *ospath;
00851 fileHandle_t f;
00852
00853 if ( !fs_searchpaths ) {
00854 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
00855 }
00856
00857 f = FS_HandleForFile();
00858 fsh[f].zipFile = qfalse;
00859
00860 ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );
00861
00862 if ( fs_debug->integer ) {
00863 Com_Printf( "FS_FOpenFileWrite: %s\n", ospath );
00864 }
00865
00866 if( FS_CreatePath( ospath ) ) {
00867 return 0;
00868 }
00869
00870
00871
00872
00873 fsh[f].handleFiles.file.o = fopen( ospath, "wb" );
00874
00875 Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );
00876
00877 fsh[f].handleSync = qfalse;
00878 if (!fsh[f].handleFiles.file.o) {
00879 f = 0;
00880 }
00881 return f;
00882 }
00883
00884
00885
00886
00887
00888
00889
00890 fileHandle_t FS_FOpenFileAppend( const char *filename ) {
00891 char *ospath;
00892 fileHandle_t f;
00893
00894 if ( !fs_searchpaths ) {
00895 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
00896 }
00897
00898 f = FS_HandleForFile();
00899 fsh[f].zipFile = qfalse;
00900
00901 Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) );
00902
00903
00904 S_ClearSoundBuffer();
00905
00906 ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename );
00907
00908 if ( fs_debug->integer ) {
00909 Com_Printf( "FS_FOpenFileAppend: %s\n", ospath );
00910 }
00911
00912 if( FS_CreatePath( ospath ) ) {
00913 return 0;
00914 }
00915
00916 fsh[f].handleFiles.file.o = fopen( ospath, "ab" );
00917 fsh[f].handleSync = qfalse;
00918 if (!fsh[f].handleFiles.file.o) {
00919 f = 0;
00920 }
00921 return f;
00922 }
00923
00924
00925
00926
00927
00928
00929
00930
00931 qboolean FS_FilenameCompare( const char *s1, const char *s2 ) {
00932 int c1, c2;
00933
00934 do {
00935 c1 = *s1++;
00936 c2 = *s2++;
00937
00938 if (c1 >= 'a' && c1 <= 'z') {
00939 c1 -= ('a' - 'A');
00940 }
00941 if (c2 >= 'a' && c2 <= 'z') {
00942 c2 -= ('a' - 'A');
00943 }
00944
00945 if ( c1 == '\\' || c1 == ':' ) {
00946 c1 = '/';
00947 }
00948 if ( c2 == '\\' || c2 == ':' ) {
00949 c2 = '/';
00950 }
00951
00952 if (c1 != c2) {
00953 return -1;
00954 }
00955 } while (c1);
00956
00957 return 0;
00958 }
00959
00960
00961
00962
00963
00964
00965 char *FS_ShiftedStrStr(const char *string, const char *substring, int shift) {
00966 char buf[MAX_STRING_TOKENS];
00967 int i;
00968
00969 for (i = 0; substring[i]; i++) {
00970 buf[i] = substring[i] + shift;
00971 }
00972 buf[i] = '\0';
00973 return strstr(string, buf);
00974 }
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986 extern qboolean com_fullyInitialized;
00987
00988 int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) {
00989 searchpath_t *search;
00990 char *netpath;
00991 pack_t *pak;
00992 fileInPack_t *pakFile;
00993 directory_t *dir;
00994 long hash;
00995 unz_s *zfi;
00996 FILE *temp;
00997 int l;
00998 char demoExt[16];
00999
01000 hash = 0;
01001
01002 if ( !fs_searchpaths ) {
01003 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
01004 }
01005
01006 if ( file == NULL ) {
01007
01008 for ( search = fs_searchpaths ; search ; search = search->next ) {
01009
01010 if ( search->pack ) {
01011 hash = FS_HashFileName(filename, search->pack->hashSize);
01012 }
01013
01014 if ( search->pack && search->pack->hashTable[hash] ) {
01015
01016 pak = search->pack;
01017 pakFile = pak->hashTable[hash];
01018 do {
01019
01020 if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
01021
01022 return qtrue;
01023 }
01024 pakFile = pakFile->next;
01025 } while(pakFile != NULL);
01026 } else if ( search->dir ) {
01027 dir = search->dir;
01028
01029 netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
01030 temp = fopen (netpath, "rb");
01031 if ( !temp ) {
01032 continue;
01033 }
01034 fclose(temp);
01035 return qtrue;
01036 }
01037 }
01038 return qfalse;
01039 }
01040
01041 if ( !filename ) {
01042 Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" );
01043 }
01044
01045 Com_sprintf (demoExt, sizeof(demoExt), ".dm_%d",PROTOCOL_VERSION );
01046
01047 if ( filename[0] == '/' || filename[0] == '\\' ) {
01048 filename++;
01049 }
01050
01051
01052
01053
01054 if ( strstr( filename, ".." ) || strstr( filename, "::" ) ) {
01055 *file = 0;
01056 return -1;
01057 }
01058
01059
01060
01061 if( com_fullyInitialized && strstr( filename, "q3key" ) ) {
01062 *file = 0;
01063 return -1;
01064 }
01065
01066
01067
01068
01069
01070 *file = FS_HandleForFile();
01071 fsh[*file].handleFiles.unique = uniqueFILE;
01072
01073 for ( search = fs_searchpaths ; search ; search = search->next ) {
01074
01075 if ( search->pack ) {
01076 hash = FS_HashFileName(filename, search->pack->hashSize);
01077 }
01078
01079 if ( search->pack && search->pack->hashTable[hash] ) {
01080
01081 if ( !FS_PakIsPure(search->pack) ) {
01082 continue;
01083 }
01084
01085
01086 pak = search->pack;
01087 pakFile = pak->hashTable[hash];
01088 do {
01089
01090 if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
01091
01092
01093
01094
01095
01096
01097 l = strlen( filename );
01098 if ( !(pak->referenced & FS_GENERAL_REF)) {
01099 if ( Q_stricmp(filename + l - 7, ".shader") != 0 &&
01100 Q_stricmp(filename + l - 4, ".txt") != 0 &&
01101 Q_stricmp(filename + l - 4, ".cfg") != 0 &&
01102 Q_stricmp(filename + l - 7, ".config") != 0 &&
01103 strstr(filename, "levelshots") == NULL &&
01104 Q_stricmp(filename + l - 4, ".bot") != 0 &&
01105 Q_stricmp(filename + l - 6, ".arena") != 0 &&
01106 Q_stricmp(filename + l - 5, ".menu") != 0) {
01107 pak->referenced |= FS_GENERAL_REF;
01108 }
01109 }
01110
01111
01112
01113 if (!(pak->referenced & FS_QAGAME_REF) && FS_ShiftedStrStr(filename, "dTZT`X!di`", 13)) {
01114 pak->referenced |= FS_QAGAME_REF;
01115 }
01116
01117
01118 if (!(pak->referenced & FS_CGAME_REF) && FS_ShiftedStrStr(filename , "\\`Zf^'jof", 7)) {
01119 pak->referenced |= FS_CGAME_REF;
01120 }
01121
01122
01123 if (!(pak->referenced & FS_UI_REF) && FS_ShiftedStrStr(filename , "pd)lqh", 5)) {
01124 pak->referenced |= FS_UI_REF;
01125 }
01126
01127 if ( uniqueFILE ) {
01128
01129 fsh[*file].handleFiles.file.z = unzReOpen (pak->pakFilename, pak->handle);
01130 if (fsh[*file].handleFiles.file.z == NULL) {
01131 Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->pakFilename);
01132 }
01133 } else {
01134 fsh[*file].handleFiles.file.z = pak->handle;
01135 }
01136 Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
01137 fsh[*file].zipFile = qtrue;
01138 zfi = (unz_s *)fsh[*file].handleFiles.file.z;
01139
01140 temp = zfi->file;
01141
01142 unzSetCurrentFileInfoPosition(pak->handle, pakFile->pos);
01143
01144 Com_Memcpy( zfi, pak->handle, sizeof(unz_s) );
01145
01146 zfi->file = temp;
01147
01148 unzOpenCurrentFile( fsh[*file].handleFiles.file.z );
01149 fsh[*file].zipFilePos = pakFile->pos;
01150
01151 if ( fs_debug->integer ) {
01152 Com_Printf( "FS_FOpenFileRead: %s (found in '%s')\n",
01153 filename, pak->pakFilename );
01154 }
01155 return zfi->cur_file_info.uncompressed_size;
01156 }
01157 pakFile = pakFile->next;
01158 } while(pakFile != NULL);
01159 } else if ( search->dir ) {
01160
01161
01162
01163
01164 l = strlen( filename );
01165
01166
01167
01168
01169
01170 if ( fs_restrict->integer || fs_numServerPaks ) {
01171
01172 if ( Q_stricmp( filename + l - 4, ".cfg" )
01173 && Q_stricmp( filename + l - 5, ".menu" )
01174 && Q_stricmp( filename + l - 5, ".game" )
01175 && Q_stricmp( filename + l - strlen(demoExt), demoExt )
01176 && Q_stricmp( filename + l - 4, ".dat" ) ) {
01177 continue;
01178 }
01179 }
01180
01181 dir = search->dir;
01182
01183 netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename );
01184 fsh[*file].handleFiles.file.o = fopen (netpath, "rb");
01185 if ( !fsh[*file].handleFiles.file.o ) {
01186 continue;
01187 }
01188
01189 if ( Q_stricmp( filename + l - 4, ".cfg" )
01190 && Q_stricmp( filename + l - 5, ".menu" )
01191 && Q_stricmp( filename + l - 5, ".game" )
01192 && Q_stricmp( filename + l - strlen(demoExt), demoExt )
01193 && Q_stricmp( filename + l - 4, ".dat" ) ) {
01194 fs_fakeChkSum = random();
01195 }
01196
01197 Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) );
01198 fsh[*file].zipFile = qfalse;
01199 if ( fs_debug->integer ) {
01200 Com_Printf( "FS_FOpenFileRead: %s (found in '%s/%s')\n", filename,
01201 dir->path, dir->gamedir );
01202 }
01203
01204
01205
01206 if ( fs_copyfiles->integer && !Q_stricmp( dir->path, fs_cdpath->string ) ) {
01207 char *copypath;
01208
01209 copypath = FS_BuildOSPath( fs_basepath->string, dir->gamedir, filename );
01210 FS_CopyFile( netpath, copypath );
01211 }
01212
01213 return FS_filelength (*file);
01214 }
01215 }
01216
01217 Com_DPrintf ("Can't find %s\n", filename);
01218 #ifdef FS_MISSING
01219 if (missingFiles) {
01220 fprintf(missingFiles, "%s\n", filename);
01221 }
01222 #endif
01223 *file = 0;
01224 return -1;
01225 }
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235 int FS_Read2( void *buffer, int len, fileHandle_t f ) {
01236 if ( !fs_searchpaths ) {
01237 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
01238 }
01239
01240 if ( !f ) {
01241 return 0;
01242 }
01243 if (fsh[f].streamed) {
01244 int r;
01245 fsh[f].streamed = qfalse;
01246 r = Sys_StreamedRead( buffer, len, 1, f);
01247 fsh[f].streamed = qtrue;
01248 return r;
01249 } else {
01250 return FS_Read( buffer, len, f);
01251 }
01252 }
01253
01254 int FS_Read( void *buffer, int len, fileHandle_t f ) {
01255 int block, remaining;
01256 int read;
01257 byte *buf;
01258 int tries;
01259
01260 if ( !fs_searchpaths ) {
01261 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
01262 }
01263
01264 if ( !f ) {
01265 return 0;
01266 }
01267
01268 buf = (byte *)buffer;
01269 fs_readCount += len;
01270
01271 if (fsh[f].zipFile == qfalse) {
01272 remaining = len;
01273 tries = 0;
01274 while (remaining) {
01275 block = remaining;
01276 read = fread (buf, 1, block, fsh[f].handleFiles.file.o);
01277 if (read == 0) {
01278
01279
01280 if (!tries) {
01281 tries = 1;
01282 } else {
01283 return len-remaining;
01284 }
01285 }
01286
01287 if (read == -1) {
01288 Com_Error (ERR_FATAL, "FS_Read: -1 bytes read");
01289 }
01290
01291 remaining -= read;
01292 buf += read;
01293 }
01294 return len;
01295 } else {
01296 return unzReadCurrentFile(fsh[f].handleFiles.file.z, buffer, len);
01297 }
01298 }
01299
01300
01301
01302
01303
01304
01305
01306
01307 int FS_Write( const void *buffer, int len, fileHandle_t h ) {
01308 int block, remaining;
01309 int written;
01310 byte *buf;
01311 int tries;
01312 FILE *f;
01313
01314 if ( !fs_searchpaths ) {
01315 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
01316 }
01317
01318 if ( !h ) {
01319 return 0;
01320 }
01321
01322 f = FS_FileForHandle(h);
01323 buf = (byte *)buffer;
01324
01325 remaining = len;
01326 tries = 0;
01327 while (remaining) {
01328 block = remaining;
01329 written = fwrite (buf, 1, block, f);
01330 if (written == 0) {
01331 if (!tries) {
01332 tries = 1;
01333 } else {
01334 Com_Printf( "FS_Write: 0 bytes written\n" );
01335 return 0;
01336 }
01337 }
01338
01339 if (written == -1) {
01340 Com_Printf( "FS_Write: -1 bytes written\n" );
01341 return 0;
01342 }
01343
01344 remaining -= written;
01345 buf += written;
01346 }
01347 if ( fsh[h].handleSync ) {
01348 fflush( f );
01349 }
01350 return len;
01351 }
01352
01353 void QDECL FS_Printf( fileHandle_t h, const char *fmt, ... ) {
01354 va_list argptr;
01355 char msg[MAXPRINTMSG];
01356
01357 va_start (argptr,fmt);
01358 Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
01359 va_end (argptr);
01360
01361 FS_Write(msg, strlen(msg), h);
01362 }
01363
01364
01365
01366
01367
01368
01369
01370 int FS_Seek( fileHandle_t f, long offset, int origin ) {
01371 int _origin;
01372 char foo[65536];
01373
01374 if ( !fs_searchpaths ) {
01375 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
01376 return -1;
01377 }
01378
01379 if (fsh[f].streamed) {
01380 fsh[f].streamed = qfalse;
01381 Sys_StreamSeek( f, offset, origin );
01382 fsh[f].streamed = qtrue;
01383 }
01384
01385 if (fsh[f].zipFile == qtrue) {
01386 if (offset == 0 && origin == FS_SEEK_SET) {
01387
01388 unzSetCurrentFileInfoPosition(fsh[f].handleFiles.file.z, fsh[f].zipFilePos);
01389 return unzOpenCurrentFile(fsh[f].handleFiles.file.z);
01390 } else if (offset<65536) {
01391
01392 unzSetCurrentFileInfoPosition(fsh[f].handleFiles.file.z, fsh[f].zipFilePos);
01393 unzOpenCurrentFile(fsh[f].handleFiles.file.z);
01394 return FS_Read(foo, offset, f);
01395 } else {
01396 Com_Error( ERR_FATAL, "ZIP FILE FSEEK NOT YET IMPLEMENTED\n" );
01397 return -1;
01398 }
01399 } else {
01400 FILE *file;
01401 file = FS_FileForHandle(f);
01402 switch( origin ) {
01403 case FS_SEEK_CUR:
01404 _origin = SEEK_CUR;
01405 break;
01406 case FS_SEEK_END:
01407 _origin = SEEK_END;
01408 break;
01409 case FS_SEEK_SET:
01410 _origin = SEEK_SET;
01411 break;
01412 default:
01413 _origin = SEEK_CUR;
01414 Com_Error( ERR_FATAL, "Bad origin in FS_Seek\n" );
01415 break;
01416 }
01417
01418 return fseek( file, offset, _origin );
01419 }
01420 }
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431 int FS_FileIsInPAK(const char *filename, int *pChecksum ) {
01432 searchpath_t *search;
01433 pack_t *pak;
01434 fileInPack_t *pakFile;
01435 long hash = 0;
01436
01437 if ( !fs_searchpaths ) {
01438 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
01439 }
01440
01441 if ( !filename ) {
01442 Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" );
01443 }
01444
01445
01446 if ( filename[0] == '/' || filename[0] == '\\' ) {
01447 filename++;
01448 }
01449
01450
01451
01452
01453 if ( strstr( filename, ".." ) || strstr( filename, "::" ) ) {
01454 return -1;
01455 }
01456
01457
01458
01459
01460
01461 for ( search = fs_searchpaths ; search ; search = search->next ) {
01462
01463 if (search->pack) {
01464 hash = FS_HashFileName(filename, search->pack->hashSize);
01465 }
01466
01467 if ( search->pack && search->pack->hashTable[hash] ) {
01468
01469 if ( !FS_PakIsPure(search->pack) ) {
01470 continue;
01471 }
01472
01473
01474 pak = search->pack;
01475 pakFile = pak->hashTable[hash];
01476 do {
01477
01478 if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
01479 if (pChecksum) {
01480 *pChecksum = pak->pure_checksum;
01481 }
01482 return 1;
01483 }
01484 pakFile = pakFile->next;
01485 } while(pakFile != NULL);
01486 }
01487 }
01488 return -1;
01489 }
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499 int FS_ReadFile( const char *qpath, void **buffer ) {
01500 fileHandle_t h;
01501 byte* buf;
01502 qboolean isConfig;
01503 int len;
01504
01505 if ( !fs_searchpaths ) {
01506 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
01507 }
01508
01509 if ( !qpath || !qpath[0] ) {
01510 Com_Error( ERR_FATAL, "FS_ReadFile with empty name\n" );
01511 }
01512
01513 buf = NULL;
01514
01515
01516
01517 if ( strstr( qpath, ".cfg" ) ) {
01518 isConfig = qtrue;
01519 if ( com_journal && com_journal->integer == 2 ) {
01520 int r;
01521
01522 Com_DPrintf( "Loading %s from journal file.\n", qpath );
01523 r = FS_Read( &len, sizeof( len ), com_journalDataFile );
01524 if ( r != sizeof( len ) ) {
01525 if (buffer != NULL) *buffer = NULL;
01526 return -1;
01527 }
01528
01529 if (!len) {
01530 if (buffer == NULL) {
01531 return 1;
01532 }
01533 *buffer = NULL;
01534 return -1;
01535 }
01536 if (buffer == NULL) {
01537 return len;
01538 }
01539
01540 buf = Hunk_AllocateTempMemory(len+1);
01541 *buffer = buf;
01542
01543 r = FS_Read( buf, len, com_journalDataFile );
01544 if ( r != len ) {
01545 Com_Error( ERR_FATAL, "Read from journalDataFile failed" );
01546 }
01547
01548 fs_loadCount++;
01549 fs_loadStack++;
01550
01551
01552 buf[len] = 0;
01553
01554 return len;
01555 }
01556 } else {
01557 isConfig = qfalse;
01558 }
01559
01560
01561 len = FS_FOpenFileRead( qpath, &h, qfalse );
01562 if ( h == 0 ) {
01563 if ( buffer ) {
01564 *buffer = NULL;
01565 }
01566
01567 if ( isConfig && com_journal && com_journal->integer == 1 ) {
01568 Com_DPrintf( "Writing zero for %s to journal file.\n", qpath );
01569 len = 0;
01570 FS_Write( &len, sizeof( len ), com_journalDataFile );
01571 FS_Flush( com_journalDataFile );
01572 }
01573 return -1;
01574 }
01575
01576 if ( !buffer ) {
01577 if ( isConfig && com_journal && com_journal->integer == 1 ) {
01578 Com_DPrintf( "Writing len for %s to journal file.\n", qpath );
01579 FS_Write( &len, sizeof( len ), com_journalDataFile );
01580 FS_Flush( com_journalDataFile );
01581 }
01582 FS_FCloseFile( h);
01583 return len;
01584 }
01585
01586 fs_loadCount++;
01587 fs_loadStack++;
01588
01589 buf = Hunk_AllocateTempMemory(len+1);
01590 *buffer = buf;
01591
01592 FS_Read (buf, len, h);
01593
01594
01595 buf[len] = 0;
01596 FS_FCloseFile( h );
01597
01598
01599 if ( isConfig && com_journal && com_journal->integer == 1 ) {
01600 Com_DPrintf( "Writing %s to journal file.\n", qpath );
01601 FS_Write( &len, sizeof( len ), com_journalDataFile );
01602 FS_Write( buf, len, com_journalDataFile );
01603 FS_Flush( com_journalDataFile );
01604 }
01605 return len;
01606 }
01607
01608
01609
01610
01611
01612
01613 void FS_FreeFile( void *buffer ) {
01614 if ( !fs_searchpaths ) {
01615 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
01616 }
01617 if ( !buffer ) {
01618 Com_Error( ERR_FATAL, "FS_FreeFile( NULL )" );
01619 }
01620 fs_loadStack--;
01621
01622 Hunk_FreeTempMemory( buffer );
01623
01624
01625 if ( fs_loadStack == 0 ) {
01626 Hunk_ClearTempMemory();
01627 }
01628 }
01629
01630
01631
01632
01633
01634
01635
01636
01637 void FS_WriteFile( const char *qpath, const void *buffer, int size ) {
01638 fileHandle_t f;
01639
01640 if ( !fs_searchpaths ) {
01641 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
01642 }
01643
01644 if ( !qpath || !buffer ) {
01645 Com_Error( ERR_FATAL, "FS_WriteFile: NULL parameter" );
01646 }
01647
01648 f = FS_FOpenFileWrite( qpath );
01649 if ( !f ) {
01650 Com_Printf( "Failed to open %s\n", qpath );
01651 return;
01652 }
01653
01654 FS_Write( buffer, size, f );
01655
01656 FS_FCloseFile( f );
01657 }
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677 static pack_t *FS_LoadZipFile( char *zipfile, const char *basename )
01678 {
01679 fileInPack_t *buildBuffer;
01680 pack_t *pack;
01681 unzFile uf;
01682 int err;
01683 unz_global_info gi;
01684 char filename_inzip[MAX_ZPATH];
01685 unz_file_info file_info;
01686 int i, len;
01687 long hash;
01688 int fs_numHeaderLongs;
01689 int *fs_headerLongs;
01690 char *namePtr;
01691
01692 fs_numHeaderLongs = 0;
01693
01694 uf = unzOpen(zipfile);
01695 err = unzGetGlobalInfo (uf,&gi);
01696
01697 if (err != UNZ_OK)
01698 return NULL;
01699
01700 fs_packFiles += gi.number_entry;
01701
01702 len = 0;
01703 unzGoToFirstFile(uf);
01704 for (i = 0; i < gi.number_entry; i++)
01705 {
01706 err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
01707 if (err != UNZ_OK) {
01708 break;
01709 }
01710 len += strlen(filename_inzip) + 1;
01711 unzGoToNextFile(uf);
01712 }
01713
01714 buildBuffer = Z_Malloc( (gi.number_entry * sizeof( fileInPack_t )) + len );
01715 namePtr = ((char *) buildBuffer) + gi.number_entry * sizeof( fileInPack_t );
01716 fs_headerLongs = Z_Malloc( gi.number_entry * sizeof(int) );
01717
01718
01719
01720 for (i = 1; i <= MAX_FILEHASH_SIZE; i <<= 1) {
01721 if (i > gi.number_entry) {
01722 break;
01723 }
01724 }
01725
01726 pack = Z_Malloc( sizeof( pack_t ) + i * sizeof(fileInPack_t *) );
01727 pack->hashSize = i;
01728 pack->hashTable = (fileInPack_t **) (((char *) pack) + sizeof( pack_t ));
01729 for(i = 0; i < pack->hashSize; i++) {
01730 pack->hashTable[i] = NULL;
01731 }
01732
01733 Q_strncpyz( pack->pakFilename, zipfile, sizeof( pack->pakFilename ) );
01734 Q_strncpyz( pack->pakBasename, basename, sizeof( pack->pakBasename ) );
01735
01736
01737 if ( strlen( pack->pakBasename ) > 4 && !Q_stricmp( pack->pakBasename + strlen( pack->pakBasename ) - 4, ".pk3" ) ) {
01738 pack->pakBasename[strlen( pack->pakBasename ) - 4] = 0;
01739 }
01740
01741 pack->handle = uf;
01742 pack->numfiles = gi.number_entry;
01743 unzGoToFirstFile(uf);
01744
01745 for (i = 0; i < gi.number_entry; i++)
01746 {
01747 err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
01748 if (err != UNZ_OK) {
01749 break;
01750 }
01751 if (file_info.uncompressed_size > 0) {
01752 fs_headerLongs[fs_numHeaderLongs++] = LittleLong(file_info.crc);
01753 }
01754 Q_strlwr( filename_inzip );
01755 hash = FS_HashFileName(filename_inzip, pack->hashSize);
01756 buildBuffer[i].name = namePtr;
01757 strcpy( buildBuffer[i].name, filename_inzip );
01758 namePtr += strlen(filename_inzip) + 1;
01759
01760 unzGetCurrentFileInfoPosition(uf, &buildBuffer[i].pos);
01761
01762 buildBuffer[i].next = pack->hashTable[hash];
01763 pack->hashTable[hash] = &buildBuffer[i];
01764 unzGoToNextFile(uf);
01765 }
01766
01767 pack->checksum = Com_BlockChecksum( fs_headerLongs, 4 * fs_numHeaderLongs );
01768 pack->pure_checksum = Com_BlockChecksumKey( fs_headerLongs, 4 * fs_numHeaderLongs, LittleLong(fs_checksumFeed) );
01769 pack->checksum = LittleLong( pack->checksum );
01770 pack->pure_checksum = LittleLong( pack->pure_checksum );
01771
01772 Z_Free(fs_headerLongs);
01773
01774 pack->buildBuffer = buildBuffer;
01775 return pack;
01776 }
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786 #define MAX_FOUND_FILES 0x1000
01787
01788 static int FS_ReturnPath( const char *zname, char *zpath, int *depth ) {
01789 int len, at, newdep;
01790
01791 newdep = 0;
01792 zpath[0] = 0;
01793 len = 0;
01794 at = 0;
01795
01796 while(zname[at] != 0)
01797 {
01798 if (zname[at]=='/' || zname[at]=='\\') {
01799 len = at;
01800 newdep++;
01801 }
01802 at++;
01803 }
01804 strcpy(zpath, zname);
01805 zpath[len] = 0;
01806 *depth = newdep;
01807
01808 return len;
01809 }
01810
01811
01812
01813
01814
01815
01816 static int FS_AddFileToList( char *name, char *list[MAX_FOUND_FILES], int nfiles ) {
01817 int i;
01818
01819 if ( nfiles == MAX_FOUND_FILES - 1 ) {
01820 return nfiles;
01821 }
01822 for ( i = 0 ; i < nfiles ; i++ ) {
01823 if ( !Q_stricmp( name, list[i] ) ) {
01824 return nfiles;
01825 }
01826 }
01827 list[nfiles] = CopyString( name );
01828 nfiles++;
01829
01830 return nfiles;
01831 }
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841 char **FS_ListFilteredFiles( const char *path, const char *extension, char *filter, int *numfiles ) {
01842 int nfiles;
01843 char **listCopy;
01844 char *list[MAX_FOUND_FILES];
01845 searchpath_t *search;
01846 int i;
01847 int pathLength;
01848 int extensionLength;
01849 int length, pathDepth, temp;
01850 pack_t *pak;
01851 fileInPack_t *buildBuffer;
01852 char zpath[MAX_ZPATH];
01853
01854 if ( !fs_searchpaths ) {
01855 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
01856 }
01857
01858 if ( !path ) {
01859 *numfiles = 0;
01860 return NULL;
01861 }
01862 if ( !extension ) {
01863 extension = "";
01864 }
01865
01866 pathLength = strlen( path );
01867 if ( path[pathLength-1] == '\\' || path[pathLength-1] == '/' ) {
01868 pathLength--;
01869 }
01870 extensionLength = strlen( extension );
01871 nfiles = 0;
01872 FS_ReturnPath(path, zpath, &pathDepth);
01873
01874
01875
01876
01877 for (search = fs_searchpaths ; search ; search = search->next) {
01878
01879 if (search->pack) {
01880
01881
01882
01883 if ( !FS_PakIsPure(search->pack) ) {
01884 continue;
01885 }
01886
01887
01888 pak = search->pack;
01889 buildBuffer = pak->buildBuffer;
01890 for (i = 0; i < pak->numfiles; i++) {
01891 char *name;
01892 int zpathLen, depth;
01893
01894
01895 name = buildBuffer[i].name;
01896
01897 if (filter) {
01898
01899 if (!Com_FilterPath( filter, name, qfalse ))
01900 continue;
01901
01902 nfiles = FS_AddFileToList( name, list, nfiles );
01903 }
01904 else {
01905
01906 zpathLen = FS_ReturnPath(name, zpath, &depth);
01907
01908 if ( (depth-pathDepth)>2 || pathLength > zpathLen || Q_stricmpn( name, path, pathLength ) ) {
01909 continue;
01910 }
01911
01912
01913 length = strlen( name );
01914 if ( length < extensionLength ) {
01915 continue;
01916 }
01917
01918 if ( Q_stricmp( name + length - extensionLength, extension ) ) {
01919 continue;
01920 }
01921
01922
01923 temp = pathLength;
01924 if (pathLength) {
01925 temp++;
01926 }
01927 nfiles = FS_AddFileToList( name + temp, list, nfiles );
01928 }
01929 }
01930 } else if (search->dir) {
01931 char *netpath;
01932 int numSysFiles;
01933 char **sysFiles;
01934 char *name;
01935
01936
01937 if ( fs_restrict->integer || fs_numServerPaks ) {
01938 continue;
01939 } else {
01940 netpath = FS_BuildOSPath( search->dir->path, search->dir->gamedir, path );
01941 sysFiles = Sys_ListFiles( netpath, extension, filter, &numSysFiles, qfalse );
01942 for ( i = 0 ; i < numSysFiles ; i++ ) {
01943
01944 name = sysFiles[i];
01945 nfiles = FS_AddFileToList( name, list, nfiles );
01946 }
01947 Sys_FreeFileList( sysFiles );
01948 }
01949 }
01950 }
01951
01952
01953 *numfiles = nfiles;
01954
01955 if ( !nfiles ) {
01956 return NULL;
01957 }
01958
01959 listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) );
01960 for ( i = 0 ; i < nfiles ; i++ ) {
01961 listCopy[i] = list[i];
01962 }
01963 listCopy[i] = NULL;
01964
01965 return listCopy;
01966 }
01967
01968
01969
01970
01971
01972
01973 char **FS_ListFiles( const char *path, const char *extension, int *numfiles ) {
01974 return FS_ListFilteredFiles( path, extension, NULL, numfiles );
01975 }
01976
01977
01978
01979
01980
01981
01982 void FS_FreeFileList( char **list ) {
01983 int i;
01984
01985 if ( !fs_searchpaths ) {
01986 Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
01987 }
01988
01989 if ( !list ) {
01990 return;
01991 }
01992
01993 for ( i = 0 ; list[i] ; i++ ) {
01994 Z_Free( list[i] );
01995 }
01996
01997 Z_Free( list );
01998 }
01999
02000
02001
02002
02003
02004
02005
02006 int FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ) {
02007 int nFiles, i, nTotal, nLen;
02008 char **pFiles = NULL;
02009
02010 *listbuf = 0;
02011 nFiles = 0;
02012 nTotal = 0;
02013
02014 if (Q_stricmp(path, "$modlist") == 0) {
02015 return FS_GetModList(listbuf, bufsize);
02016 }
02017
02018 pFiles = FS_ListFiles(path, extension, &nFiles);
02019
02020 for (i =0; i < nFiles; i++) {
02021 nLen = strlen(pFiles[i]) + 1;
02022 if (nTotal + nLen + 1 < bufsize) {
02023 strcpy(listbuf, pFiles[i]);
02024 listbuf += nLen;
02025 nTotal += nLen;
02026 }
02027 else {
02028 nFiles = i;
02029 break;
02030 }
02031 }
02032
02033 FS_FreeFileList(pFiles);
02034
02035 return nFiles;
02036 }
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046
02047
02048
02049 static unsigned int Sys_CountFileList(char **list)
02050 {
02051 int i = 0;
02052
02053 if (list)
02054 {
02055 while (*list)
02056 {
02057 list++;
02058 i++;
02059 }
02060 }
02061 return i;
02062 }
02063
02064 static char** Sys_ConcatenateFileLists( char **list0, char **list1, char **list2 )
02065 {
02066 int totalLength = 0;
02067 char** cat = NULL, **dst, **src;
02068
02069 totalLength += Sys_CountFileList(list0);
02070 totalLength += Sys_CountFileList(list1);
02071 totalLength += Sys_CountFileList(list2);
02072
02073
02074 dst = cat = Z_Malloc( ( totalLength + 1 ) * sizeof( char* ) );
02075
02076
02077 if (list0)
02078 {
02079 for (src = list0; *src; src++, dst++)
02080 *dst = *src;
02081 }
02082 if (list1)
02083 {
02084 for (src = list1; *src; src++, dst++)
02085 *dst = *src;
02086 }
02087 if (list2)
02088 {
02089 for (src = list2; *src; src++, dst++)
02090 *dst = *src;
02091 }
02092
02093
02094 *dst = NULL;
02095
02096
02097
02098 if (list0) Z_Free( list0 );
02099 if (list1) Z_Free( list1 );
02100 if (list2) Z_Free( list2 );
02101
02102 return cat;
02103 }
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113
02114 int FS_GetModList( char *listbuf, int bufsize ) {
02115 int nMods, i, j, nTotal, nLen, nPaks, nPotential, nDescLen;
02116 char **pFiles = NULL;
02117 char **pPaks = NULL;
02118 char *name, *path;
02119 char descPath[MAX_OSPATH];
02120 fileHandle_t descHandle;
02121
02122 int dummy;
02123 char **pFiles0 = NULL;
02124 char **pFiles1 = NULL;
02125 char **pFiles2 = NULL;
02126 qboolean bDrop = qfalse;
02127
02128 *listbuf = 0;
02129 nMods = nPotential = nTotal = 0;
02130
02131 pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue );
02132 pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue );
02133 pFiles2 = Sys_ListFiles( fs_cdpath->string, NULL, NULL, &dummy, qtrue );
02134
02135
02136 pFiles = Sys_ConcatenateFileLists( pFiles0, pFiles1, pFiles2 );
02137 nPotential = Sys_CountFileList(pFiles);
02138
02139 for ( i = 0 ; i < nPotential ; i++ ) {
02140 name = pFiles[i];
02141
02142
02143 if (i!=0) {
02144 bDrop = qfalse;
02145 for(j=0; j<i; j++)
02146 {
02147 if (Q_stricmp(pFiles[j],name)==0) {
02148
02149 bDrop = qtrue;
02150 break;
02151 }
02152 }
02153 }
02154 if (bDrop) {
02155 continue;
02156 }
02157
02158 if (Q_stricmp(name, "baseq3") && Q_stricmpn(name, ".", 1)) {
02159
02160
02161
02162
02163
02164 path = FS_BuildOSPath( fs_basepath->string, name, "" );
02165 nPaks = 0;
02166 pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, qfalse);
02167 Sys_FreeFileList( pPaks );
02168
02169
02170 if( nPaks <= 0 ) {
02171 path = FS_BuildOSPath( fs_cdpath->string, name, "" );
02172 nPaks = 0;
02173 pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
02174 Sys_FreeFileList( pPaks );
02175 }
02176
02177
02178 if ( nPaks <= 0 )
02179 {
02180 path = FS_BuildOSPath( fs_homepath->string, name, "" );
02181 nPaks = 0;
02182 pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse );
02183 Sys_FreeFileList( pPaks );
02184 }
02185
02186 if (nPaks > 0) {
02187 nLen = strlen(name) + 1;
02188
02189
02190 descPath[0] = '\0';
02191 strcpy(descPath, name);
02192 strcat(descPath, "/description.txt");
02193 nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle );
02194 if ( nDescLen > 0 && descHandle) {
02195 FILE *file;
02196 file = FS_FileForHandle(descHandle);
02197 Com_Memset( descPath, 0, sizeof( descPath ) );
02198 nDescLen = fread(descPath, 1, 48, file);
02199 if (nDescLen >= 0) {
02200 descPath[nDescLen] = '\0';
02201 }
02202 FS_FCloseFile(descHandle);
02203 } else {
02204 strcpy(descPath, name);
02205 }
02206 nDescLen = strlen(descPath) + 1;
02207
02208 if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) {
02209 strcpy(listbuf, name);
02210 listbuf += nLen;
02211 strcpy(listbuf, descPath);
02212 listbuf += nDescLen;
02213 nTotal += nLen + nDescLen;
02214 nMods++;
02215 }
02216 else {
02217 break;
02218 }
02219 }
02220 }
02221 }
02222 Sys_FreeFileList( pFiles );
02223
02224 return nMods;
02225 }
02226
02227
02228
02229
02230
02231
02232
02233
02234
02235
02236
02237 void FS_Dir_f( void ) {
02238 char *path;
02239 char *extension;
02240 char **dirnames;
02241 int ndirs;
02242 int i;
02243
02244 if ( Cmd_Argc() < 2 || Cmd_Argc() > 3 ) {
02245 Com_Printf( "usage: dir <directory> [extension]\n" );
02246 return;
02247 }
02248
02249 if ( Cmd_Argc() == 2 ) {
02250 path = Cmd_Argv( 1 );
02251 extension = "";
02252 } else {
02253 path = Cmd_Argv( 1 );
02254 extension = Cmd_Argv( 2 );
02255 }
02256
02257 Com_Printf( "Directory of %s %s\n", path, extension );
02258 Com_Printf( "---------------\n" );
02259
02260 dirnames = FS_ListFiles( path, extension, &ndirs );
02261
02262 for ( i = 0; i < ndirs; i++ ) {
02263 Com_Printf( "%s\n", dirnames[i] );
02264 }
02265 FS_FreeFileList( dirnames );
02266 }
02267
02268
02269
02270
02271
02272
02273 void FS_ConvertPath( char *s ) {
02274 while (*s) {
02275 if ( *s == '\\' || *s == ':' ) {
02276 *s = '/';
02277 }
02278 s++;
02279 }
02280 }
02281
02282
02283
02284
02285
02286
02287
02288
02289 int FS_PathCmp( const char *s1, const char *s2 ) {
02290 int c1, c2;
02291
02292 do {
02293 c1 = *s1++;
02294 c2 = *s2++;
02295
02296 if (c1 >= 'a' && c1 <= 'z') {
02297 c1 -= ('a' - 'A');
02298 }
02299 if (c2 >= 'a' && c2 <= 'z') {
02300 c2 -= ('a' - 'A');
02301 }
02302
02303 if ( c1 == '\\' || c1 == ':' ) {
02304 c1 = '/';
02305 }
02306 if ( c2 == '\\' || c2 == ':' ) {
02307 c2 = '/';
02308 }
02309
02310 if (c1 < c2) {
02311 return -1;
02312 }
02313 if (c1 > c2) {
02314 return 1;
02315 }
02316 } while (c1);
02317
02318 return 0;
02319 }
02320
02321
02322
02323
02324
02325
02326 void FS_SortFileList(char **filelist, int numfiles) {
02327 int i, j, k, numsortedfiles;
02328 char **sortedlist;
02329
02330 sortedlist = Z_Malloc( ( numfiles + 1 ) * sizeof( *sortedlist ) );
02331 sortedlist[0] = NULL;
02332 numsortedfiles = 0;
02333 for (i = 0; i < numfiles; i++) {
02334 for (j = 0; j < numsortedfiles; j++) {
02335 if (FS_PathCmp(filelist[i], sortedlist[j]) < 0) {
02336 break;
02337 }
02338 }
02339 for (k = numsortedfiles; k > j; k--) {
02340 sortedlist[k] = sortedlist[k-1];
02341 }
02342 sortedlist[j] = filelist[i];
02343 numsortedfiles++;
02344 }
02345 Com_Memcpy(filelist, sortedlist, numfiles * sizeof( *filelist ) );
02346 Z_Free(sortedlist);
02347 }
02348
02349
02350
02351
02352
02353
02354 void FS_NewDir_f( void ) {
02355 char *filter;
02356 char **dirnames;
02357 int ndirs;
02358 int i;
02359
02360 if ( Cmd_Argc() < 2 ) {
02361 Com_Printf( "usage: fdir <filter>\n" );
02362 Com_Printf( "example: fdir *q3dm*.bsp\n");
02363 return;
02364 }
02365
02366 filter = Cmd_Argv( 1 );
02367
02368 Com_Printf( "---------------\n" );
02369
02370 dirnames = FS_ListFilteredFiles( "", "", filter, &ndirs );
02371
02372 FS_SortFileList(dirnames, ndirs);
02373
02374 for ( i = 0; i < ndirs; i++ ) {
02375 FS_ConvertPath(dirnames[i]);
02376 Com_Printf( "%s\n", dirnames[i] );
02377 }
02378 Com_Printf( "%d files listed\n", ndirs );
02379 FS_FreeFileList( dirnames );
02380 }
02381
02382
02383
02384
02385
02386
02387
02388 void FS_Path_f( void ) {
02389 searchpath_t *s;
02390 int i;
02391
02392 Com_Printf ("Current search path:\n");
02393 for (s = fs_searchpaths; s; s = s->next) {
02394 if (s->pack) {
02395 Com_Printf ("%s (%i files)\n", s->pack->pakFilename, s->pack->numfiles);
02396 if ( fs_numServerPaks ) {
02397 if ( !FS_PakIsPure(s->pack) ) {
02398 Com_Printf( " not on the pure list\n" );
02399 } else {
02400 Com_Printf( " on the pure list\n" );
02401 }
02402 }
02403 } else {
02404 Com_Printf ("%s/%s\n", s->dir->path, s->dir->gamedir );
02405 }
02406 }
02407
02408
02409 Com_Printf( "\n" );
02410 for ( i = 1 ; i < MAX_FILE_HANDLES ; i++ ) {
02411 if ( fsh[i].handleFiles.file.o ) {
02412 Com_Printf( "handle %i: %s\n", i, fsh[i].name );
02413 }
02414 }
02415 }
02416
02417
02418
02419
02420
02421
02422
02423
02424
02425 void FS_TouchFile_f( void ) {
02426 fileHandle_t f;
02427
02428 if ( Cmd_Argc() != 2 ) {
02429 Com_Printf( "Usage: touchFile <file>\n" );
02430 return;
02431 }
02432
02433 FS_FOpenFileRead( Cmd_Argv( 1 ), &f, qfalse );
02434 if ( f ) {
02435 FS_FCloseFile( f );
02436 }
02437 }
02438
02439
02440
02441
02442 static int QDECL paksort( const void *a, const void *b ) {
02443 char *aa, *bb;
02444
02445 aa = *(char **)a;
02446 bb = *(char **)b;
02447
02448 return FS_PathCmp( aa, bb );
02449 }
02450
02451
02452
02453
02454
02455
02456
02457
02458
02459 #define MAX_PAKFILES 1024
02460 static void FS_AddGameDirectory( const char *path, const char *dir ) {
02461 searchpath_t *sp;
02462 int i;
02463 searchpath_t *search;
02464 pack_t *pak;
02465 char *pakfile;
02466 int numfiles;
02467 char **pakfiles;
02468 char *sorted[MAX_PAKFILES];
02469
02470
02471
02472 for ( sp = fs_searchpaths ; sp ; sp = sp->next ) {
02473 if ( sp->dir && !Q_stricmp(sp->dir->path, path) && !Q_stricmp(sp->dir->gamedir, dir)) {
02474 return;
02475 }
02476 }
02477
02478 Q_strncpyz( fs_gamedir, dir, sizeof( fs_gamedir ) );
02479
02480
02481
02482
02483 search = Z_Malloc (sizeof(searchpath_t));
02484 search->dir = Z_Malloc( sizeof( *search->dir ) );
02485
02486 Q_strncpyz( search->dir->path, path, sizeof( search->dir->path ) );
02487 Q_strncpyz( search->dir->gamedir, dir, sizeof( search->dir->gamedir ) );
02488 search->next = fs_searchpaths;
02489 fs_searchpaths = search;
02490
02491
02492 pakfile = FS_BuildOSPath( path, dir, "" );
02493 pakfile[ strlen(pakfile) - 1 ] = 0;
02494
02495 pakfiles = Sys_ListFiles( pakfile, ".pk3", NULL, &numfiles, qfalse );
02496
02497
02498
02499 if ( numfiles > MAX_PAKFILES ) {
02500 numfiles = MAX_PAKFILES;
02501 }
02502 for ( i = 0 ; i < numfiles ; i++ ) {
02503 sorted[i] = pakfiles[i];
02504 }
02505
02506 qsort( sorted, numfiles, 4, paksort );
02507
02508 for ( i = 0 ; i < numfiles ; i++ ) {
02509 pakfile = FS_BuildOSPath( path, dir, sorted[i] );
02510 if ( ( pak = FS_LoadZipFile( pakfile, sorted[i] ) ) == 0 )
02511 continue;
02512
02513 strcpy(pak->pakGamename, dir);
02514
02515 search = Z_Malloc (sizeof(searchpath_t));
02516 search->pack = pak;
02517 search->next = fs_searchpaths;
02518 fs_searchpaths = search;
02519 }
02520
02521
02522 Sys_FreeFileList( pakfiles );
02523 }
02524
02525
02526
02527
02528
02529
02530 qboolean FS_idPak( char *pak, char *base ) {
02531 int i;
02532
02533 for (i = 0; i < NUM_ID_PAKS; i++) {
02534 if ( !FS_FilenameCompare(pak, va("%s/pak%d", base, i)) ) {
02535 break;
02536 }
02537 }
02538 if (i < NUM_ID_PAKS) {
02539 return qtrue;
02540 }
02541 return qfalse;
02542 }
02543
02544
02545
02546
02547
02548
02549
02550
02551
02552
02553
02554
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567
02568
02569
02570 qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) {
02571 searchpath_t *sp;
02572 qboolean havepak, badchecksum;
02573 int i;
02574
02575 if ( !fs_numServerReferencedPaks ) {
02576 return qfalse;
02577 }
02578
02579 *neededpaks = 0;
02580
02581 for ( i = 0 ; i < fs_numServerReferencedPaks ; i++ ) {
02582
02583 badchecksum = qfalse;
02584 havepak = qfalse;
02585
02586
02587 if ( FS_idPak(fs_serverReferencedPakNames[i], "baseq3") || FS_idPak(fs_serverReferencedPakNames[i], "missionpack") ) {
02588 continue;
02589 }
02590
02591 for ( sp = fs_searchpaths ; sp ; sp = sp->next ) {
02592 if ( sp->pack && sp->pack->checksum == fs_serverReferencedPaks[i] ) {
02593 havepak = qtrue;
02594 break;
02595 }
02596 }
02597
02598 if ( !havepak && fs_serverReferencedPakNames[i] && *fs_serverReferencedPakNames[i] ) {
02599
02600
02601 if (dlstring)
02602 {
02603
02604 Q_strcat( neededpaks, len, "@");
02605 Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
02606 Q_strcat( neededpaks, len, ".pk3" );
02607
02608
02609 Q_strcat( neededpaks, len, "@");
02610
02611 if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
02612 {
02613 char st[MAX_ZPATH];
02614
02615
02616 Com_sprintf( st, sizeof( st ), "%s.%08x.pk3", fs_serverReferencedPakNames[i], fs_serverReferencedPaks[i] );
02617 Q_strcat( neededpaks, len, st );
02618 } else
02619 {
02620 Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
02621 Q_strcat( neededpaks, len, ".pk3" );
02622 }
02623 }
02624 else
02625 {
02626 Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] );
02627 Q_strcat( neededpaks, len, ".pk3" );
02628
02629 if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) )
02630 {
02631 Q_strcat( neededpaks, len, " (local file exists with wrong checksum)");
02632 }
02633 Q_strcat( neededpaks, len, "\n");
02634 }
02635 }
02636 }
02637
02638 if ( *neededpaks ) {
02639 return qtrue;
02640 }
02641
02642 return qfalse;
02643 }
02644
02645
02646
02647
02648
02649
02650
02651
02652 void FS_Shutdown( qboolean closemfp ) {
02653 searchpath_t *p, *next;
02654 int i;
02655
02656 for(i = 0; i < MAX_FILE_HANDLES; i++) {
02657 if (fsh[i].fileSize) {
02658 FS_FCloseFile(i);
02659 }
02660 }
02661
02662
02663 for ( p = fs_searchpaths ; p ; p = next ) {
02664 next = p->next;
02665
02666 if ( p->pack ) {
02667 unzClose(p->pack->handle);
02668 Z_Free( p->pack->buildBuffer );
02669 Z_Free( p->pack );
02670 }
02671 if ( p->dir ) {
02672 Z_Free( p->dir );
02673 }
02674 Z_Free( p );
02675 }
02676
02677
02678 fs_searchpaths = NULL;
02679
02680 Cmd_RemoveCommand( "path" );
02681 Cmd_RemoveCommand( "dir" );
02682 Cmd_RemoveCommand( "fdir" );
02683 Cmd_RemoveCommand( "touchFile" );
02684
02685 #ifdef FS_MISSING
02686 if (closemfp) {
02687 fclose(missingFiles);
02688 }
02689 #endif
02690 }
02691
02692 void Com_AppendCDKey( const char *filename );
02693 void Com_ReadCDKey( const char *filename );
02694
02695
02696
02697
02698
02699
02700
02701
02702 static void FS_ReorderPurePaks()
02703 {
02704 searchpath_t *s;
02705 int i;
02706 searchpath_t **p_insert_index,
02707 **p_previous;
02708
02709
02710 if ( !fs_numServerPaks )
02711 return;
02712
02713 fs_reordered = qfalse;
02714
02715 p_insert_index = &fs_searchpaths;
02716 for ( i = 0 ; i < fs_numServerPaks ; i++ ) {
02717 p_previous = p_insert_index;
02718 for (s = *p_insert_index; s; s = s->next) {
02719
02720 if (s->pack && fs_serverPaks[i] == s->pack->checksum) {
02721 fs_reordered = qtrue;
02722
02723 *p_previous = s->next;
02724 s->next = *p_insert_index;
02725 *p_insert_index = s;
02726
02727 p_insert_index = &s->next;
02728 break;
02729 }
02730 p_previous = &s->next;
02731 }
02732 }
02733 }
02734
02735
02736
02737
02738
02739
02740 static void FS_Startup( const char *gameName ) {
02741 const char *homePath;
02742 cvar_t *fs;
02743
02744 Com_Printf( "----- FS_Startup -----\n" );
02745
02746 fs_debug = Cvar_Get( "fs_debug", "0", 0 );
02747 fs_copyfiles = Cvar_Get( "fs_copyfiles", "0", CVAR_INIT );
02748 fs_cdpath = Cvar_Get ("fs_cdpath", Sys_DefaultCDPath(), CVAR_INIT );
02749 fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT );
02750 fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_INIT );
02751 homePath = Sys_DefaultHomePath();
02752 if (!homePath || !homePath[0]) {
02753 homePath = fs_basepath->string;
02754 }
02755 fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT );
02756 fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
02757 fs_restrict = Cvar_Get ("fs_restrict", "", CVAR_INIT );
02758
02759
02760 if (fs_cdpath->string[0]) {
02761 FS_AddGameDirectory( fs_cdpath->string, gameName );
02762 }
02763 if (fs_basepath->string[0]) {
02764 FS_AddGameDirectory( fs_basepath->string, gameName );
02765 }
02766
02767
02768 if (fs_basepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {
02769 FS_AddGameDirectory ( fs_homepath->string, gameName );
02770 }
02771
02772
02773 if ( fs_basegame->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_basegame->string, gameName ) ) {
02774 if (fs_cdpath->string[0]) {
02775 FS_AddGameDirectory(fs_cdpath->string, fs_basegame->string);
02776 }
02777 if (fs_basepath->string[0]) {
02778 FS_AddGameDirectory(fs_basepath->string, fs_basegame->string);
02779 }
02780 if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {
02781 FS_AddGameDirectory(fs_homepath->string, fs_basegame->string);
02782 }
02783 }
02784
02785
02786 if ( fs_gamedirvar->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_gamedirvar->string, gameName ) ) {
02787 if (fs_cdpath->string[0]) {
02788 FS_AddGameDirectory(fs_cdpath->string, fs_gamedirvar->string);
02789 }
02790 if (fs_basepath->string[0]) {
02791 FS_AddGameDirectory(fs_basepath->string, fs_gamedirvar->string);
02792 }
02793 if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) {
02794 FS_AddGameDirectory(fs_homepath->string, fs_gamedirvar->string);
02795 }
02796 }
02797
02798 Com_ReadCDKey( "baseq3" );
02799 fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO );
02800 if (fs && fs->string[0] != 0) {
02801 Com_AppendCDKey( fs->string );
02802 }
02803
02804
02805 Cmd_AddCommand ("path", FS_Path_f);
02806 Cmd_AddCommand ("dir", FS_Dir_f );
02807 Cmd_AddCommand ("fdir", FS_NewDir_f );
02808 Cmd_AddCommand ("touchFile", FS_TouchFile_f );
02809
02810
02811
02812 FS_ReorderPurePaks();
02813
02814
02815 FS_Path_f();
02816
02817 fs_gamedirvar->modified = qfalse;
02818
02819 Com_Printf( "----------------------\n" );
02820
02821 #ifdef FS_MISSING
02822 if (missingFiles == NULL) {
02823 missingFiles = fopen( "\\missing.txt", "ab" );
02824 }
02825 #endif
02826 Com_Printf( "%d files in pk3 files\n", fs_packFiles );
02827 }
02828
02829
02830
02831
02832
02833
02834
02835
02836
02837
02838 static void FS_SetRestrictions( void ) {
02839 searchpath_t *path;
02840
02841 #ifndef PRE_RELEASE_DEMO
02842 char *productId;
02843
02844
02845
02846
02847 if ( !fs_restrict->integer ) {
02848
02849 FS_ReadFile( "productid.txt", (void **)&productId );
02850 if ( productId ) {
02851
02852 int seed, i;
02853
02854 seed = 5000;
02855 for ( i = 0 ; i < sizeof( fs_scrambledProductId ) ; i++ ) {
02856 if ( ( fs_scrambledProductId[i] ^ (seed&255) ) != productId[i] ) {
02857 break;
02858 }
02859 seed = (69069 * seed + 1);
02860 }
02861
02862 FS_FreeFile( productId );
02863
02864 if ( i == sizeof( fs_scrambledProductId ) ) {
02865 return;
02866 }
02867 Com_Error( ERR_FATAL, "Invalid product identification" );
02868 }
02869 }
02870 #endif
02871 Cvar_Set( "fs_restrict", "1" );
02872
02873 Com_Printf( "\nRunning in restricted demo mode.\n\n" );
02874
02875
02876 FS_Shutdown(qfalse);
02877 FS_Startup( DEMOGAME );
02878
02879
02880 for ( path = fs_searchpaths ; path ; path = path->next ) {
02881 if ( path->pack ) {
02882
02883 if ( (path->pack->checksum ^ 0x02261994u) != (DEMO_PAK_CHECKSUM ^ 0x02261994u) ) {
02884 Com_Error( ERR_FATAL, "Corrupted pak0.pk3: %u", path->pack->checksum );
02885 }
02886 }
02887 }
02888 }
02889
02890
02891
02892
02893
02894
02895
02896
02897 const char *FS_GamePureChecksum( void ) {
02898 static char info[MAX_STRING_TOKENS];
02899 searchpath_t *search;
02900
02901 info[0] = 0;
02902
02903 for ( search = fs_searchpaths ; search ; search = search->next ) {
02904
02905 if ( search->pack ) {
02906 if (search->pack->referenced & FS_QAGAME_REF) {
02907 Com_sprintf(info, sizeof(info), "%d", search->pack->checksum);
02908 }
02909 }
02910 }
02911
02912 return info;
02913 }
02914
02915
02916
02917
02918
02919
02920
02921
02922
02923 const char *FS_LoadedPakChecksums( void ) {
02924 static char info[BIG_INFO_STRING];
02925 searchpath_t *search;
02926
02927 info[0] = 0;
02928
02929 for ( search = fs_searchpaths ; search ; search = search->next ) {
02930
02931 if ( !search->pack ) {
02932 continue;
02933 }
02934
02935 Q_strcat( info, sizeof( info ), va("%i ", search->pack->checksum ) );
02936 }
02937
02938 return info;
02939 }
02940
02941
02942
02943
02944
02945
02946
02947
02948
02949 const char *FS_LoadedPakNames( void ) {
02950 static char info[BIG_INFO_STRING];
02951 searchpath_t *search;
02952
02953 info[0] = 0;
02954
02955 for ( search = fs_searchpaths ; search ; search = search->next ) {
02956
02957 if ( !search->pack ) {
02958 continue;
02959 }
02960
02961 if (*info) {
02962 Q_strcat(info, sizeof( info ), " " );
02963 }
02964 Q_strcat( info, sizeof( info ), search->pack->pakBasename );
02965 }
02966
02967 return info;
02968 }
02969
02970
02971
02972
02973
02974
02975
02976
02977
02978
02979 const char *FS_LoadedPakPureChecksums( void ) {
02980 static char info[BIG_INFO_STRING];
02981 searchpath_t *search;
02982
02983 info[0] = 0;
02984
02985 for ( search = fs_searchpaths ; search ; search = search->next ) {
02986
02987 if ( !search->pack ) {
02988 continue;
02989 }
02990
02991 Q_strcat( info, sizeof( info ), va("%i ", search->pack->pure_checksum ) );
02992 }
02993
02994 return info;
02995 }
02996
02997
02998
02999
03000
03001
03002
03003
03004
03005 const char *FS_ReferencedPakChecksums( void ) {
03006 static char info[BIG_INFO_STRING];
03007 searchpath_t *search;
03008
03009 info[0] = 0;
03010
03011
03012 for ( search = fs_searchpaths ; search ; search = search->next ) {
03013
03014 if ( search->pack ) {
03015 if (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, BASEGAME, strlen(BASEGAME))) {
03016 Q_strcat( info, sizeof( info ), va("%i ", search->pack->checksum ) );
03017 }
03018 }
03019 }
03020
03021 return info;
03022 }
03023
03024
03025
03026
03027
03028
03029
03030
03031
03032
03033
03034 const char *FS_ReferencedPakPureChecksums( void ) {
03035 static char info[BIG_INFO_STRING];
03036 searchpath_t *search;
03037 int nFlags, numPaks, checksum;
03038
03039 info[0] = 0;
03040
03041 checksum = fs_checksumFeed;
03042 numPaks = 0;
03043 for (nFlags = FS_CGAME_REF; nFlags; nFlags = nFlags >> 1) {
03044 if (nFlags & FS_GENERAL_REF) {
03045
03046
03047 info[strlen(info)+1] = '\0';
03048 info[strlen(info)+2] = '\0';
03049 info[strlen(info)] = '@';
03050 info[strlen(info)] = ' ';
03051 }
03052 for ( search = fs_searchpaths ; search ; search = search->next ) {
03053
03054 if ( search->pack && (search->pack->referenced & nFlags)) {
03055 Q_strcat( info, sizeof( info ), va("%i ", search->pack->pure_checksum ) );
03056 if (nFlags & (FS_CGAME_REF | FS_UI_REF)) {
03057 break;
03058 }
03059 checksum ^= search->pack->pure_checksum;
03060 numPaks++;
03061 }
03062 }
03063 if (fs_fakeChkSum != 0) {
03064
03065 Q_strcat( info, sizeof( info ), va("%i ", fs_fakeChkSum ) );
03066 }
03067 }
03068
03069 checksum ^= numPaks;
03070 Q_strcat( info, sizeof( info ), va("%i ", checksum ) );
03071
03072 return info;
03073 }
03074
03075
03076
03077
03078
03079
03080
03081
03082
03083 const char *FS_ReferencedPakNames( void ) {
03084 static char info[BIG_INFO_STRING];
03085 searchpath_t *search;
03086
03087 info[0] = 0;
03088
03089
03090
03091 for ( search = fs_searchpaths ; search ; search = search->next ) {
03092
03093 if ( search->pack ) {
03094 if (*info) {
03095 Q_strcat(info, sizeof( info ), " " );
03096 }
03097 if (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, BASEGAME, strlen(BASEGAME))) {
03098 Q_strcat( info, sizeof( info ), search->pack->pakGamename );
03099 Q_strcat( info, sizeof( info ), "/" );
03100 Q_strcat( info, sizeof( info ), search->pack->pakBasename );
03101 }
03102 }
03103 }
03104
03105 return info;
03106 }
03107
03108
03109
03110
03111
03112
03113 void FS_ClearPakReferences( int flags ) {
03114 searchpath_t *search;
03115
03116 if ( !flags ) {
03117 flags = -1;
03118 }
03119 for ( search = fs_searchpaths; search; search = search->next ) {
03120
03121 if ( search->pack ) {
03122 search->pack->referenced &= ~flags;
03123 }
03124 }
03125 }
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138 void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames ) {
03139 int i, c, d;
03140
03141 Cmd_TokenizeString( pakSums );
03142
03143 c = Cmd_Argc();
03144 if ( c > MAX_SEARCH_PATHS ) {
03145 c = MAX_SEARCH_PATHS;
03146 }
03147
03148 fs_numServerPaks = c;
03149
03150 for ( i = 0 ; i < c ; i++ ) {
03151 fs_serverPaks[i] = atoi( Cmd_Argv( i ) );
03152 }
03153
03154 if (fs_numServerPaks) {
03155 Com_DPrintf( "Connected to a pure server.\n" );
03156 }
03157 else
03158 {
03159 if (fs_reordered)
03160 {
03161
03162
03163 Com_DPrintf( "FS search reorder is required\n" );
03164 FS_Restart(fs_checksumFeed);
03165 return;
03166 }
03167 }
03168
03169 for ( i = 0 ; i < c ; i++ ) {
03170 if (fs_serverPakNames[i]) {
03171 Z_Free(fs_serverPakNames[i]);
03172 }
03173 fs_serverPakNames[i] = NULL;
03174 }
03175 if ( pakNames && *pakNames ) {
03176 Cmd_TokenizeString( pakNames );
03177
03178 d = Cmd_Argc();
03179 if ( d > MAX_SEARCH_PATHS ) {
03180 d = MAX_SEARCH_PATHS;
03181 }
03182
03183 for ( i = 0 ; i < d ; i++ ) {
03184 fs_serverPakNames[i] = CopyString( Cmd_Argv( i ) );
03185 }
03186 }
03187 }
03188
03189
03190
03191
03192
03193
03194
03195
03196
03197
03198 void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames ) {
03199 int i, c, d;
03200
03201 Cmd_TokenizeString( pakSums );
03202
03203 c = Cmd_Argc();
03204 if ( c > MAX_SEARCH_PATHS ) {
03205 c = MAX_SEARCH_PATHS;
03206 }
03207
03208 fs_numServerReferencedPaks = c;
03209
03210 for ( i = 0 ; i < c ; i++ ) {
03211 fs_serverReferencedPaks[i] = atoi( Cmd_Argv( i ) );
03212 }
03213
03214 for ( i = 0 ; i < c ; i++ ) {
03215 if (fs_serverReferencedPakNames[i]) {
03216 Z_Free(fs_serverReferencedPakNames[i]);
03217 }
03218 fs_serverReferencedPakNames[i] = NULL;
03219 }
03220 if ( pakNames && *pakNames ) {
03221 Cmd_TokenizeString( pakNames );
03222
03223 d = Cmd_Argc();
03224 if ( d > MAX_SEARCH_PATHS ) {
03225 d = MAX_SEARCH_PATHS;
03226 }
03227
03228 for ( i = 0 ; i < d ; i++ ) {
03229 fs_serverReferencedPakNames[i] = CopyString( Cmd_Argv( i ) );
03230 }
03231 }
03232 }
03233
03234
03235
03236
03237
03238
03239
03240
03241
03242 void FS_InitFilesystem( void ) {
03243
03244
03245
03246
03247 Com_StartupVariable( "fs_cdpath" );
03248 Com_StartupVariable( "fs_basepath" );
03249 Com_StartupVariable( "fs_homepath" );
03250 Com_StartupVariable( "fs_game" );
03251 Com_StartupVariable( "fs_copyfiles" );
03252 Com_StartupVariable( "fs_restrict" );
03253
03254
03255 FS_Startup( BASEGAME );
03256
03257
03258 FS_SetRestrictions();
03259
03260
03261
03262
03263 if ( FS_ReadFile( "default.cfg", NULL ) <= 0 ) {
03264 Com_Error( ERR_FATAL, "Couldn't load default.cfg" );
03265
03266 }
03267
03268 Q_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase));
03269 Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame));
03270
03271
03272 }
03273
03274
03275
03276
03277
03278
03279
03280 void FS_Restart( int checksumFeed ) {
03281
03282
03283 FS_Shutdown(qfalse);
03284
03285
03286 fs_checksumFeed = checksumFeed;
03287
03288
03289 FS_ClearPakReferences(0);
03290
03291
03292 FS_Startup( BASEGAME );
03293
03294
03295 FS_SetRestrictions();
03296
03297
03298
03299
03300 if ( FS_ReadFile( "default.cfg", NULL ) <= 0 ) {
03301
03302
03303 if (lastValidBase[0]) {
03304 FS_PureServerSetLoadedPaks("", "");
03305 Cvar_Set("fs_basepath", lastValidBase);
03306 Cvar_Set("fs_gamedirvar", lastValidGame);
03307 lastValidBase[0] = '\0';
03308 lastValidGame[0] = '\0';
03309 Cvar_Set( "fs_restrict", "0" );
03310 FS_Restart(checksumFeed);
03311 Com_Error( ERR_DROP, "Invalid game folder\n" );
03312 return;
03313 }
03314 Com_Error( ERR_FATAL, "Couldn't load default.cfg" );
03315 }
03316
03317
03318 if ( Q_stricmp(fs_gamedirvar->string, lastValidGame) ) {
03319
03320 if ( !Com_SafeMode() ) {
03321 Cbuf_AddText ("exec q3config.cfg\n");
03322 }
03323 }
03324
03325 Q_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase));
03326 Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame));
03327
03328 }
03329
03330
03331
03332
03333
03334
03335
03336 qboolean FS_ConditionalRestart( int checksumFeed ) {
03337 if( fs_gamedirvar->modified || checksumFeed != fs_checksumFeed ) {
03338 FS_Restart( checksumFeed );
03339 return qtrue;
03340 }
03341 return qfalse;
03342 }
03343
03344
03345
03346
03347
03348
03349
03350
03351
03352 int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) {
03353 int r;
03354 qboolean sync;
03355
03356 sync = qfalse;
03357
03358 switch( mode ) {
03359 case FS_READ:
03360 r = FS_FOpenFileRead( qpath, f, qtrue );
03361 break;
03362 case FS_WRITE:
03363 *f = FS_FOpenFileWrite( qpath );
03364 r = 0;
03365 if (*f == 0) {
03366 r = -1;
03367 }
03368 break;
03369 case FS_APPEND_SYNC:
03370 sync = qtrue;
03371 case FS_APPEND:
03372 *f = FS_FOpenFileAppend( qpath );
03373 r = 0;
03374 if (*f == 0) {
03375 r = -1;
03376 }
03377 break;
03378 default:
03379 Com_Error( ERR_FATAL, "FSH_FOpenFile: bad mode" );
03380 return -1;
03381 }
03382
03383 if (!f) {
03384 return r;
03385 }
03386
03387 if ( *f ) {
03388 if (fsh[*f].zipFile == qtrue) {
03389 fsh[*f].baseOffset = unztell(fsh[*f].handleFiles.file.z);
03390 } else {
03391 fsh[*f].baseOffset = ftell(fsh[*f].handleFiles.file.o);
03392 }
03393 fsh[*f].fileSize = r;
03394 fsh[*f].streamed = qfalse;
03395
03396 if (mode == FS_READ) {
03397 Sys_BeginStreamedFile( *f, 0x4000 );
03398 fsh[*f].streamed = qtrue;
03399 }
03400 }
03401 fsh[*f].handleSync = sync;
03402
03403 return r;
03404 }
03405
03406 int FS_FTell( fileHandle_t f ) {
03407 int pos;
03408 if (fsh[f].zipFile == qtrue) {
03409 pos = unztell(fsh[f].handleFiles.file.z);
03410 } else {
03411 pos = ftell(fsh[f].handleFiles.file.o);
03412 }
03413 return pos;
03414 }
03415
03416 void FS_Flush( fileHandle_t f ) {
03417 fflush(fsh[f].handleFiles.file.o);
03418 }
03419