core/smn_filesystem.cpp
author David Anderson <dvander@alliedmods.net>
Mon Oct 15 00:38:25 2007 +0000 (2007-10-15)
changeset 1568 ecbaee393b0b
parent 1379 6b76a3d0c58d
child 1738 cb3be0b31d99
permissions -rw-r--r--
extensions can now be built for multiple engines, and will autoload from auto.X.Y folders
     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 	char realpath[PLATFORM_MAX_PATH];
   292 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   293 #ifdef PLATFORM_WINDOWS
   294 	struct _stat s;
   295 	if (_stat(realpath, &s) != 0)
   296 	{
   297 		return 0;
   298 	}
   299 	if (s.st_mode & S_IFREG)
   300 	{
   301 		return 1;
   302 	}
   303 	return 0;
   304 #elif defined PLATFORM_POSIX
   305 	struct stat s;
   306 	if (stat(realpath, &s) != 0)
   307 	{
   308 		return 0;
   309 	}
   310 	if (S_ISREG(s.st_mode))
   311 	{
   312 		return 1;
   313 	}
   314 	return 0;
   315 #endif
   316 }
   317 
   318 static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
   319 {
   320 	char *newpath, *oldpath;
   321 	int err;
   322 	if ((err=pContext->LocalToString(params[1], &newpath)) != SP_ERROR_NONE)
   323 	{
   324 		pContext->ThrowNativeErrorEx(err, NULL);
   325 		return 0;
   326 	}
   327 	if ((err=pContext->LocalToString(params[2], &oldpath)) != SP_ERROR_NONE)
   328 	{
   329 		pContext->ThrowNativeErrorEx(err, NULL);
   330 		return 0;
   331 	}
   332 
   333 	char new_realpath[PLATFORM_MAX_PATH];
   334 	g_SourceMod.BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath);
   335 	char old_realpath[PLATFORM_MAX_PATH];
   336 	g_SourceMod.BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath);
   337 
   338 #ifdef PLATFORM_WINDOWS
   339 	return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0;
   340 #elif defined PLATFORM_POSIX
   341 	return (rename(old_realpath, new_realpath)) ? 0 : 1;
   342 #endif
   343 }
   344 
   345 static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params)
   346 {
   347 	char *name;
   348 	int err;
   349 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   350 	{
   351 		pContext->ThrowNativeErrorEx(err, NULL);
   352 		return 0;
   353 	}
   354 
   355 	char realpath[PLATFORM_MAX_PATH];
   356 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   357 #ifdef PLATFORM_WINDOWS
   358 	struct _stat s;
   359 	if (_stat(realpath, &s) != 0)
   360 	{
   361 		return 0;
   362 	}
   363 	if (s.st_mode & S_IFDIR)
   364 	{
   365 		return 1;
   366 	}
   367 	return 0;
   368 #elif defined PLATFORM_POSIX
   369 	struct stat s;
   370 	if (stat(realpath, &s) != 0)
   371 	{
   372 		return 0;
   373 	}
   374 	if (S_ISDIR(s.st_mode))
   375 	{
   376 		return 1;
   377 	}
   378 	return 0;
   379 #endif
   380 }
   381 
   382 static cell_t sm_FileSize(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 -1;
   390 	}
   391 
   392 	char realpath[PLATFORM_MAX_PATH];
   393 	g_SourceMod.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 -1;
   399 	}
   400 	if (s.st_mode & S_IFREG)
   401 	{
   402 		return static_cast<cell_t>(s.st_size);
   403 	}
   404 	return -1;
   405 #elif defined PLATFORM_POSIX
   406 	struct stat s;
   407 	if (stat(realpath, &s) != 0)
   408 	{
   409 		return -1;
   410 	}
   411 	if (S_ISREG(s.st_mode))
   412 	{
   413 		return static_cast<cell_t>(s.st_size);
   414 	}
   415 	return -1;
   416 #endif
   417 }
   418 
   419 static cell_t sm_RemoveDir(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 0;
   427 	}
   428 
   429 	char realpath[PLATFORM_MAX_PATH];
   430 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   431 
   432 	return (rmdir(realpath)) ? 0 : 1;
   433 }
   434 
   435 static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params)
   436 {
   437 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   438 	HandleError herr;
   439 	HandleSecurity sec;
   440 	FILE *pFile;
   441 
   442 	sec.pOwner = NULL;
   443 	sec.pIdentity = g_pCoreIdent;
   444 
   445 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   446 		!= HandleError_None)
   447 	{
   448 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   449 	}
   450 
   451 	char *fmt;
   452 	int err;
   453 	if ((err=pContext->LocalToString(params[2], &fmt)) != SP_ERROR_NONE)
   454 	{
   455 		pContext->ThrowNativeErrorEx(err, NULL);
   456 		return 0;
   457 	}
   458 
   459 	char buffer[2048];
   460 	int arg = 3;
   461 	atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg);
   462 	fprintf(pFile, "%s\n", buffer);
   463 
   464 	return 1;
   465 }
   466 
   467 static cell_t sm_FlushFile(IPluginContext *pContext, const cell_t *params)
   468 {
   469 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   470 	HandleError herr;
   471 	HandleSecurity sec;
   472 	FILE *pFile;
   473 
   474 	sec.pOwner = NULL;
   475 	sec.pIdentity = g_pCoreIdent;
   476 
   477 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   478 		!= HandleError_None)
   479 	{
   480 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   481 	}
   482 
   483 	return (fflush(pFile) == 0) ? 1 : 0;
   484 }
   485 
   486 static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params)
   487 {
   488 	char path[PLATFORM_MAX_PATH], *fmt, *buffer;
   489 	int arg = 5;
   490 	pContext->LocalToString(params[2], &buffer);
   491 	pContext->LocalToString(params[4], &fmt);
   492 
   493 	atcprintf(path, sizeof(path), fmt, pContext, params, &arg);
   494 
   495 	return g_SourceMod.BuildPath(Path_SM_Rel, buffer, params[3], "%s", path);
   496 }
   497 
   498 static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params)
   499 {
   500 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   501 
   502 	char buffer[1024];
   503 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
   504 
   505 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   506 	{
   507 		return 0;
   508 	}
   509 
   510 	if (len >= sizeof(buffer)-2)
   511 	{
   512 		buffer[1022] = '\n';
   513 		buffer[1023] = '\0';
   514 	} else {
   515 		buffer[len++] = '\n';
   516 		buffer[len] = '\0';
   517 	}
   518 
   519 	engine->LogPrint(buffer);
   520 
   521 	return 1;
   522 }
   523 
   524 static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params)
   525 {
   526 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   527 
   528 	char buffer[1024];
   529 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
   530 
   531 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   532 	{
   533 		return 0;
   534 	}
   535 
   536 	CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
   537 	g_Logger.LogMessage("[%s] %s", pPlugin->GetFilename(), buffer);
   538 
   539 	return 1;
   540 }
   541 
   542 static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params)
   543 {
   544 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   545 
   546 	char buffer[1024];
   547 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
   548 
   549 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   550 	{
   551 		return 0;
   552 	}
   553 
   554 	CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
   555 	g_Logger.LogError("[%s] %s", pPlugin->GetFilename(), buffer);
   556 
   557 	return 1;
   558 }
   559 
   560 enum
   561 {
   562 	FileTime_LastAccess = 0,	/* Last access (not available on FAT) */
   563 	FileTime_Created = 1,		/* Creation (not available on FAT) */
   564 	FileTime_LastChange = 2,	/* Last modification */
   565 };
   566 
   567 static cell_t sm_GetFileTime(IPluginContext *pContext, const cell_t *params)
   568 {
   569 	char *name;
   570 	int err;
   571 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   572 	{
   573 		pContext->ThrowNativeErrorEx(err, NULL);
   574 		return 0;
   575 	}
   576 
   577 	char realpath[PLATFORM_MAX_PATH];
   578 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   579 
   580 #ifdef PLATFORM_WINDOWS
   581 	struct _stat s;
   582 	if (_stat(realpath, &s) != 0)
   583 #elif defined PLATFORM_POSIX
   584 	struct stat s;
   585 	if (stat(realpath, &s) != 0)
   586 #endif
   587 	{
   588 		return -1;
   589 	} else {
   590 		if (params[2] == FileTime_LastAccess)
   591 		{
   592 			return (cell_t)s.st_atime;
   593 		} else if (params[2] == FileTime_Created) {
   594 			return (cell_t)s.st_ctime;
   595 		} else if (params[2] == FileTime_LastChange) {
   596 			return (cell_t)s.st_mtime;
   597 		}
   598 	}
   599 
   600 	return -1;
   601 }
   602 
   603 static cell_t sm_LogToOpenFile(IPluginContext *pContext, const cell_t *params)
   604 {
   605 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   606 	HandleError herr;
   607 	HandleSecurity sec;
   608 	FILE *pFile;
   609 
   610 	sec.pOwner = NULL;
   611 	sec.pIdentity = g_pCoreIdent;
   612 
   613 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   614 		!= HandleError_None)
   615 	{
   616 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   617 	}
   618 
   619 	char buffer[2048];
   620 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   621 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   622 
   623 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   624 	{
   625 		return 0;
   626 	}
   627 
   628 	CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
   629 	g_Logger.LogToOpenFile(pFile, "[%s] %s", pPlugin->GetFilename(), buffer);
   630 
   631 	return 1;
   632 }
   633 
   634 static cell_t sm_LogToOpenFileEx(IPluginContext *pContext, const cell_t *params)
   635 {
   636 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   637 	HandleError herr;
   638 	HandleSecurity sec;
   639 	FILE *pFile;
   640 
   641 	sec.pOwner = NULL;
   642 	sec.pIdentity = g_pCoreIdent;
   643 
   644 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   645 		!= HandleError_None)
   646 	{
   647 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   648 	}
   649 
   650 	char buffer[2048];
   651 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   652 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   653 
   654 	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   655 	{
   656 		return 0;
   657 	}
   658 
   659 	g_Logger.LogToOpenFile(pFile, "%s", buffer);
   660 
   661 	return 1;
   662 }
   663 
   664 REGISTER_NATIVES(filesystem)
   665 {
   666 	{"OpenDirectory",			sm_OpenDirectory},
   667 	{"ReadDirEntry",			sm_ReadDirEntry},
   668 	{"OpenFile",				sm_OpenFile},
   669 	{"DeleteFile",				sm_DeleteFile},
   670 	{"ReadFileLine",			sm_ReadFileLine},
   671 	{"IsEndOfFile",				sm_IsEndOfFile},
   672 	{"FileSeek",				sm_FileSeek},
   673 	{"FilePosition",			sm_FilePosition},
   674 	{"FileExists",				sm_FileExists},
   675 	{"RenameFile",				sm_RenameFile},
   676 	{"DirExists",				sm_DirExists},
   677 	{"FileSize",				sm_FileSize},
   678 	{"RemoveDir",				sm_RemoveDir},
   679 	{"WriteFileLine",			sm_WriteFileLine},
   680 	{"BuildPath",				sm_BuildPath},
   681 	{"LogToGame",				sm_LogToGame},
   682 	{"LogMessage",				sm_LogMessage},
   683 	{"LogError",				sm_LogError},
   684 	{"FlushFile",				sm_FlushFile},
   685 	{"GetFileTime",				sm_GetFileTime},
   686 	{"LogToOpenFile",			sm_LogToOpenFile},
   687 	{"LogToOpenFileEx",			sm_LogToOpenFileEx},
   688 	{NULL,						NULL},
   689 };