core/smn_filesystem.cpp
author David Anderson <dvander@alliedmods.net>
Wed Feb 27 13:49:57 2008 +0000 (2008-02-27)
changeset 1900 457329ae65bd
parent 1854 91f2e0437e12
child 1914 0751a6430f15
permissions -rw-r--r--
fixed amb1483 - GetEntPropString() rejected FIELD_MODELNAME/FIELD_SOUNDNAME
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 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 "sm_globals.h"
    34 #include "HandleSys.h"
    35 #include "LibrarySys.h"
    36 #include "sm_stringutil.h"
    37 #include "Logger.h"
    38 #include "PluginSys.h"
    39 #include "sourcemm_api.h"
    40 
    41 HandleType_t g_FileType;
    42 HandleType_t g_DirType;
    43 
    44 class FileNatives : 
    45 	public SMGlobalClass,
    46 	public IHandleTypeDispatch
    47 {
    48 public:
    49 	virtual void OnSourceModAllInitialized()
    50 	{
    51 		g_FileType = g_HandleSys.CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    52 		g_DirType = g_HandleSys.CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    53 	}
    54 	virtual void OnSourceModShutdown()
    55 	{
    56 		g_HandleSys.RemoveType(g_DirType, g_pCoreIdent);
    57 		g_HandleSys.RemoveType(g_FileType, g_pCoreIdent);
    58 		g_DirType = 0;
    59 		g_FileType = 0;
    60 	}
    61 	virtual void OnHandleDestroy(HandleType_t type, void *object)
    62 	{
    63 		if (type == g_FileType)
    64 		{
    65 			FILE *fp = (FILE *)object;
    66 			fclose(fp);
    67 		} else if (type == g_DirType) {
    68 			IDirectory *pDir = (IDirectory *)object;
    69 			g_LibSys.CloseDirectory(pDir);
    70 		}
    71 	}
    72 } s_FileNatives;
    73 
    74 static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params)
    75 {
    76 	char *path;
    77 	int err;
    78 	if ((err=pContext->LocalToString(params[1], &path)) != SP_ERROR_NONE)
    79 	{
    80 		pContext->ThrowNativeErrorEx(err, NULL);
    81 		return 0;
    82 	}
    83 
    84 	char realpath[PLATFORM_MAX_PATH];
    85 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
    86 
    87 	IDirectory *pDir = g_LibSys.OpenDirectory(realpath);
    88 	if (!pDir)
    89 	{
    90 		return 0;
    91 	}
    92 
    93 	return g_HandleSys.CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
    94 }
    95 
    96 static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
    97 {
    98 	Handle_t hndl = static_cast<Handle_t>(params[1]);
    99 	IDirectory *pDir;
   100 	HandleError herr;
   101 	HandleSecurity sec;
   102 	int err;
   103 
   104 	sec.pOwner = NULL;
   105 	sec.pIdentity = g_pCoreIdent;
   106 
   107 	if ((herr=g_HandleSys.ReadHandle(hndl, g_DirType, &sec, (void **)&pDir))
   108 		!= HandleError_None)
   109 	{
   110 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   111 	}
   112 
   113 	if (!pDir->MoreFiles())
   114 	{
   115 		return false;
   116 	}
   117 
   118 	cell_t *filetype;
   119 	if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE)
   120 	{
   121 		pContext->ThrowNativeErrorEx(err, NULL);
   122 		return 0;
   123 	}
   124 
   125 	if (pDir->IsEntryDirectory())
   126 	{
   127 		*filetype = 1;
   128 	} else if (pDir->IsEntryFile()) {
   129 		*filetype = 2;
   130 	} else {
   131 		*filetype = 0;
   132 	}
   133 
   134 	const char *path = pDir->GetEntryName();
   135 	if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL))
   136 		!= SP_ERROR_NONE)
   137 	{
   138 		pContext->ThrowNativeErrorEx(err, NULL);
   139 		return 0;
   140 	}
   141 
   142 	pDir->NextEntry();
   143 
   144 	return true;
   145 }
   146 
   147 static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params)
   148 {
   149 	char *name, *mode;
   150 	int err;
   151 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   152 	{
   153 		pContext->ThrowNativeErrorEx(err, NULL);
   154 		return 0;
   155 	}
   156 	if ((err=pContext->LocalToString(params[2], &mode)) != SP_ERROR_NONE)
   157 	{
   158 		pContext->ThrowNativeErrorEx(err, NULL);
   159 		return 0;
   160 	}
   161 
   162 	char realpath[PLATFORM_MAX_PATH];
   163 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   164 
   165 	FILE *pFile = fopen(realpath, mode);
   166 	if (!pFile)
   167 	{
   168 		return 0;
   169 	}
   170 
   171 	return g_HandleSys.CreateHandle(g_FileType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL);
   172 }
   173 
   174 static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params)
   175 {
   176 	char *name;
   177 	int err;
   178 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   179 	{
   180 		pContext->ThrowNativeErrorEx(err, NULL);
   181 		return 0;
   182 	}
   183 
   184 	char realpath[PLATFORM_MAX_PATH];
   185 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   186 
   187 	return (unlink(realpath)) ? 0 : 1;
   188 }
   189 
   190 static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params)
   191 {
   192 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   193 	HandleError herr;
   194 	HandleSecurity sec;
   195 	FILE *pFile;
   196 	int err;
   197 
   198 	sec.pOwner = NULL;
   199 	sec.pIdentity = g_pCoreIdent;
   200 
   201 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   202 		!= HandleError_None)
   203 	{
   204 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   205 	}
   206 
   207 	char *buf;
   208 	if ((err=pContext->LocalToString(params[2], &buf)) != SP_ERROR_NONE)
   209 	{
   210 		pContext->ThrowNativeErrorEx(err, NULL);
   211 		return 0;
   212 	}
   213 
   214 	if (fgets(buf, params[3], pFile) == NULL)
   215 	{
   216 		return 0;
   217 	}
   218 
   219 	return 1;
   220 }
   221 
   222 static cell_t sm_IsEndOfFile(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 
   229 	sec.pOwner = NULL;
   230 	sec.pIdentity = g_pCoreIdent;
   231 
   232 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   233 		!= HandleError_None)
   234 	{
   235 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   236 	}
   237 
   238 	return (feof(pFile)) ? 1 : 0;
   239 }
   240 
   241 static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params)
   242 {
   243 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   244 	HandleError herr;
   245 	HandleSecurity sec;
   246 	FILE *pFile;
   247 
   248 	sec.pOwner = NULL;
   249 	sec.pIdentity = g_pCoreIdent;
   250 
   251 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   252 		!= HandleError_None)
   253 	{
   254 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   255 	}
   256 
   257 	fseek(pFile, params[2], params[3]);
   258 	
   259 	return 1;
   260 }
   261 
   262 static cell_t sm_FilePosition(IPluginContext *pContext, const cell_t *params)
   263 {
   264 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   265 	HandleError herr;
   266 	HandleSecurity sec;
   267 	FILE *pFile;
   268 
   269 	sec.pOwner = NULL;
   270 	sec.pIdentity = g_pCoreIdent;
   271 
   272 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   273 		!= HandleError_None)
   274 	{
   275 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   276 	}
   277 
   278 	return ftell(pFile);
   279 }
   280 
   281 static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params)
   282 {
   283 	char *name;
   284 	int err;
   285 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   286 	{
   287 		pContext->ThrowNativeErrorEx(err, NULL);
   288 		return 0;
   289 	}
   290 
   291 	if (params[0] >= 2 && params[2] == 1)
   292 	{
   293 		return basefilesystem->FileExists(name) ? 1 : 0;
   294 	}
   295 
   296 	char realpath[PLATFORM_MAX_PATH];
   297 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   298 #ifdef PLATFORM_WINDOWS
   299 	struct _stat s;
   300 	if (_stat(realpath, &s) != 0)
   301 	{
   302 		return 0;
   303 	}
   304 	if (s.st_mode & S_IFREG)
   305 	{
   306 		return 1;
   307 	}
   308 	return 0;
   309 #elif defined PLATFORM_POSIX
   310 	struct stat s;
   311 	if (stat(realpath, &s) != 0)
   312 	{
   313 		return 0;
   314 	}
   315 	if (S_ISREG(s.st_mode))
   316 	{
   317 		return 1;
   318 	}
   319 	return 0;
   320 #endif
   321 }
   322 
   323 static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
   324 {
   325 	char *newpath, *oldpath;
   326 	int err;
   327 	if ((err=pContext->LocalToString(params[1], &newpath)) != SP_ERROR_NONE)
   328 	{
   329 		pContext->ThrowNativeErrorEx(err, NULL);
   330 		return 0;
   331 	}
   332 	if ((err=pContext->LocalToString(params[2], &oldpath)) != SP_ERROR_NONE)
   333 	{
   334 		pContext->ThrowNativeErrorEx(err, NULL);
   335 		return 0;
   336 	}
   337 
   338 	char new_realpath[PLATFORM_MAX_PATH];
   339 	g_SourceMod.BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath);
   340 	char old_realpath[PLATFORM_MAX_PATH];
   341 	g_SourceMod.BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath);
   342 
   343 #ifdef PLATFORM_WINDOWS
   344 	return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0;
   345 #elif defined PLATFORM_POSIX
   346 	return (rename(old_realpath, new_realpath)) ? 0 : 1;
   347 #endif
   348 }
   349 
   350 static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params)
   351 {
   352 	char *name;
   353 	int err;
   354 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   355 	{
   356 		pContext->ThrowNativeErrorEx(err, NULL);
   357 		return 0;
   358 	}
   359 
   360 	char realpath[PLATFORM_MAX_PATH];
   361 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   362 #ifdef PLATFORM_WINDOWS
   363 	struct _stat s;
   364 	if (_stat(realpath, &s) != 0)
   365 	{
   366 		return 0;
   367 	}
   368 	if (s.st_mode & S_IFDIR)
   369 	{
   370 		return 1;
   371 	}
   372 	return 0;
   373 #elif defined PLATFORM_POSIX
   374 	struct stat s;
   375 	if (stat(realpath, &s) != 0)
   376 	{
   377 		return 0;
   378 	}
   379 	if (S_ISDIR(s.st_mode))
   380 	{
   381 		return 1;
   382 	}
   383 	return 0;
   384 #endif
   385 }
   386 
   387 static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params)
   388 {
   389 	char *name;
   390 	int err;
   391 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   392 	{
   393 		pContext->ThrowNativeErrorEx(err, NULL);
   394 		return -1;
   395 	}
   396 
   397 	char realpath[PLATFORM_MAX_PATH];
   398 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   399 #ifdef PLATFORM_WINDOWS
   400 	struct _stat s;
   401 	if (_stat(realpath, &s) != 0)
   402 	{
   403 		return -1;
   404 	}
   405 	if (s.st_mode & S_IFREG)
   406 	{
   407 		return static_cast<cell_t>(s.st_size);
   408 	}
   409 	return -1;
   410 #elif defined PLATFORM_POSIX
   411 	struct stat s;
   412 	if (stat(realpath, &s) != 0)
   413 	{
   414 		return -1;
   415 	}
   416 	if (S_ISREG(s.st_mode))
   417 	{
   418 		return static_cast<cell_t>(s.st_size);
   419 	}
   420 	return -1;
   421 #endif
   422 }
   423 
   424 static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params)
   425 {
   426 	char *name;
   427 	int err;
   428 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   429 	{
   430 		pContext->ThrowNativeErrorEx(err, NULL);
   431 		return 0;
   432 	}
   433 
   434 	char realpath[PLATFORM_MAX_PATH];
   435 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   436 
   437 	return (rmdir(realpath)) ? 0 : 1;
   438 }
   439 
   440 static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params)
   441 {
   442 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   443 	HandleError herr;
   444 	HandleSecurity sec;
   445 	FILE *pFile;
   446 
   447 	sec.pOwner = NULL;
   448 	sec.pIdentity = g_pCoreIdent;
   449 
   450 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   451 		!= HandleError_None)
   452 	{
   453 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   454 	}
   455 
   456 	char *fmt;
   457 	int err;
   458 	if ((err=pContext->LocalToString(params[2], &fmt)) != SP_ERROR_NONE)
   459 	{
   460 		pContext->ThrowNativeErrorEx(err, NULL);
   461 		return 0;
   462 	}
   463 
   464 	char buffer[2048];
   465 	int arg = 3;
   466 	atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg);
   467 	fprintf(pFile, "%s\n", buffer);
   468 
   469 	return 1;
   470 }
   471 
   472 static cell_t sm_FlushFile(IPluginContext *pContext, const cell_t *params)
   473 {
   474 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   475 	HandleError herr;
   476 	HandleSecurity sec;
   477 	FILE *pFile;
   478 
   479 	sec.pOwner = NULL;
   480 	sec.pIdentity = g_pCoreIdent;
   481 
   482 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   483 		!= HandleError_None)
   484 	{
   485 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   486 	}
   487 
   488 	return (fflush(pFile) == 0) ? 1 : 0;
   489 }
   490 
   491 static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params)
   492 {
   493 	char path[PLATFORM_MAX_PATH], *fmt, *buffer;
   494 	int arg = 5;
   495 	pContext->LocalToString(params[2], &buffer);
   496 	pContext->LocalToString(params[4], &fmt);
   497 
   498 	atcprintf(path, sizeof(path), fmt, pContext, params, &arg);
   499 
   500 	return g_SourceMod.BuildPath(Path_SM_Rel, buffer, params[3], "%s", path);
   501 }
   502 
   503 static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params)
   504 {
   505 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   506 
   507 	char buffer[1024];
   508 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
   509 
   510 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   511 	{
   512 		return 0;
   513 	}
   514 
   515 	if (len >= sizeof(buffer)-2)
   516 	{
   517 		buffer[1022] = '\n';
   518 		buffer[1023] = '\0';
   519 	} else {
   520 		buffer[len++] = '\n';
   521 		buffer[len] = '\0';
   522 	}
   523 
   524 	engine->LogPrint(buffer);
   525 
   526 	return 1;
   527 }
   528 
   529 static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params)
   530 {
   531 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   532 
   533 	char buffer[1024];
   534 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
   535 
   536 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   537 	{
   538 		return 0;
   539 	}
   540 
   541 	CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
   542 	g_Logger.LogMessage("[%s] %s", pPlugin->GetFilename(), buffer);
   543 
   544 	return 1;
   545 }
   546 
   547 static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params)
   548 {
   549 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   550 
   551 	char buffer[1024];
   552 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
   553 
   554 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   555 	{
   556 		return 0;
   557 	}
   558 
   559 	CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
   560 	g_Logger.LogError("[%s] %s", pPlugin->GetFilename(), buffer);
   561 
   562 	return 1;
   563 }
   564 
   565 static cell_t sm_GetFileTime(IPluginContext *pContext, const cell_t *params)
   566 {
   567 	char *name;
   568 	int err;
   569 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   570 	{
   571 		pContext->ThrowNativeErrorEx(err, NULL);
   572 		return 0;
   573 	}
   574 
   575 	time_t time_val;
   576 	char realpath[PLATFORM_MAX_PATH];
   577 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   578 
   579 	if (!g_LibSys.FileTime(realpath, (FileTimeType)params[2], &time_val))
   580 	{
   581 		return -1;
   582 	}
   583 
   584 	return (cell_t)time_val;
   585 }
   586 
   587 static cell_t sm_LogToOpenFile(IPluginContext *pContext, const cell_t *params)
   588 {
   589 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   590 	HandleError herr;
   591 	HandleSecurity sec;
   592 	FILE *pFile;
   593 
   594 	sec.pOwner = NULL;
   595 	sec.pIdentity = g_pCoreIdent;
   596 
   597 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   598 		!= HandleError_None)
   599 	{
   600 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   601 	}
   602 
   603 	char buffer[2048];
   604 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   605 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   606 
   607 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   608 	{
   609 		return 0;
   610 	}
   611 
   612 	CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
   613 	g_Logger.LogToOpenFile(pFile, "[%s] %s", pPlugin->GetFilename(), buffer);
   614 
   615 	return 1;
   616 }
   617 
   618 static cell_t sm_LogToOpenFileEx(IPluginContext *pContext, const cell_t *params)
   619 {
   620 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   621 	HandleError herr;
   622 	HandleSecurity sec;
   623 	FILE *pFile;
   624 
   625 	sec.pOwner = NULL;
   626 	sec.pIdentity = g_pCoreIdent;
   627 
   628 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   629 		!= HandleError_None)
   630 	{
   631 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   632 	}
   633 
   634 	char buffer[2048];
   635 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   636 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   637 
   638 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   639 	{
   640 		return 0;
   641 	}
   642 
   643 	g_Logger.LogToOpenFile(pFile, "%s", buffer);
   644 
   645 	return 1;
   646 }
   647 
   648 static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params)
   649 {
   650 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   651 	HandleError herr;
   652 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   653 	FILE *pFile;
   654 	size_t read = 0;
   655 
   656 	if ((herr=g_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 	if (params[4] != 1 && params[4] != 2 && params[4] != 4)
   663 	{
   664 		return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]);
   665 	}
   666 
   667 	cell_t *data;
   668 	pContext->LocalToPhysAddr(params[2], &data);
   669 
   670 	if (params[4] == 4)
   671 	{
   672 		read = fread(data, sizeof(cell_t), params[3], pFile);
   673 	}
   674 	else if (params[4] == 2)
   675 	{
   676 		int16_t val;
   677 		for (cell_t i = 0; i < params[3]; i++)
   678 		{
   679 			if (fread(&val, sizeof(int16_t), 1, pFile) != 1)
   680 			{
   681 				break;
   682 			}
   683 			data[read++] = val;
   684 		}
   685 	}
   686 	else if (params[4] == 1)
   687 	{
   688 		int8_t val;
   689 		for (cell_t i = 0; i < params[3]; i++)
   690 		{
   691 			if (fread(&val, sizeof(int8_t), 1, pFile) != 1)
   692 			{
   693 				break;
   694 			}
   695 			data[read++] = val;
   696 		}
   697 	}
   698 
   699 	if (read != (size_t)params[3] && ferror(pFile) != 0)
   700 	{
   701 		return -1;
   702 	}
   703 
   704 	return read;
   705 }
   706 
   707 static cell_t sm_ReadFileString(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 	cell_t num_read = 0;
   714 
   715 	if ((herr=g_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 	char *buffer;
   722 	pContext->LocalToString(params[2], &buffer);
   723 
   724 	char val;
   725 	while (1)
   726 	{
   727 		/* If we're in stop mode, break as soon as the buffer is full. */
   728 		if (params[4] && (params[3] == 0 || num_read >= params[3] - 1))
   729 		{
   730 			break;
   731 		}
   732 		if (fread(&val, sizeof(val), 1, pFile) != 1)
   733 		{
   734 			if (ferror(pFile))
   735 			{
   736 				return -1;
   737 			}
   738 			break;
   739 		}
   740 		if (val == '\0')
   741 		{
   742 			break;
   743 		}
   744 		if (params[3] > 0 && num_read < params[3] - 1)
   745 		{
   746 			buffer[num_read++] = val;
   747 		}
   748 	}
   749 
   750 	if (params[3] > 0)
   751 	{
   752 		buffer[num_read] = '\0';
   753 	}
   754 
   755 	return num_read;
   756 }
   757 
   758 static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params)
   759 {
   760 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   761 	HandleError herr;
   762 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   763 	FILE *pFile;
   764 
   765 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   766 		!= HandleError_None)
   767 	{
   768 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   769 	}
   770 
   771 	cell_t *data;
   772 	pContext->LocalToPhysAddr(params[2], &data);
   773 
   774 	if (params[4] != 1 && params[4] != 2 && params[4] != 4)
   775 	{
   776 		return pContext->ThrowNativeError("Invalid size specifier (%d is not 1, 2, or 4)", params[4]);
   777 	}
   778 
   779 	/* :NOTE: This really isn't compatible with big endian but we will never have to worry about that. */
   780 
   781 	if (params[4] == 4)
   782 	{
   783 		if (fwrite(data, sizeof(cell_t), params[3], pFile) != (size_t)params[3])
   784 		{
   785 			return 0;
   786 		}
   787 	}
   788 	else if (params[4] == 2)
   789 	{
   790 		for (cell_t i = 0; i < params[3]; i++)
   791 		{
   792 			if (fwrite(&data[i], sizeof(int16_t), 1, pFile) != 1)
   793 			{
   794 				return 0;
   795 			}
   796 		}
   797 	}
   798 	else if (params[4] == 1)
   799 	{
   800 		for (cell_t i = 0; i < params[3]; i++)
   801 		{
   802 			if (fwrite(&data[i], sizeof(int8_t), 1, pFile) != 1)
   803 			{
   804 				return 0;
   805 			}
   806 		}
   807 	}
   808 
   809 	return 1;
   810 }
   811 
   812 static cell_t sm_WriteFileString(IPluginContext *pContext, const cell_t *params)
   813 {
   814 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   815 	HandleError herr;
   816 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   817 	FILE *pFile;
   818 
   819 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   820 		!= HandleError_None)
   821 	{
   822 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   823 	}
   824 
   825 	char *buffer;
   826 	pContext->LocalToString(params[2], &buffer);
   827 
   828 	size_t len = strlen(buffer);
   829 
   830 	if (params[3])
   831 	{
   832 		len++;
   833 	}
   834 
   835 	return (fwrite(buffer, sizeof(char), len, pFile) == len) ? 1 : 0;
   836 }
   837 
   838 REGISTER_NATIVES(filesystem)
   839 {
   840 	{"OpenDirectory",			sm_OpenDirectory},
   841 	{"ReadDirEntry",			sm_ReadDirEntry},
   842 	{"OpenFile",				sm_OpenFile},
   843 	{"DeleteFile",				sm_DeleteFile},
   844 	{"ReadFileLine",			sm_ReadFileLine},
   845 	{"IsEndOfFile",				sm_IsEndOfFile},
   846 	{"FileSeek",				sm_FileSeek},
   847 	{"FilePosition",			sm_FilePosition},
   848 	{"FileExists",				sm_FileExists},
   849 	{"RenameFile",				sm_RenameFile},
   850 	{"DirExists",				sm_DirExists},
   851 	{"FileSize",				sm_FileSize},
   852 	{"RemoveDir",				sm_RemoveDir},
   853 	{"WriteFileLine",			sm_WriteFileLine},
   854 	{"BuildPath",				sm_BuildPath},
   855 	{"LogToGame",				sm_LogToGame},
   856 	{"LogMessage",				sm_LogMessage},
   857 	{"LogError",				sm_LogError},
   858 	{"FlushFile",				sm_FlushFile},
   859 	{"GetFileTime",				sm_GetFileTime},
   860 	{"LogToOpenFile",			sm_LogToOpenFile},
   861 	{"LogToOpenFileEx",			sm_LogToOpenFileEx},
   862 	{"ReadFile",				sm_ReadFile},
   863 	{"ReadFileString",			sm_ReadFileString},
   864 	{"WriteFile",				sm_WriteFile},
   865 	{"WriteFileString",			sm_WriteFileString},
   866 	{NULL,						NULL},
   867 };