core/logic/smn_filesystem.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 4199 6e0c63e83c8a
permissions -rw-r--r--
Update CS:GO team score gamedata.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include <sys/stat.h>
    33 #include <string.h>
    34 #include <IHandleSys.h>
    35 #include <ILibrarySys.h>
    36 #include <IPluginSys.h>
    37 #include <IForwardSys.h>
    38 #include <ISourceMod.h>
    39 #include <ITranslator.h>
    40 #include "common_logic.h"
    41 
    42 HandleType_t g_FileType;
    43 HandleType_t g_DirType;
    44 IChangeableForward *g_pLogHook = NULL;
    45 
    46 class FileNatives : 
    47 	public SMGlobalClass,
    48 	public IHandleTypeDispatch,
    49 	public IPluginsListener
    50 {
    51 public:
    52 	FileNatives()
    53 	{
    54 	}
    55 	virtual void OnSourceModAllInitialized()
    56 	{
    57 		g_FileType = handlesys->CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    58 		g_DirType = handlesys->CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    59 		g_pLogHook = forwardsys->CreateForwardEx(NULL, ET_Hook, 1, NULL, Param_String);
    60 		pluginsys->AddPluginsListener(this);
    61 	}
    62 	virtual void OnSourceModShutdown()
    63 	{
    64 		pluginsys->RemovePluginsListener(this);
    65 		forwardsys->ReleaseForward(g_pLogHook);
    66 		handlesys->RemoveType(g_DirType, g_pCoreIdent);
    67 		handlesys->RemoveType(g_FileType, g_pCoreIdent);
    68 		g_DirType = 0;
    69 		g_FileType = 0;
    70 	}
    71 	virtual void OnHandleDestroy(HandleType_t type, void *object)
    72 	{
    73 		if (type == g_FileType)
    74 		{
    75 			FILE *fp = (FILE *)object;
    76 			fclose(fp);
    77 		}
    78 		else if (type == g_DirType)
    79 		{
    80 			IDirectory *pDir = (IDirectory *)object;
    81 			libsys->CloseDirectory(pDir);
    82 		}
    83 	}
    84 	virtual void AddLogHook(IPluginFunction *pFunc)
    85 	{
    86 		g_pLogHook->AddFunction(pFunc);
    87 	}
    88 	virtual void RemoveLogHook(IPluginFunction *pFunc)
    89 	{
    90 		g_pLogHook->RemoveFunction(pFunc);
    91 	}
    92 	virtual bool LogPrint(const char *msg)
    93 	{
    94 		cell_t result = 0;
    95 		g_pLogHook->PushString(msg);
    96 		g_pLogHook->Execute(&result);
    97 		return result >= Pl_Handled;
    98 	}
    99 } s_FileNatives;
   100 
   101 bool OnLogPrint(const char *msg)
   102 {
   103 	return s_FileNatives.LogPrint(msg);
   104 }
   105 
   106 static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params)
   107 {
   108 	char *path;
   109 	int err;
   110 	if ((err=pContext->LocalToString(params[1], &path)) != SP_ERROR_NONE)
   111 	{
   112 		pContext->ThrowNativeErrorEx(err, NULL);
   113 		return 0;
   114 	}
   115 
   116 	char realpath[PLATFORM_MAX_PATH];
   117 	g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
   118 
   119 	IDirectory *pDir = libsys->OpenDirectory(realpath);
   120 	if (!pDir)
   121 	{
   122 		return 0;
   123 	}
   124 
   125 	return handlesys->CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
   126 }
   127 
   128 static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
   129 {
   130 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   131 	IDirectory *pDir;
   132 	HandleError herr;
   133 	HandleSecurity sec;
   134 	int err;
   135 
   136 	sec.pOwner = NULL;
   137 	sec.pIdentity = g_pCoreIdent;
   138 
   139 	if ((herr=handlesys->ReadHandle(hndl, g_DirType, &sec, (void **)&pDir))
   140 		!= HandleError_None)
   141 	{
   142 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   143 	}
   144 
   145 	if (!pDir->MoreFiles())
   146 	{
   147 		return false;
   148 	}
   149 
   150 	cell_t *filetype;
   151 	if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE)
   152 	{
   153 		pContext->ThrowNativeErrorEx(err, NULL);
   154 		return 0;
   155 	}
   156 
   157 	if (pDir->IsEntryDirectory())
   158 	{
   159 		*filetype = 1;
   160 	} else if (pDir->IsEntryFile()) {
   161 		*filetype = 2;
   162 	} else {
   163 		*filetype = 0;
   164 	}
   165 
   166 	const char *path = pDir->GetEntryName();
   167 	if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL))
   168 		!= SP_ERROR_NONE)
   169 	{
   170 		pContext->ThrowNativeErrorEx(err, NULL);
   171 		return 0;
   172 	}
   173 
   174 	pDir->NextEntry();
   175 
   176 	return true;
   177 }
   178 
   179 static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params)
   180 {
   181 	char *name, *mode;
   182 	int err;
   183 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   184 	{
   185 		pContext->ThrowNativeErrorEx(err, NULL);
   186 		return 0;
   187 	}
   188 	if ((err=pContext->LocalToString(params[2], &mode)) != SP_ERROR_NONE)
   189 	{
   190 		pContext->ThrowNativeErrorEx(err, NULL);
   191 		return 0;
   192 	}
   193 
   194 	char realpath[PLATFORM_MAX_PATH];
   195 	g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   196 
   197 	FILE *pFile = fopen(realpath, mode);
   198 	if (!pFile)
   199 	{
   200 		return 0;
   201 	}
   202 
   203 	return handlesys->CreateHandle(g_FileType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL);
   204 }
   205 
   206 static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params)
   207 {
   208 	char *name;
   209 	int err;
   210 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   211 	{
   212 		pContext->ThrowNativeErrorEx(err, NULL);
   213 		return 0;
   214 	}
   215 
   216 	char realpath[PLATFORM_MAX_PATH];
   217 	g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   218 
   219 	return (unlink(realpath)) ? 0 : 1;
   220 }
   221 
   222 static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params)
   223 {
   224 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   225 	HandleError herr;
   226 	HandleSecurity sec;
   227 	FILE *pFile;
   228 	int err;
   229 
   230 	sec.pOwner = NULL;
   231 	sec.pIdentity = g_pCoreIdent;
   232 
   233 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   234 		!= HandleError_None)
   235 	{
   236 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   237 	}
   238 
   239 	char *buf;
   240 	if ((err=pContext->LocalToString(params[2], &buf)) != SP_ERROR_NONE)
   241 	{
   242 		pContext->ThrowNativeErrorEx(err, NULL);
   243 		return 0;
   244 	}
   245 
   246 	if (fgets(buf, params[3], pFile) == NULL)
   247 	{
   248 		return 0;
   249 	}
   250 
   251 	return 1;
   252 }
   253 
   254 static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params)
   255 {
   256 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   257 	HandleError herr;
   258 	HandleSecurity sec;
   259 	FILE *pFile;
   260 
   261 	sec.pOwner = NULL;
   262 	sec.pIdentity = g_pCoreIdent;
   263 
   264 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   265 		!= HandleError_None)
   266 	{
   267 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   268 	}
   269 
   270 	return (feof(pFile)) ? 1 : 0;
   271 }
   272 
   273 static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params)
   274 {
   275 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   276 	HandleError herr;
   277 	HandleSecurity sec;
   278 	FILE *pFile;
   279 
   280 	sec.pOwner = NULL;
   281 	sec.pIdentity = g_pCoreIdent;
   282 
   283 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   284 		!= HandleError_None)
   285 	{
   286 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   287 	}
   288 
   289 	fseek(pFile, params[2], params[3]);
   290 	
   291 	return 1;
   292 }
   293 
   294 static cell_t sm_FilePosition(IPluginContext *pContext, const cell_t *params)
   295 {
   296 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   297 	HandleError herr;
   298 	HandleSecurity sec;
   299 	FILE *pFile;
   300 
   301 	sec.pOwner = NULL;
   302 	sec.pIdentity = g_pCoreIdent;
   303 
   304 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   305 		!= HandleError_None)
   306 	{
   307 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   308 	}
   309 
   310 	return ftell(pFile);
   311 }
   312 
   313 static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params)
   314 {
   315 	char *name;
   316 	int err;
   317 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   318 	{
   319 		pContext->ThrowNativeErrorEx(err, NULL);
   320 		return 0;
   321 	}
   322 
   323 	if (params[0] >= 2 && params[2] == 1)
   324 	{
   325 		return smcore.filesystem->FileExists(name) ? 1 : 0;
   326 	}
   327 
   328 	char realpath[PLATFORM_MAX_PATH];
   329 	g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   330 #ifdef PLATFORM_WINDOWS
   331 	struct _stat s;
   332 	if (_stat(realpath, &s) != 0)
   333 	{
   334 		return 0;
   335 	}
   336 	if (s.st_mode & S_IFREG)
   337 	{
   338 		return 1;
   339 	}
   340 	return 0;
   341 #elif defined PLATFORM_POSIX
   342 	struct stat s;
   343 	if (stat(realpath, &s) != 0)
   344 	{
   345 		return 0;
   346 	}
   347 	if (S_ISREG(s.st_mode))
   348 	{
   349 		return 1;
   350 	}
   351 	return 0;
   352 #endif
   353 }
   354 
   355 static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
   356 {
   357 	char *newpath, *oldpath;
   358 	int err;
   359 	if ((err=pContext->LocalToString(params[1], &newpath)) != SP_ERROR_NONE)
   360 	{
   361 		pContext->ThrowNativeErrorEx(err, NULL);
   362 		return 0;
   363 	}
   364 	if ((err=pContext->LocalToString(params[2], &oldpath)) != SP_ERROR_NONE)
   365 	{
   366 		pContext->ThrowNativeErrorEx(err, NULL);
   367 		return 0;
   368 	}
   369 
   370 	char new_realpath[PLATFORM_MAX_PATH];
   371 	g_pSM->BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath);
   372 	char old_realpath[PLATFORM_MAX_PATH];
   373 	g_pSM->BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath);
   374 
   375 #ifdef PLATFORM_WINDOWS
   376 	return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0;
   377 #elif defined PLATFORM_POSIX
   378 	return (rename(old_realpath, new_realpath)) ? 0 : 1;
   379 #endif
   380 }
   381 
   382 static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params)
   383 {
   384 	char *name;
   385 	int err;
   386 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   387 	{
   388 		pContext->ThrowNativeErrorEx(err, NULL);
   389 		return 0;
   390 	}
   391 
   392 	char realpath[PLATFORM_MAX_PATH];
   393 	g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   394 #ifdef PLATFORM_WINDOWS
   395 	struct _stat s;
   396 	if (_stat(realpath, &s) != 0)
   397 	{
   398 		return 0;
   399 	}
   400 	if (s.st_mode & S_IFDIR)
   401 	{
   402 		return 1;
   403 	}
   404 	return 0;
   405 #elif defined PLATFORM_POSIX
   406 	struct stat s;
   407 	if (stat(realpath, &s) != 0)
   408 	{
   409 		return 0;
   410 	}
   411 	if (S_ISDIR(s.st_mode))
   412 	{
   413 		return 1;
   414 	}
   415 	return 0;
   416 #endif
   417 }
   418 
   419 static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params)
   420 {
   421 	char *name;
   422 	int err;
   423 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   424 	{
   425 		pContext->ThrowNativeErrorEx(err, NULL);
   426 		return -1;
   427 	}
   428 
   429 	if (params[0] >= 2 && params[2] == 1)
   430 	{
   431 		if (smcore.filesystem->FileExists(name))
   432 		{
   433 			return smcore.filesystem->Size(name);
   434 		}
   435 		else
   436 		{
   437 			return -1;
   438 		}
   439 	}
   440 
   441 	char realpath[PLATFORM_MAX_PATH];
   442 	g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   443 #ifdef PLATFORM_WINDOWS
   444 	struct _stat s;
   445 	if (_stat(realpath, &s) != 0)
   446 	{
   447 		return -1;
   448 	}
   449 	if (s.st_mode & S_IFREG)
   450 	{
   451 		return static_cast<cell_t>(s.st_size);
   452 	}
   453 	return -1;
   454 #elif defined PLATFORM_POSIX
   455 	struct stat s;
   456 	if (stat(realpath, &s) != 0)
   457 	{
   458 		return -1;
   459 	}
   460 	if (S_ISREG(s.st_mode))
   461 	{
   462 		return static_cast<cell_t>(s.st_size);
   463 	}
   464 	return -1;
   465 #endif
   466 }
   467 
   468 static cell_t sm_CreateDirectory(IPluginContext *pContext, const cell_t *params)
   469 {
   470 	char *name;
   471 	char realpath[PLATFORM_MAX_PATH];
   472 
   473 	pContext->LocalToString(params[1], &name);
   474 	g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   475 
   476 #if defined PLATFORM_WINDOWS
   477 	return mkdir(realpath) == 0;
   478 #else
   479 	return mkdir(realpath, params[2]) == 0;
   480 #endif
   481 }
   482 
   483 static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params)
   484 {
   485 	char *name;
   486 	int err;
   487 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   488 	{
   489 		pContext->ThrowNativeErrorEx(err, NULL);
   490 		return 0;
   491 	}
   492 
   493 	char realpath[PLATFORM_MAX_PATH];
   494 	g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   495 
   496 	return (rmdir(realpath)) ? 0 : 1;
   497 }
   498 
   499 static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params)
   500 {
   501 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   502 	HandleError herr;
   503 	HandleSecurity sec;
   504 	FILE *pFile;
   505 
   506 	sec.pOwner = NULL;
   507 	sec.pIdentity = g_pCoreIdent;
   508 
   509 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   510 		!= HandleError_None)
   511 	{
   512 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   513 	}
   514 
   515 	char *fmt;
   516 	int err;
   517 	if ((err=pContext->LocalToString(params[2], &fmt)) != SP_ERROR_NONE)
   518 	{
   519 		pContext->ThrowNativeErrorEx(err, NULL);
   520 		return 0;
   521 	}
   522 
   523 	char buffer[2048];
   524 	int arg = 3;
   525 	smcore.atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg);
   526 	fprintf(pFile, "%s\n", buffer);
   527 
   528 	return 1;
   529 }
   530 
   531 static cell_t sm_FlushFile(IPluginContext *pContext, const cell_t *params)
   532 {
   533 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   534 	HandleError herr;
   535 	HandleSecurity sec;
   536 	FILE *pFile;
   537 
   538 	sec.pOwner = NULL;
   539 	sec.pIdentity = g_pCoreIdent;
   540 
   541 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   542 		!= HandleError_None)
   543 	{
   544 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   545 	}
   546 
   547 	return (fflush(pFile) == 0) ? 1 : 0;
   548 }
   549 
   550 static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params)
   551 {
   552 	char path[PLATFORM_MAX_PATH], *fmt, *buffer;
   553 	int arg = 5;
   554 	pContext->LocalToString(params[2], &buffer);
   555 	pContext->LocalToString(params[4], &fmt);
   556 
   557 	smcore.atcprintf(path, sizeof(path), fmt, pContext, params, &arg);
   558 
   559 	return g_pSM->BuildPath(Path_SM_Rel, buffer, params[3], "%s", path);
   560 }
   561 
   562 static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params)
   563 {
   564 	g_pSM->SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
   565 
   566 	char buffer[1024];
   567 	size_t len = g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 1);
   568 
   569 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   570 	{
   571 		return 0;
   572 	}
   573 
   574 	if (len >= sizeof(buffer)-2)
   575 	{
   576 		buffer[1022] = '\n';
   577 		buffer[1023] = '\0';
   578 	} else {
   579 		buffer[len++] = '\n';
   580 		buffer[len] = '\0';
   581 	}
   582 
   583 	smcore.LogToGame(buffer);
   584 
   585 	return 1;
   586 }
   587 
   588 static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params)
   589 {
   590 	g_pSM->SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
   591 
   592 	char buffer[1024];
   593 	g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 1);
   594 
   595 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   596 	{
   597 		return 0;
   598 	}
   599 
   600 	IPlugin *pPlugin = pluginsys->FindPluginByContext(pContext->GetContext());
   601 	smcore.Log("[%s] %s", pPlugin->GetFilename(), buffer);
   602 
   603 	return 1;
   604 }
   605 
   606 static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params)
   607 {
   608 	g_pSM->SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
   609 
   610 	char buffer[1024];
   611 	g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 1);
   612 
   613 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   614 	{
   615 		return 0;
   616 	}
   617 
   618 	IPlugin *pPlugin = pluginsys->FindPluginByContext(pContext->GetContext());
   619 	smcore.LogError("[%s] %s", pPlugin->GetFilename(), buffer);
   620 
   621 	return 1;
   622 }
   623 
   624 static cell_t sm_GetFileTime(IPluginContext *pContext, const cell_t *params)
   625 {
   626 	char *name;
   627 	int err;
   628 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   629 	{
   630 		pContext->ThrowNativeErrorEx(err, NULL);
   631 		return 0;
   632 	}
   633 
   634 	time_t time_val;
   635 	char realpath[PLATFORM_MAX_PATH];
   636 	g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   637 
   638 	if (!libsys->FileTime(realpath, (FileTimeType)params[2], &time_val))
   639 	{
   640 		return -1;
   641 	}
   642 
   643 	return (cell_t)time_val;
   644 }
   645 
   646 static cell_t sm_LogToOpenFile(IPluginContext *pContext, const cell_t *params)
   647 {
   648 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   649 	HandleError herr;
   650 	HandleSecurity sec;
   651 	FILE *pFile;
   652 
   653 	sec.pOwner = NULL;
   654 	sec.pIdentity = g_pCoreIdent;
   655 
   656 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   657 		!= HandleError_None)
   658 	{
   659 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   660 	}
   661 
   662 	char buffer[2048];
   663 	g_pSM->SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
   664 	g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 2);
   665 
   666 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   667 	{
   668 		return 0;
   669 	}
   670 
   671 	IPlugin *pPlugin = pluginsys->FindPluginByContext(pContext->GetContext());
   672 	smcore.LogToFile(pFile, "[%s] %s", pPlugin->GetFilename(), buffer);
   673 
   674 	return 1;
   675 }
   676 
   677 static cell_t sm_LogToOpenFileEx(IPluginContext *pContext, const cell_t *params)
   678 {
   679 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   680 	HandleError herr;
   681 	HandleSecurity sec;
   682 	FILE *pFile;
   683 
   684 	sec.pOwner = NULL;
   685 	sec.pIdentity = g_pCoreIdent;
   686 
   687 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   688 		!= HandleError_None)
   689 	{
   690 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   691 	}
   692 
   693 	char buffer[2048];
   694 	g_pSM->SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
   695 	g_pSM->FormatString(buffer, sizeof(buffer), pContext, params, 2);
   696 
   697 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   698 	{
   699 		return 0;
   700 	}
   701 
   702 	smcore.LogToFile(pFile, "%s", buffer);
   703 
   704 	return 1;
   705 }
   706 
   707 static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params)
   708 {
   709 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   710 	HandleError herr;
   711 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   712 	FILE *pFile;
   713 	size_t read = 0;
   714 
   715 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   716 		!= HandleError_None)
   717 	{
   718 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   719 	}
   720 
   721 	if (params[4] != 1 && params[4] != 2 && params[4] != 4)
   722 	{
   723 		return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]);
   724 	}
   725 
   726 	cell_t *data;
   727 	pContext->LocalToPhysAddr(params[2], &data);
   728 
   729 	if (params[4] == 4)
   730 	{
   731 		read = fread(data, sizeof(cell_t), params[3], pFile);
   732 	}
   733 	else if (params[4] == 2)
   734 	{
   735 		uint16_t val;
   736 		for (cell_t i = 0; i < params[3]; i++)
   737 		{
   738 			if (fread(&val, sizeof(uint16_t), 1, pFile) != 1)
   739 			{
   740 				break;
   741 			}
   742 			data[read++] = val;
   743 		}
   744 	}
   745 	else if (params[4] == 1)
   746 	{
   747 		uint8_t val;
   748 		for (cell_t i = 0; i < params[3]; i++)
   749 		{
   750 			if (fread(&val, sizeof(uint8_t), 1, pFile) != 1)
   751 			{
   752 				break;
   753 			}
   754 			data[read++] = val;
   755 		}
   756 	}
   757 
   758 	if (read != (size_t)params[3] && ferror(pFile) != 0)
   759 	{
   760 		return -1;
   761 	}
   762 
   763 	return read;
   764 }
   765 
   766 static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params)
   767 {
   768 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   769 	HandleError herr;
   770 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   771 	FILE *pFile;
   772 	cell_t num_read = 0;
   773 
   774 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   775 		!= HandleError_None)
   776 	{
   777 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   778 	}
   779 
   780 	char *buffer;
   781 	pContext->LocalToString(params[2], &buffer);
   782 
   783 	if (params[4] != -1)
   784 	{
   785 		if (size_t(params[4]) > size_t(params[3]))
   786 		{
   787 			return pContext->ThrowNativeError("read_count (%u) is greater than buffer size (%u)",
   788 				params[4],
   789 				params[3]);
   790 		}
   791 
   792 		num_read = (cell_t)fread(buffer, 1, params[4], pFile);
   793 
   794 		if (num_read != params[4] && ferror(pFile))
   795 		{
   796 			return -1;
   797 		}
   798 
   799 		return num_read;
   800 	}
   801 
   802 	char val;
   803 	while (1)
   804 	{
   805 		if (params[3] == 0 || num_read >= params[3] - 1)
   806 		{
   807 			break;
   808 		}
   809 		if (fread(&val, sizeof(val), 1, pFile) != 1)
   810 		{
   811 			if (ferror(pFile))
   812 			{
   813 				return -1;
   814 			}
   815 			break;
   816 		}
   817 		if (val == '\0')
   818 		{
   819 			break;
   820 		}
   821 		if (params[3] > 0 && num_read < params[3] - 1)
   822 		{
   823 			buffer[num_read++] = val;
   824 		}
   825 	}
   826 
   827 	if (params[3] > 0)
   828 	{
   829 		buffer[num_read] = '\0';
   830 	}
   831 
   832 	return num_read;
   833 }
   834 
   835 static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params)
   836 {
   837 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   838 	HandleError herr;
   839 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   840 	FILE *pFile;
   841 
   842 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   843 		!= HandleError_None)
   844 	{
   845 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   846 	}
   847 
   848 	cell_t *data;
   849 	pContext->LocalToPhysAddr(params[2], &data);
   850 
   851 	if (params[4] != 1 && params[4] != 2 && params[4] != 4)
   852 	{
   853 		return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]);
   854 	}
   855 
   856 	/* :NOTE: This really isn't compatible with big endian but we will never have to worry about that. */
   857 
   858 	if (params[4] == 4)
   859 	{
   860 		if (fwrite(data, sizeof(cell_t), params[3], pFile) != (size_t)params[3])
   861 		{
   862 			return 0;
   863 		}
   864 	}
   865 	else if (params[4] == 2)
   866 	{
   867 		for (cell_t i = 0; i < params[3]; i++)
   868 		{
   869 			if (fwrite(&data[i], sizeof(int16_t), 1, pFile) != 1)
   870 			{
   871 				return 0;
   872 			}
   873 		}
   874 	}
   875 	else if (params[4] == 1)
   876 	{
   877 		for (cell_t i = 0; i < params[3]; i++)
   878 		{
   879 			if (fwrite(&data[i], sizeof(int8_t), 1, pFile) != 1)
   880 			{
   881 				return 0;
   882 			}
   883 		}
   884 	}
   885 
   886 	return 1;
   887 }
   888 
   889 static cell_t sm_WriteFileString(IPluginContext *pContext, const cell_t *params)
   890 {
   891 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   892 	HandleError herr;
   893 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   894 	FILE *pFile;
   895 
   896 	if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   897 		!= HandleError_None)
   898 	{
   899 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   900 	}
   901 
   902 	char *buffer;
   903 	pContext->LocalToString(params[2], &buffer);
   904 
   905 	size_t len = strlen(buffer);
   906 
   907 	if (params[3])
   908 	{
   909 		len++;
   910 	}
   911 
   912 	return (fwrite(buffer, sizeof(char), len, pFile) == len) ? 1 : 0;
   913 }
   914 
   915 static cell_t sm_AddGameLogHook(IPluginContext *pContext, const cell_t *params)
   916 {
   917 	IPluginFunction *pFunction;
   918 
   919 	if ((pFunction=pContext->GetFunctionById(params[1])) == NULL)
   920 	{
   921 		return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
   922 	}
   923 
   924 	s_FileNatives.AddLogHook(pFunction);
   925 	
   926 	return 1;
   927 }
   928 
   929 static cell_t sm_RemoveGameLogHook(IPluginContext *pContext, const cell_t *params)
   930 {
   931 	IPluginFunction *pFunction;
   932 
   933 	if ((pFunction=pContext->GetFunctionById(params[1])) == NULL)
   934 	{
   935 		return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
   936 	}
   937 
   938 	s_FileNatives.RemoveLogHook(pFunction);
   939 
   940 	return 1;
   941 }
   942 
   943 REGISTER_NATIVES(filesystem)
   944 {
   945 	{"OpenDirectory",			sm_OpenDirectory},
   946 	{"ReadDirEntry",			sm_ReadDirEntry},
   947 	{"OpenFile",				sm_OpenFile},
   948 	{"DeleteFile",				sm_DeleteFile},
   949 	{"ReadFileLine",			sm_ReadFileLine},
   950 	{"IsEndOfFile",				sm_IsEndOfFile},
   951 	{"FileSeek",				sm_FileSeek},
   952 	{"FilePosition",			sm_FilePosition},
   953 	{"FileExists",				sm_FileExists},
   954 	{"RenameFile",				sm_RenameFile},
   955 	{"DirExists",				sm_DirExists},
   956 	{"FileSize",				sm_FileSize},
   957 	{"RemoveDir",				sm_RemoveDir},
   958 	{"WriteFileLine",			sm_WriteFileLine},
   959 	{"BuildPath",				sm_BuildPath},
   960 	{"LogToGame",				sm_LogToGame},
   961 	{"LogMessage",				sm_LogMessage},
   962 	{"LogError",				sm_LogError},
   963 	{"FlushFile",				sm_FlushFile},
   964 	{"GetFileTime",				sm_GetFileTime},
   965 	{"LogToOpenFile",			sm_LogToOpenFile},
   966 	{"LogToOpenFileEx",			sm_LogToOpenFileEx},
   967 	{"ReadFile",				sm_ReadFile},
   968 	{"ReadFileString",			sm_ReadFileString},
   969 	{"WriteFile",				sm_WriteFile},
   970 	{"WriteFileString",			sm_WriteFileString},
   971 	{"AddGameLogHook",			sm_AddGameLogHook},
   972 	{"RemoveGameLogHook",		sm_RemoveGameLogHook},
   973 	{"CreateDirectory",			sm_CreateDirectory},
   974 	{NULL,						NULL},
   975 };