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