1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/smn_filesystem.cpp Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,963 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include <sys/stat.h>
1.36 +#include "sm_globals.h"
1.37 +#include "HandleSys.h"
1.38 +#include "LibrarySys.h"
1.39 +#include "sm_stringutil.h"
1.40 +#include "Logger.h"
1.41 +#include "PluginSys.h"
1.42 +#include "sourcemm_api.h"
1.43 +#include "ForwardSys.h"
1.44 +
1.45 +SH_DECL_HOOK1_void(IVEngineServer, LogPrint, SH_NOATTRIB, false, const char *);
1.46 +
1.47 +HandleType_t g_FileType;
1.48 +HandleType_t g_DirType;
1.49 +IChangeableForward *g_pLogHook = NULL;
1.50 +
1.51 +class FileNatives :
1.52 + public SMGlobalClass,
1.53 + public IHandleTypeDispatch,
1.54 + public IPluginsListener
1.55 +{
1.56 +public:
1.57 + FileNatives()
1.58 + {
1.59 + m_bIsLoggingHooked = false;
1.60 + }
1.61 + virtual void OnSourceModAllInitialized()
1.62 + {
1.63 + g_FileType = g_HandleSys.CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL);
1.64 + g_DirType = g_HandleSys.CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL);
1.65 + g_pLogHook = g_Forwards.CreateForwardEx(NULL, ET_Hook, 1, NULL, Param_String);
1.66 + g_PluginSys.AddPluginsListener(this);
1.67 + }
1.68 + virtual void OnSourceModShutdown()
1.69 + {
1.70 + g_PluginSys.RemovePluginsListener(this);
1.71 + if (m_bIsLoggingHooked)
1.72 + {
1.73 + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, LogPrint, engine, this, &FileNatives::LogPrint, false);
1.74 + m_bIsLoggingHooked = false;
1.75 + }
1.76 + g_Forwards.ReleaseForward(g_pLogHook);
1.77 + g_HandleSys.RemoveType(g_DirType, g_pCoreIdent);
1.78 + g_HandleSys.RemoveType(g_FileType, g_pCoreIdent);
1.79 + g_DirType = 0;
1.80 + g_FileType = 0;
1.81 + }
1.82 + virtual void OnHandleDestroy(HandleType_t type, void *object)
1.83 + {
1.84 + if (type == g_FileType)
1.85 + {
1.86 + FILE *fp = (FILE *)object;
1.87 + fclose(fp);
1.88 + }
1.89 + else if (type == g_DirType)
1.90 + {
1.91 + IDirectory *pDir = (IDirectory *)object;
1.92 + g_LibSys.CloseDirectory(pDir);
1.93 + }
1.94 + }
1.95 + virtual void OnPluginDestroyed(IPlugin *plugin)
1.96 + {
1.97 + if (m_bIsLoggingHooked && g_pLogHook->GetFunctionCount() == 0)
1.98 + {
1.99 + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, LogPrint, engine, this, &FileNatives::LogPrint, false);
1.100 + m_bIsLoggingHooked = false;
1.101 + }
1.102 + }
1.103 + virtual void AddLogHook(IPluginFunction *pFunc)
1.104 + {
1.105 + if (!m_bIsLoggingHooked)
1.106 + {
1.107 + SH_ADD_HOOK_MEMFUNC(IVEngineServer, LogPrint, engine, this, &FileNatives::LogPrint, false);
1.108 + m_bIsLoggingHooked = true;
1.109 + }
1.110 +
1.111 + g_pLogHook->AddFunction(pFunc);
1.112 + }
1.113 + virtual void RemoveLogHook(IPluginFunction *pFunc)
1.114 + {
1.115 + g_pLogHook->RemoveFunction(pFunc);
1.116 +
1.117 + if (m_bIsLoggingHooked && g_pLogHook->GetFunctionCount() == 0)
1.118 + {
1.119 + SH_REMOVE_HOOK_MEMFUNC(IVEngineServer, LogPrint, engine, this, &FileNatives::LogPrint, false);
1.120 + m_bIsLoggingHooked = false;
1.121 + }
1.122 + }
1.123 + virtual void LogPrint(const char *msg)
1.124 + {
1.125 + cell_t result;
1.126 +
1.127 + result = 0;
1.128 +
1.129 + g_in_game_log_hook = true;
1.130 + g_pLogHook->PushString(msg);
1.131 + g_pLogHook->Execute(&result);
1.132 + g_in_game_log_hook = false;
1.133 +
1.134 + if (result >= Pl_Handled)
1.135 + {
1.136 + RETURN_META(MRES_SUPERCEDE);
1.137 + }
1.138 + }
1.139 +private:
1.140 + bool m_bIsLoggingHooked;
1.141 +} s_FileNatives;
1.142 +
1.143 +static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params)
1.144 +{
1.145 + char *path;
1.146 + int err;
1.147 + if ((err=pContext->LocalToString(params[1], &path)) != SP_ERROR_NONE)
1.148 + {
1.149 + pContext->ThrowNativeErrorEx(err, NULL);
1.150 + return 0;
1.151 + }
1.152 +
1.153 + char realpath[PLATFORM_MAX_PATH];
1.154 + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
1.155 +
1.156 + IDirectory *pDir = g_LibSys.OpenDirectory(realpath);
1.157 + if (!pDir)
1.158 + {
1.159 + return 0;
1.160 + }
1.161 +
1.162 + return g_HandleSys.CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
1.163 +}
1.164 +
1.165 +static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
1.166 +{
1.167 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.168 + IDirectory *pDir;
1.169 + HandleError herr;
1.170 + HandleSecurity sec;
1.171 + int err;
1.172 +
1.173 + sec.pOwner = NULL;
1.174 + sec.pIdentity = g_pCoreIdent;
1.175 +
1.176 + if ((herr=g_HandleSys.ReadHandle(hndl, g_DirType, &sec, (void **)&pDir))
1.177 + != HandleError_None)
1.178 + {
1.179 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.180 + }
1.181 +
1.182 + if (!pDir->MoreFiles())
1.183 + {
1.184 + return false;
1.185 + }
1.186 +
1.187 + cell_t *filetype;
1.188 + if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE)
1.189 + {
1.190 + pContext->ThrowNativeErrorEx(err, NULL);
1.191 + return 0;
1.192 + }
1.193 +
1.194 + if (pDir->IsEntryDirectory())
1.195 + {
1.196 + *filetype = 1;
1.197 + } else if (pDir->IsEntryFile()) {
1.198 + *filetype = 2;
1.199 + } else {
1.200 + *filetype = 0;
1.201 + }
1.202 +
1.203 + const char *path = pDir->GetEntryName();
1.204 + if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL))
1.205 + != SP_ERROR_NONE)
1.206 + {
1.207 + pContext->ThrowNativeErrorEx(err, NULL);
1.208 + return 0;
1.209 + }
1.210 +
1.211 + pDir->NextEntry();
1.212 +
1.213 + return true;
1.214 +}
1.215 +
1.216 +static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params)
1.217 +{
1.218 + char *name, *mode;
1.219 + int err;
1.220 + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
1.221 + {
1.222 + pContext->ThrowNativeErrorEx(err, NULL);
1.223 + return 0;
1.224 + }
1.225 + if ((err=pContext->LocalToString(params[2], &mode)) != SP_ERROR_NONE)
1.226 + {
1.227 + pContext->ThrowNativeErrorEx(err, NULL);
1.228 + return 0;
1.229 + }
1.230 +
1.231 + char realpath[PLATFORM_MAX_PATH];
1.232 + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
1.233 +
1.234 + FILE *pFile = fopen(realpath, mode);
1.235 + if (!pFile)
1.236 + {
1.237 + return 0;
1.238 + }
1.239 +
1.240 + return g_HandleSys.CreateHandle(g_FileType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL);
1.241 +}
1.242 +
1.243 +static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params)
1.244 +{
1.245 + char *name;
1.246 + int err;
1.247 + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
1.248 + {
1.249 + pContext->ThrowNativeErrorEx(err, NULL);
1.250 + return 0;
1.251 + }
1.252 +
1.253 + char realpath[PLATFORM_MAX_PATH];
1.254 + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
1.255 +
1.256 + return (unlink(realpath)) ? 0 : 1;
1.257 +}
1.258 +
1.259 +static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params)
1.260 +{
1.261 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.262 + HandleError herr;
1.263 + HandleSecurity sec;
1.264 + FILE *pFile;
1.265 + int err;
1.266 +
1.267 + sec.pOwner = NULL;
1.268 + sec.pIdentity = g_pCoreIdent;
1.269 +
1.270 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.271 + != HandleError_None)
1.272 + {
1.273 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.274 + }
1.275 +
1.276 + char *buf;
1.277 + if ((err=pContext->LocalToString(params[2], &buf)) != SP_ERROR_NONE)
1.278 + {
1.279 + pContext->ThrowNativeErrorEx(err, NULL);
1.280 + return 0;
1.281 + }
1.282 +
1.283 + if (fgets(buf, params[3], pFile) == NULL)
1.284 + {
1.285 + return 0;
1.286 + }
1.287 +
1.288 + return 1;
1.289 +}
1.290 +
1.291 +static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params)
1.292 +{
1.293 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.294 + HandleError herr;
1.295 + HandleSecurity sec;
1.296 + FILE *pFile;
1.297 +
1.298 + sec.pOwner = NULL;
1.299 + sec.pIdentity = g_pCoreIdent;
1.300 +
1.301 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.302 + != HandleError_None)
1.303 + {
1.304 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.305 + }
1.306 +
1.307 + return (feof(pFile)) ? 1 : 0;
1.308 +}
1.309 +
1.310 +static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params)
1.311 +{
1.312 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.313 + HandleError herr;
1.314 + HandleSecurity sec;
1.315 + FILE *pFile;
1.316 +
1.317 + sec.pOwner = NULL;
1.318 + sec.pIdentity = g_pCoreIdent;
1.319 +
1.320 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.321 + != HandleError_None)
1.322 + {
1.323 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.324 + }
1.325 +
1.326 + fseek(pFile, params[2], params[3]);
1.327 +
1.328 + return 1;
1.329 +}
1.330 +
1.331 +static cell_t sm_FilePosition(IPluginContext *pContext, const cell_t *params)
1.332 +{
1.333 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.334 + HandleError herr;
1.335 + HandleSecurity sec;
1.336 + FILE *pFile;
1.337 +
1.338 + sec.pOwner = NULL;
1.339 + sec.pIdentity = g_pCoreIdent;
1.340 +
1.341 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.342 + != HandleError_None)
1.343 + {
1.344 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.345 + }
1.346 +
1.347 + return ftell(pFile);
1.348 +}
1.349 +
1.350 +static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params)
1.351 +{
1.352 + char *name;
1.353 + int err;
1.354 + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
1.355 + {
1.356 + pContext->ThrowNativeErrorEx(err, NULL);
1.357 + return 0;
1.358 + }
1.359 +
1.360 + if (params[0] >= 2 && params[2] == 1)
1.361 + {
1.362 + return basefilesystem->FileExists(name) ? 1 : 0;
1.363 + }
1.364 +
1.365 + char realpath[PLATFORM_MAX_PATH];
1.366 + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
1.367 +#ifdef PLATFORM_WINDOWS
1.368 + struct _stat s;
1.369 + if (_stat(realpath, &s) != 0)
1.370 + {
1.371 + return 0;
1.372 + }
1.373 + if (s.st_mode & S_IFREG)
1.374 + {
1.375 + return 1;
1.376 + }
1.377 + return 0;
1.378 +#elif defined PLATFORM_POSIX
1.379 + struct stat s;
1.380 + if (stat(realpath, &s) != 0)
1.381 + {
1.382 + return 0;
1.383 + }
1.384 + if (S_ISREG(s.st_mode))
1.385 + {
1.386 + return 1;
1.387 + }
1.388 + return 0;
1.389 +#endif
1.390 +}
1.391 +
1.392 +static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
1.393 +{
1.394 + char *newpath, *oldpath;
1.395 + int err;
1.396 + if ((err=pContext->LocalToString(params[1], &newpath)) != SP_ERROR_NONE)
1.397 + {
1.398 + pContext->ThrowNativeErrorEx(err, NULL);
1.399 + return 0;
1.400 + }
1.401 + if ((err=pContext->LocalToString(params[2], &oldpath)) != SP_ERROR_NONE)
1.402 + {
1.403 + pContext->ThrowNativeErrorEx(err, NULL);
1.404 + return 0;
1.405 + }
1.406 +
1.407 + char new_realpath[PLATFORM_MAX_PATH];
1.408 + g_SourceMod.BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath);
1.409 + char old_realpath[PLATFORM_MAX_PATH];
1.410 + g_SourceMod.BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath);
1.411 +
1.412 +#ifdef PLATFORM_WINDOWS
1.413 + return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0;
1.414 +#elif defined PLATFORM_POSIX
1.415 + return (rename(old_realpath, new_realpath)) ? 0 : 1;
1.416 +#endif
1.417 +}
1.418 +
1.419 +static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params)
1.420 +{
1.421 + char *name;
1.422 + int err;
1.423 + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
1.424 + {
1.425 + pContext->ThrowNativeErrorEx(err, NULL);
1.426 + return 0;
1.427 + }
1.428 +
1.429 + char realpath[PLATFORM_MAX_PATH];
1.430 + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
1.431 +#ifdef PLATFORM_WINDOWS
1.432 + struct _stat s;
1.433 + if (_stat(realpath, &s) != 0)
1.434 + {
1.435 + return 0;
1.436 + }
1.437 + if (s.st_mode & S_IFDIR)
1.438 + {
1.439 + return 1;
1.440 + }
1.441 + return 0;
1.442 +#elif defined PLATFORM_POSIX
1.443 + struct stat s;
1.444 + if (stat(realpath, &s) != 0)
1.445 + {
1.446 + return 0;
1.447 + }
1.448 + if (S_ISDIR(s.st_mode))
1.449 + {
1.450 + return 1;
1.451 + }
1.452 + return 0;
1.453 +#endif
1.454 +}
1.455 +
1.456 +static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params)
1.457 +{
1.458 + char *name;
1.459 + int err;
1.460 + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
1.461 + {
1.462 + pContext->ThrowNativeErrorEx(err, NULL);
1.463 + return -1;
1.464 + }
1.465 +
1.466 + char realpath[PLATFORM_MAX_PATH];
1.467 + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
1.468 +#ifdef PLATFORM_WINDOWS
1.469 + struct _stat s;
1.470 + if (_stat(realpath, &s) != 0)
1.471 + {
1.472 + return -1;
1.473 + }
1.474 + if (s.st_mode & S_IFREG)
1.475 + {
1.476 + return static_cast<cell_t>(s.st_size);
1.477 + }
1.478 + return -1;
1.479 +#elif defined PLATFORM_POSIX
1.480 + struct stat s;
1.481 + if (stat(realpath, &s) != 0)
1.482 + {
1.483 + return -1;
1.484 + }
1.485 + if (S_ISREG(s.st_mode))
1.486 + {
1.487 + return static_cast<cell_t>(s.st_size);
1.488 + }
1.489 + return -1;
1.490 +#endif
1.491 +}
1.492 +
1.493 +static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params)
1.494 +{
1.495 + char *name;
1.496 + int err;
1.497 + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
1.498 + {
1.499 + pContext->ThrowNativeErrorEx(err, NULL);
1.500 + return 0;
1.501 + }
1.502 +
1.503 + char realpath[PLATFORM_MAX_PATH];
1.504 + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
1.505 +
1.506 + return (rmdir(realpath)) ? 0 : 1;
1.507 +}
1.508 +
1.509 +static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params)
1.510 +{
1.511 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.512 + HandleError herr;
1.513 + HandleSecurity sec;
1.514 + FILE *pFile;
1.515 +
1.516 + sec.pOwner = NULL;
1.517 + sec.pIdentity = g_pCoreIdent;
1.518 +
1.519 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.520 + != HandleError_None)
1.521 + {
1.522 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.523 + }
1.524 +
1.525 + char *fmt;
1.526 + int err;
1.527 + if ((err=pContext->LocalToString(params[2], &fmt)) != SP_ERROR_NONE)
1.528 + {
1.529 + pContext->ThrowNativeErrorEx(err, NULL);
1.530 + return 0;
1.531 + }
1.532 +
1.533 + char buffer[2048];
1.534 + int arg = 3;
1.535 + atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg);
1.536 + fprintf(pFile, "%s\n", buffer);
1.537 +
1.538 + return 1;
1.539 +}
1.540 +
1.541 +static cell_t sm_FlushFile(IPluginContext *pContext, const cell_t *params)
1.542 +{
1.543 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.544 + HandleError herr;
1.545 + HandleSecurity sec;
1.546 + FILE *pFile;
1.547 +
1.548 + sec.pOwner = NULL;
1.549 + sec.pIdentity = g_pCoreIdent;
1.550 +
1.551 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.552 + != HandleError_None)
1.553 + {
1.554 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.555 + }
1.556 +
1.557 + return (fflush(pFile) == 0) ? 1 : 0;
1.558 +}
1.559 +
1.560 +static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params)
1.561 +{
1.562 + char path[PLATFORM_MAX_PATH], *fmt, *buffer;
1.563 + int arg = 5;
1.564 + pContext->LocalToString(params[2], &buffer);
1.565 + pContext->LocalToString(params[4], &fmt);
1.566 +
1.567 + atcprintf(path, sizeof(path), fmt, pContext, params, &arg);
1.568 +
1.569 + return g_SourceMod.BuildPath(Path_SM_Rel, buffer, params[3], "%s", path);
1.570 +}
1.571 +
1.572 +static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params)
1.573 +{
1.574 + g_SourceMod.SetGlobalTarget(LANG_SERVER);
1.575 +
1.576 + char buffer[1024];
1.577 + size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
1.578 +
1.579 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
1.580 + {
1.581 + return 0;
1.582 + }
1.583 +
1.584 + if (len >= sizeof(buffer)-2)
1.585 + {
1.586 + buffer[1022] = '\n';
1.587 + buffer[1023] = '\0';
1.588 + } else {
1.589 + buffer[len++] = '\n';
1.590 + buffer[len] = '\0';
1.591 + }
1.592 +
1.593 + Engine_LogPrintWrapper(buffer);
1.594 +
1.595 + return 1;
1.596 +}
1.597 +
1.598 +static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params)
1.599 +{
1.600 + g_SourceMod.SetGlobalTarget(LANG_SERVER);
1.601 +
1.602 + char buffer[1024];
1.603 + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
1.604 +
1.605 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
1.606 + {
1.607 + return 0;
1.608 + }
1.609 +
1.610 + CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
1.611 + g_Logger.LogMessage("[%s] %s", pPlugin->GetFilename(), buffer);
1.612 +
1.613 + return 1;
1.614 +}
1.615 +
1.616 +static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params)
1.617 +{
1.618 + g_SourceMod.SetGlobalTarget(LANG_SERVER);
1.619 +
1.620 + char buffer[1024];
1.621 + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
1.622 +
1.623 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
1.624 + {
1.625 + return 0;
1.626 + }
1.627 +
1.628 + CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
1.629 + g_Logger.LogError("[%s] %s", pPlugin->GetFilename(), buffer);
1.630 +
1.631 + return 1;
1.632 +}
1.633 +
1.634 +static cell_t sm_GetFileTime(IPluginContext *pContext, const cell_t *params)
1.635 +{
1.636 + char *name;
1.637 + int err;
1.638 + if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
1.639 + {
1.640 + pContext->ThrowNativeErrorEx(err, NULL);
1.641 + return 0;
1.642 + }
1.643 +
1.644 + time_t time_val;
1.645 + char realpath[PLATFORM_MAX_PATH];
1.646 + g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
1.647 +
1.648 + if (!g_LibSys.FileTime(realpath, (FileTimeType)params[2], &time_val))
1.649 + {
1.650 + return -1;
1.651 + }
1.652 +
1.653 + return (cell_t)time_val;
1.654 +}
1.655 +
1.656 +static cell_t sm_LogToOpenFile(IPluginContext *pContext, const cell_t *params)
1.657 +{
1.658 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.659 + HandleError herr;
1.660 + HandleSecurity sec;
1.661 + FILE *pFile;
1.662 +
1.663 + sec.pOwner = NULL;
1.664 + sec.pIdentity = g_pCoreIdent;
1.665 +
1.666 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.667 + != HandleError_None)
1.668 + {
1.669 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.670 + }
1.671 +
1.672 + char buffer[2048];
1.673 + g_SourceMod.SetGlobalTarget(LANG_SERVER);
1.674 + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1.675 +
1.676 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
1.677 + {
1.678 + return 0;
1.679 + }
1.680 +
1.681 + CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
1.682 + g_Logger.LogToOpenFile(pFile, "[%s] %s", pPlugin->GetFilename(), buffer);
1.683 +
1.684 + return 1;
1.685 +}
1.686 +
1.687 +static cell_t sm_LogToOpenFileEx(IPluginContext *pContext, const cell_t *params)
1.688 +{
1.689 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.690 + HandleError herr;
1.691 + HandleSecurity sec;
1.692 + FILE *pFile;
1.693 +
1.694 + sec.pOwner = NULL;
1.695 + sec.pIdentity = g_pCoreIdent;
1.696 +
1.697 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.698 + != HandleError_None)
1.699 + {
1.700 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.701 + }
1.702 +
1.703 + char buffer[2048];
1.704 + g_SourceMod.SetGlobalTarget(LANG_SERVER);
1.705 + g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1.706 +
1.707 + if (pContext->GetContext()->n_err != SP_ERROR_NONE)
1.708 + {
1.709 + return 0;
1.710 + }
1.711 +
1.712 + g_Logger.LogToOpenFile(pFile, "%s", buffer);
1.713 +
1.714 + return 1;
1.715 +}
1.716 +
1.717 +static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params)
1.718 +{
1.719 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.720 + HandleError herr;
1.721 + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1.722 + FILE *pFile;
1.723 + size_t read = 0;
1.724 +
1.725 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.726 + != HandleError_None)
1.727 + {
1.728 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.729 + }
1.730 +
1.731 + if (params[4] != 1 && params[4] != 2 && params[4] != 4)
1.732 + {
1.733 + return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]);
1.734 + }
1.735 +
1.736 + cell_t *data;
1.737 + pContext->LocalToPhysAddr(params[2], &data);
1.738 +
1.739 + if (params[4] == 4)
1.740 + {
1.741 + read = fread(data, sizeof(cell_t), params[3], pFile);
1.742 + }
1.743 + else if (params[4] == 2)
1.744 + {
1.745 + int16_t val;
1.746 + for (cell_t i = 0; i < params[3]; i++)
1.747 + {
1.748 + if (fread(&val, sizeof(int16_t), 1, pFile) != 1)
1.749 + {
1.750 + break;
1.751 + }
1.752 + data[read++] = val;
1.753 + }
1.754 + }
1.755 + else if (params[4] == 1)
1.756 + {
1.757 + int8_t val;
1.758 + for (cell_t i = 0; i < params[3]; i++)
1.759 + {
1.760 + if (fread(&val, sizeof(int8_t), 1, pFile) != 1)
1.761 + {
1.762 + break;
1.763 + }
1.764 + data[read++] = val;
1.765 + }
1.766 + }
1.767 +
1.768 + if (read != (size_t)params[3] && ferror(pFile) != 0)
1.769 + {
1.770 + return -1;
1.771 + }
1.772 +
1.773 + return read;
1.774 +}
1.775 +
1.776 +static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params)
1.777 +{
1.778 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.779 + HandleError herr;
1.780 + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1.781 + FILE *pFile;
1.782 + cell_t num_read = 0;
1.783 +
1.784 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.785 + != HandleError_None)
1.786 + {
1.787 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.788 + }
1.789 +
1.790 + char *buffer;
1.791 + pContext->LocalToString(params[2], &buffer);
1.792 +
1.793 + char val;
1.794 + while (1)
1.795 + {
1.796 + /* If we're in stop mode, break as soon as the buffer is full. */
1.797 + if (params[4] && (params[3] == 0 || num_read >= params[3] - 1))
1.798 + {
1.799 + break;
1.800 + }
1.801 + if (fread(&val, sizeof(val), 1, pFile) != 1)
1.802 + {
1.803 + if (ferror(pFile))
1.804 + {
1.805 + return -1;
1.806 + }
1.807 + break;
1.808 + }
1.809 + if (val == '\0')
1.810 + {
1.811 + break;
1.812 + }
1.813 + if (params[3] > 0 && num_read < params[3] - 1)
1.814 + {
1.815 + buffer[num_read++] = val;
1.816 + }
1.817 + }
1.818 +
1.819 + if (params[3] > 0)
1.820 + {
1.821 + buffer[num_read] = '\0';
1.822 + }
1.823 +
1.824 + return num_read;
1.825 +}
1.826 +
1.827 +static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params)
1.828 +{
1.829 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.830 + HandleError herr;
1.831 + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1.832 + FILE *pFile;
1.833 +
1.834 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.835 + != HandleError_None)
1.836 + {
1.837 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.838 + }
1.839 +
1.840 + cell_t *data;
1.841 + pContext->LocalToPhysAddr(params[2], &data);
1.842 +
1.843 + if (params[4] != 1 && params[4] != 2 && params[4] != 4)
1.844 + {
1.845 + return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]);
1.846 + }
1.847 +
1.848 + /* :NOTE: This really isn't compatible with big endian but we will never have to worry about that. */
1.849 +
1.850 + if (params[4] == 4)
1.851 + {
1.852 + if (fwrite(data, sizeof(cell_t), params[3], pFile) != (size_t)params[3])
1.853 + {
1.854 + return 0;
1.855 + }
1.856 + }
1.857 + else if (params[4] == 2)
1.858 + {
1.859 + for (cell_t i = 0; i < params[3]; i++)
1.860 + {
1.861 + if (fwrite(&data[i], sizeof(int16_t), 1, pFile) != 1)
1.862 + {
1.863 + return 0;
1.864 + }
1.865 + }
1.866 + }
1.867 + else if (params[4] == 1)
1.868 + {
1.869 + for (cell_t i = 0; i < params[3]; i++)
1.870 + {
1.871 + if (fwrite(&data[i], sizeof(int8_t), 1, pFile) != 1)
1.872 + {
1.873 + return 0;
1.874 + }
1.875 + }
1.876 + }
1.877 +
1.878 + return 1;
1.879 +}
1.880 +
1.881 +static cell_t sm_WriteFileString(IPluginContext *pContext, const cell_t *params)
1.882 +{
1.883 + Handle_t hndl = static_cast<Handle_t>(params[1]);
1.884 + HandleError herr;
1.885 + HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1.886 + FILE *pFile;
1.887 +
1.888 + if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
1.889 + != HandleError_None)
1.890 + {
1.891 + return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
1.892 + }
1.893 +
1.894 + char *buffer;
1.895 + pContext->LocalToString(params[2], &buffer);
1.896 +
1.897 + size_t len = strlen(buffer);
1.898 +
1.899 + if (params[3])
1.900 + {
1.901 + len++;
1.902 + }
1.903 +
1.904 + return (fwrite(buffer, sizeof(char), len, pFile) == len) ? 1 : 0;
1.905 +}
1.906 +
1.907 +static cell_t sm_AddGameLogHook(IPluginContext *pContext, const cell_t *params)
1.908 +{
1.909 + IPluginFunction *pFunction;
1.910 +
1.911 + if ((pFunction=pContext->GetFunctionById(params[1])) == NULL)
1.912 + {
1.913 + return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
1.914 + }
1.915 +
1.916 + s_FileNatives.AddLogHook(pFunction);
1.917 +
1.918 + return 1;
1.919 +}
1.920 +
1.921 +static cell_t sm_RemoveGameLogHook(IPluginContext *pContext, const cell_t *params)
1.922 +{
1.923 + IPluginFunction *pFunction;
1.924 +
1.925 + if ((pFunction=pContext->GetFunctionById(params[1])) == NULL)
1.926 + {
1.927 + return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
1.928 + }
1.929 +
1.930 + s_FileNatives.RemoveLogHook(pFunction);
1.931 +
1.932 + return 1;
1.933 +}
1.934 +
1.935 +REGISTER_NATIVES(filesystem)
1.936 +{
1.937 + {"OpenDirectory", sm_OpenDirectory},
1.938 + {"ReadDirEntry", sm_ReadDirEntry},
1.939 + {"OpenFile", sm_OpenFile},
1.940 + {"DeleteFile", sm_DeleteFile},
1.941 + {"ReadFileLine", sm_ReadFileLine},
1.942 + {"IsEndOfFile", sm_IsEndOfFile},
1.943 + {"FileSeek", sm_FileSeek},
1.944 + {"FilePosition", sm_FilePosition},
1.945 + {"FileExists", sm_FileExists},
1.946 + {"RenameFile", sm_RenameFile},
1.947 + {"DirExists", sm_DirExists},
1.948 + {"FileSize", sm_FileSize},
1.949 + {"RemoveDir", sm_RemoveDir},
1.950 + {"WriteFileLine", sm_WriteFileLine},
1.951 + {"BuildPath", sm_BuildPath},
1.952 + {"LogToGame", sm_LogToGame},
1.953 + {"LogMessage", sm_LogMessage},
1.954 + {"LogError", sm_LogError},
1.955 + {"FlushFile", sm_FlushFile},
1.956 + {"GetFileTime", sm_GetFileTime},
1.957 + {"LogToOpenFile", sm_LogToOpenFile},
1.958 + {"LogToOpenFileEx", sm_LogToOpenFileEx},
1.959 + {"ReadFile", sm_ReadFile},
1.960 + {"ReadFileString", sm_ReadFileString},
1.961 + {"WriteFile", sm_WriteFile},
1.962 + {"WriteFileString", sm_WriteFileString},
1.963 + {"AddGameLogHook", sm_AddGameLogHook},
1.964 + {"RemoveGameLogHook", sm_RemoveGameLogHook},
1.965 + {NULL, NULL},
1.966 +};