Add ValveFS support to more filesystem functions: OpenDirectory (CloseHandle on directory) ReadDirEntry DirExists CreateDirectory RenameFile

This commit is contained in:
Nicholas Hastings 2014-08-06 13:15:24 -07:00
parent f2b19e6c87
commit 4e5b1a58ce
4 changed files with 205 additions and 52 deletions

View File

@ -82,7 +82,9 @@ class IFileSystem_Logic
{ {
public: public:
virtual const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle) = 0; virtual const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle) = 0;
virtual const char *FindFirst(const char *pWildCard, FileFindHandle_t *pHandle) = 0;
virtual const char *FindNext(FileFindHandle_t handle) = 0; virtual const char *FindNext(FileFindHandle_t handle) = 0;
virtual bool FindIsDirectory(FileFindHandle_t handle) = 0;
virtual void FindClose(FileFindHandle_t handle) = 0; virtual void FindClose(FileFindHandle_t handle) = 0;
virtual FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0) = 0; virtual FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0) = 0;
virtual void Close(FileHandle_t file) = 0; virtual void Close(FileHandle_t file) = 0;
@ -98,6 +100,9 @@ public:
virtual void Flush(FileHandle_t file) = 0; virtual void Flush(FileHandle_t file) = 0;
virtual bool IsOk(FileHandle_t file) = 0; virtual bool IsOk(FileHandle_t file) = 0;
virtual void RemoveFile(const char *pRelativePath, const char *pathID = 0) = 0; virtual void RemoveFile(const char *pRelativePath, const char *pathID = 0) = 0;
virtual void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID = 0) = 0;
virtual bool IsDirectory(const char *pFileName, const char *pathID = 0) = 0;
virtual void CreateDirHierarchy(const char *path, const char *pathID = 0) = 0;
}; };
namespace SourceMod namespace SourceMod

View File

@ -42,6 +42,7 @@
HandleType_t g_FileType; HandleType_t g_FileType;
HandleType_t g_ValveFileType; HandleType_t g_ValveFileType;
HandleType_t g_DirType; HandleType_t g_DirType;
HandleType_t g_ValveDirType;
IChangeableForward *g_pLogHook = NULL; IChangeableForward *g_pLogHook = NULL;
enum class FSType enum class FSType
@ -161,6 +162,13 @@ private:
FSType _fstype; FSType _fstype;
}; };
struct ValveDirectory
{
FileFindHandle_t hndl;
char szFirstPath[PLATFORM_MAX_PATH];
bool bHandledFirstPath;
};
class FileNatives : class FileNatives :
public SMGlobalClass, public SMGlobalClass,
public IHandleTypeDispatch, public IHandleTypeDispatch,
@ -175,6 +183,7 @@ public:
g_FileType = handlesys->CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL); g_FileType = handlesys->CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL);
g_ValveFileType = handlesys->CreateType("ValveFile", this, 0, NULL, NULL, g_pCoreIdent, NULL); g_ValveFileType = handlesys->CreateType("ValveFile", this, 0, NULL, NULL, g_pCoreIdent, NULL);
g_DirType = handlesys->CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL); g_DirType = handlesys->CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL);
g_ValveDirType = handlesys->CreateType("ValveDirectory", this, 0, NULL, NULL, g_pCoreIdent, NULL);
g_pLogHook = forwardsys->CreateForwardEx(NULL, ET_Hook, 1, NULL, Param_String); g_pLogHook = forwardsys->CreateForwardEx(NULL, ET_Hook, 1, NULL, Param_String);
pluginsys->AddPluginsListener(this); pluginsys->AddPluginsListener(this);
} }
@ -185,9 +194,11 @@ public:
handlesys->RemoveType(g_DirType, g_pCoreIdent); handlesys->RemoveType(g_DirType, g_pCoreIdent);
handlesys->RemoveType(g_FileType, g_pCoreIdent); handlesys->RemoveType(g_FileType, g_pCoreIdent);
handlesys->RemoveType(g_ValveFileType, g_pCoreIdent); handlesys->RemoveType(g_ValveFileType, g_pCoreIdent);
handlesys->RemoveType(g_ValveDirType, g_pCoreIdent);
g_DirType = 0; g_DirType = 0;
g_FileType = 0; g_FileType = 0;
g_ValveFileType = 0; g_ValveFileType = 0;
g_ValveDirType = 0;
} }
virtual void OnHandleDestroy(HandleType_t type, void *object) virtual void OnHandleDestroy(HandleType_t type, void *object)
{ {
@ -206,6 +217,12 @@ public:
FileHandle_t fp = (FileHandle_t) object; FileHandle_t fp = (FileHandle_t) object;
smcore.filesystem->Close(fp); smcore.filesystem->Close(fp);
} }
else if (type == g_ValveDirType)
{
ValveDirectory *valveDir = (ValveDirectory *)object;
smcore.filesystem->FindClose(valveDir->hndl);
delete valveDir;
}
} }
virtual void AddLogHook(IPluginFunction *pFunc) virtual void AddLogHook(IPluginFunction *pFunc)
{ {
@ -239,6 +256,28 @@ static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params)
return 0; return 0;
} }
Handle_t handle = 0;
if (params[0] <= 1 || !params[2])
{
char wildcardedPath[PLATFORM_MAX_PATH];
snprintf(wildcardedPath, sizeof(wildcardedPath), "%s*", path);
ValveDirectory *valveDir = new ValveDirectory;
const char *pFirst = smcore.filesystem->FindFirst(wildcardedPath, &valveDir->hndl);
if (pFirst)
{
valveDir->bHandledFirstPath = false;
strncpy(valveDir->szFirstPath, pFirst, sizeof(ValveDirectory::szFirstPath));
}
else
{
valveDir->bHandledFirstPath = true;
}
handle = handlesys->CreateHandle(g_ValveDirType, valveDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
}
else
{
char realpath[PLATFORM_MAX_PATH]; char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path); g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
@ -248,13 +287,16 @@ static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params)
return 0; return 0;
} }
return handlesys->CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL); handle = handlesys->CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
}
return handle;
} }
static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
{ {
Handle_t hndl = static_cast<Handle_t>(params[1]); Handle_t hndl = static_cast<Handle_t>(params[1]);
IDirectory *pDir; void *pTempDir;
HandleError herr; HandleError herr;
HandleSecurity sec; HandleSecurity sec;
int err; int err;
@ -262,15 +304,12 @@ static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
sec.pOwner = NULL; sec.pOwner = NULL;
sec.pIdentity = g_pCoreIdent; sec.pIdentity = g_pCoreIdent;
if ((herr=handlesys->ReadHandle(hndl, g_DirType, &sec, (void **)&pDir)) if ((herr=handlesys->ReadHandle(hndl, g_DirType, &sec, &pTempDir)) == HandleError_None)
!= HandleError_None)
{ {
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); IDirectory *pDir = (IDirectory *)pTempDir;
}
if (!pDir->MoreFiles()) if (!pDir->MoreFiles())
{ {
return false; return 0;
} }
cell_t *filetype; cell_t *filetype;
@ -292,14 +331,63 @@ static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
const char *path = pDir->GetEntryName(); const char *path = pDir->GetEntryName();
if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL)) if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL))
!= SP_ERROR_NONE) != SP_ERROR_NONE)
{
return pContext->ThrowNativeErrorEx(err, NULL);
}
pDir->NextEntry();
}
else if ((herr=handlesys->ReadHandle(hndl, g_ValveDirType, &sec, &pTempDir)) == HandleError_None)
{
ValveDirectory *valveDir = (ValveDirectory *)pTempDir;
const char *pEntry = NULL;
if (!valveDir->bHandledFirstPath)
{
if (valveDir->szFirstPath[0])
{
pEntry = valveDir->szFirstPath;
}
}
else
{
pEntry = smcore.filesystem->FindNext(valveDir->hndl);
}
valveDir->bHandledFirstPath = true;
// No more entries
if (!pEntry)
{
return 0;
}
if ((err=pContext->StringToLocalUTF8(params[2], params[3], pEntry, NULL))
!= SP_ERROR_NONE)
{
return pContext->ThrowNativeErrorEx(err, NULL);
}
cell_t *filetype;
if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE)
{ {
pContext->ThrowNativeErrorEx(err, NULL); pContext->ThrowNativeErrorEx(err, NULL);
return 0; return 0;
} }
pDir->NextEntry(); if (smcore.filesystem->FindIsDirectory(valveDir->hndl))
{
*filetype = 1;
} else {
*filetype = 2;
}
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
return true; return 1;
} }
static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params) static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params)
@ -551,6 +639,12 @@ static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
return 0; return 0;
} }
if (params[0] >= 3 && params[3] == 1)
{
smcore.filesystem->RenameFile(oldpath, newpath);
return 1;
}
char new_realpath[PLATFORM_MAX_PATH]; char new_realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath); g_pSM->BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath);
char old_realpath[PLATFORM_MAX_PATH]; char old_realpath[PLATFORM_MAX_PATH];
@ -573,6 +667,11 @@ static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params)
return 0; return 0;
} }
if (params[0] >= 2 && params[2] == 1)
{
return smcore.filesystem->IsDirectory(name) ? 1 : 0;
}
char realpath[PLATFORM_MAX_PATH]; char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
#ifdef PLATFORM_WINDOWS #ifdef PLATFORM_WINDOWS
@ -652,9 +751,22 @@ static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params)
static cell_t sm_CreateDirectory(IPluginContext *pContext, const cell_t *params) static cell_t sm_CreateDirectory(IPluginContext *pContext, const cell_t *params)
{ {
char *name; char *name;
char realpath[PLATFORM_MAX_PATH];
pContext->LocalToString(params[1], &name); pContext->LocalToString(params[1], &name);
if (params[0] >= 3 && params[3] == 1)
{
if (smcore.filesystem->IsDirectory(name))
return 0;
smcore.filesystem->CreateDirHierarchy(name);
if (smcore.filesystem->IsDirectory(name))
return 1;
return 0;
}
char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
#if defined PLATFORM_WINDOWS #if defined PLATFORM_WINDOWS

View File

@ -142,10 +142,18 @@ public:
{ {
return filesystem->FindFirstEx(pWildCard, pPathID, pHandle); return filesystem->FindFirstEx(pWildCard, pPathID, pHandle);
} }
const char *FindFirst(const char *pWildCard, FileFindHandle_t *pHandle)
{
return filesystem->FindFirst(pWildCard, pHandle);
}
const char *FindNext(FileFindHandle_t handle) const char *FindNext(FileFindHandle_t handle)
{ {
return filesystem->FindNext(handle); return filesystem->FindNext(handle);
} }
bool FindIsDirectory(FileFindHandle_t handle)
{
return filesystem->FindIsDirectory(handle);
}
void FindClose(FileFindHandle_t handle) void FindClose(FileFindHandle_t handle)
{ {
filesystem->FindClose(handle); filesystem->FindClose(handle);
@ -206,6 +214,18 @@ public:
{ {
filesystem->RemoveFile(pRelativePath, pathID); filesystem->RemoveFile(pRelativePath, pathID);
} }
void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID)
{
filesystem->RenameFile(pOldPath, pNewPath, pathID);
}
bool IsDirectory(const char *pFileName, const char *pathID)
{
return filesystem->IsDirectory(pFileName, pathID);
}
void CreateDirHierarchy(const char *path, const char *pathID)
{
filesystem->CreateDirHierarchy(path, pathID);
}
}; };
static VFileSystem_Logic logic_filesystem; static VFileSystem_Logic logic_filesystem;

View File

@ -108,9 +108,13 @@ native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[],
* @note OpenDirectory() supports the "file://" notation. * @note OpenDirectory() supports the "file://" notation.
* *
* @param path Path to open. * @param path Path to open.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in any of
* the GAME search paths, rather than solely files
* existing directly in the gamedir.
* @return A Handle to the directory, INVALID_HANDLE on open error. * @return A Handle to the directory, INVALID_HANDLE on open error.
*/ */
native Handle:OpenDirectory(const String:path[]); native Handle:OpenDirectory(const String:path[], bool:use_valve_fs=false);
/** /**
* Reads the current directory entry as a local filename, then moves to the next file. * Reads the current directory entry as a local filename, then moves to the next file.
@ -149,8 +153,8 @@ native Handle:OpenFile(const String:file[], const String:mode[], bool:use_valve_
* *
* @param path Path of the file to delete. * @param path Path of the file to delete.
* @param use_valve_fs If true, the Valve file system will be used instead. * @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in any of * This can be used to delete files existing in the game's
* the GAME search paths, rather than solely files * DEFAULT_WRITE_PATH search path, rather than solely files
* existing directly in the gamedir. * existing directly in the gamedir.
* @return True on success, false otherwise. * @return True on success, false otherwise.
*/ */
@ -323,17 +327,24 @@ native bool:FileExists(const String:path[], bool:use_valve_fs=false);
* *
* @param newpath New path to the file. * @param newpath New path to the file.
* @param oldpath Path to the existing file. * @param oldpath Path to the existing file.
* @return True on success, false otherwise. * @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to rename files in the game's
* DEFAULT_WRITE_PATH search path, rather than directly in the gamedir.
* @return True on success or use_valve_fs specified, false otherwise.
*/ */
native bool:RenameFile(const String:newpath[], const String:oldpath[]); native bool:RenameFile(const String:newpath[], const String:oldpath[], bool:use_valve_fs=false);
/** /**
* Checks if a directory exists. * Checks if a directory exists.
* *
* @param path Path to the directory. * @param path Path to the directory.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in any of
* the GAME search paths, rather than solely files
* existing directly in the gamedir.
* @return True if the directory exists, false otherwise. * @return True if the directory exists, false otherwise.
*/ */
native bool:DirExists(const String:path[]); native bool:DirExists(const String:path[], bool:use_valve_fs=false);
/** /**
* Get the file size in bytes. * Get the file size in bytes.
@ -352,7 +363,8 @@ native FileSize(const String:path[], bool:use_valve_fs=false);
* is immediately written to the file. * is immediately written to the file.
* *
* @param file Handle to the file. * @param file Handle to the file.
* @return True on success, false on failure. * @return True on success or use_valve_fs specified with OpenFile,
* otherwise false on failure.
*/ */
native FlushFile(Handle:file); native FlushFile(Handle:file);
@ -381,6 +393,10 @@ native bool:RemoveDir(const String:path[]);
* @param path Path to create. * @param path Path to create.
* @param mode Permissions (default is o=rx,g=rx,u=rwx). Note that folders must have * @param mode Permissions (default is o=rx,g=rx,u=rwx). Note that folders must have
* the execute bit set on Linux. On Windows, the mode is ignored. * the execute bit set on Linux. On Windows, the mode is ignored.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to create folders in the game's
* DEFAULT_WRITE_PATH search path, rather than directly in the gamedir.
* In this case, mode is ignored.
*/ */
native bool:CreateDirectory(const String:path[], mode); native bool:CreateDirectory(const String:path[], mode);