diff --git a/Engine/source/platformPOSIX/POSIXConsole.cpp b/Engine/source/platformPOSIX/POSIXConsole.cpp index 5e9f810ec..28ed43be8 100644 --- a/Engine/source/platformPOSIX/POSIXConsole.cpp +++ b/Engine/source/platformPOSIX/POSIXConsole.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "platformX86UNIX/platformX86UNIX.h" +#include "platformPOSIX/platformPOSIX.h" #include "platformPOSIX/POSIXStdConsole.h" #include "platformPOSIX/POSIXUtils.h" #include "platform/input/event.h" diff --git a/Engine/source/platformPOSIX/POSIXFileio.cpp b/Engine/source/platformPOSIX/POSIXFileio.cpp index 8bdcea7b5..a9e6a7046 100644 --- a/Engine/source/platformPOSIX/POSIXFileio.cpp +++ b/Engine/source/platformPOSIX/POSIXFileio.cpp @@ -1,3 +1,62 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +/* JMQ: + + Here's the scoop on unix file IO. The windows platform makes some + assumptions about fileio: 1) the file system is case-insensitive, and + 2) the platform can write to the directory in which + the game is running. Both of these are usually false on linux. So, to + compensate, we "route" created files and directories to the user's home + directory (see GetPrefPath()). When a file is to be accessed, the code + looks in the home directory first. If the file is not found there and the + open mode is read only, the code will look in the game installation + directory. Files are never created or modified in the game directory. + + For case-sensitivity, the MungePath code will test whether a given path + specified by the engine exists. If not, it will use the ResolvePathCaseInsensitive function + which will try to determine if an actual filesystem path matches the + specified path case insensitive. If one is found, the actual path + transparently (we hope) replaces the one requested by the engine. + + The preference directory is global to all torque executables with the same + name. You should make sure you keep it clean if you build from multiple + torque development trees. +*/ + +#if defined(__FreeBSD__) +#include +#endif +#include + +/* these are for reading directors, getting stats, etc. */ +#include +#include +#include +#include +#include +#include +#include + #include "core/fileio.h" #include "core/util/tVector.h" #include "core/stringTable.h" @@ -7,10 +66,6 @@ #include "cinterface/c_controlInterface.h" #include "core/volume.h" -/* these are for reading directors, getting stats, etc. */ -#include -#include - const int MaxPath = PATH_MAX; //------------------------------------------------------------------------------ @@ -87,4 +142,1202 @@ bool ResolvePathCaseInsensitive(char* pathName, S32 pathNameSize, bool requiredA dStrncpy(pathName, tempBuf, pathNameSize); return foundMatch; -} \ No newline at end of file +} + +#ifndef __APPLE__ + +// evil hack to get around insane X windows #define-happy header files +#ifdef Status +#undef Status +#endif + +#include "platformX86UNIX/platformX86UNIX.h" + +extern int x86UNIXOpen(const char *path, int oflag); +extern int x86UNIXClose(int fd); +extern ssize_t x86UNIXRead(int fd, void *buf, size_t nbytes); +extern ssize_t x86UNIXWrite(int fd, const void *buf, size_t nbytes); +extern bool ResolvePathCaseInsensitive(char* pathName, S32 pathNameSize, bool requiredAbsolute); + +const int MaxPath = PATH_MAX; + +namespace +{ + const char sTempDir[] = "/tmp/"; + + static char sBinPathName[MaxPath] = ""; + static char *sBinName = sBinPathName; + bool sUseRedirect = true; +} + +StringTableEntry osGetTemporaryDirectory() +{ + return StringTable->insert(sTempDir); +} + +// Various handy utility functions: +//------------------------------------------------------------------------------ +// find all \ in a path and convert them in place to / +static void ForwardSlash(char *str) +{ + while(*str) + { + if(*str == '\\') + *str = '/'; + str++; + } +} + +//------------------------------------------------------------------------------ +// copy a file from src to dest +static bool CopyFile(const char* src, const char* dest) +{ + S32 srcFd = x86UNIXOpen(src, O_RDONLY); + S32 destFd = x86UNIXOpen(dest, O_WRONLY | O_CREAT | O_TRUNC); + bool error = false; + + if (srcFd != -1 && destFd != -1) + { + const int BufSize = 8192; + char buf[BufSize]; + S32 bytesRead = 0; + while ((bytesRead = x86UNIXRead(srcFd, buf, BufSize)) > 0) + { + // write data + if (x86UNIXWrite(destFd, buf, bytesRead) == -1) + { + error = true; + break; + } + } + + if (bytesRead == -1) + error = true; + } + + if (srcFd != -1) + x86UNIXClose(srcFd); + if (destFd != -1) + x86UNIXClose(destFd); + + if (error) + { + Con::errorf("Error copying file: %s, %s", src, dest); + remove(dest); + } + return error; +} + +bool dPathCopy(const char *fromName, const char *toName, bool nooverwrite) +{ + return CopyFile(fromName,toName); +} + +//----------------------------------------------------------------------------- +static char sgPrefDir[MaxPath]; +static bool sgPrefDirInitialized = false; + +// get the "pref dir", which is where game output files are stored. the pref +// dir is ~/PREF_DIR_ROOT/PREF_DIR_GAME_NAME +static const char* GetPrefDir() +{ + if (sgPrefDirInitialized) + return sgPrefDir; + + if (sUseRedirect) + { + const char *home = getenv("HOME"); + AssertFatal(home, "HOME environment variable must be set"); + + dSprintf(sgPrefDir, MaxPath, "%s/%s/%s", + home, PREF_DIR_ROOT, PREF_DIR_GAME_NAME); + } + else + { + getcwd(sgPrefDir, MaxPath); + } + + sgPrefDirInitialized = true; + return sgPrefDir; +} + +//----------------------------------------------------------------------------- +// Returns true if the pathname exists, false otherwise. If isFile is true, +// the pathname is assumed to be a file path, and only the directory part +// will be examined (everything before last /) +bool DirExists(char* pathname, bool isFile) +{ + static char testpath[20000]; + dStrncpy(testpath, pathname, sizeof(testpath)); + if (isFile) + { + // find the last / and make it into null + char* lastSlash = dStrrchr(testpath, '/'); + if (lastSlash != NULL) + *lastSlash = 0; + } + return Platform::isDirectory(testpath); +} + +//----------------------------------------------------------------------------- +// Munge the specified path. +static void MungePath(char* dest, S32 destSize, + const char* src, const char* absolutePrefix) +{ + char tempBuf[MaxPath]; + dStrncpy(dest, src, MaxPath); + + // translate all \ to / + ForwardSlash(dest); + + // if it is relative, make it absolute with the absolutePrefix + if (dest[0] != '/') + { + AssertFatal(absolutePrefix, "Absolute Prefix must not be NULL"); + + dSprintf(tempBuf, MaxPath, "%s/%s", + absolutePrefix, dest); + + // copy the result back into dest + dStrncpy(dest, tempBuf, destSize); + } + + // if the path exists, we're done + struct stat filestat; + if (stat(dest, &filestat) != -1) + return; + + // otherwise munge the case of the path + ResolvePathCaseInsensitive(dest, destSize, true); +} + +//----------------------------------------------------------------------------- +enum +{ + TOUCH, + DELETE +}; + +//----------------------------------------------------------------------------- +// perform a modification on the specified file. allowed modifications are +// specified in the enum above. +bool ModifyFile(const char * name, S32 modType) +{ + if(!name || (dStrlen(name) >= MaxPath) || dStrstr(name, "../") != NULL) + return(false); + + // if its absolute skip it + if (name[0]=='/' || name[0]=='\\') + return(false); + + // only modify files in home directory + char prefPathName[MaxPath]; + MungePath(prefPathName, MaxPath, name, GetPrefDir()); + + if (modType == TOUCH) + return(utime(prefPathName, 0) != -1); + else if (modType == DELETE) + return (remove(prefPathName) == 0); + else + AssertFatal(false, "Unknown File Mod type"); + return false; +} + +//----------------------------------------------------------------------------- +static bool RecurseDumpPath(const char *path, const char* relativePath, const char *pattern, Vector &fileVector, S32 currentDepth = 0, S32 recurseDepth = -1) +{ + char search[1024]; + + dSprintf(search, sizeof(search), "%s", path, pattern); + + DIR *directory = opendir(search); + + if (directory == NULL) + return false; + + struct dirent *fEntry; + fEntry = readdir(directory); // read the first "file" in the directory + + if (fEntry == NULL) + { + closedir(directory); + return false; + } + + do + { + char filename[BUFSIZ+1]; + struct stat fStat; + + dSprintf(filename, sizeof(filename), "%s/%s", search, fEntry->d_name); // "construct" the file name + stat(filename, &fStat); // get the file stats + + if ( (fStat.st_mode & S_IFMT) == S_IFDIR ) + { + // Directory + // skip . and .. directories + if (dStrcmp(fEntry->d_name, ".") == 0 || dStrcmp(fEntry->d_name, "..") == 0) + continue; + + // skip excluded directories + if( Platform::isExcludedDirectory(fEntry->d_name)) + continue; + + + char child[MaxPath]; + dSprintf(child, sizeof(child), "%s/%s", path, fEntry->d_name); + char* childRelative = NULL; + char childRelativeBuf[MaxPath]; + if (relativePath) + { + dSprintf(childRelativeBuf, sizeof(childRelativeBuf), "%s/%s", + relativePath, fEntry->d_name); + childRelative = childRelativeBuf; + } + if (currentDepth < recurseDepth || recurseDepth == -1 ) + RecurseDumpPath(child, childRelative, pattern, fileVector, currentDepth+1, recurseDepth); + } + else + { + // File + + // add it to the list + fileVector.increment(); + Platform::FileInfo& rInfo = fileVector.last(); + + if (relativePath) + rInfo.pFullPath = StringTable->insert(relativePath); + else + rInfo.pFullPath = StringTable->insert(path); + rInfo.pFileName = StringTable->insert(fEntry->d_name); + rInfo.fileSize = fStat.st_size; + //dPrintf("Adding file: %s/%s\n", rInfo.pFullPath, rInfo.pFileName); + } + + } while( (fEntry = readdir(directory)) != NULL ); + + closedir(directory); + return true; +} + +//----------------------------------------------------------------------------- +bool dFileDelete(const char * name) +{ + return ModifyFile(name, DELETE); +} + +//----------------------------------------------------------------------------- +bool dFileTouch(const char * name) +{ + return ModifyFile(name, TOUCH); +} + +bool dFileRename(const char *oldName, const char *newName) +{ + AssertFatal( oldName != NULL && newName != NULL, "dFileRename - NULL file name" ); + + // only modify files in home directory + TempAlloc oldPrefPathName(MaxPath); + TempAlloc newPrefPathName(MaxPath); + MungePath(oldPrefPathName, MaxPath, oldName, GetPrefDir()); + MungePath(newPrefPathName, MaxPath, newName, GetPrefDir()); + + return rename(oldPrefPathName, newPrefPathName) == 0; +} + +//----------------------------------------------------------------------------- +// Constructors & Destructor +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// After construction, the currentStatus will be Closed and the capabilities +// will be 0. +//----------------------------------------------------------------------------- +File::File() + : currentStatus(Closed), capability(0) +{ + // AssertFatal(sizeof(int) == sizeof(void *), "File::File: cannot cast void* to int"); + + handle = (void *)NULL; +} + +//----------------------------------------------------------------------------- +// insert a copy constructor here... (currently disabled) +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Destructor +//----------------------------------------------------------------------------- +File::~File() +{ + close(); + handle = (void *)NULL; +} + +//----------------------------------------------------------------------------- +// Open a file in the mode specified by openMode (Read, Write, or ReadWrite). +// Truncate the file if the mode is either Write or ReadWrite and truncate is +// true. +// +// Sets capability appropriate to the openMode. +// Returns the currentStatus of the file. +//----------------------------------------------------------------------------- +File::FileStatus File::open(const char *filename, const AccessMode openMode) +{ + AssertFatal(NULL != filename, "File::open: NULL filename"); + AssertWarn(NULL == handle, "File::open: handle already valid"); + + // Close the file if it was already open... + if (Closed != currentStatus) + close(); + + char prefPathName[MaxPath]; + char gamePathName[MaxPath]; + char cwd[MaxPath]; + getcwd(cwd, MaxPath); + MungePath(prefPathName, MaxPath, filename, GetPrefDir()); + MungePath(gamePathName, MaxPath, filename, cwd); + + int oflag; + struct stat filestat; + handle = (void *)dRealMalloc(sizeof(int)); + + switch (openMode) + { + case Read: + oflag = O_RDONLY; + break; + case Write: + oflag = O_WRONLY | O_CREAT | O_TRUNC; + break; + case ReadWrite: + oflag = O_RDWR | O_CREAT; + // if the file does not exist copy it before reading/writing + if (stat(prefPathName, &filestat) == -1) + bool ret = CopyFile(gamePathName, prefPathName); + break; + case WriteAppend: + oflag = O_WRONLY | O_CREAT | O_APPEND; + // if the file does not exist copy it before appending + if (stat(prefPathName, &filestat) == -1) + bool ret = CopyFile(gamePathName, prefPathName); + break; + default: + AssertFatal(false, "File::open: bad access mode"); // impossible + } + + // if we are writing, make sure output path exists + if (openMode == Write || openMode == ReadWrite || openMode == WriteAppend) + Platform::createPath(prefPathName); + + int fd = -1; + fd = x86UNIXOpen(prefPathName, oflag); + if (fd == -1 && openMode == Read) + // for read only files we can use the gamePathName + fd = x86UNIXOpen(gamePathName, oflag); + + dMemcpy(handle, &fd, sizeof(int)); + +#ifdef DEBUG + // fprintf(stdout,"fd = %d, handle = %d\n", fd, *((int *)handle)); +#endif + + if (*((int *)handle) == -1) + { + // handle not created successfully + Con::errorf("Can't open file: %s", filename); + return setStatus(); + } + else + { + // successfully created file, so set the file capabilities... + switch (openMode) + { + case Read: + capability = U32(FileRead); + break; + case Write: + case WriteAppend: + capability = U32(FileWrite); + break; + case ReadWrite: + capability = U32(FileRead) | + U32(FileWrite); + break; + default: + AssertFatal(false, "File::open: bad access mode"); + } + return currentStatus = Ok; // success! + } +} + +//----------------------------------------------------------------------------- +// Get the current position of the file pointer. +//----------------------------------------------------------------------------- +U32 File::getPosition() const +{ + AssertFatal(Closed != currentStatus, "File::getPosition: file closed"); + AssertFatal(NULL != handle, "File::getPosition: invalid file handle"); + +#ifdef DEBUG + // fprintf(stdout, "handle = %d\n",*((int *)handle));fflush(stdout); +#endif + return (U32) lseek(*((int *)handle), 0, SEEK_CUR); +} + +//----------------------------------------------------------------------------- +// Set the position of the file pointer. +// Absolute and relative positioning is supported via the absolutePos +// parameter. +// +// If positioning absolutely, position MUST be positive - an IOError results if +// position is negative. +// Position can be negative if positioning relatively, however positioning +// before the start of the file is an IOError. +// +// Returns the currentStatus of the file. +//----------------------------------------------------------------------------- +File::FileStatus File::setPosition(S32 position, bool absolutePos) +{ + AssertFatal(Closed != currentStatus, "File::setPosition: file closed"); + AssertFatal(NULL != handle, "File::setPosition: invalid file handle"); + + if (Ok != currentStatus && EOS != currentStatus) + return currentStatus; + + U32 finalPos = 0; + + if (absolutePos) + { + AssertFatal(0 <= position, "File::setPosition: negative absolute position"); + + // position beyond EOS is OK + finalPos = lseek(*((int *)handle), position, SEEK_SET); + } + else + { + AssertFatal((getPosition() >= (U32)abs(position) && 0 > position) || 0 <= position, "File::setPosition: negative relative position"); + + // position beyond EOS is OK + finalPos = lseek(*((int *)handle), position, SEEK_CUR); + } + + if (0xffffffff == finalPos) + return setStatus(); // unsuccessful + else if (finalPos >= getSize()) + return currentStatus = EOS; // success, at end of file + else + return currentStatus = Ok; // success! +} + +//----------------------------------------------------------------------------- +// Get the size of the file in bytes. +// It is an error to query the file size for a Closed file, or for one with an +// error status. +//----------------------------------------------------------------------------- +U32 File::getSize() const +{ + AssertWarn(Closed != currentStatus, "File::getSize: file closed"); + AssertFatal(NULL != handle, "File::getSize: invalid file handle"); + + if (Ok == currentStatus || EOS == currentStatus) + { + long currentOffset = getPosition(); // keep track of our current position + long fileSize; + lseek(*((int *)handle), 0, SEEK_END); // seek to the end of the file + fileSize = getPosition(); // get the file size + lseek(*((int *)handle), currentOffset, SEEK_SET); // seek back to our old offset + return fileSize; // success! + } + else + return 0; // unsuccessful +} + +//----------------------------------------------------------------------------- +// Flush the file. +// It is an error to flush a read-only file. +// Returns the currentStatus of the file. +//----------------------------------------------------------------------------- +File::FileStatus File::flush() +{ + AssertFatal(Closed != currentStatus, "File::flush: file closed"); + AssertFatal(NULL != handle, "File::flush: invalid file handle"); + AssertFatal(true == hasCapability(FileWrite), "File::flush: cannot flush a read-only file"); + + if (fsync(*((int *)handle)) == 0) + return currentStatus = Ok; // success! + else + return setStatus(); // unsuccessful +} + +//----------------------------------------------------------------------------- +// Close the File. +// +// Returns the currentStatus +//----------------------------------------------------------------------------- +File::FileStatus File::close() +{ + // if the handle is non-NULL, close it if necessary and free it + if (NULL != handle) + { + // make a local copy of the handle value and + // free the handle + int handleVal = *((int *)handle); + dRealFree(handle); + handle = (void *)NULL; + + // close the handle if it is valid + if (handleVal != -1 && x86UNIXClose(handleVal) != 0) + return setStatus(); // unsuccessful + } + // Set the status to closed + return currentStatus = Closed; +} + +//----------------------------------------------------------------------------- +// Self-explanatory. +//----------------------------------------------------------------------------- +File::FileStatus File::getStatus() const +{ + return currentStatus; +} + +//----------------------------------------------------------------------------- +// Sets and returns the currentStatus when an error has been encountered. +//----------------------------------------------------------------------------- +File::FileStatus File::setStatus() +{ + Con::printf("File IO error: %s", strerror(errno)); + return currentStatus = IOError; +} + +//----------------------------------------------------------------------------- +// Sets and returns the currentStatus to status. +//----------------------------------------------------------------------------- +File::FileStatus File::setStatus(File::FileStatus status) +{ + return currentStatus = status; +} + +//----------------------------------------------------------------------------- +// Read from a file. +// The number of bytes to read is passed in size, the data is returned in src. +// The number of bytes read is available in bytesRead if a non-Null pointer is +// provided. +//----------------------------------------------------------------------------- +File::FileStatus File::read(U32 size, char *dst, U32 *bytesRead) +{ +#ifdef DEBUG + // fprintf(stdout,"reading %d bytes\n",size);fflush(stdout); +#endif + AssertFatal(Closed != currentStatus, "File::read: file closed"); + AssertFatal(NULL != handle, "File::read: invalid file handle"); + AssertFatal(NULL != dst, "File::read: NULL destination pointer"); + AssertFatal(true == hasCapability(FileRead), "File::read: file lacks capability"); + AssertWarn(0 != size, "File::read: size of zero"); + + /* show stats for this file */ +#ifdef DEBUG + //struct stat st; + //fstat(*((int *)handle), &st); + //fprintf(stdout,"file size = %d\n", st.st_size); +#endif + /****************************/ + + if (Ok != currentStatus || 0 == size) + return currentStatus; + else + { + long lastBytes; + long *bytes = (NULL == bytesRead) ? &lastBytes : (long *)bytesRead; + if ( (*((U32 *)bytes) = x86UNIXRead(*((int *)handle), dst, size)) == -1) + { +#ifdef DEBUG + // fprintf(stdout,"unsuccessful: %d\n", *((U32 *)bytes));fflush(stdout); +#endif + return setStatus(); // unsuccessful + } else { + // dst[*((U32 *)bytes)] = '\0'; + if (*((U32 *)bytes) != size || *((U32 *)bytes) == 0) { +#ifdef DEBUG + // fprintf(stdout,"end of stream: %d\n", *((U32 *)bytes));fflush(stdout); +#endif + return currentStatus = EOS; // end of stream + } + } + } + // dst[*bytesRead] = '\0'; +#ifdef DEBUG + //fprintf(stdout, "We read:\n"); + //fprintf(stdout, "====================================================\n"); + //fprintf(stdout, "%s\n",dst); + //fprintf(stdout, "====================================================\n"); + //fprintf(stdout,"read ok: %d\n", *bytesRead);fflush(stdout); +#endif + return currentStatus = Ok; // successfully read size bytes +} + +//----------------------------------------------------------------------------- +// Write to a file. +// The number of bytes to write is passed in size, the data is passed in src. +// The number of bytes written is available in bytesWritten if a non-Null +// pointer is provided. +//----------------------------------------------------------------------------- +File::FileStatus File::write(U32 size, const char *src, U32 *bytesWritten) +{ + // JMQ: despite the U32 parameters, the maximum filesize supported by this + // function is probably the max value of S32, due to the unix syscall + // api. + AssertFatal(Closed != currentStatus, "File::write: file closed"); + AssertFatal(NULL != handle, "File::write: invalid file handle"); + AssertFatal(NULL != src, "File::write: NULL source pointer"); + AssertFatal(true == hasCapability(FileWrite), "File::write: file lacks capability"); + AssertWarn(0 != size, "File::write: size of zero"); + + if ((Ok != currentStatus && EOS != currentStatus) || 0 == size) + return currentStatus; + else + { + S32 numWritten = x86UNIXWrite(*((int *)handle), src, size); + if (numWritten < 0) + return setStatus(); + + if (bytesWritten) + *bytesWritten = static_cast(numWritten); + return currentStatus = Ok; + } +} + +//----------------------------------------------------------------------------- +// Self-explanatory. JMQ: No explanation needed. Move along. These aren't +// the droids you're looking for. +//----------------------------------------------------------------------------- +bool File::hasCapability(Capability cap) const +{ + return (0 != (U32(cap) & capability)); +} + +//----------------------------------------------------------------------------- +S32 Platform::compareFileTimes(const FileTime &a, const FileTime &b) +{ + if(a > b) + return 1; + if(a < b) + return -1; + return 0; +} + +//----------------------------------------------------------------------------- +static bool GetFileTimes(const char *filePath, FileTime *createTime, FileTime *modifyTime) +{ + struct stat fStat; + + if (stat(filePath, &fStat) == -1) + return false; + + if(createTime) + { + // no where does SysV/BSD UNIX keep a record of a file's + // creation time. instead of creation time I'll just use + // changed time for now. + *createTime = fStat.st_ctime; + } + if(modifyTime) + { + *modifyTime = fStat.st_mtime; + } + + return true; +} + +//----------------------------------------------------------------------------- +bool Platform::getFileTimes(const char *filePath, FileTime *createTime, FileTime *modifyTime) +{ + char pathName[MaxPath]; + + // if it starts with cwd, we need to strip that off so that we can look for + // the file in the pref dir + char cwd[MaxPath]; + getcwd(cwd, MaxPath); + if (dStrstr(filePath, cwd) == filePath) + filePath = filePath + dStrlen(cwd) + 1; + + // if its relative, first look in the pref dir + if (filePath[0] != '/' && filePath[0] != '\\') + { + MungePath(pathName, MaxPath, filePath, GetPrefDir()); + if (GetFileTimes(pathName, createTime, modifyTime)) + return true; + } + + // here if the path is absolute or not in the pref dir + MungePath(pathName, MaxPath, filePath, cwd); + return GetFileTimes(pathName, createTime, modifyTime); +} + +//----------------------------------------------------------------------------- +bool Platform::createPath(const char *file) +{ + char pathbuf[MaxPath]; + const char *dir; + pathbuf[0] = 0; + U32 pathLen = 0; + + // all paths should be created in home directory + char prefPathName[MaxPath]; + MungePath(prefPathName, MaxPath, file, GetPrefDir()); + file = prefPathName; + + // does the directory exist already? + if (DirExists(prefPathName, true)) // true means that the path is a filepath + return true; + + while((dir = dStrchr(file, '/')) != NULL) + { + dStrncpy(pathbuf + pathLen, file, dir - file); + pathbuf[pathLen + dir-file] = 0; + bool ret = mkdir(pathbuf, 0700); + pathLen += dir - file; + pathbuf[pathLen++] = '/'; + file = dir + 1; + } + return true; +} + +// JMQ: Platform:cdFileExists in unimplemented +//------------------------------------------------------------------------------ +// bool Platform::cdFileExists(const char *filePath, const char *volumeName, +// S32 serialNum) +// { +// } + +//----------------------------------------------------------------------------- +bool Platform::dumpPath(const char *path, Vector &fileVector, int depth) +{ + const char* pattern = "*"; + + // if it is not absolute, dump the pref dir first + if (path[0] != '/' && path[0] != '\\') + { + char prefPathName[MaxPath]; + MungePath(prefPathName, MaxPath, path, GetPrefDir()); + RecurseDumpPath(prefPathName, path, pattern, fileVector, 0, depth); + } + + // munge the requested path and dump it + char mungedPath[MaxPath]; + char cwd[MaxPath]; + getcwd(cwd, MaxPath); + MungePath(mungedPath, MaxPath, path, cwd); + return RecurseDumpPath(mungedPath, path, pattern, fileVector, 0, depth); +} + +//----------------------------------------------------------------------------- +StringTableEntry Platform::getCurrentDirectory() +{ + char cwd_buf[2048]; + getcwd(cwd_buf, 2047); + return StringTable->insert(cwd_buf); +} + +//----------------------------------------------------------------------------- +bool Platform::setCurrentDirectory(StringTableEntry newDir) +{ + if (Platform::getWebDeployment()) + return true; + + TempAlloc< UTF8 > buf( dStrlen( newDir ) + 2 ); + + dStrcpy( buf, newDir, buf.size ); + + ForwardSlash( buf ); + return chdir( buf ) == 0; +} + +//----------------------------------------------------------------------------- +const char *Platform::getUserDataDirectory() +{ + return StringTable->insert( GetPrefDir() ); +} + +//----------------------------------------------------------------------------- +StringTableEntry Platform::getUserHomeDirectory() +{ + char *home = getenv( "HOME" ); + return StringTable->insert( home ); +} + +StringTableEntry Platform::getExecutablePath() +{ + if( !sBinPathName[0] ) + { + const char *cpath; + if( (cpath = torque_getexecutablepath()) ) + { + dStrncpy(sBinPathName, cpath, sizeof(sBinPathName)); + chdir(sBinPathName); + } + else + { + getcwd(sBinPathName, sizeof(sBinPathName)-1); + } + } + + return StringTable->insert(sBinPathName); +} + +//----------------------------------------------------------------------------- +bool Platform::isFile(const char *pFilePath) +{ + if (!pFilePath || !*pFilePath) + return false; + // Get file info + struct stat fStat; + if (stat(pFilePath, &fStat) < 0) + { + // Since file does not exist on disk see if it exists in a zip file loaded + return Torque::FS::IsFile(pFilePath); + } + + // if the file is a "regular file" then true + if ( (fStat.st_mode & S_IFMT) == S_IFREG) + return true; + // must be some other file (directory, device, etc.) + return false; +} + +//----------------------------------------------------------------------------- +S32 Platform::getFileSize(const char *pFilePath) +{ + if (!pFilePath || !*pFilePath) + return -1; + // Get the file info + struct stat fStat; + if (stat(pFilePath, &fStat) < 0) + return -1; + // if the file is a "regular file" then return the size + if ( (fStat.st_mode & S_IFMT) == S_IFREG) + return fStat.st_size; + // Must be something else or we can't read the file. + return -1; +} + +//----------------------------------------------------------------------------- +bool Platform::isDirectory(const char *pDirPath) +{ + if (!pDirPath || !*pDirPath) + return false; + + // Get file info + struct stat fStat; + if (stat(pDirPath, &fStat) < 0) + return false; + + // if the file is a Directory then true + if ( (fStat.st_mode & S_IFMT) == S_IFDIR) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +bool Platform::isSubDirectory(const char *pParent, const char *pDir) +{ + if (!pParent || !*pDir) + return false; + + // this is somewhat of a brute force method but we need to be 100% sure + // that the user cannot enter things like ../dir or /dir etc,... + DIR *directory; + + directory = opendir(pParent); + if (directory == NULL) + return false; + + struct dirent *fEntry; + fEntry = readdir(directory); + if ( fEntry == NULL ) + { + closedir(directory); + return false; + } + + do + { + char dirBuf[MaxPath]; + struct stat fStat; + + dSprintf(dirBuf, sizeof(dirBuf), "%s/%s", pParent, fEntry->d_name); + if (stat(dirBuf, &fStat) < 0) + continue; + // if it is a directory... + if ( (fStat.st_mode & S_IFMT) == S_IFDIR) + { + // and the names match + if (dStrcmp(pDir, fEntry->d_name ) == 0) + { + // then we have a real sub directory + closedir(directory); + return true; + } + } + } while( (fEntry = readdir(directory)) != NULL ); + + closedir(directory); + return false; +} + +//----------------------------------------------------------------------------- + + +// This is untested -- BJG + +bool Platform::fileTimeToString(FileTime * time, char * string, U32 strLen) +{ + if(!time || !string) + return(false); + + dSprintf(string, strLen, "%ld", *time); + return(true); +} + +bool Platform::stringToFileTime(const char * string, FileTime * time) +{ + if(!time || !string) + return(false); + + *time = dAtoi(string); + + return(true); +} + +bool Platform::hasSubDirectory(const char *pPath) +{ + if (!pPath) + return false; + + struct dirent *d; + DIR *dip; + dip = opendir(pPath); + if (dip == NULL) + return false; + + while ((d = readdir(dip))) + { + bool isDir = false; + if (d->d_type == DT_UNKNOWN) + { + char child [1024]; + if ((pPath[dStrlen(pPath) - 1] == '/')) + dSprintf(child, 1024, "%s%s", pPath, d->d_name); + else + dSprintf(child, 1024, "%s/%s", pPath, d->d_name); + isDir = Platform::isDirectory (child); + } + else if (d->d_type & DT_DIR) + isDir = true; + if( isDir ) + { + // Skip the . and .. directories + if (dStrcmp(d->d_name, ".") == 0 ||dStrcmp(d->d_name, "..") == 0) + continue; + if (Platform::isExcludedDirectory(d->d_name)) + continue; + Platform::clearExcludedDirectories(); + closedir(dip); + return true; + } + } + closedir(dip); + Platform::clearExcludedDirectories(); + return false; +} + +bool Platform::fileDelete(const char * name) +{ + return ModifyFile(name, DELETE); +} + +static bool recurseDumpDirectories(const char *basePath, const char *subPath, Vector &directoryVector, S32 currentDepth, S32 recurseDepth, bool noBasePath) +{ + char Path[1024]; + DIR *dip; + struct dirent *d; + + dsize_t trLen = basePath ? dStrlen(basePath) : 0; + dsize_t subtrLen = subPath ? dStrlen(subPath) : 0; + char trail = trLen > 0 ? basePath[trLen - 1] : '\0'; + char subTrail = subtrLen > 0 ? subPath[subtrLen - 1] : '\0'; + char subLead = subtrLen > 0 ? subPath[0] : '\0'; + + if (trail == '/') + { + if (subPath && (dStrncmp(subPath, "", 1) != 0)) + { + if (subTrail == '/') + dSprintf(Path, 1024, "%s%s", basePath, subPath); + else + dSprintf(Path, 1024, "%s%s/", basePath, subPath); + } + else + dSprintf(Path, 1024, "%s", basePath); + } + else + { + if (subPath && (dStrncmp(subPath, "", 1) != 0)) + { + if (subTrail == '/') + dSprintf(Path, 1024, "%s%s", basePath, subPath); + else + dSprintf(Path, 1024, "%s%s/", basePath, subPath); + } + else + dSprintf(Path, 1024, "%s/", basePath); + } + + dip = opendir(Path); + if (dip == NULL) + return false; + + ////////////////////////////////////////////////////////////////////////// + // add path to our return list ( provided it is valid ) + ////////////////////////////////////////////////////////////////////////// + if (!Platform::isExcludedDirectory(subPath)) + { + if (noBasePath) + { + // We have a path and it's not an empty string or an excluded directory + if ( (subPath && (dStrncmp (subPath, "", 1) != 0)) ) + directoryVector.push_back(StringTable->insert(subPath)); + } + else + { + if ( (subPath && (dStrncmp(subPath, "", 1) != 0)) ) + { + char szPath[1024]; + dMemset(szPath, 0, 1024); + if (trail == '/') + { + if ((basePath[dStrlen(basePath) - 1]) != '/') + dSprintf(szPath, 1024, "%s%s", basePath, &subPath[1]); + else + dSprintf(szPath, 1024, "%s%s", basePath, subPath); + } + else + { + if ((basePath[dStrlen(basePath) - 1]) != '/') + dSprintf(szPath, 1024, "%s%s", basePath, subPath); + else + dSprintf(szPath, 1024, "%s/%s", basePath, subPath); + } + + directoryVector.push_back(StringTable->insert(szPath)); + } + else + directoryVector.push_back(StringTable->insert(basePath)); + } + } + ////////////////////////////////////////////////////////////////////////// + // Iterate through and grab valid directories + ////////////////////////////////////////////////////////////////////////// + + while ((d = readdir(dip))) + { + bool isDir; + isDir = false; + if (d->d_type == DT_UNKNOWN) + { + char child [1024]; + if (Path[dStrlen(Path) - 1] == '/') + dSprintf(child, 1024, "%s%s", Path, d->d_name); + else + dSprintf(child, 1024, "%s/%s", Path, d->d_name); + isDir = Platform::isDirectory (child); + } + else if (d->d_type & DT_DIR) + isDir = true; + + if ( isDir ) + { + if (dStrcmp(d->d_name, ".") == 0 || + dStrcmp(d->d_name, "..") == 0) + continue; + if (Platform::isExcludedDirectory(d->d_name)) + continue; + if ( (subPath && (dStrncmp(subPath, "", 1) != 0)) ) + { + char child[1024]; + if ((subPath[dStrlen(subPath) - 1] == '/')) + dSprintf(child, 1024, "%s%s", subPath, d->d_name); + else + dSprintf(child, 1024, "%s/%s", subPath, d->d_name); + if (currentDepth < recurseDepth || recurseDepth == -1 ) + recurseDumpDirectories(basePath, child, directoryVector, + currentDepth + 1, recurseDepth, + noBasePath); + } + else + { + char child[1024]; + if ( (basePath[dStrlen(basePath) - 1]) == '/') + dStrcpy (child, d->d_name, 1024); + else + dSprintf(child, 1024, "/%s", d->d_name); + if (currentDepth < recurseDepth || recurseDepth == -1) + recurseDumpDirectories(basePath, child, directoryVector, + currentDepth + 1, recurseDepth, + noBasePath); + } + } + } + closedir(dip); + return true; +} + +bool Platform::dumpDirectories(const char *path, Vector &directoryVector, S32 depth, bool noBasePath) +{ +#ifdef TORQUE_POSIX_PATH_CASE_INSENSITIVE + dsize_t pathLength = dStrlen(path); + char* caseSensitivePath = new char[pathLength + 1]; + + // Load path into temporary buffer + dMemcpy(caseSensitivePath, path, pathLength); + caseSensitivePath[pathLength] = 0x00; + ResolvePathCaseInsensitive(caseSensitivePath, pathLength, false); +#else + const char* caseSensitivePath = path; +#endif + + bool retVal = recurseDumpDirectories(caseSensitivePath, "", directoryVector, -1, depth, noBasePath); + clearExcludedDirectories(); + +#ifdef TORQUE_POSIX_PATH_CASE_INSENSITIVE + delete[] caseSensitivePath; +#endif + return retVal; +} + +StringTableEntry Platform::getExecutableName() +{ + return StringTable->insert(sBinName); +} + +extern "C" +{ +void setExePathName(const char* exePathName) +{ + if (exePathName == NULL) + sBinPathName[0] = '\0'; + else + dStrncpy(sBinPathName, exePathName, sizeof(sBinPathName)); + + // set the base exe name field + char *binName = dStrrchr(sBinPathName, '/'); + if( !binName ) + binName = sBinPathName; + else + *binName++ = '\0'; + sBinName = binName; +} +} +#endif \ No newline at end of file diff --git a/Engine/source/platformPOSIX/POSIXMemory.cpp b/Engine/source/platformPOSIX/POSIXMemory.cpp index ad08a313f..32b92c52c 100644 --- a/Engine/source/platformPOSIX/POSIXMemory.cpp +++ b/Engine/source/platformPOSIX/POSIXMemory.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "platformX86UNIX/platformX86UNIX.h" +#include "platformPOSIX/platformPOSIX.h" #include #include diff --git a/Engine/source/platformPOSIX/POSIXState.h b/Engine/source/platformPOSIX/POSIXState.h index 7d35667bc..dec62b2ee 100644 --- a/Engine/source/platformPOSIX/POSIXState.h +++ b/Engine/source/platformPOSIX/POSIXState.h @@ -21,7 +21,7 @@ //----------------------------------------------------------------------------- #include "math/mPoint2.h" -#include "platformX86UNIX/platformX86UNIX.h" +#include "platformPOSIX/platformPOSIX.h" //#include "platformX86UNIX/platformGL.h" #include "core/strings/stringFunctions.h" diff --git a/Engine/source/platformPOSIX/POSIXStrings.cpp b/Engine/source/platformPOSIX/POSIXStrings.cpp index f531409d9..f4b69c16b 100644 --- a/Engine/source/platformPOSIX/POSIXStrings.cpp +++ b/Engine/source/platformPOSIX/POSIXStrings.cpp @@ -20,7 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#include "platformX86UNIX/platformX86UNIX.h" +#include "platformPOSIX/platformPOSIX.h" #include "core/strings/stringFunctions.h" #include #include diff --git a/Engine/source/platformPOSIX/POSIXUtils.cpp b/Engine/source/platformPOSIX/POSIXUtils.cpp index b87d92c49..fc5c416ff 100644 --- a/Engine/source/platformPOSIX/POSIXUtils.cpp +++ b/Engine/source/platformPOSIX/POSIXUtils.cpp @@ -31,7 +31,7 @@ #include #include -#include "platformX86UNIX/platformX86UNIX.h" +#include "platformPOSIX/platformPOSIX.h" #include "platformPOSIX/POSIXUtils.h" UnixUtils *UUtils = NULL; diff --git a/Engine/source/platformX86UNIX/platformX86UNIX.h b/Engine/source/platformPOSIX/platformPOSIX.h similarity index 97% rename from Engine/source/platformX86UNIX/platformX86UNIX.h rename to Engine/source/platformPOSIX/platformPOSIX.h index 19481dd31..0f4d7828b 100644 --- a/Engine/source/platformX86UNIX/platformX86UNIX.h +++ b/Engine/source/platformPOSIX/platformPOSIX.h @@ -20,8 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- -#ifndef _PLATFORMX86UNIX_H_ -#define _PLATFORMX86UNIX_H_ +#pragma once #ifndef _PLATFORM_H_ #include "platform/platform.h" @@ -66,4 +65,3 @@ extern "C" // x86UNIX doesn't have a way to automatically get the executable file name void setExePathName(const char* exePathName); } -#endif diff --git a/Engine/source/platformX86UNIX/x86UNIXFileio.cpp b/Engine/source/platformX86UNIX/x86UNIXFileio.cpp deleted file mode 100644 index d702d6417..000000000 --- a/Engine/source/platformX86UNIX/x86UNIXFileio.cpp +++ /dev/null @@ -1,1261 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (c) 2012 GarageGames, LLC -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//----------------------------------------------------------------------------- - - /* JMQ: - - Here's the scoop on unix file IO. The windows platform makes some - assumptions about fileio: 1) the file system is case-insensitive, and - 2) the platform can write to the directory in which - the game is running. Both of these are usually false on linux. So, to - compensate, we "route" created files and directories to the user's home - directory (see GetPrefPath()). When a file is to be accessed, the code - looks in the home directory first. If the file is not found there and the - open mode is read only, the code will look in the game installation - directory. Files are never created or modified in the game directory. - - For case-sensitivity, the MungePath code will test whether a given path - specified by the engine exists. If not, it will use the ResolvePathCaseInsensitive function - which will try to determine if an actual filesystem path matches the - specified path case insensitive. If one is found, the actual path - transparently (we hope) replaces the one requested by the engine. - - The preference directory is global to all torque executables with the same - name. You should make sure you keep it clean if you build from multiple - torque development trees. - */ - - // evil hack to get around insane X windows #define-happy header files - #ifdef Status - #undef Status - #endif - - #include "platformX86UNIX/platformX86UNIX.h" - #include "core/fileio.h" - #include "core/util/tVector.h" - #include "core/stringTable.h" - #include "console/console.h" - #include "core/strings/stringFunctions.h" - #include "util/tempAlloc.h" - #include "cinterface/c_controlInterface.h" - #include "core/volume.h" - - #if defined(__FreeBSD__) - #include - #endif - #include - - /* these are for reading directors, getting stats, etc. */ - #include - #include - #include - #include - #include - #include - #include - - extern int x86UNIXOpen(const char *path, int oflag); - extern int x86UNIXClose(int fd); - extern ssize_t x86UNIXRead(int fd, void *buf, size_t nbytes); - extern ssize_t x86UNIXWrite(int fd, const void *buf, size_t nbytes); - extern bool ResolvePathCaseInsensitive(char* pathName, S32 pathNameSize, bool requiredAbsolute); - - const int MaxPath = PATH_MAX; - - namespace - { - const char sTempDir[] = "/tmp/"; - - static char sBinPathName[MaxPath] = ""; - static char *sBinName = sBinPathName; - bool sUseRedirect = true; - } - - StringTableEntry osGetTemporaryDirectory() - { - return StringTable->insert(sTempDir); - } - - // Various handy utility functions: - //------------------------------------------------------------------------------ - // find all \ in a path and convert them in place to / - static void ForwardSlash(char *str) - { - while(*str) - { - if(*str == '\\') - *str = '/'; - str++; - } - } - - //------------------------------------------------------------------------------ - // copy a file from src to dest - static bool CopyFile(const char* src, const char* dest) - { - S32 srcFd = x86UNIXOpen(src, O_RDONLY); - S32 destFd = x86UNIXOpen(dest, O_WRONLY | O_CREAT | O_TRUNC); - bool error = false; - - if (srcFd != -1 && destFd != -1) - { - const int BufSize = 8192; - char buf[BufSize]; - S32 bytesRead = 0; - while ((bytesRead = x86UNIXRead(srcFd, buf, BufSize)) > 0) - { - // write data - if (x86UNIXWrite(destFd, buf, bytesRead) == -1) - { - error = true; - break; - } - } - - if (bytesRead == -1) - error = true; - } - - if (srcFd != -1) - x86UNIXClose(srcFd); - if (destFd != -1) - x86UNIXClose(destFd); - - if (error) - { - Con::errorf("Error copying file: %s, %s", src, dest); - remove(dest); - } - return error; - } - -bool dPathCopy(const char *fromName, const char *toName, bool nooverwrite) -{ - return CopyFile(fromName,toName); -} - - //----------------------------------------------------------------------------- - static char sgPrefDir[MaxPath]; - static bool sgPrefDirInitialized = false; - - // get the "pref dir", which is where game output files are stored. the pref - // dir is ~/PREF_DIR_ROOT/PREF_DIR_GAME_NAME - static const char* GetPrefDir() - { - if (sgPrefDirInitialized) - return sgPrefDir; - - if (sUseRedirect) - { - const char *home = getenv("HOME"); - AssertFatal(home, "HOME environment variable must be set"); - - dSprintf(sgPrefDir, MaxPath, "%s/%s/%s", - home, PREF_DIR_ROOT, PREF_DIR_GAME_NAME); - } - else - { - getcwd(sgPrefDir, MaxPath); - } - - sgPrefDirInitialized = true; - return sgPrefDir; - } - - //----------------------------------------------------------------------------- - // Returns true if the pathname exists, false otherwise. If isFile is true, - // the pathname is assumed to be a file path, and only the directory part - // will be examined (everything before last /) - bool DirExists(char* pathname, bool isFile) - { - static char testpath[20000]; - dStrncpy(testpath, pathname, sizeof(testpath)); - if (isFile) - { - // find the last / and make it into null - char* lastSlash = dStrrchr(testpath, '/'); - if (lastSlash != NULL) - *lastSlash = 0; - } - return Platform::isDirectory(testpath); - } - - //----------------------------------------------------------------------------- - // Munge the specified path. - static void MungePath(char* dest, S32 destSize, - const char* src, const char* absolutePrefix) - { - char tempBuf[MaxPath]; - dStrncpy(dest, src, MaxPath); - - // translate all \ to / - ForwardSlash(dest); - - // if it is relative, make it absolute with the absolutePrefix - if (dest[0] != '/') - { - AssertFatal(absolutePrefix, "Absolute Prefix must not be NULL"); - - dSprintf(tempBuf, MaxPath, "%s/%s", - absolutePrefix, dest); - - // copy the result back into dest - dStrncpy(dest, tempBuf, destSize); - } - - // if the path exists, we're done - struct stat filestat; - if (stat(dest, &filestat) != -1) - return; - - // otherwise munge the case of the path - ResolvePathCaseInsensitive(dest, destSize, true); - } - - //----------------------------------------------------------------------------- - enum - { - TOUCH, - DELETE - }; - - //----------------------------------------------------------------------------- - // perform a modification on the specified file. allowed modifications are - // specified in the enum above. - bool ModifyFile(const char * name, S32 modType) - { - if(!name || (dStrlen(name) >= MaxPath) || dStrstr(name, "../") != NULL) - return(false); - - // if its absolute skip it - if (name[0]=='/' || name[0]=='\\') - return(false); - - // only modify files in home directory - char prefPathName[MaxPath]; - MungePath(prefPathName, MaxPath, name, GetPrefDir()); - - if (modType == TOUCH) - return(utime(prefPathName, 0) != -1); - else if (modType == DELETE) - return (remove(prefPathName) == 0); - else - AssertFatal(false, "Unknown File Mod type"); - return false; - } - - //----------------------------------------------------------------------------- - static bool RecurseDumpPath(const char *path, const char* relativePath, const char *pattern, Vector &fileVector, S32 currentDepth = 0, S32 recurseDepth = -1) - { - char search[1024]; - - dSprintf(search, sizeof(search), "%s", path, pattern); - - DIR *directory = opendir(search); - - if (directory == NULL) - return false; - - struct dirent *fEntry; - fEntry = readdir(directory); // read the first "file" in the directory - - if (fEntry == NULL) - { - closedir(directory); - return false; - } - - do - { - char filename[BUFSIZ+1]; - struct stat fStat; - - dSprintf(filename, sizeof(filename), "%s/%s", search, fEntry->d_name); // "construct" the file name - stat(filename, &fStat); // get the file stats - - if ( (fStat.st_mode & S_IFMT) == S_IFDIR ) - { - // Directory - // skip . and .. directories - if (dStrcmp(fEntry->d_name, ".") == 0 || dStrcmp(fEntry->d_name, "..") == 0) - continue; - - // skip excluded directories - if( Platform::isExcludedDirectory(fEntry->d_name)) - continue; - - - char child[MaxPath]; - dSprintf(child, sizeof(child), "%s/%s", path, fEntry->d_name); - char* childRelative = NULL; - char childRelativeBuf[MaxPath]; - if (relativePath) - { - dSprintf(childRelativeBuf, sizeof(childRelativeBuf), "%s/%s", - relativePath, fEntry->d_name); - childRelative = childRelativeBuf; - } - if (currentDepth < recurseDepth || recurseDepth == -1 ) - RecurseDumpPath(child, childRelative, pattern, fileVector, currentDepth+1, recurseDepth); - } - else - { - // File - - // add it to the list - fileVector.increment(); - Platform::FileInfo& rInfo = fileVector.last(); - - if (relativePath) - rInfo.pFullPath = StringTable->insert(relativePath); - else - rInfo.pFullPath = StringTable->insert(path); - rInfo.pFileName = StringTable->insert(fEntry->d_name); - rInfo.fileSize = fStat.st_size; - //dPrintf("Adding file: %s/%s\n", rInfo.pFullPath, rInfo.pFileName); - } - - } while( (fEntry = readdir(directory)) != NULL ); - - closedir(directory); - return true; - } - - //----------------------------------------------------------------------------- - bool dFileDelete(const char * name) - { - return ModifyFile(name, DELETE); - } - - //----------------------------------------------------------------------------- - bool dFileTouch(const char * name) - { - return ModifyFile(name, TOUCH); - } - - bool dFileRename(const char *oldName, const char *newName) - { - AssertFatal( oldName != NULL && newName != NULL, "dFileRename - NULL file name" ); - - // only modify files in home directory - TempAlloc oldPrefPathName(MaxPath); - TempAlloc newPrefPathName(MaxPath); - MungePath(oldPrefPathName, MaxPath, oldName, GetPrefDir()); - MungePath(newPrefPathName, MaxPath, newName, GetPrefDir()); - - return rename(oldPrefPathName, newPrefPathName) == 0; - } - - //----------------------------------------------------------------------------- - // Constructors & Destructor - //----------------------------------------------------------------------------- - - //----------------------------------------------------------------------------- - // After construction, the currentStatus will be Closed and the capabilities - // will be 0. - //----------------------------------------------------------------------------- - File::File() - : currentStatus(Closed), capability(0) - { - // AssertFatal(sizeof(int) == sizeof(void *), "File::File: cannot cast void* to int"); - - handle = (void *)NULL; - } - - //----------------------------------------------------------------------------- - // insert a copy constructor here... (currently disabled) - //----------------------------------------------------------------------------- - - //----------------------------------------------------------------------------- - // Destructor - //----------------------------------------------------------------------------- - File::~File() - { - close(); - handle = (void *)NULL; - } - - //----------------------------------------------------------------------------- - // Open a file in the mode specified by openMode (Read, Write, or ReadWrite). - // Truncate the file if the mode is either Write or ReadWrite and truncate is - // true. - // - // Sets capability appropriate to the openMode. - // Returns the currentStatus of the file. - //----------------------------------------------------------------------------- - File::FileStatus File::open(const char *filename, const AccessMode openMode) - { - AssertFatal(NULL != filename, "File::open: NULL filename"); - AssertWarn(NULL == handle, "File::open: handle already valid"); - - // Close the file if it was already open... - if (Closed != currentStatus) - close(); - - char prefPathName[MaxPath]; - char gamePathName[MaxPath]; - char cwd[MaxPath]; - getcwd(cwd, MaxPath); - MungePath(prefPathName, MaxPath, filename, GetPrefDir()); - MungePath(gamePathName, MaxPath, filename, cwd); - - int oflag; - struct stat filestat; - handle = (void *)dRealMalloc(sizeof(int)); - - switch (openMode) - { - case Read: - oflag = O_RDONLY; - break; - case Write: - oflag = O_WRONLY | O_CREAT | O_TRUNC; - break; - case ReadWrite: - oflag = O_RDWR | O_CREAT; - // if the file does not exist copy it before reading/writing - if (stat(prefPathName, &filestat) == -1) - bool ret = CopyFile(gamePathName, prefPathName); - break; - case WriteAppend: - oflag = O_WRONLY | O_CREAT | O_APPEND; - // if the file does not exist copy it before appending - if (stat(prefPathName, &filestat) == -1) - bool ret = CopyFile(gamePathName, prefPathName); - break; - default: - AssertFatal(false, "File::open: bad access mode"); // impossible - } - - // if we are writing, make sure output path exists - if (openMode == Write || openMode == ReadWrite || openMode == WriteAppend) - Platform::createPath(prefPathName); - - int fd = -1; - fd = x86UNIXOpen(prefPathName, oflag); - if (fd == -1 && openMode == Read) - // for read only files we can use the gamePathName - fd = x86UNIXOpen(gamePathName, oflag); - - dMemcpy(handle, &fd, sizeof(int)); - - #ifdef DEBUG - // fprintf(stdout,"fd = %d, handle = %d\n", fd, *((int *)handle)); - #endif - - if (*((int *)handle) == -1) - { - // handle not created successfully - Con::errorf("Can't open file: %s", filename); - return setStatus(); - } - else - { - // successfully created file, so set the file capabilities... - switch (openMode) - { - case Read: - capability = U32(FileRead); - break; - case Write: - case WriteAppend: - capability = U32(FileWrite); - break; - case ReadWrite: - capability = U32(FileRead) | - U32(FileWrite); - break; - default: - AssertFatal(false, "File::open: bad access mode"); - } - return currentStatus = Ok; // success! - } - } - - //----------------------------------------------------------------------------- - // Get the current position of the file pointer. - //----------------------------------------------------------------------------- - U32 File::getPosition() const - { - AssertFatal(Closed != currentStatus, "File::getPosition: file closed"); - AssertFatal(NULL != handle, "File::getPosition: invalid file handle"); - - #ifdef DEBUG - // fprintf(stdout, "handle = %d\n",*((int *)handle));fflush(stdout); - #endif - return (U32) lseek(*((int *)handle), 0, SEEK_CUR); - } - - //----------------------------------------------------------------------------- - // Set the position of the file pointer. - // Absolute and relative positioning is supported via the absolutePos - // parameter. - // - // If positioning absolutely, position MUST be positive - an IOError results if - // position is negative. - // Position can be negative if positioning relatively, however positioning - // before the start of the file is an IOError. - // - // Returns the currentStatus of the file. - //----------------------------------------------------------------------------- - File::FileStatus File::setPosition(S32 position, bool absolutePos) - { - AssertFatal(Closed != currentStatus, "File::setPosition: file closed"); - AssertFatal(NULL != handle, "File::setPosition: invalid file handle"); - - if (Ok != currentStatus && EOS != currentStatus) - return currentStatus; - - U32 finalPos = 0; - - if (absolutePos) - { - AssertFatal(0 <= position, "File::setPosition: negative absolute position"); - - // position beyond EOS is OK - finalPos = lseek(*((int *)handle), position, SEEK_SET); - } - else - { - AssertFatal((getPosition() >= (U32)abs(position) && 0 > position) || 0 <= position, "File::setPosition: negative relative position"); - - // position beyond EOS is OK - finalPos = lseek(*((int *)handle), position, SEEK_CUR); - } - - if (0xffffffff == finalPos) - return setStatus(); // unsuccessful - else if (finalPos >= getSize()) - return currentStatus = EOS; // success, at end of file - else - return currentStatus = Ok; // success! - } - - //----------------------------------------------------------------------------- - // Get the size of the file in bytes. - // It is an error to query the file size for a Closed file, or for one with an - // error status. - //----------------------------------------------------------------------------- - U32 File::getSize() const - { - AssertWarn(Closed != currentStatus, "File::getSize: file closed"); - AssertFatal(NULL != handle, "File::getSize: invalid file handle"); - - if (Ok == currentStatus || EOS == currentStatus) - { - long currentOffset = getPosition(); // keep track of our current position - long fileSize; - lseek(*((int *)handle), 0, SEEK_END); // seek to the end of the file - fileSize = getPosition(); // get the file size - lseek(*((int *)handle), currentOffset, SEEK_SET); // seek back to our old offset - return fileSize; // success! - } - else - return 0; // unsuccessful - } - - //----------------------------------------------------------------------------- - // Flush the file. - // It is an error to flush a read-only file. - // Returns the currentStatus of the file. - //----------------------------------------------------------------------------- - File::FileStatus File::flush() - { - AssertFatal(Closed != currentStatus, "File::flush: file closed"); - AssertFatal(NULL != handle, "File::flush: invalid file handle"); - AssertFatal(true == hasCapability(FileWrite), "File::flush: cannot flush a read-only file"); - - if (fsync(*((int *)handle)) == 0) - return currentStatus = Ok; // success! - else - return setStatus(); // unsuccessful - } - - //----------------------------------------------------------------------------- - // Close the File. - // - // Returns the currentStatus - //----------------------------------------------------------------------------- - File::FileStatus File::close() - { - // if the handle is non-NULL, close it if necessary and free it - if (NULL != handle) - { - // make a local copy of the handle value and - // free the handle - int handleVal = *((int *)handle); - dRealFree(handle); - handle = (void *)NULL; - - // close the handle if it is valid - if (handleVal != -1 && x86UNIXClose(handleVal) != 0) - return setStatus(); // unsuccessful - } - // Set the status to closed - return currentStatus = Closed; - } - - //----------------------------------------------------------------------------- - // Self-explanatory. - //----------------------------------------------------------------------------- - File::FileStatus File::getStatus() const - { - return currentStatus; - } - - //----------------------------------------------------------------------------- - // Sets and returns the currentStatus when an error has been encountered. - //----------------------------------------------------------------------------- - File::FileStatus File::setStatus() - { - Con::printf("File IO error: %s", strerror(errno)); - return currentStatus = IOError; - } - - //----------------------------------------------------------------------------- - // Sets and returns the currentStatus to status. - //----------------------------------------------------------------------------- - File::FileStatus File::setStatus(File::FileStatus status) - { - return currentStatus = status; - } - - //----------------------------------------------------------------------------- - // Read from a file. - // The number of bytes to read is passed in size, the data is returned in src. - // The number of bytes read is available in bytesRead if a non-Null pointer is - // provided. - //----------------------------------------------------------------------------- - File::FileStatus File::read(U32 size, char *dst, U32 *bytesRead) - { - #ifdef DEBUG - // fprintf(stdout,"reading %d bytes\n",size);fflush(stdout); - #endif - AssertFatal(Closed != currentStatus, "File::read: file closed"); - AssertFatal(NULL != handle, "File::read: invalid file handle"); - AssertFatal(NULL != dst, "File::read: NULL destination pointer"); - AssertFatal(true == hasCapability(FileRead), "File::read: file lacks capability"); - AssertWarn(0 != size, "File::read: size of zero"); - - /* show stats for this file */ - #ifdef DEBUG - //struct stat st; - //fstat(*((int *)handle), &st); - //fprintf(stdout,"file size = %d\n", st.st_size); - #endif - /****************************/ - - if (Ok != currentStatus || 0 == size) - return currentStatus; - else - { - long lastBytes; - long *bytes = (NULL == bytesRead) ? &lastBytes : (long *)bytesRead; - if ( (*((U32 *)bytes) = x86UNIXRead(*((int *)handle), dst, size)) == -1) - { - #ifdef DEBUG - // fprintf(stdout,"unsuccessful: %d\n", *((U32 *)bytes));fflush(stdout); - #endif - return setStatus(); // unsuccessful - } else { - // dst[*((U32 *)bytes)] = '\0'; - if (*((U32 *)bytes) != size || *((U32 *)bytes) == 0) { - #ifdef DEBUG - // fprintf(stdout,"end of stream: %d\n", *((U32 *)bytes));fflush(stdout); - #endif - return currentStatus = EOS; // end of stream - } - } - } - // dst[*bytesRead] = '\0'; - #ifdef DEBUG - //fprintf(stdout, "We read:\n"); - //fprintf(stdout, "====================================================\n"); - //fprintf(stdout, "%s\n",dst); - //fprintf(stdout, "====================================================\n"); - //fprintf(stdout,"read ok: %d\n", *bytesRead);fflush(stdout); - #endif - return currentStatus = Ok; // successfully read size bytes - } - - //----------------------------------------------------------------------------- - // Write to a file. - // The number of bytes to write is passed in size, the data is passed in src. - // The number of bytes written is available in bytesWritten if a non-Null - // pointer is provided. - //----------------------------------------------------------------------------- - File::FileStatus File::write(U32 size, const char *src, U32 *bytesWritten) - { - // JMQ: despite the U32 parameters, the maximum filesize supported by this - // function is probably the max value of S32, due to the unix syscall - // api. - AssertFatal(Closed != currentStatus, "File::write: file closed"); - AssertFatal(NULL != handle, "File::write: invalid file handle"); - AssertFatal(NULL != src, "File::write: NULL source pointer"); - AssertFatal(true == hasCapability(FileWrite), "File::write: file lacks capability"); - AssertWarn(0 != size, "File::write: size of zero"); - - if ((Ok != currentStatus && EOS != currentStatus) || 0 == size) - return currentStatus; - else - { - S32 numWritten = x86UNIXWrite(*((int *)handle), src, size); - if (numWritten < 0) - return setStatus(); - - if (bytesWritten) - *bytesWritten = static_cast(numWritten); - return currentStatus = Ok; - } - } - - //----------------------------------------------------------------------------- - // Self-explanatory. JMQ: No explanation needed. Move along. These aren't - // the droids you're looking for. - //----------------------------------------------------------------------------- - bool File::hasCapability(Capability cap) const - { - return (0 != (U32(cap) & capability)); - } - - //----------------------------------------------------------------------------- - S32 Platform::compareFileTimes(const FileTime &a, const FileTime &b) - { - if(a > b) - return 1; - if(a < b) - return -1; - return 0; - } - - //----------------------------------------------------------------------------- - static bool GetFileTimes(const char *filePath, FileTime *createTime, FileTime *modifyTime) - { - struct stat fStat; - - if (stat(filePath, &fStat) == -1) - return false; - - if(createTime) - { - // no where does SysV/BSD UNIX keep a record of a file's - // creation time. instead of creation time I'll just use - // changed time for now. - *createTime = fStat.st_ctime; - } - if(modifyTime) - { - *modifyTime = fStat.st_mtime; - } - - return true; - } - - //----------------------------------------------------------------------------- - bool Platform::getFileTimes(const char *filePath, FileTime *createTime, FileTime *modifyTime) - { - char pathName[MaxPath]; - - // if it starts with cwd, we need to strip that off so that we can look for - // the file in the pref dir - char cwd[MaxPath]; - getcwd(cwd, MaxPath); - if (dStrstr(filePath, cwd) == filePath) - filePath = filePath + dStrlen(cwd) + 1; - - // if its relative, first look in the pref dir - if (filePath[0] != '/' && filePath[0] != '\\') - { - MungePath(pathName, MaxPath, filePath, GetPrefDir()); - if (GetFileTimes(pathName, createTime, modifyTime)) - return true; - } - - // here if the path is absolute or not in the pref dir - MungePath(pathName, MaxPath, filePath, cwd); - return GetFileTimes(pathName, createTime, modifyTime); - } - - //----------------------------------------------------------------------------- - bool Platform::createPath(const char *file) - { - char pathbuf[MaxPath]; - const char *dir; - pathbuf[0] = 0; - U32 pathLen = 0; - - // all paths should be created in home directory - char prefPathName[MaxPath]; - MungePath(prefPathName, MaxPath, file, GetPrefDir()); - file = prefPathName; - - // does the directory exist already? - if (DirExists(prefPathName, true)) // true means that the path is a filepath - return true; - - while((dir = dStrchr(file, '/')) != NULL) - { - dStrncpy(pathbuf + pathLen, file, dir - file); - pathbuf[pathLen + dir-file] = 0; - bool ret = mkdir(pathbuf, 0700); - pathLen += dir - file; - pathbuf[pathLen++] = '/'; - file = dir + 1; - } - return true; - } - - // JMQ: Platform:cdFileExists in unimplemented - //------------------------------------------------------------------------------ - // bool Platform::cdFileExists(const char *filePath, const char *volumeName, - // S32 serialNum) - // { - // } - - //----------------------------------------------------------------------------- - bool Platform::dumpPath(const char *path, Vector &fileVector, int depth) - { - const char* pattern = "*"; - - // if it is not absolute, dump the pref dir first - if (path[0] != '/' && path[0] != '\\') - { - char prefPathName[MaxPath]; - MungePath(prefPathName, MaxPath, path, GetPrefDir()); - RecurseDumpPath(prefPathName, path, pattern, fileVector, 0, depth); - } - - // munge the requested path and dump it - char mungedPath[MaxPath]; - char cwd[MaxPath]; - getcwd(cwd, MaxPath); - MungePath(mungedPath, MaxPath, path, cwd); - return RecurseDumpPath(mungedPath, path, pattern, fileVector, 0, depth); - } - - //----------------------------------------------------------------------------- - StringTableEntry Platform::getCurrentDirectory() - { - char cwd_buf[2048]; - getcwd(cwd_buf, 2047); - return StringTable->insert(cwd_buf); - } - - //----------------------------------------------------------------------------- - bool Platform::setCurrentDirectory(StringTableEntry newDir) - { - if (Platform::getWebDeployment()) - return true; - - TempAlloc< UTF8 > buf( dStrlen( newDir ) + 2 ); - - dStrcpy( buf, newDir, buf.size ); - - ForwardSlash( buf ); - return chdir( buf ) == 0; - } - - //----------------------------------------------------------------------------- - const char *Platform::getUserDataDirectory() - { - return StringTable->insert( GetPrefDir() ); - } - - //----------------------------------------------------------------------------- - StringTableEntry Platform::getUserHomeDirectory() - { - char *home = getenv( "HOME" ); - return StringTable->insert( home ); - } - - StringTableEntry Platform::getExecutablePath() -{ - if( !sBinPathName[0] ) - { - const char *cpath; - if( (cpath = torque_getexecutablepath()) ) - { - dStrncpy(sBinPathName, cpath, sizeof(sBinPathName)); - chdir(sBinPathName); - } - else - { - getcwd(sBinPathName, sizeof(sBinPathName)-1); - } - } - - return StringTable->insert(sBinPathName); -} - - //----------------------------------------------------------------------------- - bool Platform::isFile(const char *pFilePath) - { - if (!pFilePath || !*pFilePath) - return false; - // Get file info - struct stat fStat; - if (stat(pFilePath, &fStat) < 0) - { - // Since file does not exist on disk see if it exists in a zip file loaded - return Torque::FS::IsFile(pFilePath); - } - - // if the file is a "regular file" then true - if ( (fStat.st_mode & S_IFMT) == S_IFREG) - return true; - // must be some other file (directory, device, etc.) - return false; - } - - //----------------------------------------------------------------------------- - S32 Platform::getFileSize(const char *pFilePath) - { - if (!pFilePath || !*pFilePath) - return -1; - // Get the file info - struct stat fStat; - if (stat(pFilePath, &fStat) < 0) - return -1; - // if the file is a "regular file" then return the size - if ( (fStat.st_mode & S_IFMT) == S_IFREG) - return fStat.st_size; - // Must be something else or we can't read the file. - return -1; - } - - //----------------------------------------------------------------------------- - bool Platform::isDirectory(const char *pDirPath) - { - if (!pDirPath || !*pDirPath) - return false; - - // Get file info - struct stat fStat; - if (stat(pDirPath, &fStat) < 0) - return false; - - // if the file is a Directory then true - if ( (fStat.st_mode & S_IFMT) == S_IFDIR) - return true; - - return false; - } - - //----------------------------------------------------------------------------- - bool Platform::isSubDirectory(const char *pParent, const char *pDir) - { - if (!pParent || !*pDir) - return false; - - // this is somewhat of a brute force method but we need to be 100% sure - // that the user cannot enter things like ../dir or /dir etc,... - DIR *directory; - - directory = opendir(pParent); - if (directory == NULL) - return false; - - struct dirent *fEntry; - fEntry = readdir(directory); - if ( fEntry == NULL ) - { - closedir(directory); - return false; - } - - do - { - char dirBuf[MaxPath]; - struct stat fStat; - - dSprintf(dirBuf, sizeof(dirBuf), "%s/%s", pParent, fEntry->d_name); - if (stat(dirBuf, &fStat) < 0) - continue; - // if it is a directory... - if ( (fStat.st_mode & S_IFMT) == S_IFDIR) - { - // and the names match - if (dStrcmp(pDir, fEntry->d_name ) == 0) - { - // then we have a real sub directory - closedir(directory); - return true; - } - } - } while( (fEntry = readdir(directory)) != NULL ); - - closedir(directory); - return false; - } - - //----------------------------------------------------------------------------- - - - // This is untested -- BJG - - bool Platform::fileTimeToString(FileTime * time, char * string, U32 strLen) - { - if(!time || !string) - return(false); - - dSprintf(string, strLen, "%ld", *time); - return(true); - } - - bool Platform::stringToFileTime(const char * string, FileTime * time) - { - if(!time || !string) - return(false); - - *time = dAtoi(string); - - return(true); - } - - bool Platform::hasSubDirectory(const char *pPath) - { - if (!pPath) - return false; - - struct dirent *d; - DIR *dip; - dip = opendir(pPath); - if (dip == NULL) - return false; - - while ((d = readdir(dip))) - { - bool isDir = false; - if (d->d_type == DT_UNKNOWN) - { - char child [1024]; - if ((pPath[dStrlen(pPath) - 1] == '/')) - dSprintf(child, 1024, "%s%s", pPath, d->d_name); - else - dSprintf(child, 1024, "%s/%s", pPath, d->d_name); - isDir = Platform::isDirectory (child); - } - else if (d->d_type & DT_DIR) - isDir = true; - if( isDir ) - { - // Skip the . and .. directories - if (dStrcmp(d->d_name, ".") == 0 ||dStrcmp(d->d_name, "..") == 0) - continue; - if (Platform::isExcludedDirectory(d->d_name)) - continue; - Platform::clearExcludedDirectories(); - closedir(dip); - return true; - } - } - closedir(dip); - Platform::clearExcludedDirectories(); - return false; - } - - bool Platform::fileDelete(const char * name) - { - return ModifyFile(name, DELETE); - } - - static bool recurseDumpDirectories(const char *basePath, const char *subPath, Vector &directoryVector, S32 currentDepth, S32 recurseDepth, bool noBasePath) - { - char Path[1024]; - DIR *dip; - struct dirent *d; - - dsize_t trLen = basePath ? dStrlen(basePath) : 0; - dsize_t subtrLen = subPath ? dStrlen(subPath) : 0; - char trail = trLen > 0 ? basePath[trLen - 1] : '\0'; - char subTrail = subtrLen > 0 ? subPath[subtrLen - 1] : '\0'; - char subLead = subtrLen > 0 ? subPath[0] : '\0'; - - if (trail == '/') - { - if (subPath && (dStrncmp(subPath, "", 1) != 0)) - { - if (subTrail == '/') - dSprintf(Path, 1024, "%s%s", basePath, subPath); - else - dSprintf(Path, 1024, "%s%s/", basePath, subPath); - } - else - dSprintf(Path, 1024, "%s", basePath); - } - else - { - if (subPath && (dStrncmp(subPath, "", 1) != 0)) - { - if (subTrail == '/') - dSprintf(Path, 1024, "%s%s", basePath, subPath); - else - dSprintf(Path, 1024, "%s%s/", basePath, subPath); - } - else - dSprintf(Path, 1024, "%s/", basePath); - } - - dip = opendir(Path); - if (dip == NULL) - return false; - - ////////////////////////////////////////////////////////////////////////// - // add path to our return list ( provided it is valid ) - ////////////////////////////////////////////////////////////////////////// - if (!Platform::isExcludedDirectory(subPath)) - { - if (noBasePath) - { - // We have a path and it's not an empty string or an excluded directory - if ( (subPath && (dStrncmp (subPath, "", 1) != 0)) ) - directoryVector.push_back(StringTable->insert(subPath)); - } - else - { - if ( (subPath && (dStrncmp(subPath, "", 1) != 0)) ) - { - char szPath[1024]; - dMemset(szPath, 0, 1024); - if (trail == '/') - { - if ((basePath[dStrlen(basePath) - 1]) != '/') - dSprintf(szPath, 1024, "%s%s", basePath, &subPath[1]); - else - dSprintf(szPath, 1024, "%s%s", basePath, subPath); - } - else - { - if ((basePath[dStrlen(basePath) - 1]) != '/') - dSprintf(szPath, 1024, "%s%s", basePath, subPath); - else - dSprintf(szPath, 1024, "%s/%s", basePath, subPath); - } - - directoryVector.push_back(StringTable->insert(szPath)); - } - else - directoryVector.push_back(StringTable->insert(basePath)); - } - } - ////////////////////////////////////////////////////////////////////////// - // Iterate through and grab valid directories - ////////////////////////////////////////////////////////////////////////// - - while ((d = readdir(dip))) - { - bool isDir; - isDir = false; - if (d->d_type == DT_UNKNOWN) - { - char child [1024]; - if (Path[dStrlen(Path) - 1] == '/') - dSprintf(child, 1024, "%s%s", Path, d->d_name); - else - dSprintf(child, 1024, "%s/%s", Path, d->d_name); - isDir = Platform::isDirectory (child); - } - else if (d->d_type & DT_DIR) - isDir = true; - - if ( isDir ) - { - if (dStrcmp(d->d_name, ".") == 0 || - dStrcmp(d->d_name, "..") == 0) - continue; - if (Platform::isExcludedDirectory(d->d_name)) - continue; - if ( (subPath && (dStrncmp(subPath, "", 1) != 0)) ) - { - char child[1024]; - if ((subPath[dStrlen(subPath) - 1] == '/')) - dSprintf(child, 1024, "%s%s", subPath, d->d_name); - else - dSprintf(child, 1024, "%s/%s", subPath, d->d_name); - if (currentDepth < recurseDepth || recurseDepth == -1 ) - recurseDumpDirectories(basePath, child, directoryVector, - currentDepth + 1, recurseDepth, - noBasePath); - } - else - { - char child[1024]; - if ( (basePath[dStrlen(basePath) - 1]) == '/') - dStrcpy (child, d->d_name, 1024); - else - dSprintf(child, 1024, "/%s", d->d_name); - if (currentDepth < recurseDepth || recurseDepth == -1) - recurseDumpDirectories(basePath, child, directoryVector, - currentDepth + 1, recurseDepth, - noBasePath); - } - } - } - closedir(dip); - return true; - } - - bool Platform::dumpDirectories(const char *path, Vector &directoryVector, S32 depth, bool noBasePath) - { -#ifdef TORQUE_POSIX_PATH_CASE_INSENSITIVE - dsize_t pathLength = dStrlen(path); - char* caseSensitivePath = new char[pathLength + 1]; - - // Load path into temporary buffer - dMemcpy(caseSensitivePath, path, pathLength); - caseSensitivePath[pathLength] = 0x00; - ResolvePathCaseInsensitive(caseSensitivePath, pathLength, false); -#else - const char* caseSensitivePath = path; -#endif - - bool retVal = recurseDumpDirectories(caseSensitivePath, "", directoryVector, -1, depth, noBasePath); - clearExcludedDirectories(); - -#ifdef TORQUE_POSIX_PATH_CASE_INSENSITIVE - delete[] caseSensitivePath; -#endif - return retVal; - } - -StringTableEntry Platform::getExecutableName() -{ - return StringTable->insert(sBinName); -} - -extern "C" -{ - void setExePathName(const char* exePathName) - { - if (exePathName == NULL) - sBinPathName[0] = '\0'; - else - dStrncpy(sBinPathName, exePathName, sizeof(sBinPathName)); - - // set the base exe name field - char *binName = dStrrchr(sBinPathName, '/'); - if( !binName ) - binName = sBinPathName; - else - *binName++ = '\0'; - sBinName = binName; - } -}