-int vfsLoadFile (const char *filename, void **bufferptr, int index)
-{
- int i, count = 0;
- char tmp[NAME_MAX], fixed[NAME_MAX];
- GSList *lst;
-
- // filename is a full path
- if (index == -1)
- {
- long len;
- FILE *f;
-
- f = fopen (filename, "rb");
- if (f == NULL)
- return -1;
-
- fseek (f, 0, SEEK_END);
- len = ftell (f);
- rewind (f);
-
- *bufferptr = safe_malloc (len+1);
- if (*bufferptr == NULL)
- return -1;
-
- fread (*bufferptr, 1, len, f);
- fclose (f);
-
- // we need to end the buffer with a 0
- ((char*) (*bufferptr))[len] = 0;
-
- return len;
- }
-
- *bufferptr = NULL;
- strcpy (fixed, filename);
- vfsFixDOSName (fixed);
- g_strdown (fixed);
-
- for (i = 0; i < g_numDirs; i++)
- {
- strcpy (tmp, g_strDirs[i]);
- strcat (tmp, filename);
- if (access (tmp, R_OK) == 0)
- {
- if (count == index)
- {
- long len;
- FILE *f;
-
- f = fopen (tmp, "rb");
- if (f == NULL)
- return -1;
-
- fseek (f, 0, SEEK_END);
- len = ftell (f);
- rewind (f);
-
- *bufferptr = safe_malloc (len+1);
- if (*bufferptr == NULL)
- return -1;
-
- fread (*bufferptr, 1, len, f);
- fclose (f);
-
- // we need to end the buffer with a 0
- ((char*) (*bufferptr))[len] = 0;
-
- return len;
- }
-
- count++;
- }
- }
-
- for (lst = g_pakFiles; lst != NULL; lst = g_slist_next (lst))
- {
- VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data;
-
- if (strcmp (file->name, fixed) != 0)
- continue;
-
- if (count == index)
- {
- memcpy (file->zipfile, &file->zipinfo, sizeof (unz_s));
-
- if (unzOpenCurrentFile (file->zipfile) != UNZ_OK)
- return -1;
-
- *bufferptr = safe_malloc (file->size+1);
- // we need to end the buffer with a 0
- ((char*) (*bufferptr))[file->size] = 0;
-
- i = unzReadCurrentFile (file->zipfile , *bufferptr, file->size);
- unzCloseCurrentFile (file->zipfile);
- if (i < 0)
- return -1;
- else
- return file->size;
- }
-
- count++;
- }
-
- return -1;
+int vfsLoadFile( const char *filename, void **bufferptr, int index ){
+ int i, count = 0;
+ char tmp[NAME_MAX], fixed[NAME_MAX];
+ char *lower;
+ GSList *lst;
+
+ // filename is a full path
+ if ( index == -1 ) {
+ long len;
+ FILE *f;
+
+ f = fopen( filename, "rb" );
+ if ( f == NULL ) {
+ return -1;
+ }
+
+ fseek( f, 0, SEEK_END );
+ len = ftell( f );
+ rewind( f );
+
+ *bufferptr = safe_malloc( len + 1 );
+ if ( *bufferptr == NULL ) {
+ fclose( f );
+ return -1;
+ }
+
+ if ( fread( *bufferptr, 1, len, f ) != (size_t) len ) {
+ fclose( f );
+ return -1;
+ }
+ fclose( f );
+
+ // we need to end the buffer with a 0
+ ( (char*) ( *bufferptr ) )[len] = 0;
+
+ return len;
+ }
+
+ *bufferptr = NULL;
+ strncpy( fixed, filename, sizeof( fixed ) );
+ vfsFixDOSName( fixed );
+ lower = g_ascii_strdown( fixed, -1 );
+
+ for ( i = 0; i < g_numDirs; i++ )
+ {
+ strcpy( tmp, g_strDirs[i] );
+ strcat( tmp, filename );
+ if ( access( tmp, R_OK ) == 0 ) {
+ if ( count == index ) {
+ long len;
+ FILE *f;
+
+ f = fopen( tmp, "rb" );
+ if ( f == NULL ) {
+ return -1;
+ }
+
+ fseek( f, 0, SEEK_END );
+ len = ftell( f );
+ rewind( f );
+
+ *bufferptr = safe_malloc( len + 1 );
+ if ( *bufferptr == NULL ) {
+ fclose( f );
+ return -1;
+ }
+
+ if ( fread( *bufferptr, 1, len, f ) != (size_t) len ) {
+ fclose( f );
+ return -1;
+ }
+ fclose( f );
+
+ // we need to end the buffer with a 0
+ ( (char*) ( *bufferptr ) )[len] = 0;
+
+ return len;
+ }
+
+ count++;
+ }
+ }
+
+ // Do not resolve more than 5 recursive symbolic links to
+ // prevent circular symbolic links.
+ int max_symlink_depth = 5;
+
+ openSymlinkTarget:
+ for ( lst = g_pakFiles; lst != NULL; lst = g_slist_next( lst ) )
+ {
+ VFS_PAKFILE* file = (VFS_PAKFILE*)lst->data;
+
+ if ( strcmp( file->name, lower ) != 0 ) {
+ continue;
+ }
+
+ if ( count == index ) {
+
+ if ( unzGoToFilePos( file->zipfile, &file->zippos ) != UNZ_OK ) {
+ return -1;
+ }
+ if ( unzOpenCurrentFile( file->zipfile ) != UNZ_OK ) {
+ return -1;
+ }
+
+ unz_file_info64 fileInfo;
+ if ( unzGetCurrentFileInfo64( file->zipfile, &fileInfo, filename, sizeof(filename), NULL, 0, NULL, 0 ) != UNZ_OK ) {
+ return -1;
+ }
+
+ *bufferptr = safe_malloc( file->size + 1 );
+ // we need to end the buffer with a 0
+ ( (char*) ( *bufferptr ) )[file->size] = 0;
+
+ i = unzReadCurrentFile( file->zipfile, *bufferptr, file->size );
+ unzCloseCurrentFile( file->zipfile );
+
+ if ( isSymlink( &fileInfo ) ) {
+ Sys_FPrintf( SYS_VRB, "Found symbolic link: \"%s\"\n", filename );
+
+ if ( max_symlink_depth == 0 ) {
+ Sys_FPrintf( SYS_WRN, "Maximum symbolic link depth reached\n" );
+ g_free( lower );
+ return -1;
+ }
+
+ max_symlink_depth--;
+
+ const char* relative = (const char*) *bufferptr;
+ char resolved[MAX_FILENAME_BUF];
+
+ resolveSymlinkPath( file->name, relative, resolved );
+
+ Sys_FPrintf( SYS_VRB, "Resolved symbolic link: \"%s\"\n", resolved );
+
+ g_free( lower );
+ strncpy( fixed, resolved, sizeof( fixed ) );
+ vfsFixDOSName( fixed );
+ lower = g_ascii_strdown( fixed, -1 );
+
+ // slow as possible full iteration of the archive
+ goto openSymlinkTarget;
+ }
+
+ if ( i < 0 ) {
+ g_free( lower );
+ return -1;
+ }
+ else{
+ g_free( lower );
+ return file->size;
+ }
+ }
+
+ count++;
+ }
+
+ g_free( lower );
+ return -1;