Merge pull request #713 from Ragora/feature-vfs-security

Feature: VFS Security
This commit is contained in:
Brian Roberts 2022-06-16 21:23:49 -05:00 committed by GitHub
commit b753c9d91c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 425 additions and 126 deletions

View file

@ -1426,7 +1426,7 @@ void AssetImportConfig::loadSISFile(Torque::Path filePath)
String settingsFile = settingsFilePath + "/" + fileExtension + ".sis";
FileObject* fileObj = new FileObject();
if (Platform::isFile(settingsFile))
if (Torque::FS::IsFile(settingsFile))
{
if (!fileObj->readMemory(settingsFile.c_str()))
{
@ -2170,7 +2170,7 @@ void AssetImporter::processShapeMaterialInfo(AssetImportObject* assetItem, S32 m
if (fullFilePath.isNotEmpty())
{
if (!Platform::isFile(fullFilePath.c_str()))
if (!Torque::FS::IsFile(fullFilePath.c_str()))
{
//could be a stale path reference, such as if it was downloaded elsewhere. Trim to just the filename and see
//if we can find it there
@ -2182,7 +2182,7 @@ void AssetImporter::processShapeMaterialInfo(AssetImportObject* assetItem, S32 m
if(filePath.getPath().isEmpty())
fullFilePath = shapePathBase + "/" + fullFilePath;
if (Platform::isFile(fullFilePath.c_str()))
if (Torque::FS::IsFile(fullFilePath.c_str()))
{
filePath = Torque::Path(fullFilePath);
}
@ -2316,7 +2316,7 @@ void AssetImporter::validateAsset(AssetImportObject* assetItem)
}
}
if (!assetItem->filePath.isEmpty() && !assetItem->generatedAsset && !Platform::isFile(assetItem->filePath.getFullPath().c_str()))
if (!assetItem->filePath.isEmpty() && !assetItem->generatedAsset && !Torque::FS::IsFile(assetItem->filePath.getFullPath().c_str()))
{
assetItem->status = "Error";
assetItem->statusType = "MissingFile";
@ -2806,15 +2806,20 @@ 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
dStrcpy(qualifiedFromFile, originalPath.c_str(), sizeof(qualifiedFromFile));
dStrcpy(qualifiedToFile, assetPath.c_str(), sizeof(qualifiedToFile));
#endif
newAsset->setAssetName(assetName);
newAsset->setImageFileName(imageFileName.c_str());
//If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
//file path for reimporting support later
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Platform::isFile(qualifiedFromFile))
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Torque::FS::IsFile(qualifiedFromFile))
{
newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
}
@ -2843,7 +2848,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);
@ -2869,11 +2874,15 @@ Torque::Path AssetImporter::importMaterialAsset(AssetImportObject* assetItem)
char qualifiedFromFile[2048];
#ifndef TORQUE_SECURE_VFS
Platform::makeFullPathName(originalPath.c_str(), qualifiedFromFile, sizeof(qualifiedFromFile));
#else
dStrcpy(qualifiedFromFile, originalPath.c_str(), sizeof(qualifiedFromFile));
#endif
newAsset->setAssetName(assetName);
if (!isReimport && Platform::isFile(qualifiedFromFile))
if (!isReimport && Torque::FS::IsFile(qualifiedFromFile))
{
newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
}
@ -3035,11 +3044,17 @@ 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
dStrcpy(qualifiedFromFile, originalPath.c_str(), sizeof(qualifiedFromFile));
dStrcpy(qualifiedToFile, assetPath.c_str(), sizeof(qualifiedToFile));
dStrcpy(qualifiedFromCSFile, originalConstructorPath.c_str(), sizeof(qualifiedFromCSFile));
dStrcpy(qualifiedToCSFile, constructorPath.c_str(), sizeof(qualifiedToCSFile));
#endif
newAsset->setAssetName(assetName);
newAsset->setShapeFile(shapeFileName.c_str());
@ -3057,7 +3072,7 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem)
//If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
//file path for reimporting support later
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Platform::isFile(qualifiedFromFile))
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Torque::FS::IsFile(qualifiedFromFile))
{
newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
}
@ -3121,7 +3136,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);
@ -3130,9 +3145,9 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem)
if (!isInPlace)
{
if (Platform::isFile(qualifiedFromCSFile))
if (Torque::FS::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);
@ -3149,7 +3164,7 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem)
else
{
//We're doing an in-place import, so double check we've already got a constructor file in the expected spot
if (Platform::isFile(qualifiedFromCSFile))
if (Torque::FS::IsFile(qualifiedFromCSFile))
{
//Yup, found it, we're good to go
makeNewConstructor = false;
@ -3162,7 +3177,7 @@ Torque::Path AssetImporter::importShapeAsset(AssetImportObject* assetItem)
Torque::Path constrFilePath = qualifiedFromCSFile;
constrFilePath.setExtension("cs");
if (Platform::isFile(constrFilePath.getFullPath().c_str()))
if (Torque::FS::IsFile(constrFilePath.getFullPath().c_str()))
{
//Yup, found it, we're good to go
makeNewConstructor = false;
@ -3324,15 +3339,20 @@ 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
dStrcpy(qualifiedFromFile, originalPath.c_str(), sizeof(qualifiedFromFile));
dStrcpy(qualifiedToFile, assetPath.c_str(), sizeof(qualifiedToFile));
#endif
newAsset->setAssetName(assetName);
newAsset->setSoundFile(imageFileName.c_str());
//If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
//file path for reimporting support later
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Platform::isFile(qualifiedFromFile))
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Torque::FS::IsFile(qualifiedFromFile))
{
newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
}
@ -3351,7 +3371,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);
@ -3380,15 +3400,20 @@ 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
dStrcpy(qualifiedFromFile, originalPath.c_str(), sizeof(qualifiedFromFile));
dStrcpy(qualifiedToFile, assetPath.c_str(), sizeof(qualifiedToFile));
#endif
newAsset->setAssetName(assetName);
newAsset->setAnimationFile(imageFileName.c_str());
//If it's not a re-import, check that the file isn't being in-place imported. If it isn't, store off the original
//file path for reimporting support later
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Platform::isFile(qualifiedFromFile))
if (!isReimport && String::compare(qualifiedFromFile, qualifiedToFile) && Torque::FS::IsFile(qualifiedFromFile))
{
newAsset->setDataField(StringTable->insert("originalFilePath"), nullptr, qualifiedFromFile);
}
@ -3407,7 +3432,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);

View file

@ -330,15 +330,15 @@ void ReflectionProbe::handleDeleteAction()
if (mReflectionModeType != StaticCubemap)
{
String prefilPath = getPrefilterMapPath();
if (Platform::isFile(prefilPath))
if (Torque::FS::IsFile(prefilPath))
{
Platform::fileDelete(prefilPath);
Torque::FS::Remove(prefilPath);
}
String irrPath = getIrradianceMapPath();
if (Platform::isFile(irrPath))
if (Torque::FS::IsFile(irrPath))
{
Platform::fileDelete(irrPath);
Torque::FS::Remove(irrPath);
}
}

View file

@ -2157,7 +2157,7 @@ DefineEngineFunction( gotoWebPage, void, ( const char* address ),,
// the bogus url, and hope for the best.
String addr;
if( Platform::isFile( address ) || Platform::isDirectory( address ) )
if( Torque::FS::IsFile( address ) || Torque::FS::IsDirectory( address ) )
{
#ifdef TORQUE2D_TOOLS_FIXME
addr = String::ToString( "file://%s", address );

View file

@ -368,15 +368,11 @@ DefineEngineFunction(getFileCRC, S32, ( const char* fileName ),,
"@ingroup FileSystem")
{
String cleanfilename(Torque::Path::CleanSeparators(fileName));
Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), cleanfilename.c_str());
Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode( givenPath );
Torque::FS::FileNodeRef fileRef = Torque::FS::GetFileNode( fileName );
if ( fileRef == NULL )
{
Con::errorf("getFileCRC() - could not access file: [%s]", givenPath.getFullPath().c_str() );
Con::errorf("getFileCRC() - could not access file: [%s]", fileName );
return -1;
}
@ -391,10 +387,7 @@ DefineEngineFunction(isFile, bool, ( const char* fileName ),,
"@ingroup FileSystem")
{
String cleanfilename(Torque::Path::CleanSeparators(fileName));
Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), cleanfilename.c_str());
Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
Torque::Path givenPath(fileName);
if (givenPath.getFileName().isEmpty() && givenPath.getExtension().isNotEmpty())
{
@ -415,11 +408,7 @@ DefineEngineFunction(isScriptFile, bool, (const char* fileName), ,
"@ingroup FileSystem")
{
String cleanfilename(Torque::Path::CleanSeparators(fileName));
Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), cleanfilename.c_str());
Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
return Torque::FS::IsScriptFile(givenPath.getFullPath());
return Torque::FS::IsScriptFile(fileName);
}
DefineEngineFunction( IsDirectory, bool, ( const char* directory ),,
@ -432,11 +421,7 @@ DefineEngineFunction( IsDirectory, bool, ( const char* directory ),,
"@ingroup FileSystem")
{
String dir(Torque::Path::CleanSeparators(directory));
Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), dir.c_str());
Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
return Torque::FS::IsDirectory( givenPath );
return Torque::FS::IsDirectory( directory );
}
DefineEngineFunction(isWriteableFileName, bool, ( const char* fileName ),,
@ -447,14 +432,7 @@ DefineEngineFunction(isWriteableFileName, bool, ( const char* fileName ),,
"@ingroup FileSystem")
{
String filename(Torque::Path::CleanSeparators(fileName));
Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), filename.c_str());
Torque::Path givenPath(Torque::Path::CompressPath(sgScriptFilenameBuffer));
Torque::FS::FileSystemRef fs = Torque::FS::GetFileSystem(givenPath);
Torque::Path path = fs->mapTo(givenPath);
return !Torque::FS::IsReadOnly(path);
return !Torque::FS::IsReadOnly(fileName);
}
DefineEngineFunction(startFileChangeNotifications, void, (),,
@ -487,7 +465,12 @@ DefineEngineFunction(getDirectoryList, String, ( const char* path, S32 depth ),
{
// Grab the full path.
char fullpath[1024];
#ifdef TORQUE_SECURE_VFS
dStrcpy(fullpath, path, sizeof(fullpath));
#else
Platform::makeFullPathName(String::compare(path, "/") == 0 ? "" : path, fullpath, sizeof(fullpath));
#endif
//dSprintf(fullpath, 511, "%s/%s", Platform::getWorkingDirectory(), path);
@ -501,7 +484,7 @@ DefineEngineFunction(getDirectoryList, String, ( const char* path, S32 depth ),
// Dump the directories.
Vector<StringTableEntry> directories;
Platform::dumpDirectories(fullpath, directories, depth, true);
Torque::FS::DumpDirectories(fullpath, directories, depth, true);
if( directories.empty() )
return "";
@ -539,8 +522,12 @@ DefineEngineFunction(fileSize, S32, ( const char* fileName ),,
"@ingroup FileSystem")
{
Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileName);
return Platform::getFileSize( sgScriptFilenameBuffer );
StrongRefPtr<Torque::FS::FileNode> node = Torque::FS::GetFileNode(fileName);
if (node.isValid())
{
return node->getSize();
}
return -1;
}
DefineEngineFunction( fileModifiedTime, String, ( const char* fileName ),,
@ -550,20 +537,20 @@ DefineEngineFunction( fileModifiedTime, String, ( const char* fileName ),,
"@return Formatted string (OS specific) containing modified time, \"9/3/2010 12:33:47 PM\" for example\n"
"@ingroup FileSystem")
{
Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileName);
Torque::FS::FileNodeRef node = Torque::FS::GetFileNode(fileName);
FileTime ft = {0};
Platform::getFileTimes( sgScriptFilenameBuffer, NULL, &ft );
if (node)
{
Platform::LocalTime lt = node->getModifiedTime().toLocalTime();
Platform::LocalTime lt = {0};
Platform::fileToLocalTime( ft, &lt );
String fileStr = Platform::localTimeToString( lt );
char *buffer = Con::getReturnBuffer( fileStr.size() );
dStrcpy( buffer, fileStr, fileStr.size() );
return buffer;
String fileStr = Platform::localTimeToString(lt);
char *buffer = Con::getReturnBuffer(fileStr.size());
dStrcpy(buffer, fileStr, fileStr.size());
return buffer;
}
return "";
}
DefineEngineFunction( fileCreatedTime, String, ( const char* fileName ),,
@ -573,20 +560,20 @@ DefineEngineFunction( fileCreatedTime, String, ( const char* fileName ),,
"@return Formatted string (OS specific) containing created time, \"9/3/2010 12:33:47 PM\" for example\n"
"@ingroup FileSystem")
{
Con::expandScriptFilename( sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileName );
Torque::FS::FileNodeRef node = Torque::FS::GetFileNode(fileName);
FileTime ft = {0};
Platform::getFileTimes( sgScriptFilenameBuffer, &ft, NULL );
if (node)
{
Platform::LocalTime lt = node->getCreatedTime().toLocalTime();
Platform::LocalTime lt = {0};
Platform::fileToLocalTime( ft, &lt );
String fileStr = Platform::localTimeToString(lt);
String fileStr = Platform::localTimeToString( lt );
char *buffer = Con::getReturnBuffer(fileStr.size());
dStrcpy(buffer, fileStr, fileStr.size());
char *buffer = Con::getReturnBuffer( fileStr.size() );
dStrcpy( buffer, fileStr, fileStr.size() );
return buffer;
return buffer;
}
return "";
}
DefineEngineFunction(compareFileTimes, S32, (const char* fileA, const char* fileB), ("", ""),
@ -597,17 +584,33 @@ DefineEngineFunction(compareFileTimes, S32, (const char* fileA, const char* file
"@return S32. If value is 1, then fileA is newer. If value is -1, then fileB is newer. If value is 0, they are equal.\n"
"@ingroup FileSystem")
{
Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileA);
Torque::FS::FileNodeRef nodeA = Torque::FS::GetFileNode(fileA);
Torque::FS::FileNodeRef nodeB = Torque::FS::GetFileNode(fileB);
FileTime fileATime = { 0 };
Platform::getFileTimes(sgScriptFilenameBuffer, NULL, &fileATime);
// Can't do anything if either file doesn't exist
if (!nodeA || !nodeB)
{
return 0;
}
Con::expandScriptFilename(sgScriptFilenameBuffer, sizeof(sgScriptFilenameBuffer), fileB);
Torque::FS::FileNode::Attributes fileAAttributes;
Torque::FS::FileNode::Attributes fileBAttributes;
FileTime fileBTime = { 0 };
Platform::getFileTimes(sgScriptFilenameBuffer, NULL, &fileBTime);
// If retrieval of attributes fails, we can't compare
if (!nodeA->getAttributes(&fileAAttributes) || !nodeB->getAttributes(&fileBAttributes))
{
return 0;
}
return Platform::compareFileTimes(fileATime, fileBTime);
if (fileAAttributes.mtime > fileBAttributes.mtime)
{
return 1;
}
else if (fileAAttributes.mtime < fileBAttributes.mtime)
{
return -1;
}
return 0;
}
DefineEngineFunction(fileDelete, bool, ( const char* path ),,
@ -618,13 +621,7 @@ DefineEngineFunction(fileDelete, bool, ( const char* path ),,
"@return True if file was successfully deleted\n"
"@ingroup FileSystem")
{
static char fileName[1024];
static char sandboxFileName[1024];
Con::expandScriptFilename( fileName, sizeof( fileName ), path );
Platform::makeFullPathName(fileName, sandboxFileName, sizeof(sandboxFileName));
return dFileDelete(sandboxFileName);
return Torque::FS::Remove(path);
}
@ -839,13 +836,7 @@ DefineEngineFunction( pathCopy, bool, ( const char* fromFile, const char* toFile
"@note Only present in a Tools build of Torque.\n"
"@ingroup FileSystem")
{
char qualifiedFromFile[ 2048 ];
char qualifiedToFile[ 2048 ];
Platform::makeFullPathName( fromFile, qualifiedFromFile, sizeof( qualifiedFromFile ) );
Platform::makeFullPathName( toFile, qualifiedToFile, sizeof( qualifiedToFile ) );
return dPathCopy( qualifiedFromFile, qualifiedToFile, noOverwrite );
return Torque::FS::CopyFile(fromFile, toFile, noOverwrite);
}
//-----------------------------------------------------------------------------
@ -857,7 +848,11 @@ DefineEngineFunction( getCurrentDirectory, String, (),,
"@see getWorkingDirectory()"
"@ingroup FileSystem")
{
#ifdef TORQUE_SECURE_VFS
return Torque::FS::GetCwd();
#else
return Platform::getCurrentDirectory();
#endif
}
//-----------------------------------------------------------------------------
@ -870,8 +865,11 @@ DefineEngineFunction( setCurrentDirectory, bool, ( const char* path ),,
"@note Only present in a Tools build of Torque.\n"
"@ingroup FileSystem")
{
#ifdef TORQUE_SECURE_VFS
return Torque::FS::SetCwd(path);
#else
return Platform::setCurrentDirectory( StringTable->insert( path ) );
#endif
}
//-----------------------------------------------------------------------------
@ -885,11 +883,7 @@ DefineEngineFunction( createPath, bool, ( const char* path ),,
"@note Only present in a Tools build of Torque.\n"
"@ingroup FileSystem" )
{
static char pathName[1024];
Con::expandScriptFilename( pathName, sizeof( pathName ), path );
return Platform::createPath( pathName );
return Torque::FS::CreatePath(path);
}
DefineEngineFunction(deleteDirectory, bool, (const char* path), ,

View file

@ -46,7 +46,8 @@ namespace Torque
mBuffer = dMalloc(mBufferSize);
dMemset(mBuffer, 0, mBufferSize);
mModified = Time::getCurrentTime();
mLastAccess = mModified;
mLastAccess = mModified;
mCreated = mModified;
mFileSystem = fs;
}
@ -62,6 +63,7 @@ namespace Torque
attr->size = mFileSize;
attr->mtime = mModified;
attr->atime = mLastAccess;
attr->ctime = mCreated;
return true;
}
@ -81,6 +83,7 @@ namespace Torque
U32 mBufferSize; // This is the size of the memory buffer >= mFileSize
U32 mFileSize; // This is the size of the "file" <= mBufferSize
Time mModified; // Last modified
Time mCreated; // When Created
Time mLastAccess; // Last access
MemFileSystem* mFileSystem;
};
@ -508,4 +511,4 @@ namespace Torque
}
} // Namespace Mem
} // Namespace Torque
} // Namespace Torque

View file

@ -129,4 +129,4 @@ namespace Torque
} // Namespace
} // Namespace
#endif
#endif

View file

@ -195,4 +195,29 @@ void Time::get(S32 *pyear, S32 *pmonth, S32 *pday, S32 *phour, S32 *pminute, S32
*pmicrosecond = time % OneSecond;
}
Platform::LocalTime Time::toLocalTime()
{
Platform::LocalTime result;
result.isdst = false;
S32 year;
S32 month;
S32 day;
S32 hour;
S32 minute;
S32 second;
S32 microsecond;
get(&year, &month, &day, &hour, &minute, &second, &microsecond);
result.year = year - 1900;
result.month = month - 1;
result.yearday = day;
result.hour = hour;
result.min = minute;
result.sec = second;
result.monthday = day % 32;
result.weekday = day % 7;
return result;
}
} // Namespace

View file

@ -26,7 +26,9 @@
#ifndef _TORQUE_TYPES_H_
#include "platform/types.h"
#endif
#ifndef _PLATFORM_H_
#include "platform/platform.h"
#endif
#if defined(TORQUE_COMPILER_VISUALC)
#define TORQUE_CONSTANT_S64(a) (a##I64)
@ -105,6 +107,8 @@ public:
S64 getMicroseconds() const;
S64 getInternalRepresentation() const;
Platform::LocalTime toLocalTime();
private:
class Tester
{

View file

@ -86,6 +86,7 @@ public:
// use the mod time for both mod and access time, since we only have mod time in the CD
attr->mtime = ZipArchive::DOSTimeToTime(mZipEntry->mCD.mModTime, mZipEntry->mCD.mModDate);
attr->atime = ZipArchive::DOSTimeToTime(mZipEntry->mCD.mModTime, mZipEntry->mCD.mModDate);
attr->ctime = ZipArchive::DOSTimeToTime(mZipEntry->mCD.mModTime, mZipEntry->mCD.mModDate);
attr->size = mZipEntry->mCD.mUncompressedSize;
return true;
@ -197,6 +198,7 @@ public:
// use the mod time for both mod and access time, since we only have mod time in the CD
attr->mtime = ZipArchive::DOSTimeToTime(mZipEntry->mCD.mModTime, mZipEntry->mCD.mModDate);
attr->atime = ZipArchive::DOSTimeToTime(mZipEntry->mCD.mModTime, mZipEntry->mCD.mModDate);
attr->ctime = ZipArchive::DOSTimeToTime(mZipEntry->mCD.mModTime, mZipEntry->mCD.mModDate);
attr->size = mZipEntry->mCD.mUncompressedSize;
return true;
@ -291,6 +293,7 @@ public:
ZipArchive::ZipEntry* zipEntry = mArchive->getRoot();
attr->mtime = ZipArchive::DOSTimeToTime(zipEntry->mCD.mModTime, zipEntry->mCD.mModDate);
attr->atime = ZipArchive::DOSTimeToTime(zipEntry->mCD.mModTime, zipEntry->mCD.mModDate);
attr->ctime = ZipArchive::DOSTimeToTime(zipEntry->mCD.mModTime, zipEntry->mCD.mModDate);
attr->size = zipEntry->mCD.mUncompressedSize;
return true;

View file

@ -75,4 +75,4 @@ private:
}
#endif
#endif

View file

@ -255,6 +255,64 @@ File::~File() {}
Directory::Directory() {}
Directory::~Directory() {}
bool Directory::dump(Vector<Path>& out)
{
const Path sourcePath = getName();
FileNode::Attributes currentAttributes;
while (read(&currentAttributes))
{
Path currentPath = sourcePath;
currentPath.appendPath(currentPath.getFileName());
currentPath.setFileName(currentAttributes.name);
out.push_back(currentPath);
}
return true;
}
bool Directory::dumpFiles(Vector<Path>& out)
{
const Path sourcePath = getName();
FileNode::Attributes currentAttributes;
while (read(&currentAttributes))
{
Path currentPath = sourcePath;
currentPath.appendPath(currentPath.getFileName());
currentPath.setFileName(currentAttributes.name);
if (IsFile(currentPath))
{
out.push_back(currentPath);
}
}
return true;
}
bool Directory::dumpDirectories(Vector<Path>& out)
{
const Path sourcePath = getName();
FileNode::Attributes currentAttributes;
while (read(&currentAttributes))
{
Path currentPath = sourcePath;
currentPath.appendPath(currentPath.getFileName());
currentPath.setFileName(currentAttributes.name);
const bool result = IsDirectory(currentPath);
if (result)
{
out.push_back(currentPath);
}
}
return true;
}
FileNode::FileNode()
: mChecksum(0)
@ -273,6 +331,18 @@ Time FileNode::getModifiedTime()
return attrs.mtime;
}
Time FileNode::getCreatedTime()
{
Attributes attrs;
bool success = getAttributes(&attrs);
if (!success)
return Time();
return attrs.ctime;
}
U64 FileNode::getSize()
{
Attributes attrs;
@ -500,6 +570,90 @@ 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;
}
bool MountSystem::_dumpDirectories(DirectoryRef directory, Vector<StringTableEntry>& directories, S32 depth, bool noBasePath, S32 currentDepth, const Path& basePath)
{
Vector<Torque::Path> directoryPaths;
if (!directory->dumpDirectories(directoryPaths))
{
return false;
}
// Queries against / will return a directory count of 1, but the code relies on actual directory entries (Eg. /data) so we handle that special case
const U32 basePathDirectoryCount = String::compare(basePath.getFullPathWithoutRoot(), "/") == 0 ? basePath.getDirectoryCount() - 1 : basePath.getDirectoryCount();
for (U32 iteration = 0; iteration < directoryPaths.size(); ++iteration)
{
const Path& directoryPath = directoryPaths[iteration];
// Load the full path to the directory unless we're not supposed to include base paths
String directoryPathString = directoryPath.getFullPath().c_str();
if (noBasePath)
{
// Build a path representing the directory tree *after* the base path query but excluding the base
// So if we queried for data/ and are currently processing data/ExampleModule/datablocks we want to output
// ExampleModule/datablocks
Path newDirectoryPath;
for (U32 iteration = basePathDirectoryCount; iteration < directoryPath.getDirectoryCount(); ++iteration)
{
if (iteration > basePathDirectoryCount)
{
newDirectoryPath.setPath(newDirectoryPath.getPath() + "/");
}
newDirectoryPath.setPath(newDirectoryPath.getPath() + directoryPath.getDirectory(iteration));
}
newDirectoryPath.setFileName(directoryPath.getFileName());
newDirectoryPath.setExtension(directoryPath.getExtension());
directoryPathString = newDirectoryPath.getFullPathWithoutRoot();
}
// Output result and enumerate subdirectories if we're not too deep according to the depth parameter
directories.push_back(StringTable->insert(directoryPathString, true));
if (currentDepth <= depth)
{
const String subdirectoryPath = directoryPath.getFullPath() + "/";
DirectoryRef nextDirectory = OpenDirectory(subdirectoryPath);
_dumpDirectories(nextDirectory, directories, depth, noBasePath, currentDepth + 1, basePath);
}
}
return true;
}
bool MountSystem::dumpDirectories(const Path& path, Vector<StringTableEntry>& directories, S32 depth, bool noBasePath)
{
if (!isDirectory(path))
{
return false;
}
DirectoryRef sourceDirectory = openDirectory(path);
return _dumpDirectories(sourceDirectory, directories, depth, noBasePath, 1, path);
}
FileRef MountSystem::createFile(const Path& path)
{
Path np = _normalize(path);
@ -792,22 +946,19 @@ bool MountSystem::isDirectory(const Path& path, FileSystemRef fsRef)
{
FileNode::Attributes attr;
bool result = false;
if (fsRef.isNull())
{
if (getFileAttributes(path,&attr))
return attr.flags & FileNode::Directory;
return false;
if (getFileAttributes(path, &attr))
result = (attr.flags & FileNode::Directory) != 0;
}
else
{
FileNodeRef fnRef = fsRef->resolve(path);
if (fnRef.isNull())
return false;
if (fnRef->getAttributes(&attr))
return attr.flags & FileNode::Directory;
return false;
if (!fnRef.isNull() && fnRef->getAttributes(&attr))
result = (attr.flags & FileNode::Directory) != 0;
}
return result;
}
bool MountSystem::isReadOnly(const Path& path)
@ -905,6 +1056,16 @@ 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);
}
bool DumpDirectories(const Path& path, Vector<StringTableEntry>& directories, S32 depth, bool noBasePath)
{
return sgMountSystem.dumpDirectories(path, directories, depth, noBasePath);
}
DirectoryRef CreateDirectory(const Path &path)
{
return sgMountSystem.createDirectory(path);

View file

@ -114,6 +114,7 @@ public:
String name; ///< File/Directory name
Time mtime; ///< Last modified time
Time atime; ///< Last access time
Time ctime; ///< Creation Time
U64 size;
};
@ -128,6 +129,7 @@ public:
// Convenience routines - may be overridden for optimal access
virtual Time getModifiedTime(); ///< @note This will return Time() on failure
virtual Time getCreatedTime(); ///< @note This will return Time() on failure
virtual U64 getSize(); ///< @note This will return 0 on failure
virtual U32 getChecksum(); ///< @note This will return 0 on failure
@ -201,7 +203,11 @@ public:
// Functions
virtual bool open() = 0;
virtual bool close() = 0;
virtual bool read(Attributes*) = 0;
virtual bool read(Attributes*) = 0;
bool dump(Vector<Path>& out);
bool dumpFiles(Vector<Path>& out);
bool dumpDirectories(Vector<Path>& out);
};
typedef WeakRefPtr<Directory> DirectoryPtr;
@ -335,6 +341,9 @@ public:
virtual ~MountSystem() {}
FileRef createFile(const Path& path);
bool copyFile(const Path& source, const Path& destination, bool noOverwrite);
bool dumpDirectories(const Path& path, Vector<StringTableEntry>& directories, S32 depth, bool noBasePath);
DirectoryRef createDirectory(const Path& path, FileSystemRef fs = NULL);
virtual bool createPath(const Path& path);
@ -374,6 +383,8 @@ public:
void startFileChangeNotifications();
void stopFileChangeNotifications();
private:
bool _dumpDirectories(DirectoryRef directory, Vector<StringTableEntry>& directories, S32 depth, bool noBasePath, S32 currentDepth, const Path& basePath);
protected:
virtual void _log(const String& msg);
@ -538,6 +549,12 @@ 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);
/// Retrieve list of directories in the specified directory.
bool DumpDirectories(const Path& path, Vector<StringTableEntry>& directories, S32 depth, bool noBasePath);
/// Create a directory.
/// The directory object is returned in a closed state.
///@ingroup VolumeSystem

View file

@ -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;

View file

@ -328,8 +328,13 @@ char * Platform::makeFullPathName(const char *path, char *buffer, U32 size, cons
// [rene, 05/05/2008] Based on overall file handling in Torque, it does not seem to make
// that much sense to me to base things off the current working directory here.
#ifndef TORQUE_SCECURE_VFS
if(cwd == NULL)
cwd = Con::isCurrentScriptToolScript() ? Platform::getMainDotCsDir() : Platform::getCurrentDirectory();
#else
if (cwd == NULL)
cwd = "game:/";
#endif
dStrncpy(buffer, cwd, size);
buffer[size-1] = 0;

View file

@ -20,6 +20,7 @@
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "platform/platform.h"
#if defined(TORQUE_OS_WIN)
@ -48,7 +49,49 @@ bool MountDefaults()
if ( !mounted )
return false;
#ifdef TORQUE_SECURE_VFS
mounted = Mount("/", createNativeFS(path));
if (!mounted)
{
return false;
}
#endif
#ifndef TORQUE_DISABLE_VIRTUAL_MOUNT_SYSTEM
// Always mount the data & home dir so scripts work in either configuration. This is used for eg. preferences storage.
Path dataDirectory = Platform::getUserDataDirectory();
Path appDataDirectory = Path::Join(dataDirectory.getFullPath().c_str(), '/', TORQUE_APP_NAME);
Path homeDirectory = Platform::getUserHomeDirectory();
Path appHomeDirectory = Path::Join(homeDirectory.getFullPath().c_str(), '/', TORQUE_APP_NAME);
// Ensure the root of the data directory exists before trying to mount data VFS
if (!Platform::FS::IsDirectory(appDataDirectory) && !Platform::FS::CreateDirectory(appDataDirectory))
{
// NOTE: We can't Con::errorf here because it doesn't actually output by this point in execution
}
// Ensure the root of the home directory exists before trying to mount home VFS
if (!Platform::FS::IsDirectory(appHomeDirectory) && !Platform::FS::CreateDirectory(appHomeDirectory))
{
// NOTE: We can't Con::errorf here because it doesn't actually output by this point in execution
}
// data:/ points to a directory that is usually buried someplace harder to reach on OS
mounted = Mount("data", Platform::FS::createNativeFS(appDataDirectory.getFullPath()));
if (!mounted)
{
// NOTE: We can't Con::errorf here because it doesn't actually output by this point in execution
return false;
}
// home:/ refers to your Documents/<APPNAME> folder which is easier to reach than the data:/ mount
mounted = Mount("home", Platform::FS::createNativeFS(appHomeDirectory.getFullPath()));
if (!mounted)
{
// NOTE: We can't Con::errorf here because it doesn't actually output by this point in execution
return false;
}
// Note that the VirtualMountSystem must be enabled in volume.cpp for zip support to work.
return MountZips("game");
#else

View file

@ -135,6 +135,7 @@ static void copyStatAttributes(const struct stat& info, FileNode::Attributes* at
attr->size = info.st_size;
attr->mtime = UnixTimeToTime(info.st_mtime);
attr->atime = UnixTimeToTime(info.st_atime);
attr->ctime = UnixTimeToTime(info.st_ctime);
}
@ -595,6 +596,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 +613,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;
}

View file

@ -143,6 +143,10 @@ static void _CopyStatAttributes(const WIN32_FIND_DATAW& info, FileNode::Attribut
attr->atime = Win32FileTimeToTime(
info.ftLastAccessTime.dwLowDateTime,
info.ftLastAccessTime.dwHighDateTime);
attr->ctime = Win32FileTimeToTime(
info.ftCreationTime.dwLowDateTime,
info.ftCreationTime.dwHighDateTime);
}
@ -758,6 +762,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 +797,7 @@ bool Platform::FS::InstallFileSystems()
wd += '/';
Platform::FS::SetCwd(wd);
#endif
return true;
}

View file

@ -284,10 +284,7 @@ bool SFXProfile::_preloadBuffer()
Resource<SFXResource>& SFXProfile::getResource()
{
char buf[1024];
FileName fullFilename = String(Platform::makeFullPathName(mFilename, buf, sizeof(buf)));
if (!mResource && SFXResource::exists(fullFilename))
if (!mResource && SFXResource::exists(mFilename))
mResource = SFXResource::load(mFilename);
else
mResource = NULL;

View file

@ -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"

View file

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

View file

@ -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()

View file

@ -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@"