diff --git a/Engine/source/T3D/assets/assetImporter.cpp b/Engine/source/T3D/assets/assetImporter.cpp index 7c0bda9ae..221e776dd 100644 --- a/Engine/source/T3D/assets/assetImporter.cpp +++ b/Engine/source/T3D/assets/assetImporter.cpp @@ -2660,8 +2660,16 @@ Torque::Path AssetImporter::importImageAsset(AssetImportObject* assetItem) char qualifiedFromFile[2048]; char qualifiedToFile[2048]; +#ifndef TORQUE_SECURE_VFS Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile)); Platform::makeFullPathName(assetPath.c_str(), qualifiedToFile, sizeof(qualifiedToFile)); +#else + dMemset(qualifiedFromFile, 0x00, sizeof(qualifiedFromFile)); + dMemset(qualifiedToFile, 0x00, sizeof(qualifiedToFile)); + + dMemcpy(qualifiedFromFile, originalPath.c_str(), originalPath.size()); + dMemcpy(qualifiedToFile, assetPath.c_str(), assetPath.size()); +#endif newAsset->setAssetName(assetName); newAsset->setImageFileName(imageFileName.c_str()); @@ -2697,7 +2705,7 @@ Torque::Path AssetImporter::importImageAsset(AssetImportObject* assetItem) { bool isInPlace = !String::compare(qualifiedFromFile, qualifiedToFile); - if (!isInPlace && !dPathCopy(qualifiedFromFile, qualifiedToFile, !isReimport)) + if (!isInPlace && !Torque::FS::CopyFile(qualifiedFromFile, qualifiedToFile, !isReimport)) { dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", assetItem->filePath.getFullPath().c_str()); activityLog.push_back(importLogBuffer); @@ -2725,7 +2733,12 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem) char qualifiedFromFile[2048]; +#ifndef TORQUE_SECURE_VFS Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile)); +#else + dMemset(qualifiedFromFile, 0x00, sizeof(qualifiedFromFile)); + dMemcpy(qualifiedFromFile, originalPath.c_str(), originalPath.size()); +#endif newAsset->setAssetName(assetName); newAsset->setScriptFile(scriptName.c_str()); @@ -3000,11 +3013,22 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem) char qualifiedFromCSFile[2048]; char qualifiedToCSFile[2048]; +#ifndef TORQUE_SECURE_VFS Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile)); Platform::makeFullPathName(assetPath.c_str(), qualifiedToFile, sizeof(qualifiedToFile)); - Platform::makeFullPathName(originalConstructorPath.c_str(), qualifiedFromCSFile, sizeof(qualifiedFromCSFile)); Platform::makeFullPathName(constructorPath.c_str(), qualifiedToCSFile, sizeof(qualifiedToCSFile)); +#else + dMemset(qualifiedFromFile, 0x00, sizeof(qualifiedFromFile)); + dMemset(qualifiedToFile, 0x00, sizeof(qualifiedToFile)); + dMemset(qualifiedFromCSFile, 0x00, sizeof(qualifiedFromCSFile)); + dMemset(qualifiedToCSFile, 0x00, sizeof(qualifiedToCSFile)); + + dMemcpy(qualifiedFromFile, originalPath.c_str(), originalPath.size()); + dMemcpy(qualifiedToFile, assetPath.c_str(), assetPath.size()); + dMemcpy(qualifiedFromCSFile, originalConstructorPath.c_str(), originalConstructorPath.size()); + dMemcpy(qualifiedToCSFile, constructorPath.c_str(), constructorPath.size()); +#endif newAsset->setAssetName(assetName); newAsset->setShapeFile(shapeFileName.c_str()); @@ -3086,7 +3110,7 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem) { bool isInPlace = !String::compare(qualifiedFromFile, qualifiedToFile); - if (!isInPlace && !dPathCopy(qualifiedFromFile, qualifiedToFile, !isReimport)) + if (!isInPlace && !Torque::FS::CopyFile(qualifiedFromFile, qualifiedToFile, !isReimport)) { dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", qualifiedFromFile); activityLog.push_back(importLogBuffer); @@ -3097,7 +3121,7 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem) { if (Platform::isFile(qualifiedFromCSFile)) { - if (!dPathCopy(qualifiedFromCSFile, qualifiedToCSFile, !isReimport)) + if (!Torque::FS::CopyFile(qualifiedFromCSFile, qualifiedToCSFile, !isReimport)) { dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", qualifiedFromCSFile); activityLog.push_back(importLogBuffer); @@ -3289,8 +3313,16 @@ Torque::Path AssetImporter::importSoundAsset(AssetImportObject* assetItem) char qualifiedFromFile[2048]; char qualifiedToFile[2048]; +#ifndef TORQUE_SECURE_VFS Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile)); Platform::makeFullPathName(assetPath.c_str(), qualifiedToFile, sizeof(qualifiedToFile)); +#else + dMemset(qualifiedFromFile, 0x00, sizeof(qualifiedFromFile)); + dMemset(qualifiedToFile, 0x00, sizeof(qualifiedToFile)); + + dMemcpy(qualifiedFromFile, originalPath.c_str(), originalPath.size()); + dMemcpy(qualifiedToFile, assetPath.c_str(), assetPath.size()); +#endif newAsset->setAssetName(assetName); newAsset->setSoundFile(imageFileName.c_str()); @@ -3316,7 +3348,7 @@ Torque::Path AssetImporter::importSoundAsset(AssetImportObject* assetItem) { bool isInPlace = !String::compare(qualifiedFromFile, qualifiedToFile); - if (!isInPlace && !dPathCopy(qualifiedFromFile, qualifiedToFile, !isReimport)) + if (!isInPlace && !Torque::FS::CopyFile(qualifiedFromFile, qualifiedToFile, !isReimport)) { dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", assetItem->filePath.getFullPath().c_str()); activityLog.push_back(importLogBuffer); @@ -3345,8 +3377,16 @@ Torque::Path AssetImporter::importShapeAnimationAsset(AssetImportObject* assetIt char qualifiedFromFile[2048]; char qualifiedToFile[2048]; +#ifndef TORQUE_SECURE_VFS Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile)); Platform::makeFullPathName(assetPath.c_str(), qualifiedToFile, sizeof(qualifiedToFile)); +#else + dMemset(qualifiedFromFile, 0x00, sizeof(qualifiedFromFile)); + dMemset(qualifiedToFile, 0x00, sizeof(qualifiedToFile)); + + dMemcpy(qualifiedFromFile, originalPath.c_str(), originalPath.size()); + dMemcpy(qualifiedToFile, assetPath.c_str(), assetPath.size()); +#endif newAsset->setAssetName(assetName); newAsset->setAnimationFile(imageFileName.c_str()); @@ -3372,7 +3412,7 @@ Torque::Path AssetImporter::importShapeAnimationAsset(AssetImportObject* assetIt { bool isInPlace = !String::compare(qualifiedFromFile, qualifiedToFile); - if (!isInPlace && !dPathCopy(qualifiedFromFile, qualifiedToFile, !isReimport)) + if (!isInPlace && !Torque::FS::CopyFile(qualifiedFromFile, qualifiedToFile, !isReimport)) { dSprintf(importLogBuffer, sizeof(importLogBuffer), "Error! Unable to copy file %s", assetItem->filePath.getFullPath().c_str()); activityLog.push_back(importLogBuffer); diff --git a/Engine/source/core/volume.cpp b/Engine/source/core/volume.cpp index d056ee331..570dcc2cd 100644 --- a/Engine/source/core/volume.cpp +++ b/Engine/source/core/volume.cpp @@ -500,6 +500,28 @@ Path MountSystem::_normalize(const Path& path) return po; } +bool MountSystem::copyFile(const Path& source, const Path& destination, bool noOverwrite) +{ + // Exit out early if we're not overriding + if (isFile(destination) && noOverwrite) + { + return true; + } + + FileRef sourceFile = openFile(source, FS::File::AccessMode::Read); + const U64 sourceFileSize = sourceFile->getSize(); + + void* writeBuffer = dMalloc(sourceFileSize); + sourceFile->read(writeBuffer, sourceFileSize); + + FileRef destinationFile = openFile(destination, FS::File::AccessMode::Write); + const bool success = destinationFile->write(writeBuffer, sourceFileSize) == sourceFileSize; + + dFree(writeBuffer); + + return success; +} + FileRef MountSystem::createFile(const Path& path) { Path np = _normalize(path); @@ -909,6 +931,11 @@ FileRef CreateFile(const Path &path) return sgMountSystem.createFile(path); } +bool CopyFile(const Path& source, const Path& destination, bool noOverwrite) +{ + return sgMountSystem.copyFile(source, destination, noOverwrite); +} + DirectoryRef CreateDirectory(const Path &path) { return sgMountSystem.createDirectory(path); diff --git a/Engine/source/core/volume.h b/Engine/source/core/volume.h index 18112322f..627fdb58a 100644 --- a/Engine/source/core/volume.h +++ b/Engine/source/core/volume.h @@ -335,6 +335,7 @@ public: virtual ~MountSystem() {} FileRef createFile(const Path& path); + bool copyFile(const Path& source, const Path& destination, bool noOverwrite); DirectoryRef createDirectory(const Path& path, FileSystemRef fs = NULL); virtual bool createPath(const Path& path); @@ -538,6 +539,9 @@ DirectoryRef OpenDirectory(const Path &file); ///@ingroup VolumeSystem FileRef CreateFile(const Path &file); +/// Copy a file from one location to another. +bool CopyFile(const Path& source, const Path& destination, bool noOverride); + /// Create a directory. /// The directory object is returned in a closed state. ///@ingroup VolumeSystem diff --git a/Engine/source/persistence/taml/taml.cpp b/Engine/source/persistence/taml/taml.cpp index b05b0d8bc..114466e39 100644 --- a/Engine/source/persistence/taml/taml.cpp +++ b/Engine/source/persistence/taml/taml.cpp @@ -212,8 +212,13 @@ ImplementEnumType(_TamlFormatMode, AssertFatal(pSimObject != NULL, "Cannot write a NULL object."); AssertFatal(pFilename != NULL, "Cannot write to a NULL filename."); - // Expand the file-name into the file-path buffer. + // Expand the file-name into the file-path buffer unless we're a secure VFS +#ifndef TORQUE_SECURE_VFS Con::expandToolScriptFilename(mFilePathBuffer, sizeof(mFilePathBuffer), pFilename); +#else + dMemset(mFilePathBuffer, 0x00, sizeof(mFilePathBuffer)); + dMemcpy(mFilePathBuffer, pFilename, dStrlen(pFilename)); +#endif FileStream stream; diff --git a/Engine/source/platform/platformVolume.cpp b/Engine/source/platform/platformVolume.cpp index 5f0595ef0..dccd52f0d 100644 --- a/Engine/source/platform/platformVolume.cpp +++ b/Engine/source/platform/platformVolume.cpp @@ -20,6 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- +#include "console/console.h" #include "platform/platform.h" #if defined(TORQUE_OS_WIN) @@ -30,6 +31,7 @@ #include "platform/platformVolume.h" #include "core/util/zip/zipVolume.h" +#include "core/memVolume.h" using namespace Torque; using namespace Torque::FS; @@ -48,6 +50,34 @@ bool MountDefaults() if ( !mounted ) return false; +#ifdef TORQUE_SECURE_VFS + // Set working directory to where the executable is + StringTableEntry executablePath = Platform::getExecutablePath(); + SetCwd(executablePath); + + // FIXME: Should we use the asset path here as well? + mounted = Mount("/", createNativeFS(executablePath)); + if (!mounted) + { + return false; + } +#endif + + // Always mount the data dir so scripts work in either configuration. This is used for eg. preferences storage. + Path dataDirectory = Platform::getUserDataDirectory(); + Path appDataDirectory; + appDataDirectory.setPath(dataDirectory.getFileName()); + dataDirectory.appendPath(appDataDirectory); + + dataDirectory.setFileName(TORQUE_APP_NAME); + + Con::errorf("RAW DATA: %s", dataDirectory.getFullPath().c_str()); + mounted = Mount("data", Platform::FS::createNativeFS(dataDirectory.getFullPath())); + if (!mounted) + { + return false; + } + #ifndef TORQUE_DISABLE_VIRTUAL_MOUNT_SYSTEM // Note that the VirtualMountSystem must be enabled in volume.cpp for zip support to work. return MountZips("game"); diff --git a/Engine/source/platformPOSIX/posixVolume.cpp b/Engine/source/platformPOSIX/posixVolume.cpp index d06dccd13..3a1067aa6 100644 --- a/Engine/source/platformPOSIX/posixVolume.cpp +++ b/Engine/source/platformPOSIX/posixVolume.cpp @@ -595,6 +595,7 @@ String Platform::FS::getAssetDir() /// file systems. bool Platform::FS::InstallFileSystems() { +#ifndef TORQUE_SECURE_VFS Platform::FS::Mount( "/", Platform::FS::createNativeFS( String() ) ); // Setup the current working dir. @@ -611,6 +612,7 @@ bool Platform::FS::InstallFileSystems() // Mount the home directory if (char* home = getenv("HOME")) Platform::FS::Mount( "home", Platform::FS::createNativeFS(home) ); +#endif return true; } diff --git a/Engine/source/platformWin32/winVolume.cpp b/Engine/source/platformWin32/winVolume.cpp index 5d168ac95..779a5d7b9 100644 --- a/Engine/source/platformWin32/winVolume.cpp +++ b/Engine/source/platformWin32/winVolume.cpp @@ -758,6 +758,7 @@ String Platform::FS::getAssetDir() /// file systems. bool Platform::FS::InstallFileSystems() { +#ifndef TORQUE_SECURE_VFS WCHAR buffer[1024]; // [8/24/2009 tomb] This stops Windows from complaining about drives that have no disks in @@ -792,6 +793,7 @@ bool Platform::FS::InstallFileSystems() wd += '/'; Platform::FS::SetCwd(wd); +#endif return true; } diff --git a/Engine/source/windowManager/sdl/sdlWindowMgr.cpp b/Engine/source/windowManager/sdl/sdlWindowMgr.cpp index 4a00294c8..f86e09a09 100644 --- a/Engine/source/windowManager/sdl/sdlWindowMgr.cpp +++ b/Engine/source/windowManager/sdl/sdlWindowMgr.cpp @@ -22,6 +22,8 @@ #include "windowManager/sdl/sdlWindowMgr.h" #include "platformSDL/sdlInputManager.h" +#include "platform/platformVolume.h" +#include "core/util/path.h" #include "gfx/gfxDevice.h" #include "core/util/journal/process.h" #include "core/strings/unicode.h" @@ -35,6 +37,26 @@ void sdl_CloseSplashWindow(void* hinst); #ifdef TORQUE_SDL +#ifdef TORQUE_SECURE_VFS +PlatformWindowManagerSDL::DragAndDropFSInfo::DragAndDropFSInfo() +{ +} + +PlatformWindowManagerSDL::DragAndDropFSInfo::DragAndDropFSInfo(String rootName, Torque::FS::FileSystemRef fileSystem) : mRootName(rootName), mDragAndDropFS(fileSystem) +{ + if (!Torque::FS::Mount(rootName, fileSystem)) + { + Con::errorf("Could not mount drag and drop FS!"); + } +} + +PlatformWindowManagerSDL::DragAndDropFSInfo::~DragAndDropFSInfo() +{ +// FIXME: Cleanup - we can't simply do this unmount due to the way the hash mapping works +// Torque::FS::Unmount(mDragAndDropFS); +} +#endif + PlatformWindowManager * CreatePlatformWindowManager() { return new PlatformWindowManagerSDL(); @@ -427,7 +449,61 @@ void PlatformWindowManagerSDL::_process() if (!Platform::isDirectory(fileName) && !Platform::isFile(fileName)) break; +#ifdef TORQUE_SECURE_VFS + // Determine what the directory is so we can mount it + Torque::Path targetDirectory = Torque::Path(fileName); + + // If we're dropping a file, strip off file information - otherwise if a directory mount it directly + if (Platform::isFile(fileName)) + { + targetDirectory.setExtension(""); + targetDirectory.setFileName(""); + } + const String directoryName = targetDirectory.getDirectory(targetDirectory.getDirectoryCount() - 1); + + auto dropFSMount = mActiveDragAndDropFSByPath.find(targetDirectory); + if (dropFSMount == mActiveDragAndDropFSByPath.end()) + { + Torque::FS::FileSystemRef newMount = Platform::FS::createNativeFS(targetDirectory.getFullPath()); + + // Search for an unused root in case we have duplicate names + U32 rootCounter = 1; + String chosenRootName = directoryName; + auto search = mActiveDragAndDropByRoot.find(chosenRootName); + while (search != mActiveDragAndDropByRoot.end()) + { + char buffer[32]; + dSprintf(buffer, 32, "%u", rootCounter); + chosenRootName = directoryName + buffer; + + search = mActiveDragAndDropByRoot.find(chosenRootName); + } + + mActiveDragAndDropFSByPath[targetDirectory] = DragAndDropFSInfo(directoryName, newMount); + mActiveDragAndDropFSByPath[chosenRootName] = mActiveDragAndDropFSByPath[targetDirectory]; + } + + DragAndDropFSInfo& filesystemInformation = mActiveDragAndDropFSByPath[targetDirectory]; + + // Load source file information + Torque::Path sourceFile = fileName; + + // Build a reference to the file in VFS + Torque::Path targetFile; + targetFile.setRoot(filesystemInformation.mRootName); + targetFile.setPath("/"); + + // Only copy file & extension information if we're dropping a file + if (Platform::isFile(fileName)) + { + targetFile.setFileName(sourceFile.getFileName()); + targetFile.setExtension(sourceFile.getExtension()); + } + + Con::executef("onDropFile", StringTable->insert(targetFile.getFullPath())); +#else Con::executef("onDropFile", StringTable->insert(fileName)); +#endif SDL_free(fileName); // Free dropped_filedir memory break; diff --git a/Engine/source/windowManager/sdl/sdlWindowMgr.h b/Engine/source/windowManager/sdl/sdlWindowMgr.h index 45cd3bfe3..c5456e50d 100644 --- a/Engine/source/windowManager/sdl/sdlWindowMgr.h +++ b/Engine/source/windowManager/sdl/sdlWindowMgr.h @@ -27,6 +27,7 @@ #include "gfx/gfxStructs.h" #include "windowManager/sdl/sdlWindow.h" #include "core/util/tVector.h" +#include "core/volume.h" struct SDL_Window; class FileDialog; // TODO SDL REMOVE @@ -57,6 +58,18 @@ public: RAW_INPUT = 2 /// < We only want raw input. }; +#ifdef TORQUE_SECURE_VFS + struct DragAndDropFSInfo + { + String mRootName; + Torque::FS::FileSystemRef mDragAndDropFS; + + DragAndDropFSInfo(); + DragAndDropFSInfo(String rootName, Torque::FS::FileSystemRef fileSystem); + ~DragAndDropFSInfo(); + }; +#endif + protected: friend class PlatformWindowSDL; friend class FileDialog; // TODO SDL REMOVE @@ -97,6 +110,11 @@ protected: /// After it is handled, it will return to state NONE. KeyboardInputState mInputState; +#ifdef TORQUE_SECURE_VFS + HashMap mActiveDragAndDropByRoot; + HashMap mActiveDragAndDropFSByPath; +#endif + public: PlatformWindowManagerSDL(); ~PlatformWindowManagerSDL(); diff --git a/Templates/BaseGame/game/core/utility/scripts/helperFunctions.tscript b/Templates/BaseGame/game/core/utility/scripts/helperFunctions.tscript index 98d616529..0743b149e 100644 --- a/Templates/BaseGame/game/core/utility/scripts/helperFunctions.tscript +++ b/Templates/BaseGame/game/core/utility/scripts/helperFunctions.tscript @@ -175,7 +175,7 @@ function getUserPath() function getPrefpath() { - $prefPath = getUserPath() @ "/preferences"; + $prefPath = "data:/preferences"; return $prefPath; } diff --git a/Tools/CMake/torque3d.cmake b/Tools/CMake/torque3d.cmake index 2f5a0b6ac..f018d7d76 100644 --- a/Tools/CMake/torque3d.cmake +++ b/Tools/CMake/torque3d.cmake @@ -169,6 +169,9 @@ if(NOT MSVC AND NOT APPLE) # handle single-configuration generator mark_as_advanced(TORQUE_ADDITIONAL_LINKER_FLAGS) endif() +option(TORQUE_SECURE_VFS "Secure VFS configuration. Arbitrary script access to file system will be heavily restricted." OFF) +mark_as_advanced(TORQUE_SECURE_VFS) + option(TORQUE_MULTITHREAD "Multi Threading" ON) mark_as_advanced(TORQUE_MULTITHREAD) @@ -999,4 +1002,4 @@ if(TORQUE_SDL) else() set_target_properties(SDL2 PROPERTIES FOLDER ${TORQUE_LIBS_FOLDER_NAME}) endif() -endif() \ No newline at end of file +endif() diff --git a/Tools/CMake/torqueConfig.h.in b/Tools/CMake/torqueConfig.h.in index 9e045b1d5..449e12614 100644 --- a/Tools/CMake/torqueConfig.h.in +++ b/Tools/CMake/torqueConfig.h.in @@ -50,6 +50,9 @@ /// Define me if you want path case insensitivity support in ZIP files. #cmakedefine TORQUE_ZIP_PATH_CASE_INSENSITIVE +/// Define me if you want to enable secure VFS support. +#cmakedefine TORQUE_SECURE_VFS + /// Define me if you want to enable multithreading support. #cmakedefine TORQUE_MULTITHREAD @@ -225,4 +228,4 @@ #endif /// Password to use when opening encrypted zip files. Change this to whatever the password is for your zips. -#define DEFAULT_ZIP_PASSWORD "@TORQUE_APP_PASSWORD@" \ No newline at end of file +#define DEFAULT_ZIP_PASSWORD "@TORQUE_APP_PASSWORD@"