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