From 4e5b1a58cef2166249e4e44369bce7e33d52bf52 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Wed, 6 Aug 2014 13:15:24 -0700 Subject: [PATCH] Add ValveFS support to more filesystem functions: OpenDirectory (CloseHandle on directory) ReadDirEntry DirExists CreateDirectory RenameFile --- core/logic/intercom.h | 5 + core/logic/smn_filesystem.cpp | 202 ++++++++++++++++++++++++++-------- core/logic_bridge.cpp | 20 ++++ plugins/include/files.inc | 30 +++-- 4 files changed, 205 insertions(+), 52 deletions(-) diff --git a/core/logic/intercom.h b/core/logic/intercom.h index 3df0a5b4..16b96f43 100644 --- a/core/logic/intercom.h +++ b/core/logic/intercom.h @@ -82,7 +82,9 @@ class IFileSystem_Logic { public: 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 bool FindIsDirectory(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 void Close(FileHandle_t file) = 0; @@ -98,6 +100,9 @@ public: virtual void Flush(FileHandle_t file) = 0; virtual bool IsOk(FileHandle_t file) = 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 diff --git a/core/logic/smn_filesystem.cpp b/core/logic/smn_filesystem.cpp index e2f2add4..71147762 100644 --- a/core/logic/smn_filesystem.cpp +++ b/core/logic/smn_filesystem.cpp @@ -42,6 +42,7 @@ HandleType_t g_FileType; HandleType_t g_ValveFileType; HandleType_t g_DirType; +HandleType_t g_ValveDirType; IChangeableForward *g_pLogHook = NULL; enum class FSType @@ -161,6 +162,13 @@ private: FSType _fstype; }; +struct ValveDirectory +{ + FileFindHandle_t hndl; + char szFirstPath[PLATFORM_MAX_PATH]; + bool bHandledFirstPath; +}; + class FileNatives : public SMGlobalClass, public IHandleTypeDispatch, @@ -175,6 +183,7 @@ public: 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_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); pluginsys->AddPluginsListener(this); } @@ -185,9 +194,11 @@ public: handlesys->RemoveType(g_DirType, g_pCoreIdent); handlesys->RemoveType(g_FileType, g_pCoreIdent); handlesys->RemoveType(g_ValveFileType, g_pCoreIdent); + handlesys->RemoveType(g_ValveDirType, g_pCoreIdent); g_DirType = 0; g_FileType = 0; g_ValveFileType = 0; + g_ValveDirType = 0; } virtual void OnHandleDestroy(HandleType_t type, void *object) { @@ -206,6 +217,12 @@ public: FileHandle_t fp = (FileHandle_t) object; 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) { @@ -238,23 +255,48 @@ static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params) pContext->ThrowNativeErrorEx(err, NULL); return 0; } - - char realpath[PLATFORM_MAX_PATH]; - g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path); - - IDirectory *pDir = libsys->OpenDirectory(realpath); - if (!pDir) + + Handle_t handle = 0; + + if (params[0] <= 1 || !params[2]) { - return 0; + 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]; + g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path); - return handlesys->CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL); + IDirectory *pDir = libsys->OpenDirectory(realpath); + if (!pDir) + { + return 0; + } + + handle = handlesys->CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL); + } + + return handle; } static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); - IDirectory *pDir; + void *pTempDir; HandleError herr; HandleSecurity sec; int err; @@ -262,44 +304,90 @@ static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params) sec.pOwner = NULL; sec.pIdentity = g_pCoreIdent; - if ((herr=handlesys->ReadHandle(hndl, g_DirType, &sec, (void **)&pDir)) - != HandleError_None) + if ((herr=handlesys->ReadHandle(hndl, g_DirType, &sec, &pTempDir)) == HandleError_None) + { + IDirectory *pDir = (IDirectory *)pTempDir; + if (!pDir->MoreFiles()) + { + return 0; + } + + cell_t *filetype; + if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE) + { + pContext->ThrowNativeErrorEx(err, NULL); + return 0; + } + + if (pDir->IsEntryDirectory()) + { + *filetype = 1; + } else if (pDir->IsEntryFile()) { + *filetype = 2; + } else { + *filetype = 0; + } + + const char *path = pDir->GetEntryName(); + if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL)) + != 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); + return 0; + } + + if (smcore.filesystem->FindIsDirectory(valveDir->hndl)) + { + *filetype = 1; + } else { + *filetype = 2; + } + } + else { return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr); } - if (!pDir->MoreFiles()) - { - return false; - } - - cell_t *filetype; - if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE) - { - pContext->ThrowNativeErrorEx(err, NULL); - return 0; - } - - if (pDir->IsEntryDirectory()) - { - *filetype = 1; - } else if (pDir->IsEntryFile()) { - *filetype = 2; - } else { - *filetype = 0; - } - - const char *path = pDir->GetEntryName(); - if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL)) - != SP_ERROR_NONE) - { - pContext->ThrowNativeErrorEx(err, NULL); - return 0; - } - - pDir->NextEntry(); - - return true; + return 1; } static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params) @@ -550,6 +638,12 @@ static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params) pContext->ThrowNativeErrorEx(err, NULL); return 0; } + + if (params[0] >= 3 && params[3] == 1) + { + smcore.filesystem->RenameFile(oldpath, newpath); + return 1; + } char new_realpath[PLATFORM_MAX_PATH]; g_pSM->BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath); @@ -572,6 +666,11 @@ static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params) pContext->ThrowNativeErrorEx(err, NULL); return 0; } + + if (params[0] >= 2 && params[2] == 1) + { + return smcore.filesystem->IsDirectory(name) ? 1 : 0; + } char realpath[PLATFORM_MAX_PATH]; g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); @@ -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) { char *name; - char realpath[PLATFORM_MAX_PATH]; - 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); #if defined PLATFORM_WINDOWS diff --git a/core/logic_bridge.cpp b/core/logic_bridge.cpp index 3603dd85..7ddf8a62 100644 --- a/core/logic_bridge.cpp +++ b/core/logic_bridge.cpp @@ -142,10 +142,18 @@ public: { 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) { return filesystem->FindNext(handle); } + bool FindIsDirectory(FileFindHandle_t handle) + { + return filesystem->FindIsDirectory(handle); + } void FindClose(FileFindHandle_t handle) { filesystem->FindClose(handle); @@ -206,6 +214,18 @@ public: { 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; diff --git a/plugins/include/files.inc b/plugins/include/files.inc index 5986b184..742ac3ce 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -108,9 +108,13 @@ native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[], * @note OpenDirectory() supports the "file://" notation. * * @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. */ -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. @@ -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 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 + * This can be used to delete files existing in the game's + * DEFAULT_WRITE_PATH search path, rather than solely files * existing directly in the gamedir. * @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 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. * * @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. */ -native bool:DirExists(const String:path[]); +native bool:DirExists(const String:path[], bool:use_valve_fs=false); /** * 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. * * @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); @@ -381,6 +393,10 @@ native bool:RemoveDir(const String:path[]); * @param path Path to create. * @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. + * @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);