mirror of
https://github.com/YGGverse/xash3d-fwgs.git
synced 2025-03-10 04:31:16 +00:00
filesystem: apply caseinsensitivity to file creation
Replace fs_writedir with fs_writepath, exposing current writeable searchpath. Fix caseinsensitive FS_Search Remove unused argument from listdirectory() Minor optimizations and refactoring
This commit is contained in:
parent
41aa867a21
commit
fe1aba3561
@ -42,14 +42,14 @@ static inline qboolean IsIdGamedir( const char *id )
|
|||||||
!Q_strcmp( id, "GAMEDOWNLOAD" );
|
!Q_strcmp( id, "GAMEDOWNLOAD" );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const char* IdToDir( const char *id )
|
static inline const char *IdToDir( const char *id )
|
||||||
{
|
{
|
||||||
if( !Q_strcmp( id, "GAME" ))
|
if( !Q_strcmp( id, "GAME" ))
|
||||||
return GI->gamefolder;
|
return GI->gamefolder;
|
||||||
else if( !Q_strcmp( id, "GAMEDOWNLOAD" ))
|
else if( !Q_strcmp( id, "GAMEDOWNLOAD" ))
|
||||||
return va( "%s/downloaded", GI->gamefolder );
|
return va( "%s/downloaded", GI->gamefolder );
|
||||||
else if( !Q_strcmp( id, "GAMECONFIG" ))
|
else if( !Q_strcmp( id, "GAMECONFIG" ))
|
||||||
return fs_writedir; // full path here so it's totally our write allowed directory
|
return fs_writepath->filename; // full path here so it's totally our write allowed directory
|
||||||
else if( !Q_strcmp( id, "PLATFORM" ))
|
else if( !Q_strcmp( id, "PLATFORM" ))
|
||||||
return "platform"; // stub
|
return "platform"; // stub
|
||||||
else if( !Q_strcmp( id, "CONFIG" ))
|
else if( !Q_strcmp( id, "CONFIG" ))
|
||||||
|
293
filesystem/dir.c
293
filesystem/dir.c
@ -41,7 +41,7 @@ typedef struct dir_s
|
|||||||
struct dir_s *entries; // sorted
|
struct dir_s *entries; // sorted
|
||||||
} dir_t;
|
} dir_t;
|
||||||
|
|
||||||
static int FS_SortDir( const void *_a, const void *_b )
|
static int FS_SortDirEntries( const void *_a, const void *_b )
|
||||||
{
|
{
|
||||||
const dir_t *a = _a;
|
const dir_t *a = _a;
|
||||||
const dir_t *b = _b;
|
const dir_t *b = _b;
|
||||||
@ -65,25 +65,19 @@ static void FS_InitDirEntries( dir_t *dir, const stringlist_t *list )
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( !list->numstrings )
|
|
||||||
{
|
|
||||||
dir->numentries = DIRENTRY_EMPTY_DIRECTORY;
|
|
||||||
dir->entries = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dir->numentries = list->numstrings;
|
dir->numentries = list->numstrings;
|
||||||
dir->entries = Mem_Malloc( fs_mempool, sizeof( dir_t ) * dir->numentries );
|
dir->entries = Mem_Malloc( fs_mempool, sizeof( dir_t ) * dir->numentries );
|
||||||
|
|
||||||
for( i = 0; i < list->numstrings; i++ )
|
for( i = 0; i < list->numstrings; i++ )
|
||||||
{
|
{
|
||||||
dir_t *entry = &dir->entries[i];
|
dir_t *entry = &dir->entries[i];
|
||||||
|
|
||||||
Q_strncpy( entry->name, list->strings[i], sizeof( entry->name ));
|
Q_strncpy( entry->name, list->strings[i], sizeof( entry->name ));
|
||||||
entry->numentries = DIRENTRY_NOT_SCANNED;
|
entry->numentries = DIRENTRY_NOT_SCANNED;
|
||||||
entry->entries = NULL;
|
entry->entries = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
qsort( dir->entries, dir->numentries, sizeof( dir->entries[0] ), FS_SortDir );
|
qsort( dir->entries, dir->numentries, sizeof( dir->entries[0] ), FS_SortDirEntries );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FS_PopulateDirEntries( dir_t *dir, const char *path )
|
static void FS_PopulateDirEntries( dir_t *dir, const char *path )
|
||||||
@ -102,8 +96,16 @@ static void FS_PopulateDirEntries( dir_t *dir, const char *path )
|
|||||||
}
|
}
|
||||||
|
|
||||||
stringlistinit( &list );
|
stringlistinit( &list );
|
||||||
listdirectory( &list, path, false );
|
listdirectory( &list, path );
|
||||||
FS_InitDirEntries( dir, &list );
|
if( !list.numstrings )
|
||||||
|
{
|
||||||
|
dir->numentries = DIRENTRY_EMPTY_DIRECTORY;
|
||||||
|
dir->entries = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FS_InitDirEntries( dir, &list );
|
||||||
|
}
|
||||||
stringlistfreecontents( &list );
|
stringlistfreecontents( &list );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -112,12 +114,10 @@ static int FS_FindDirEntry( dir_t *dir, const char *name )
|
|||||||
{
|
{
|
||||||
int left, right;
|
int left, right;
|
||||||
|
|
||||||
if( dir->numentries < 0 )
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
// look for the file (binary search)
|
// look for the file (binary search)
|
||||||
left = 0;
|
left = 0;
|
||||||
right = dir->numentries - 1;
|
right = dir->numentries - 1;
|
||||||
|
|
||||||
while( left <= right )
|
while( left <= right )
|
||||||
{
|
{
|
||||||
int middle = (left + right) / 2;
|
int middle = (left + right) / 2;
|
||||||
@ -142,30 +142,37 @@ static void FS_MergeDirEntries( dir_t *dir, const stringlist_t *list )
|
|||||||
int i;
|
int i;
|
||||||
dir_t temp;
|
dir_t temp;
|
||||||
|
|
||||||
|
// glorified realloc for sorted dir entries
|
||||||
|
// make new array and copy old entries with same name and subentries
|
||||||
|
// everything else get freed
|
||||||
|
|
||||||
FS_InitDirEntries( &temp, list );
|
FS_InitDirEntries( &temp, list );
|
||||||
|
|
||||||
// copy all entries that has the same name and has subentries
|
|
||||||
for( i = 0; i < dir->numentries; i++ )
|
for( i = 0; i < dir->numentries; i++ )
|
||||||
{
|
{
|
||||||
|
dir_t *oldentry = &dir->entries[i];
|
||||||
|
dir_t *newentry;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
// don't care about directories without subentries
|
// don't care about directories without subentries
|
||||||
if( dir->entries == NULL )
|
if( oldentry->entries == NULL )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// try to find this directory in new tree
|
// try to find this directory in new tree
|
||||||
j = FS_FindDirEntry( &temp, dir->entries[i].name );
|
j = FS_FindDirEntry( &temp, oldentry->name );
|
||||||
|
|
||||||
// not found, free memory
|
// not found, free memory
|
||||||
if( j < 0 )
|
if( j < 0 )
|
||||||
{
|
{
|
||||||
FS_FreeDirEntries( &dir->entries[i] );
|
FS_FreeDirEntries( oldentry );
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// found directory, move all entries
|
// found directory, move all entries
|
||||||
temp.entries[j].numentries = dir->entries[i].numentries;
|
newentry = &temp.entries[j];
|
||||||
temp.entries[j].entries = dir->entries[i].entries;
|
|
||||||
|
newentry->numentries = oldentry->numentries;
|
||||||
|
newentry->entries = oldentry->entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we can free old tree and replace it with temporary
|
// now we can free old tree and replace it with temporary
|
||||||
@ -177,216 +184,141 @@ static void FS_MergeDirEntries( dir_t *dir, const stringlist_t *list )
|
|||||||
static int FS_MaybeUpdateDirEntries( dir_t *dir, const char *path, const char *entryname )
|
static int FS_MaybeUpdateDirEntries( dir_t *dir, const char *path, const char *entryname )
|
||||||
{
|
{
|
||||||
stringlist_t list;
|
stringlist_t list;
|
||||||
qboolean update = false;
|
int ret;
|
||||||
int idx;
|
|
||||||
|
|
||||||
stringlistinit( &list );
|
stringlistinit( &list );
|
||||||
listdirectory( &list, path, false );
|
listdirectory( &list, path );
|
||||||
|
|
||||||
// find the reason to update entries list
|
if( list.numstrings == 0 ) // empty directory
|
||||||
if( list.numstrings != dir->numentries )
|
|
||||||
{
|
{
|
||||||
// small optimization to not search string in the list
|
FS_FreeDirEntries( dir );
|
||||||
// and directly go updating entries
|
dir->numentries = DIRENTRY_EMPTY_DIRECTORY;
|
||||||
update = true;
|
ret = -1;
|
||||||
|
}
|
||||||
|
else if( dir->numentries < 0 ) // not initialized or was empty
|
||||||
|
{
|
||||||
|
FS_InitDirEntries( dir, &list );
|
||||||
|
ret = FS_FindDirEntry( dir, entryname );
|
||||||
|
}
|
||||||
|
else if( list.numstrings != dir->numentries ) // quick update
|
||||||
|
{
|
||||||
|
FS_MergeDirEntries( dir, &list );
|
||||||
|
ret = FS_FindDirEntry( dir, entryname );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for( idx = 0; idx < list.numstrings; idx++ )
|
// do heavy compare if directory now have an entry we need
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0; i < list.numstrings; i++ )
|
||||||
{
|
{
|
||||||
if( !Q_stricmp( list.strings[idx], entryname ))
|
if( !Q_stricmp( list.strings[i], entryname ))
|
||||||
{
|
|
||||||
update = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( i != list.numstrings )
|
||||||
|
{
|
||||||
|
FS_MergeDirEntries( dir, &list );
|
||||||
|
ret = FS_FindDirEntry( dir, entryname );
|
||||||
|
}
|
||||||
|
else ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !update )
|
|
||||||
{
|
|
||||||
stringlistfreecontents( &list );
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
FS_MergeDirEntries( dir, &list );
|
|
||||||
stringlistfreecontents( &list );
|
stringlistfreecontents( &list );
|
||||||
return FS_FindDirEntry( dir, entryname );
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
static inline qboolean FS_AppendToPath( char *dst, size_t *pi, const size_t len, const char *src, const char *path, const char *err )
|
||||||
qboolean FS_FixFileCase( dir_t *dir, const char *path, char *dst, size_t len, qboolean createpath )
|
|
||||||
{
|
{
|
||||||
const char *prev = path;
|
size_t i = *pi;
|
||||||
const char *next = Q_strchrnul( prev, PATH_SEPARATOR );
|
|
||||||
size_t i = Q_strlen( dst ); // dst is expected to have searchpath filename
|
|
||||||
|
|
||||||
while( true )
|
i += Q_strncpy( &dst[i], src, len - i );
|
||||||
|
*pi = i;
|
||||||
|
|
||||||
|
if( i >= len )
|
||||||
{
|
{
|
||||||
|
Con_Printf( S_ERROR "FS_FixFileCase: overflow while searching %s (%s)\n", path, err );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean FS_FixFileCase( dir_t *dir, const char *path, char *dst, const size_t len, qboolean createpath )
|
||||||
|
{
|
||||||
|
const char *prev, *next;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
if( !FS_AppendToPath( dst, &i, len, dir->name, path, "init" ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for( prev = path, next = Q_strchrnul( prev, PATH_SEPARATOR );
|
||||||
|
;
|
||||||
|
prev = next + 1, next = Q_strchrnul( prev, PATH_SEPARATOR ))
|
||||||
|
{
|
||||||
|
qboolean uptodate = false; // do not run second scan if we're just updated our directory list
|
||||||
|
size_t temp;
|
||||||
char entryname[MAX_SYSPATH];
|
char entryname[MAX_SYSPATH];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
// this subdirectory is case insensitive, just slam everything that's left
|
// this subdirectory is case insensitive, just slam everything that's left
|
||||||
if( dir->numentries == DIRENTRY_CASEINSENSITIVE )
|
if( dir->numentries == DIRENTRY_CASEINSENSITIVE )
|
||||||
{
|
{
|
||||||
i += Q_strncpy( &dst[i], prev, len - i );
|
if( !FS_AppendToPath( dst, &i, len, prev, path, "caseinsensitive entry" ))
|
||||||
if( i >= len )
|
|
||||||
{
|
|
||||||
Con_Printf( "%s: overflow while searching %s (caseinsensitive entry)\n", __FUNCTION__, path );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate cache if needed
|
|
||||||
if( dir->numentries == DIRENTRY_NOT_SCANNED )
|
if( dir->numentries == DIRENTRY_NOT_SCANNED )
|
||||||
|
{
|
||||||
|
// read directory first time
|
||||||
FS_PopulateDirEntries( dir, dst );
|
FS_PopulateDirEntries( dir, dst );
|
||||||
|
uptodate = true;
|
||||||
|
}
|
||||||
|
|
||||||
// get our entry name
|
// get our entry name
|
||||||
Q_strncpy( entryname, prev, next - prev + 1 );
|
Q_strncpy( entryname, prev, next - prev + 1 );
|
||||||
ret = FS_FindDirEntry( dir, entryname );
|
|
||||||
|
|
||||||
// didn't found, but does it exists in FS?
|
// didn't found, but does it exists in FS?
|
||||||
if( ret < 0 )
|
if(( ret = FS_FindDirEntry( dir, entryname )) < 0 )
|
||||||
{
|
{
|
||||||
ret = FS_MaybeUpdateDirEntries( dir, dst, entryname );
|
// if we're creating files or folders, we don't care if path doesn't exist
|
||||||
|
// so copy everything that's left and exit without an error
|
||||||
|
if( uptodate || ( ret = FS_MaybeUpdateDirEntries( dir, dst, entryname )) < 0 )
|
||||||
|
return createpath ? FS_AppendToPath( dst, &i, len, prev, path, "create path" ) : false;
|
||||||
|
|
||||||
if( ret < 0 )
|
uptodate = true;
|
||||||
{
|
|
||||||
// if we're creating files or folders, we don't care if path doesn't exist
|
|
||||||
// so copy everything that's left and exit without an error
|
|
||||||
if( createpath )
|
|
||||||
{
|
|
||||||
i += Q_strncpy( &dst[i], prev, len - i );
|
|
||||||
if( i >= len )
|
|
||||||
{
|
|
||||||
Con_Printf( "%s: overflow while searching %s (create path)\n", __FUNCTION__, path );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dir = &dir->entries[ret];
|
dir = &dir->entries[ret];
|
||||||
ret = Q_strncpy( &dst[i], dir->name, len - i );
|
temp = i;
|
||||||
|
if( !FS_AppendToPath( dst, &temp, len, dir->name, path, "case fix" ))
|
||||||
|
return false;
|
||||||
|
|
||||||
// file not found, rescan...
|
if( !uptodate && !FS_SysFileOrFolderExists( dst )) // file not found, rescan...
|
||||||
if( !FS_SysFileOrFolderExists( dst ))
|
|
||||||
{
|
{
|
||||||
// strip failed part
|
dst[i] = 0; // strip failed part
|
||||||
dst[i] = 0;
|
|
||||||
|
|
||||||
ret = FS_MaybeUpdateDirEntries( dir, dst, entryname );
|
// if we're creating files or folders, we don't care if path doesn't exist
|
||||||
|
// so copy everything that's left and exit without an error
|
||||||
// file not found, exit... =/
|
if(( ret = FS_MaybeUpdateDirEntries( dir, dst, entryname )) < 0 )
|
||||||
if( ret < 0 )
|
return createpath ? FS_AppendToPath( dst, &i, len, prev, path, "create path rescan" ) : false;
|
||||||
{
|
|
||||||
// if we're creating files or folders, we don't care if path doesn't exist
|
|
||||||
// so copy everything that's left and exit without an error
|
|
||||||
if( createpath )
|
|
||||||
{
|
|
||||||
i += Q_strncpy( &dst[i], prev, len - i );
|
|
||||||
if( i >= len )
|
|
||||||
{
|
|
||||||
Con_Printf( "%s: overflow while searching %s (create path 2)\n", __FUNCTION__, path );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dir = &dir->entries[ret];
|
dir = &dir->entries[ret];
|
||||||
ret = Q_strncpy( &dst[i], dir->name, len - i );
|
if( !FS_AppendToPath( dst, &temp, len, dir->name, path, "case fix rescan" ))
|
||||||
}
|
|
||||||
|
|
||||||
i += ret;
|
|
||||||
if( i >= len ) // overflow!
|
|
||||||
{
|
|
||||||
Con_Printf( "%s: overflow while searching %s (appending fixed file name)\n", __FUNCTION__, path );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// end of string, found file, return
|
|
||||||
if( next[0] == '\0' )
|
|
||||||
break;
|
|
||||||
|
|
||||||
// move pointer one character forward, find next path split character
|
|
||||||
prev = next + 1;
|
|
||||||
next = Q_strchrnul( prev, PATH_SEPARATOR );
|
|
||||||
i += Q_strncpy( &dst[i], PATH_SEPARATOR_STR, len - i );
|
|
||||||
if( i >= len ) // overflow!
|
|
||||||
{
|
|
||||||
Con_Printf( "%s: overflow while searching %s (path separator)\n", __FUNCTION__, path );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
qboolean FS_FixFileCase( dir_t *dir, const char *path, char *dst, size_t len, qboolean createpath )
|
|
||||||
{
|
|
||||||
const char *prev = path;
|
|
||||||
const char *next = Q_strchrnul( prev, PATH_SEPARATOR );
|
|
||||||
size_t i = Q_strlen( dst ); // dst is expected to have searchpath filename
|
|
||||||
|
|
||||||
while( true )
|
|
||||||
{
|
|
||||||
stringlist_t list;
|
|
||||||
char entryname[MAX_SYSPATH];
|
|
||||||
int idx;
|
|
||||||
|
|
||||||
// get our entry name
|
|
||||||
Q_strncpy( entryname, prev, next - prev + 1 );
|
|
||||||
|
|
||||||
stringlistinit( &list );
|
|
||||||
listdirectory( &list, dst, false );
|
|
||||||
|
|
||||||
for( idx = 0; idx < list.numstrings; idx++ )
|
|
||||||
{
|
|
||||||
if( !Q_stricmp( list.strings[idx], entryname ))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( idx != list.numstrings )
|
|
||||||
{
|
|
||||||
i += Q_strncpy( &dst[i], list.strings[idx], len - i );
|
|
||||||
if( i >= len ) // overflow!
|
|
||||||
{
|
|
||||||
Con_Printf( "%s: overflow while searching %s (appending fixed file name)\n", __FUNCTION__, path );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
i = temp;
|
||||||
{
|
|
||||||
stringlistfreecontents( &list );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
stringlistfreecontents( &list );
|
|
||||||
|
|
||||||
// end of string, found file, return
|
// end of string, found file, return
|
||||||
if( next[0] == '\0' )
|
if( next[0] == '\0' || ( next[0] == PATH_SEPARATOR && next[1] == '\0' ))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// move pointer one character forward, find next path split character
|
if( !FS_AppendToPath( dst, &i, len, PATH_SEPARATOR_STR, path, "path separator" ))
|
||||||
prev = next + 1;
|
|
||||||
next = Q_strchrnul( prev, PATH_SEPARATOR );
|
|
||||||
i += Q_strncpy( &dst[i], PATH_SEPARATOR_STR, len - i );
|
|
||||||
if( i >= len ) // overflow!
|
|
||||||
{
|
|
||||||
Con_Printf( "%s: overflow while searching %s (path separator)\n", __FUNCTION__, path );
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static void FS_Close_DIR( searchpath_t *search )
|
static void FS_Close_DIR( searchpath_t *search )
|
||||||
{
|
{
|
||||||
@ -403,7 +335,6 @@ static int FS_FindFile_DIR( searchpath_t *search, const char *path, char *fixedn
|
|||||||
{
|
{
|
||||||
char netpath[MAX_SYSPATH];
|
char netpath[MAX_SYSPATH];
|
||||||
|
|
||||||
Q_strncpy( netpath, search->filename, sizeof( netpath ));
|
|
||||||
if( !FS_FixFileCase( search->dir, path, netpath, sizeof( netpath ), false ))
|
if( !FS_FixFileCase( search->dir, path, netpath, sizeof( netpath ), false ))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -438,12 +369,16 @@ static void FS_Search_DIR( searchpath_t *search, stringlist_t *list, const char
|
|||||||
if( basepathlength ) memcpy( basepath, pattern, basepathlength );
|
if( basepathlength ) memcpy( basepath, pattern, basepathlength );
|
||||||
basepath[basepathlength] = '\0';
|
basepath[basepathlength] = '\0';
|
||||||
|
|
||||||
Q_snprintf( netpath, sizeof( netpath ), "%s%s", search->filename, basepath );
|
if( !FS_FixFileCase( search->dir, basepath, netpath, sizeof( netpath ), false ))
|
||||||
|
{
|
||||||
|
Mem_Free( basepath );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
stringlistinit( &dirlist );
|
stringlistinit( &dirlist );
|
||||||
listdirectory( &dirlist, netpath, caseinsensitive );
|
listdirectory( &dirlist, netpath );
|
||||||
|
|
||||||
Q_strncpy( temp, basepath, sizeof( temp ) );
|
Q_strncpy( temp, basepath, sizeof( temp ));
|
||||||
|
|
||||||
for( dirlistindex = 0; dirlistindex < dirlist.numstrings; dirlistindex++ )
|
for( dirlistindex = 0; dirlistindex < dirlist.numstrings; dirlistindex++ )
|
||||||
{
|
{
|
||||||
@ -500,7 +435,7 @@ void FS_InitDirectorySearchpath( searchpath_t *search, const char *path, int fla
|
|||||||
|
|
||||||
// create cache root
|
// create cache root
|
||||||
search->dir = Mem_Malloc( fs_mempool, sizeof( dir_t ));
|
search->dir = Mem_Malloc( fs_mempool, sizeof( dir_t ));
|
||||||
search->dir->name[0] = 0; // root has no filename, unused
|
Q_strncpy( search->dir->name, search->filename, sizeof( search->dir->name ));
|
||||||
FS_PopulateDirEntries( search->dir, path );
|
FS_PopulateDirEntries( search->dir, path );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,6 @@ poolhandle_t fs_mempool;
|
|||||||
searchpath_t *fs_searchpaths = NULL; // chain
|
searchpath_t *fs_searchpaths = NULL; // chain
|
||||||
char fs_rodir[MAX_SYSPATH];
|
char fs_rodir[MAX_SYSPATH];
|
||||||
char fs_rootdir[MAX_SYSPATH];
|
char fs_rootdir[MAX_SYSPATH];
|
||||||
char fs_writedir[MAX_SYSPATH]; // path that game allows to overwrite, delete and rename files (and create new of course)
|
|
||||||
searchpath_t *fs_writepath;
|
searchpath_t *fs_writepath;
|
||||||
|
|
||||||
static char fs_basedir[MAX_SYSPATH]; // base game directory
|
static char fs_basedir[MAX_SYSPATH]; // base game directory
|
||||||
@ -193,10 +192,8 @@ static void listlowercase( stringlist_t *list )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void listdirectory( stringlist_t *list, const char *path, qboolean lowercase )
|
void listdirectory( stringlist_t *list, const char *path )
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
signed char *c;
|
|
||||||
#if XASH_WIN32
|
#if XASH_WIN32
|
||||||
char pattern[4096];
|
char pattern[4096];
|
||||||
struct _finddata_t n_file;
|
struct _finddata_t n_file;
|
||||||
@ -307,7 +304,7 @@ static qboolean FS_AddArchive_Fullpath( const char *file, qboolean *already_load
|
|||||||
================
|
================
|
||||||
FS_AddGameDirectory
|
FS_AddGameDirectory
|
||||||
|
|
||||||
Sets fs_writedir, adds the directory to the head of the path,
|
Sets fs_writepath, adds the directory to the head of the path,
|
||||||
then loads and adds pak1.pak pak2.pak ...
|
then loads and adds pak1.pak pak2.pak ...
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
@ -319,7 +316,7 @@ void FS_AddGameDirectory( const char *dir, uint flags )
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
stringlistinit( &list );
|
stringlistinit( &list );
|
||||||
listdirectory( &list, dir, false );
|
listdirectory( &list, dir );
|
||||||
stringlistsort( &list );
|
stringlistsort( &list );
|
||||||
|
|
||||||
// add any PAK package in the directory
|
// add any PAK package in the directory
|
||||||
@ -351,10 +348,7 @@ void FS_AddGameDirectory( const char *dir, uint flags )
|
|||||||
// (unpacked files have the priority over packed files)
|
// (unpacked files have the priority over packed files)
|
||||||
search = FS_AddDir_Fullpath( dir, NULL, flags );
|
search = FS_AddDir_Fullpath( dir, NULL, flags );
|
||||||
if( !FBitSet( flags, FS_NOWRITE_PATH ))
|
if( !FBitSet( flags, FS_NOWRITE_PATH ))
|
||||||
{
|
|
||||||
Q_strncpy( fs_writedir, dir, sizeof( fs_writedir ));
|
|
||||||
fs_writepath = search;
|
fs_writepath = search;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1318,7 +1312,7 @@ qboolean FS_InitStdio( qboolean caseinsensitive, const char *rootdir, const char
|
|||||||
}
|
}
|
||||||
|
|
||||||
stringlistinit( &dirs );
|
stringlistinit( &dirs );
|
||||||
listdirectory( &dirs, fs_rodir, false );
|
listdirectory( &dirs, fs_rodir );
|
||||||
stringlistsort( &dirs );
|
stringlistsort( &dirs );
|
||||||
|
|
||||||
for( i = 0; i < dirs.numstrings; i++ )
|
for( i = 0; i < dirs.numstrings; i++ )
|
||||||
@ -1342,7 +1336,7 @@ qboolean FS_InitStdio( qboolean caseinsensitive, const char *rootdir, const char
|
|||||||
|
|
||||||
// validate directories
|
// validate directories
|
||||||
stringlistinit( &dirs );
|
stringlistinit( &dirs );
|
||||||
listdirectory( &dirs, "./", false );
|
listdirectory( &dirs, "./" );
|
||||||
stringlistsort( &dirs );
|
stringlistsort( &dirs );
|
||||||
|
|
||||||
for( i = 0; i < dirs.numstrings; i++ )
|
for( i = 0; i < dirs.numstrings; i++ )
|
||||||
@ -1794,8 +1788,11 @@ file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly )
|
|||||||
char real_path[MAX_SYSPATH];
|
char real_path[MAX_SYSPATH];
|
||||||
|
|
||||||
// open the file on disk directly
|
// open the file on disk directly
|
||||||
Q_sprintf( real_path, "%s/%s", fs_writedir, filepath );
|
if( !FS_FixFileCase( fs_writepath->dir, filepath, real_path, sizeof( real_path ), true ))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
FS_CreatePath( real_path ); // Create directories up to the file
|
FS_CreatePath( real_path ); // Create directories up to the file
|
||||||
|
|
||||||
return FS_SysOpen( real_path, mode );
|
return FS_SysOpen( real_path, mode );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2455,25 +2452,40 @@ rename specified file from gamefolder
|
|||||||
*/
|
*/
|
||||||
qboolean FS_Rename( const char *oldname, const char *newname )
|
qboolean FS_Rename( const char *oldname, const char *newname )
|
||||||
{
|
{
|
||||||
char oldpath[MAX_SYSPATH], newpath[MAX_SYSPATH];
|
char oldname2[MAX_SYSPATH], newname2[MAX_SYSPATH], oldpath[MAX_SYSPATH], newpath[MAX_SYSPATH];
|
||||||
qboolean iRet;
|
int ret;
|
||||||
|
|
||||||
if( !oldname || !newname || !*oldname || !*newname )
|
if( !COM_CheckString( oldname ) || !COM_CheckString( newname ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// no work done
|
// no work done
|
||||||
if( !Q_stricmp( oldname, newname ))
|
if( !Q_stricmp( oldname, newname ))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Q_snprintf( oldpath, sizeof( oldpath ), "%s%s", fs_writedir, oldname );
|
// fix up slashes
|
||||||
Q_snprintf( newpath, sizeof( newpath ), "%s%s", fs_writedir, newname );
|
Q_strncpy( oldname2, oldname, sizeof( oldname2 ));
|
||||||
|
Q_strncpy( newname2, newname, sizeof( newname2 ));
|
||||||
|
|
||||||
COM_FixSlashes( oldpath );
|
COM_FixSlashes( oldname2 );
|
||||||
COM_FixSlashes( newpath );
|
COM_FixSlashes( newname2 );
|
||||||
|
|
||||||
iRet = rename( oldpath, newpath );
|
// file does not exist
|
||||||
|
if( !FS_FixFileCase( fs_writepath->dir, oldname2, oldpath, sizeof( oldpath ), false ))
|
||||||
|
return false;
|
||||||
|
|
||||||
return (iRet == 0);
|
// exit if overflowed
|
||||||
|
if( !FS_FixFileCase( fs_writepath->dir, newname2, newpath, sizeof( newpath ), true ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ret = rename( oldpath, newpath );
|
||||||
|
if( ret < 0 )
|
||||||
|
{
|
||||||
|
Con_Printf( "%s: failed to rename file %s (%s) to %s (%s): %s\n",
|
||||||
|
__FUNCTION__, oldpath, oldname2, newpath, newname2, strerror( errno ));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2485,17 +2497,26 @@ delete specified file from gamefolder
|
|||||||
*/
|
*/
|
||||||
qboolean GAME_EXPORT FS_Delete( const char *path )
|
qboolean GAME_EXPORT FS_Delete( const char *path )
|
||||||
{
|
{
|
||||||
char real_path[MAX_SYSPATH];
|
char path2[MAX_SYSPATH], real_path[MAX_SYSPATH];
|
||||||
qboolean iRet;
|
int ret;
|
||||||
|
|
||||||
if( !path || !*path )
|
if( !COM_CheckString( path ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Q_snprintf( real_path, sizeof( real_path ), "%s%s", fs_writedir, path );
|
Q_strncpy( path2, path, sizeof( path2 ));
|
||||||
COM_FixSlashes( real_path );
|
COM_FixSlashes( path2 );
|
||||||
iRet = remove( real_path );
|
|
||||||
|
|
||||||
return (iRet == 0);
|
if( !FS_FixFileCase( fs_writepath->dir, path2, real_path, sizeof( real_path ), true ))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
ret = remove( real_path );
|
||||||
|
if( ret < 0 )
|
||||||
|
{
|
||||||
|
Con_Printf( "%s: failed to delete file %s (%s): %s\n", __FUNCTION__, real_path, path, strerror( errno ));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2556,7 +2577,7 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly )
|
|||||||
{
|
{
|
||||||
if( gamedironly && !FBitSet( searchpath->flags, FS_GAMEDIRONLY_SEARCH_FLAGS ))
|
if( gamedironly && !FBitSet( searchpath->flags, FS_GAMEDIRONLY_SEARCH_FLAGS ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
searchpath->pfnSearch( searchpath, &resultlist, pattern, caseinsensitive );
|
searchpath->pfnSearch( searchpath, &resultlist, pattern, caseinsensitive );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ typedef struct searchpath_s
|
|||||||
string filename;
|
string filename;
|
||||||
int type;
|
int type;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
dir_t *dir;
|
dir_t *dir;
|
||||||
@ -91,12 +91,12 @@ typedef struct searchpath_s
|
|||||||
|
|
||||||
extern fs_globals_t FI;
|
extern fs_globals_t FI;
|
||||||
extern searchpath_t *fs_searchpaths;
|
extern searchpath_t *fs_searchpaths;
|
||||||
|
extern searchpath_t *fs_writepath;
|
||||||
extern poolhandle_t fs_mempool;
|
extern poolhandle_t fs_mempool;
|
||||||
extern fs_interface_t g_engfuncs;
|
extern fs_interface_t g_engfuncs;
|
||||||
extern qboolean fs_ext_path;
|
extern qboolean fs_ext_path;
|
||||||
extern char fs_rodir[MAX_SYSPATH];
|
extern char fs_rodir[MAX_SYSPATH];
|
||||||
extern char fs_rootdir[MAX_SYSPATH];
|
extern char fs_rootdir[MAX_SYSPATH];
|
||||||
extern char fs_writedir[MAX_SYSPATH];
|
|
||||||
extern fs_api_t g_api;
|
extern fs_api_t g_api;
|
||||||
|
|
||||||
#define GI FI.GameInfo
|
#define GI FI.GameInfo
|
||||||
@ -164,7 +164,7 @@ void stringlistinit( stringlist_t *list );
|
|||||||
void stringlistfreecontents( stringlist_t *list );
|
void stringlistfreecontents( stringlist_t *list );
|
||||||
void stringlistappend( stringlist_t *list, char *text );
|
void stringlistappend( stringlist_t *list, char *text );
|
||||||
void stringlistsort( stringlist_t *list );
|
void stringlistsort( stringlist_t *list );
|
||||||
void listdirectory( stringlist_t *list, const char *path, qboolean lowercase );
|
void listdirectory( stringlist_t *list, const char *path );
|
||||||
|
|
||||||
// filesystem ops
|
// filesystem ops
|
||||||
int FS_FileExists( const char *filename, int gamedironly );
|
int FS_FileExists( const char *filename, int gamedironly );
|
||||||
@ -212,6 +212,7 @@ qboolean FS_AddZip_Fullpath( const char *zipfile, qboolean *already_loaded, int
|
|||||||
// dir.c
|
// dir.c
|
||||||
//
|
//
|
||||||
searchpath_t *FS_AddDir_Fullpath( const char *path, qboolean *already_loaded, int flags );
|
searchpath_t *FS_AddDir_Fullpath( const char *path, qboolean *already_loaded, int flags );
|
||||||
|
qboolean FS_FixFileCase( dir_t *dir, const char *path, char *dst, const size_t len, qboolean createpath );
|
||||||
void FS_InitDirectorySearchpath( searchpath_t *search, const char *path, int flags );
|
void FS_InitDirectorySearchpath( searchpath_t *search, const char *path, int flags );
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
Loading…
x
Reference in New Issue
Block a user