core/smn_filesystem.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jun 17 07:32:31 2007 +0000 (2007-06-17)
changeset 969 0cd7fc27e054
parent 821 c5b4dca7f8ac
child 1011 b413072540fd
permissions -rw-r--r--
fixed a state bug in the gameconf parser that would break parsing after a signature section was done
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include <sys/stat.h>
    16 #include "sm_globals.h"
    17 #include "HandleSys.h"
    18 #include "LibrarySys.h"
    19 #include "sm_stringutil.h"
    20 #include "Logger.h"
    21 #include "PluginSys.h"
    22 #include "sourcemm_api.h"
    23 
    24 HandleType_t g_FileType;
    25 HandleType_t g_DirType;
    26 
    27 class FileNatives : 
    28 	public SMGlobalClass,
    29 	public IHandleTypeDispatch
    30 {
    31 public:
    32 	virtual void OnSourceModAllInitialized()
    33 	{
    34 		g_FileType = g_HandleSys.CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    35 		g_DirType = g_HandleSys.CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    36 	}
    37 	virtual void OnSourceModShutdown()
    38 	{
    39 		g_HandleSys.RemoveType(g_DirType, g_pCoreIdent);
    40 		g_HandleSys.RemoveType(g_FileType, g_pCoreIdent);
    41 		g_DirType = 0;
    42 		g_FileType = 0;
    43 	}
    44 	virtual void OnHandleDestroy(HandleType_t type, void *object)
    45 	{
    46 		if (type == g_FileType)
    47 		{
    48 			FILE *fp = (FILE *)object;
    49 			fclose(fp);
    50 		} else if (type == g_DirType) {
    51 			IDirectory *pDir = (IDirectory *)object;
    52 			g_LibSys.CloseDirectory(pDir);
    53 		}
    54 	}
    55 };
    56 
    57 
    58 static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params)
    59 {
    60 	char *path;
    61 	int err;
    62 	if ((err=pContext->LocalToString(params[1], &path)) != SP_ERROR_NONE)
    63 	{
    64 		pContext->ThrowNativeErrorEx(err, NULL);
    65 		return 0;
    66 	}
    67 
    68 	char realpath[PLATFORM_MAX_PATH];
    69 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
    70 
    71 	IDirectory *pDir = g_LibSys.OpenDirectory(realpath);
    72 	if (!pDir)
    73 	{
    74 		return 0;
    75 	}
    76 
    77 	return g_HandleSys.CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
    78 }
    79 
    80 static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
    81 {
    82 	Handle_t hndl = static_cast<Handle_t>(params[1]);
    83 	IDirectory *pDir;
    84 	HandleError herr;
    85 	HandleSecurity sec;
    86 	int err;
    87 
    88 	sec.pOwner = NULL;
    89 	sec.pIdentity = g_pCoreIdent;
    90 
    91 	if ((herr=g_HandleSys.ReadHandle(hndl, g_DirType, &sec, (void **)&pDir))
    92 		!= HandleError_None)
    93 	{
    94 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
    95 	}
    96 
    97 	if (!pDir->MoreFiles())
    98 	{
    99 		return false;
   100 	}
   101 
   102 	cell_t *filetype;
   103 	if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE)
   104 	{
   105 		pContext->ThrowNativeErrorEx(err, NULL);
   106 		return 0;
   107 	}
   108 
   109 	if (pDir->IsEntryDirectory())
   110 	{
   111 		*filetype = 1;
   112 	} else if (pDir->IsEntryFile()) {
   113 		*filetype = 2;
   114 	} else {
   115 		*filetype = 0;
   116 	}
   117 
   118 	const char *path = pDir->GetEntryName();
   119 	if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL))
   120 		!= SP_ERROR_NONE)
   121 	{
   122 		pContext->ThrowNativeErrorEx(err, NULL);
   123 		return 0;
   124 	}
   125 
   126 	pDir->NextEntry();
   127 
   128 	return true;
   129 }
   130 
   131 static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params)
   132 {
   133 	char *name, *mode;
   134 	int err;
   135 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   136 	{
   137 		pContext->ThrowNativeErrorEx(err, NULL);
   138 		return 0;
   139 	}
   140 	if ((err=pContext->LocalToString(params[2], &mode)) != SP_ERROR_NONE)
   141 	{
   142 		pContext->ThrowNativeErrorEx(err, NULL);
   143 		return 0;
   144 	}
   145 
   146 	char realpath[PLATFORM_MAX_PATH];
   147 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   148 
   149 	FILE *pFile = fopen(realpath, mode);
   150 	if (!pFile)
   151 	{
   152 		return 0;
   153 	}
   154 
   155 	return g_HandleSys.CreateHandle(g_FileType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL);
   156 }
   157 
   158 static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params)
   159 {
   160 	char *name;
   161 	int err;
   162 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   163 	{
   164 		pContext->ThrowNativeErrorEx(err, NULL);
   165 		return 0;
   166 	}
   167 
   168 	char realpath[PLATFORM_MAX_PATH];
   169 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   170 
   171 	return (unlink(realpath)) ? 0 : 1;
   172 }
   173 
   174 static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params)
   175 {
   176 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   177 	HandleError herr;
   178 	HandleSecurity sec;
   179 	FILE *pFile;
   180 	int err;
   181 
   182 	sec.pOwner = NULL;
   183 	sec.pIdentity = g_pCoreIdent;
   184 
   185 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   186 		!= HandleError_None)
   187 	{
   188 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   189 	}
   190 
   191 	char *buf;
   192 	if ((err=pContext->LocalToString(params[2], &buf)) != SP_ERROR_NONE)
   193 	{
   194 		pContext->ThrowNativeErrorEx(err, NULL);
   195 		return 0;
   196 	}
   197 
   198 	if (fgets(buf, params[3], pFile) == NULL)
   199 	{
   200 		return 0;
   201 	}
   202 
   203 	return 1;
   204 }
   205 
   206 static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params)
   207 {
   208 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   209 	HandleError herr;
   210 	HandleSecurity sec;
   211 	FILE *pFile;
   212 
   213 	sec.pOwner = NULL;
   214 	sec.pIdentity = g_pCoreIdent;
   215 
   216 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   217 		!= HandleError_None)
   218 	{
   219 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   220 	}
   221 
   222 	return (feof(pFile)) ? 1 : 0;
   223 }
   224 
   225 static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params)
   226 {
   227 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   228 	HandleError herr;
   229 	HandleSecurity sec;
   230 	FILE *pFile;
   231 
   232 	sec.pOwner = NULL;
   233 	sec.pIdentity = g_pCoreIdent;
   234 
   235 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   236 		!= HandleError_None)
   237 	{
   238 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   239 	}
   240 
   241 	fseek(pFile, params[2], params[3]);
   242 	
   243 	return 1;
   244 }
   245 
   246 static cell_t sm_FilePosition(IPluginContext *pContext, const cell_t *params)
   247 {
   248 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   249 	HandleError herr;
   250 	HandleSecurity sec;
   251 	FILE *pFile;
   252 
   253 	sec.pOwner = NULL;
   254 	sec.pIdentity = g_pCoreIdent;
   255 
   256 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   257 		!= HandleError_None)
   258 	{
   259 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   260 	}
   261 
   262 	return ftell(pFile);
   263 }
   264 
   265 static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params)
   266 {
   267 	char *name;
   268 	int err;
   269 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   270 	{
   271 		pContext->ThrowNativeErrorEx(err, NULL);
   272 		return 0;
   273 	}
   274 
   275 	char realpath[PLATFORM_MAX_PATH];
   276 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   277 #ifdef PLATFORM_WINDOWS
   278 	struct _stat s;
   279 	if (_stat(realpath, &s) != 0)
   280 	{
   281 		return 0;
   282 	}
   283 	if (s.st_mode & S_IFREG)
   284 	{
   285 		return 1;
   286 	}
   287 	return 0;
   288 #elif defined PLATFORM_POSIX
   289 	struct stat s;
   290 	if (stat(realpath, &s) != 0)
   291 	{
   292 		return 0;
   293 	}
   294 	if (S_ISREG(s.st_mode))
   295 	{
   296 		return 1;
   297 	}
   298 	return 0;
   299 #endif
   300 }
   301 
   302 static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
   303 {
   304 	char *newpath, *oldpath;
   305 	int err;
   306 	if ((err=pContext->LocalToString(params[1], &newpath)) != SP_ERROR_NONE)
   307 	{
   308 		pContext->ThrowNativeErrorEx(err, NULL);
   309 		return 0;
   310 	}
   311 	if ((err=pContext->LocalToString(params[2], &oldpath)) != SP_ERROR_NONE)
   312 	{
   313 		pContext->ThrowNativeErrorEx(err, NULL);
   314 		return 0;
   315 	}
   316 
   317 	char new_realpath[PLATFORM_MAX_PATH];
   318 	g_SourceMod.BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath);
   319 	char old_realpath[PLATFORM_MAX_PATH];
   320 	g_SourceMod.BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath);
   321 
   322 #ifdef PLATFORM_WINDOWS
   323 	return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0;
   324 #elif defined PLATFORM_POSIX
   325 	return (rename(old_realpath, new_realpath)) ? 0 : 1;
   326 #endif
   327 }
   328 
   329 static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params)
   330 {
   331 	char *name;
   332 	int err;
   333 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   334 	{
   335 		pContext->ThrowNativeErrorEx(err, NULL);
   336 		return 0;
   337 	}
   338 
   339 	char realpath[PLATFORM_MAX_PATH];
   340 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   341 #ifdef PLATFORM_WINDOWS
   342 	struct _stat s;
   343 	if (_stat(realpath, &s) != 0)
   344 	{
   345 		return 0;
   346 	}
   347 	if (s.st_mode & S_IFDIR)
   348 	{
   349 		return 1;
   350 	}
   351 	return 0;
   352 #elif defined PLATFORM_POSIX
   353 	struct stat s;
   354 	if (stat(realpath, &s) != 0)
   355 	{
   356 		return 0;
   357 	}
   358 	if (S_ISDIR(s.st_mode))
   359 	{
   360 		return 1;
   361 	}
   362 	return 0;
   363 #endif
   364 }
   365 
   366 static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params)
   367 {
   368 	char *name;
   369 	int err;
   370 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   371 	{
   372 		pContext->ThrowNativeErrorEx(err, NULL);
   373 		return -1;
   374 	}
   375 
   376 	char realpath[PLATFORM_MAX_PATH];
   377 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   378 #ifdef PLATFORM_WINDOWS
   379 	struct _stat s;
   380 	if (_stat(realpath, &s) != 0)
   381 	{
   382 		return -1;
   383 	}
   384 	if (s.st_mode & S_IFREG)
   385 	{
   386 		return static_cast<cell_t>(s.st_size);
   387 	}
   388 	return -1;
   389 #elif defined PLATFORM_POSIX
   390 	struct stat s;
   391 	if (stat(realpath, &s) != 0)
   392 	{
   393 		return -1;
   394 	}
   395 	if (S_ISREG(s.st_mode))
   396 	{
   397 		return static_cast<cell_t>(s.st_size);
   398 	}
   399 	return -1;
   400 #endif
   401 }
   402 
   403 static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params)
   404 {
   405 	char *name;
   406 	int err;
   407 	if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
   408 	{
   409 		pContext->ThrowNativeErrorEx(err, NULL);
   410 		return 0;
   411 	}
   412 
   413 	char realpath[PLATFORM_MAX_PATH];
   414 	g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
   415 
   416 	return (rmdir(realpath)) ? 0 : 1;
   417 }
   418 
   419 static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params)
   420 {
   421 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   422 	HandleError herr;
   423 	HandleSecurity sec;
   424 	FILE *pFile;
   425 
   426 	sec.pOwner = NULL;
   427 	sec.pIdentity = g_pCoreIdent;
   428 
   429 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   430 		!= HandleError_None)
   431 	{
   432 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   433 	}
   434 
   435 	char *fmt;
   436 	int err;
   437 	if ((err=pContext->LocalToString(params[2], &fmt)) != SP_ERROR_NONE)
   438 	{
   439 		pContext->ThrowNativeErrorEx(err, NULL);
   440 		return 0;
   441 	}
   442 
   443 	char buffer[2048];
   444 	int arg = 3;
   445 	atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg);
   446 	fprintf(pFile, "%s\n", buffer);
   447 
   448 	return 1;
   449 }
   450 
   451 static cell_t sm_FlushFile(IPluginContext *pContext, const cell_t *params)
   452 {
   453 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   454 	HandleError herr;
   455 	HandleSecurity sec;
   456 	FILE *pFile;
   457 
   458 	sec.pOwner = NULL;
   459 	sec.pIdentity = g_pCoreIdent;
   460 
   461 	if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
   462 		!= HandleError_None)
   463 	{
   464 		return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
   465 	}
   466 
   467 	return (fflush(pFile) == 0) ? 1 : 0;
   468 }
   469 
   470 static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params)
   471 {
   472 	char path[PLATFORM_MAX_PATH], *fmt, *buffer;
   473 	int arg = 5;
   474 	pContext->LocalToString(params[2], &buffer);
   475 	pContext->LocalToString(params[4], &fmt);
   476 
   477 	atcprintf(path, sizeof(path), fmt, pContext, params, &arg);
   478 
   479 	return g_SourceMod.BuildPath(Path_SM_Rel, buffer, params[3], "%s", path);
   480 }
   481 
   482 static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params)
   483 {
   484 	char buffer[1024];
   485 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
   486 
   487 	if (len >= sizeof(buffer)-2)
   488 	{
   489 		buffer[1022] = '\n';
   490 		buffer[1023] = '\0';
   491 	} else {
   492 		buffer[len++] = '\n';
   493 		buffer[len] = '\0';
   494 	}
   495 
   496 	engine->LogPrint(buffer);
   497 
   498 	return 1;
   499 }
   500 
   501 static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params)
   502 {
   503 	char buffer[1024];
   504 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
   505 
   506 	IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
   507 	g_Logger.LogMessage("[%s] %s", pPlugin->GetFilename(), buffer);
   508 
   509 	return 1;
   510 }
   511 
   512 static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params)
   513 {
   514 	char buffer[1024];
   515 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
   516 
   517 	IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
   518 	g_Logger.LogError("[%s] %s", pPlugin->GetFilename(), buffer);
   519 
   520 	return 1;
   521 }
   522 
   523 static FileNatives s_FileNatives;
   524 
   525 REGISTER_NATIVES(filesystem)
   526 {
   527 	{"OpenDirectory",			sm_OpenDirectory},
   528 	{"ReadDirEntry",			sm_ReadDirEntry},
   529 	{"OpenFile",				sm_OpenFile},
   530 	{"DeleteFile",				sm_DeleteFile},
   531 	{"ReadFileLine",			sm_ReadFileLine},
   532 	{"IsEndOfFile",				sm_IsEndOfFile},
   533 	{"FileSeek",				sm_FileSeek},
   534 	{"FilePosition",			sm_FilePosition},
   535 	{"FileExists",				sm_FileExists},
   536 	{"RenameFile",				sm_RenameFile},
   537 	{"DirExists",				sm_DirExists},
   538 	{"FileSize",				sm_FileSize},
   539 	{"RemoveDir",				sm_RemoveDir},
   540 	{"WriteFileLine",			sm_WriteFileLine},
   541 	{"BuildPath",				sm_BuildPath},
   542 	{"LogToGame",				sm_LogToGame},
   543 	{"LogMessage",				sm_LogMessage},
   544 	{"LogError",				sm_LogError},
   545 	{"FlushFile",				sm_FlushFile},
   546 	{NULL,						NULL},
   547 };