Преглед на файлове

* Feature: Initial secure VFS implementation with asset import capability.

Robert MacGregor преди 3 години
родител
ревизия
277cdf67b0

+ 46 - 6
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);

+ 27 - 0
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);

+ 4 - 0
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

+ 6 - 1
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;
 

+ 30 - 0
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");

+ 2 - 0
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;
 }

+ 2 - 0
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;
 }

+ 76 - 0
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;

+ 18 - 0
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<String, DragAndDropFSInfo> mActiveDragAndDropByRoot;
+   HashMap<Torque::Path, DragAndDropFSInfo> mActiveDragAndDropFSByPath;
+#endif
+
 public:
    PlatformWindowManagerSDL();
    ~PlatformWindowManagerSDL();

+ 1 - 1
Templates/BaseGame/game/core/utility/scripts/helperFunctions.tscript

@@ -175,7 +175,7 @@ function getUserPath()
 
 function getPrefpath()
 {
-   $prefPath = getUserPath() @ "/preferences";
+   $prefPath = "data:/preferences";
 	return $prefPath;
 }
 

+ 4 - 1
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()
+endif()

+ 4 - 1
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@"
+#define DEFAULT_ZIP_PASSWORD     "@TORQUE_APP_PASSWORD@"