3 * =============================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * =============================================================================
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.
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
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/>.
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>.
33 #include "sm_globals.h"
34 #include "HandleSys.h"
35 #include "LibrarySys.h"
36 #include "sm_stringutil.h"
38 #include "PluginSys.h"
39 #include "sourcemm_api.h"
41 HandleType_t g_FileType;
42 HandleType_t g_DirType;
46 public IHandleTypeDispatch
49 virtual void OnSourceModAllInitialized()
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);
54 virtual void OnSourceModShutdown()
56 g_HandleSys.RemoveType(g_DirType, g_pCoreIdent);
57 g_HandleSys.RemoveType(g_FileType, g_pCoreIdent);
61 virtual void OnHandleDestroy(HandleType_t type, void *object)
63 if (type == g_FileType)
65 FILE *fp = (FILE *)object;
67 } else if (type == g_DirType) {
68 IDirectory *pDir = (IDirectory *)object;
69 g_LibSys.CloseDirectory(pDir);
75 static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params)
79 if ((err=pContext->LocalToString(params[1], &path)) != SP_ERROR_NONE)
81 pContext->ThrowNativeErrorEx(err, NULL);
85 char realpath[PLATFORM_MAX_PATH];
86 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
88 IDirectory *pDir = g_LibSys.OpenDirectory(realpath);
94 return g_HandleSys.CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
97 static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
99 Handle_t hndl = static_cast<Handle_t>(params[1]);
106 sec.pIdentity = g_pCoreIdent;
108 if ((herr=g_HandleSys.ReadHandle(hndl, g_DirType, &sec, (void **)&pDir))
111 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
114 if (!pDir->MoreFiles())
120 if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE)
122 pContext->ThrowNativeErrorEx(err, NULL);
126 if (pDir->IsEntryDirectory())
129 } else if (pDir->IsEntryFile()) {
135 const char *path = pDir->GetEntryName();
136 if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL))
139 pContext->ThrowNativeErrorEx(err, NULL);
148 static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params)
152 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
154 pContext->ThrowNativeErrorEx(err, NULL);
157 if ((err=pContext->LocalToString(params[2], &mode)) != SP_ERROR_NONE)
159 pContext->ThrowNativeErrorEx(err, NULL);
163 char realpath[PLATFORM_MAX_PATH];
164 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
166 FILE *pFile = fopen(realpath, mode);
172 return g_HandleSys.CreateHandle(g_FileType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL);
175 static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params)
179 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
181 pContext->ThrowNativeErrorEx(err, NULL);
185 char realpath[PLATFORM_MAX_PATH];
186 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
188 return (unlink(realpath)) ? 0 : 1;
191 static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params)
193 Handle_t hndl = static_cast<Handle_t>(params[1]);
200 sec.pIdentity = g_pCoreIdent;
202 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
205 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
209 if ((err=pContext->LocalToString(params[2], &buf)) != SP_ERROR_NONE)
211 pContext->ThrowNativeErrorEx(err, NULL);
215 if (fgets(buf, params[3], pFile) == NULL)
223 static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params)
225 Handle_t hndl = static_cast<Handle_t>(params[1]);
231 sec.pIdentity = g_pCoreIdent;
233 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
236 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
239 return (feof(pFile)) ? 1 : 0;
242 static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params)
244 Handle_t hndl = static_cast<Handle_t>(params[1]);
250 sec.pIdentity = g_pCoreIdent;
252 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
255 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
258 fseek(pFile, params[2], params[3]);
263 static cell_t sm_FilePosition(IPluginContext *pContext, const cell_t *params)
265 Handle_t hndl = static_cast<Handle_t>(params[1]);
271 sec.pIdentity = g_pCoreIdent;
273 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
276 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
282 static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params)
286 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
288 pContext->ThrowNativeErrorEx(err, NULL);
292 char realpath[PLATFORM_MAX_PATH];
293 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
294 #ifdef PLATFORM_WINDOWS
296 if (_stat(realpath, &s) != 0)
300 if (s.st_mode & S_IFREG)
305 #elif defined PLATFORM_POSIX
307 if (stat(realpath, &s) != 0)
311 if (S_ISREG(s.st_mode))
319 static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
321 char *newpath, *oldpath;
323 if ((err=pContext->LocalToString(params[1], &newpath)) != SP_ERROR_NONE)
325 pContext->ThrowNativeErrorEx(err, NULL);
328 if ((err=pContext->LocalToString(params[2], &oldpath)) != SP_ERROR_NONE)
330 pContext->ThrowNativeErrorEx(err, NULL);
334 char new_realpath[PLATFORM_MAX_PATH];
335 g_SourceMod.BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath);
336 char old_realpath[PLATFORM_MAX_PATH];
337 g_SourceMod.BuildPath(Path_Game, old_realpath, sizeof(old_realpath), "%s", oldpath);
339 #ifdef PLATFORM_WINDOWS
340 return (MoveFileA(old_realpath, new_realpath)) ? 1 : 0;
341 #elif defined PLATFORM_POSIX
342 return (rename(old_realpath, new_realpath)) ? 0 : 1;
346 static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params)
350 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
352 pContext->ThrowNativeErrorEx(err, NULL);
356 char realpath[PLATFORM_MAX_PATH];
357 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
358 #ifdef PLATFORM_WINDOWS
360 if (_stat(realpath, &s) != 0)
364 if (s.st_mode & S_IFDIR)
369 #elif defined PLATFORM_POSIX
371 if (stat(realpath, &s) != 0)
375 if (S_ISDIR(s.st_mode))
383 static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params)
387 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
389 pContext->ThrowNativeErrorEx(err, NULL);
393 char realpath[PLATFORM_MAX_PATH];
394 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
395 #ifdef PLATFORM_WINDOWS
397 if (_stat(realpath, &s) != 0)
401 if (s.st_mode & S_IFREG)
403 return static_cast<cell_t>(s.st_size);
406 #elif defined PLATFORM_POSIX
408 if (stat(realpath, &s) != 0)
412 if (S_ISREG(s.st_mode))
414 return static_cast<cell_t>(s.st_size);
420 static cell_t sm_RemoveDir(IPluginContext *pContext, const cell_t *params)
424 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
426 pContext->ThrowNativeErrorEx(err, NULL);
430 char realpath[PLATFORM_MAX_PATH];
431 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
433 return (rmdir(realpath)) ? 0 : 1;
436 static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params)
438 Handle_t hndl = static_cast<Handle_t>(params[1]);
444 sec.pIdentity = g_pCoreIdent;
446 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
449 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
454 if ((err=pContext->LocalToString(params[2], &fmt)) != SP_ERROR_NONE)
456 pContext->ThrowNativeErrorEx(err, NULL);
462 atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg);
463 fprintf(pFile, "%s\n", buffer);
468 static cell_t sm_FlushFile(IPluginContext *pContext, const cell_t *params)
470 Handle_t hndl = static_cast<Handle_t>(params[1]);
476 sec.pIdentity = g_pCoreIdent;
478 if ((herr=g_HandleSys.ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
481 return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
484 return (fflush(pFile) == 0) ? 1 : 0;
487 static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params)
489 char path[PLATFORM_MAX_PATH], *fmt, *buffer;
491 pContext->LocalToString(params[2], &buffer);
492 pContext->LocalToString(params[4], &fmt);
494 atcprintf(path, sizeof(path), fmt, pContext, params, &arg);
496 return g_SourceMod.BuildPath(Path_SM_Rel, buffer, params[3], "%s", path);
499 static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params)
501 g_SourceMod.SetGlobalTarget(LANG_SERVER);
504 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
506 if (len >= sizeof(buffer)-2)
511 buffer[len++] = '\n';
515 engine->LogPrint(buffer);
520 static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params)
522 g_SourceMod.SetGlobalTarget(LANG_SERVER);
525 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
527 IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
528 g_Logger.LogMessage("[%s] %s", pPlugin->GetFilename(), buffer);
533 static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params)
535 g_SourceMod.SetGlobalTarget(LANG_SERVER);
538 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
540 IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
541 g_Logger.LogError("[%s] %s", pPlugin->GetFilename(), buffer);
548 FileTime_LastAccess = 0, /* Last access (not available on FAT) */
549 FileTime_Created = 1, /* Creation (not available on FAT) */
550 FileTime_LastChange = 2, /* Last modification */
553 static cell_t sm_GetFileTime(IPluginContext *pContext, const cell_t *params)
557 if ((err=pContext->LocalToString(params[1], &name)) != SP_ERROR_NONE)
559 pContext->ThrowNativeErrorEx(err, NULL);
563 char realpath[PLATFORM_MAX_PATH];
564 g_SourceMod.BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
566 #ifdef PLATFORM_WINDOWS
568 if (_stat(realpath, &s) != 0)
569 #elif defined PLATFORM_POSIX
571 if (stat(path, &s) != 0)
576 if (params[2] == FileTime_LastAccess)
578 return (cell_t)s.st_atime;
579 } else if (params[2] == FileTime_Created) {
580 return (cell_t)s.st_ctime;
581 } else if (params[2] == FileTime_LastChange) {
582 return (cell_t)s.st_mtime;
589 static FileNatives s_FileNatives;
591 REGISTER_NATIVES(filesystem)
593 {"OpenDirectory", sm_OpenDirectory},
594 {"ReadDirEntry", sm_ReadDirEntry},
595 {"OpenFile", sm_OpenFile},
596 {"DeleteFile", sm_DeleteFile},
597 {"ReadFileLine", sm_ReadFileLine},
598 {"IsEndOfFile", sm_IsEndOfFile},
599 {"FileSeek", sm_FileSeek},
600 {"FilePosition", sm_FilePosition},
601 {"FileExists", sm_FileExists},
602 {"RenameFile", sm_RenameFile},
603 {"DirExists", sm_DirExists},
604 {"FileSize", sm_FileSize},
605 {"RemoveDir", sm_RemoveDir},
606 {"WriteFileLine", sm_WriteFileLine},
607 {"BuildPath", sm_BuildPath},
608 {"LogToGame", sm_LogToGame},
609 {"LogMessage", sm_LogMessage},
610 {"LogError", sm_LogError},
611 {"FlushFile", sm_FlushFile},
612 {"GetFileTime", sm_GetFileTime},