POSIXFileio.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. /* JMQ:
  23. Here's the scoop on unix file IO. The windows platform makes some
  24. assumptions about fileio: 1) the file system is case-insensitive, and
  25. 2) the platform can write to the directory in which
  26. the game is running. Both of these are usually false on linux. So, to
  27. compensate, we "route" created files and directories to the user's home
  28. directory (see GetPrefPath()). When a file is to be accessed, the code
  29. looks in the home directory first. If the file is not found there and the
  30. open mode is read only, the code will look in the game installation
  31. directory. Files are never created or modified in the game directory.
  32. For case-sensitivity, the MungePath code will test whether a given path
  33. specified by the engine exists. If not, it will use the ResolvePathCaseInsensitive function
  34. which will try to determine if an actual filesystem path matches the
  35. specified path case insensitive. If one is found, the actual path
  36. transparently (we hope) replaces the one requested by the engine.
  37. The preference directory is global to all torque executables with the same
  38. name. You should make sure you keep it clean if you build from multiple
  39. torque development trees.
  40. */
  41. #if defined(__FreeBSD__)
  42. #include <sys/types.h>
  43. #endif
  44. #if defined(__APPLE__)
  45. #include <sys/syslimits.h>
  46. #endif
  47. #include <utime.h>
  48. /* these are for reading directors, getting stats, etc. */
  49. #include <dirent.h>
  50. #include <sys/types.h>
  51. #include <sys/stat.h>
  52. #include <unistd.h>
  53. #include <fcntl.h>
  54. #include <errno.h>
  55. #include <stdlib.h>
  56. #include "core/fileio.h"
  57. #include "core/util/tVector.h"
  58. #include "core/stringTable.h"
  59. #include "console/console.h"
  60. #include "core/strings/stringFunctions.h"
  61. #include "util/tempAlloc.h"
  62. #include "cinterface/c_controlInterface.h"
  63. #include "core/volume.h"
  64. const int MaxPath = PATH_MAX;
  65. //------------------------------------------------------------------------------
  66. // munge the case of the specified pathName. This means try to find the actual
  67. // filename in with case-insensitive matching on the specified pathName, and
  68. // store the actual found name.
  69. bool ResolvePathCaseInsensitive(char* pathName, S32 pathNameSize, bool requiredAbsolute)
  70. {
  71. char tempBuf[MaxPath];
  72. dStrncpy(tempBuf, pathName, pathNameSize);
  73. // Check if we're an absolute path
  74. if (pathName[0] != '/')
  75. {
  76. AssertFatal(!requiredAbsolute, "PATH must be absolute");
  77. return false;
  78. }
  79. struct stat filestat;
  80. const int MaxPathEl = 200;
  81. char *currChar = pathName;
  82. char testPath[MaxPath];
  83. char pathEl[MaxPathEl];
  84. bool done = false;
  85. bool foundMatch = false;
  86. dStrncpy(tempBuf, "/", MaxPath);
  87. currChar++;
  88. while (!done)
  89. {
  90. char* termChar = dStrchr(currChar, '/');
  91. if (termChar == NULL)
  92. termChar = dStrchr(currChar, '\0');
  93. AssertFatal(termChar, "Can't find / or NULL terminator");
  94. S32 pathElLen = (termChar - currChar);
  95. dStrncpy(pathEl, currChar, pathElLen);
  96. pathEl[pathElLen] = '\0';
  97. dStrncpy(testPath, tempBuf, MaxPath);
  98. dStrcat(testPath, pathEl, MaxPath);
  99. if (stat(testPath, &filestat) != -1)
  100. {
  101. dStrncpy(tempBuf, testPath, MaxPath);
  102. }
  103. else
  104. {
  105. DIR *dir = opendir(tempBuf);
  106. struct dirent* ent;
  107. while (dir != NULL && (ent = readdir(dir)) != NULL)
  108. {
  109. if (dStricmp(pathEl, ent->d_name) == 0)
  110. {
  111. foundMatch = true;
  112. dStrcat(tempBuf, ent->d_name, MaxPath);
  113. break;
  114. }
  115. }
  116. if (!foundMatch)
  117. dStrncpy(tempBuf, testPath, MaxPath);
  118. if (dir)
  119. closedir(dir);
  120. }
  121. if (*termChar == '/')
  122. {
  123. dStrcat(tempBuf, "/", MaxPath);
  124. termChar++;
  125. currChar = termChar;
  126. }
  127. else
  128. done = true;
  129. }
  130. dStrncpy(pathName, tempBuf, pathNameSize);
  131. return foundMatch;
  132. }
  133. #ifndef __APPLE__
  134. // evil hack to get around insane X windows #define-happy header files
  135. #ifdef Status
  136. #undef Status
  137. #endif
  138. #include "platformPOSIX/platformPOSIX.h"
  139. extern int x86UNIXOpen(const char *path, int oflag);
  140. extern int x86UNIXClose(int fd);
  141. extern ssize_t x86UNIXRead(int fd, void *buf, size_t nbytes);
  142. extern ssize_t x86UNIXWrite(int fd, const void *buf, size_t nbytes);
  143. extern bool ResolvePathCaseInsensitive(char* pathName, S32 pathNameSize, bool requiredAbsolute);
  144. namespace
  145. {
  146. const char sTempDir[] = "/tmp/";
  147. static char sBinPathName[MaxPath] = "";
  148. static char *sBinName = sBinPathName;
  149. bool sUseRedirect = true;
  150. }
  151. StringTableEntry osGetTemporaryDirectory()
  152. {
  153. return StringTable->insert(sTempDir);
  154. }
  155. // Various handy utility functions:
  156. //------------------------------------------------------------------------------
  157. // find all \ in a path and convert them in place to /
  158. static void ForwardSlash(char *str)
  159. {
  160. while(*str)
  161. {
  162. if(*str == '\\')
  163. *str = '/';
  164. str++;
  165. }
  166. }
  167. //------------------------------------------------------------------------------
  168. // copy a file from src to dest
  169. static bool CopyFile(const char* src, const char* dest)
  170. {
  171. S32 srcFd = x86UNIXOpen(src, O_RDONLY);
  172. S32 destFd = x86UNIXOpen(dest, O_WRONLY | O_CREAT | O_TRUNC);
  173. bool error = false;
  174. if (srcFd != -1 && destFd != -1)
  175. {
  176. const int BufSize = 8192;
  177. char buf[BufSize];
  178. S32 bytesRead = 0;
  179. while ((bytesRead = x86UNIXRead(srcFd, buf, BufSize)) > 0)
  180. {
  181. // write data
  182. if (x86UNIXWrite(destFd, buf, bytesRead) == -1)
  183. {
  184. error = true;
  185. break;
  186. }
  187. }
  188. if (bytesRead == -1)
  189. error = true;
  190. }
  191. if (srcFd != -1)
  192. x86UNIXClose(srcFd);
  193. if (destFd != -1)
  194. x86UNIXClose(destFd);
  195. if (error)
  196. {
  197. Con::errorf("Error copying file: %s, %s", src, dest);
  198. remove(dest);
  199. }
  200. return error;
  201. }
  202. bool dPathCopy(const char *fromName, const char *toName, bool nooverwrite)
  203. {
  204. return CopyFile(fromName,toName);
  205. }
  206. //-----------------------------------------------------------------------------
  207. static char sgPrefDir[MaxPath];
  208. static bool sgPrefDirInitialized = false;
  209. // get the "pref dir", which is where game output files are stored. the pref
  210. // dir is ~/PREF_DIR_ROOT/PREF_DIR_GAME_NAME
  211. static const char* GetPrefDir()
  212. {
  213. if (sgPrefDirInitialized)
  214. return sgPrefDir;
  215. if (sUseRedirect)
  216. {
  217. const char *home = getenv("HOME");
  218. AssertFatal(home, "HOME environment variable must be set");
  219. dSprintf(sgPrefDir, MaxPath, "%s/%s/%s",
  220. home, PREF_DIR_ROOT, PREF_DIR_GAME_NAME);
  221. }
  222. else
  223. {
  224. getcwd(sgPrefDir, MaxPath);
  225. }
  226. sgPrefDirInitialized = true;
  227. return sgPrefDir;
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Returns true if the pathname exists, false otherwise. If isFile is true,
  231. // the pathname is assumed to be a file path, and only the directory part
  232. // will be examined (everything before last /)
  233. bool DirExists(char* pathname, bool isFile)
  234. {
  235. static char testpath[20000];
  236. dStrncpy(testpath, pathname, sizeof(testpath));
  237. if (isFile)
  238. {
  239. // find the last / and make it into null
  240. char* lastSlash = dStrrchr(testpath, '/');
  241. if (lastSlash != NULL)
  242. *lastSlash = 0;
  243. }
  244. return Platform::isDirectory(testpath);
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Munge the specified path.
  248. static void MungePath(char* dest, S32 destSize,
  249. const char* src, const char* absolutePrefix)
  250. {
  251. char tempBuf[MaxPath];
  252. dStrncpy(dest, src, MaxPath);
  253. // translate all \ to /
  254. ForwardSlash(dest);
  255. // if it is relative, make it absolute with the absolutePrefix
  256. if (dest[0] != '/')
  257. {
  258. AssertFatal(absolutePrefix, "Absolute Prefix must not be NULL");
  259. dSprintf(tempBuf, MaxPath, "%s/%s",
  260. absolutePrefix, dest);
  261. // copy the result back into dest
  262. dStrncpy(dest, tempBuf, destSize);
  263. }
  264. // if the path exists, we're done
  265. struct stat filestat;
  266. if (stat(dest, &filestat) != -1)
  267. return;
  268. // otherwise munge the case of the path
  269. ResolvePathCaseInsensitive(dest, destSize, true);
  270. }
  271. //-----------------------------------------------------------------------------
  272. enum
  273. {
  274. TOUCH,
  275. DELETE
  276. };
  277. //-----------------------------------------------------------------------------
  278. // perform a modification on the specified file. allowed modifications are
  279. // specified in the enum above.
  280. bool ModifyFile(const char * name, S32 modType)
  281. {
  282. if(!name || (dStrlen(name) >= MaxPath) || dStrstr(name, "../") != NULL)
  283. return(false);
  284. // if its absolute skip it
  285. if (name[0]=='/' || name[0]=='\\')
  286. return(false);
  287. // only modify files in home directory
  288. char prefPathName[MaxPath];
  289. MungePath(prefPathName, MaxPath, name, GetPrefDir());
  290. if (modType == TOUCH)
  291. return(utime(prefPathName, 0) != -1);
  292. else if (modType == DELETE)
  293. return (remove(prefPathName) == 0);
  294. else
  295. AssertFatal(false, "Unknown File Mod type");
  296. return false;
  297. }
  298. //-----------------------------------------------------------------------------
  299. static bool RecurseDumpPath(const char *path, const char* relativePath, const char *pattern, Vector<Platform::FileInfo> &fileVector, S32 currentDepth = 0, S32 recurseDepth = -1)
  300. {
  301. char search[1024];
  302. dSprintf(search, sizeof(search), "%s", path, pattern);
  303. DIR *directory = opendir(search);
  304. if (directory == NULL)
  305. return false;
  306. struct dirent *fEntry;
  307. fEntry = readdir(directory); // read the first "file" in the directory
  308. if (fEntry == NULL)
  309. {
  310. closedir(directory);
  311. return false;
  312. }
  313. do
  314. {
  315. char filename[BUFSIZ+1];
  316. struct stat fStat;
  317. dSprintf(filename, sizeof(filename), "%s/%s", search, fEntry->d_name); // "construct" the file name
  318. stat(filename, &fStat); // get the file stats
  319. if ( (fStat.st_mode & S_IFMT) == S_IFDIR )
  320. {
  321. // Directory
  322. // skip . and .. directories
  323. if (dStrcmp(fEntry->d_name, ".") == 0 || dStrcmp(fEntry->d_name, "..") == 0)
  324. continue;
  325. // skip excluded directories
  326. if( Platform::isExcludedDirectory(fEntry->d_name))
  327. continue;
  328. char child[MaxPath];
  329. dSprintf(child, sizeof(child), "%s/%s", path, fEntry->d_name);
  330. char* childRelative = NULL;
  331. char childRelativeBuf[MaxPath];
  332. if (relativePath)
  333. {
  334. dSprintf(childRelativeBuf, sizeof(childRelativeBuf), "%s/%s",
  335. relativePath, fEntry->d_name);
  336. childRelative = childRelativeBuf;
  337. }
  338. if (currentDepth < recurseDepth || recurseDepth == -1 )
  339. RecurseDumpPath(child, childRelative, pattern, fileVector, currentDepth+1, recurseDepth);
  340. }
  341. else
  342. {
  343. // File
  344. // add it to the list
  345. fileVector.increment();
  346. Platform::FileInfo& rInfo = fileVector.last();
  347. if (relativePath)
  348. rInfo.pFullPath = StringTable->insert(relativePath);
  349. else
  350. rInfo.pFullPath = StringTable->insert(path);
  351. rInfo.pFileName = StringTable->insert(fEntry->d_name);
  352. rInfo.fileSize = fStat.st_size;
  353. //dPrintf("Adding file: %s/%s\n", rInfo.pFullPath, rInfo.pFileName);
  354. }
  355. } while( (fEntry = readdir(directory)) != NULL );
  356. closedir(directory);
  357. return true;
  358. }
  359. //-----------------------------------------------------------------------------
  360. bool dFileDelete(const char * name)
  361. {
  362. return ModifyFile(name, DELETE);
  363. }
  364. //-----------------------------------------------------------------------------
  365. bool dFileTouch(const char * name)
  366. {
  367. return ModifyFile(name, TOUCH);
  368. }
  369. bool dFileRename(const char *oldName, const char *newName)
  370. {
  371. AssertFatal( oldName != NULL && newName != NULL, "dFileRename - NULL file name" );
  372. // only modify files in home directory
  373. TempAlloc<char> oldPrefPathName(MaxPath);
  374. TempAlloc<char> newPrefPathName(MaxPath);
  375. MungePath(oldPrefPathName, MaxPath, oldName, GetPrefDir());
  376. MungePath(newPrefPathName, MaxPath, newName, GetPrefDir());
  377. return rename(oldPrefPathName, newPrefPathName) == 0;
  378. }
  379. //-----------------------------------------------------------------------------
  380. // Constructors & Destructor
  381. //-----------------------------------------------------------------------------
  382. //-----------------------------------------------------------------------------
  383. // After construction, the currentStatus will be Closed and the capabilities
  384. // will be 0.
  385. //-----------------------------------------------------------------------------
  386. File::File()
  387. : currentStatus(Closed), capability(0)
  388. {
  389. // AssertFatal(sizeof(int) == sizeof(void *), "File::File: cannot cast void* to int");
  390. handle = (void *)NULL;
  391. }
  392. //-----------------------------------------------------------------------------
  393. // insert a copy constructor here... (currently disabled)
  394. //-----------------------------------------------------------------------------
  395. //-----------------------------------------------------------------------------
  396. // Destructor
  397. //-----------------------------------------------------------------------------
  398. File::~File()
  399. {
  400. close();
  401. handle = (void *)NULL;
  402. }
  403. //-----------------------------------------------------------------------------
  404. // Open a file in the mode specified by openMode (Read, Write, or ReadWrite).
  405. // Truncate the file if the mode is either Write or ReadWrite and truncate is
  406. // true.
  407. //
  408. // Sets capability appropriate to the openMode.
  409. // Returns the currentStatus of the file.
  410. //-----------------------------------------------------------------------------
  411. File::FileStatus File::open(const char *filename, const AccessMode openMode)
  412. {
  413. AssertFatal(NULL != filename, "File::open: NULL filename");
  414. AssertWarn(NULL == handle, "File::open: handle already valid");
  415. // Close the file if it was already open...
  416. if (Closed != currentStatus)
  417. close();
  418. char prefPathName[MaxPath];
  419. char gamePathName[MaxPath];
  420. char cwd[MaxPath];
  421. getcwd(cwd, MaxPath);
  422. MungePath(prefPathName, MaxPath, filename, GetPrefDir());
  423. MungePath(gamePathName, MaxPath, filename, cwd);
  424. int oflag;
  425. struct stat filestat;
  426. handle = (void *)dRealMalloc(sizeof(int));
  427. switch (openMode)
  428. {
  429. case Read:
  430. oflag = O_RDONLY;
  431. break;
  432. case Write:
  433. oflag = O_WRONLY | O_CREAT | O_TRUNC;
  434. break;
  435. case ReadWrite:
  436. oflag = O_RDWR | O_CREAT;
  437. // if the file does not exist copy it before reading/writing
  438. if (stat(prefPathName, &filestat) == -1)
  439. bool ret = CopyFile(gamePathName, prefPathName);
  440. break;
  441. case WriteAppend:
  442. oflag = O_WRONLY | O_CREAT | O_APPEND;
  443. // if the file does not exist copy it before appending
  444. if (stat(prefPathName, &filestat) == -1)
  445. bool ret = CopyFile(gamePathName, prefPathName);
  446. break;
  447. default:
  448. AssertFatal(false, "File::open: bad access mode"); // impossible
  449. }
  450. // if we are writing, make sure output path exists
  451. if (openMode == Write || openMode == ReadWrite || openMode == WriteAppend)
  452. Platform::createPath(prefPathName);
  453. int fd = -1;
  454. fd = x86UNIXOpen(prefPathName, oflag);
  455. if (fd == -1 && openMode == Read)
  456. // for read only files we can use the gamePathName
  457. fd = x86UNIXOpen(gamePathName, oflag);
  458. dMemcpy(handle, &fd, sizeof(int));
  459. #ifdef DEBUG
  460. // fprintf(stdout,"fd = %d, handle = %d\n", fd, *((int *)handle));
  461. #endif
  462. if (*((int *)handle) == -1)
  463. {
  464. // handle not created successfully
  465. Con::errorf("Can't open file: %s", filename);
  466. return setStatus();
  467. }
  468. else
  469. {
  470. // successfully created file, so set the file capabilities...
  471. switch (openMode)
  472. {
  473. case Read:
  474. capability = U32(FileRead);
  475. break;
  476. case Write:
  477. case WriteAppend:
  478. capability = U32(FileWrite);
  479. break;
  480. case ReadWrite:
  481. capability = U32(FileRead) |
  482. U32(FileWrite);
  483. break;
  484. default:
  485. AssertFatal(false, "File::open: bad access mode");
  486. }
  487. return currentStatus = Ok; // success!
  488. }
  489. }
  490. //-----------------------------------------------------------------------------
  491. // Get the current position of the file pointer.
  492. //-----------------------------------------------------------------------------
  493. U32 File::getPosition() const
  494. {
  495. AssertFatal(Closed != currentStatus, "File::getPosition: file closed");
  496. AssertFatal(NULL != handle, "File::getPosition: invalid file handle");
  497. #ifdef DEBUG
  498. // fprintf(stdout, "handle = %d\n",*((int *)handle));fflush(stdout);
  499. #endif
  500. return (U32) lseek(*((int *)handle), 0, SEEK_CUR);
  501. }
  502. //-----------------------------------------------------------------------------
  503. // Set the position of the file pointer.
  504. // Absolute and relative positioning is supported via the absolutePos
  505. // parameter.
  506. //
  507. // If positioning absolutely, position MUST be positive - an IOError results if
  508. // position is negative.
  509. // Position can be negative if positioning relatively, however positioning
  510. // before the start of the file is an IOError.
  511. //
  512. // Returns the currentStatus of the file.
  513. //-----------------------------------------------------------------------------
  514. File::FileStatus File::setPosition(S32 position, bool absolutePos)
  515. {
  516. AssertFatal(Closed != currentStatus, "File::setPosition: file closed");
  517. AssertFatal(NULL != handle, "File::setPosition: invalid file handle");
  518. if (Ok != currentStatus && EOS != currentStatus)
  519. return currentStatus;
  520. U32 finalPos = 0;
  521. if (absolutePos)
  522. {
  523. AssertFatal(0 <= position, "File::setPosition: negative absolute position");
  524. // position beyond EOS is OK
  525. finalPos = lseek(*((int *)handle), position, SEEK_SET);
  526. }
  527. else
  528. {
  529. AssertFatal((getPosition() >= (U32)abs(position) && 0 > position) || 0 <= position, "File::setPosition: negative relative position");
  530. // position beyond EOS is OK
  531. finalPos = lseek(*((int *)handle), position, SEEK_CUR);
  532. }
  533. if (0xffffffff == finalPos)
  534. return setStatus(); // unsuccessful
  535. else if (finalPos >= getSize())
  536. return currentStatus = EOS; // success, at end of file
  537. else
  538. return currentStatus = Ok; // success!
  539. }
  540. //-----------------------------------------------------------------------------
  541. // Get the size of the file in bytes.
  542. // It is an error to query the file size for a Closed file, or for one with an
  543. // error status.
  544. //-----------------------------------------------------------------------------
  545. U32 File::getSize() const
  546. {
  547. AssertWarn(Closed != currentStatus, "File::getSize: file closed");
  548. AssertFatal(NULL != handle, "File::getSize: invalid file handle");
  549. if (Ok == currentStatus || EOS == currentStatus)
  550. {
  551. long currentOffset = getPosition(); // keep track of our current position
  552. long fileSize;
  553. lseek(*((int *)handle), 0, SEEK_END); // seek to the end of the file
  554. fileSize = getPosition(); // get the file size
  555. lseek(*((int *)handle), currentOffset, SEEK_SET); // seek back to our old offset
  556. return fileSize; // success!
  557. }
  558. else
  559. return 0; // unsuccessful
  560. }
  561. //-----------------------------------------------------------------------------
  562. // Flush the file.
  563. // It is an error to flush a read-only file.
  564. // Returns the currentStatus of the file.
  565. //-----------------------------------------------------------------------------
  566. File::FileStatus File::flush()
  567. {
  568. AssertFatal(Closed != currentStatus, "File::flush: file closed");
  569. AssertFatal(NULL != handle, "File::flush: invalid file handle");
  570. AssertFatal(true == hasCapability(FileWrite), "File::flush: cannot flush a read-only file");
  571. if (fsync(*((int *)handle)) == 0)
  572. return currentStatus = Ok; // success!
  573. else
  574. return setStatus(); // unsuccessful
  575. }
  576. //-----------------------------------------------------------------------------
  577. // Close the File.
  578. //
  579. // Returns the currentStatus
  580. //-----------------------------------------------------------------------------
  581. File::FileStatus File::close()
  582. {
  583. // if the handle is non-NULL, close it if necessary and free it
  584. if (NULL != handle)
  585. {
  586. // make a local copy of the handle value and
  587. // free the handle
  588. int handleVal = *((int *)handle);
  589. dRealFree(handle);
  590. handle = (void *)NULL;
  591. // close the handle if it is valid
  592. if (handleVal != -1 && x86UNIXClose(handleVal) != 0)
  593. return setStatus(); // unsuccessful
  594. }
  595. // Set the status to closed
  596. return currentStatus = Closed;
  597. }
  598. //-----------------------------------------------------------------------------
  599. // Self-explanatory.
  600. //-----------------------------------------------------------------------------
  601. File::FileStatus File::getStatus() const
  602. {
  603. return currentStatus;
  604. }
  605. //-----------------------------------------------------------------------------
  606. // Sets and returns the currentStatus when an error has been encountered.
  607. //-----------------------------------------------------------------------------
  608. File::FileStatus File::setStatus()
  609. {
  610. Con::printf("File IO error: %s", strerror(errno));
  611. return currentStatus = IOError;
  612. }
  613. //-----------------------------------------------------------------------------
  614. // Sets and returns the currentStatus to status.
  615. //-----------------------------------------------------------------------------
  616. File::FileStatus File::setStatus(File::FileStatus status)
  617. {
  618. return currentStatus = status;
  619. }
  620. //-----------------------------------------------------------------------------
  621. // Read from a file.
  622. // The number of bytes to read is passed in size, the data is returned in src.
  623. // The number of bytes read is available in bytesRead if a non-Null pointer is
  624. // provided.
  625. //-----------------------------------------------------------------------------
  626. File::FileStatus File::read(U32 size, char *dst, U32 *bytesRead)
  627. {
  628. #ifdef DEBUG
  629. // fprintf(stdout,"reading %d bytes\n",size);fflush(stdout);
  630. #endif
  631. AssertFatal(Closed != currentStatus, "File::read: file closed");
  632. AssertFatal(NULL != handle, "File::read: invalid file handle");
  633. AssertFatal(NULL != dst, "File::read: NULL destination pointer");
  634. AssertFatal(true == hasCapability(FileRead), "File::read: file lacks capability");
  635. AssertWarn(0 != size, "File::read: size of zero");
  636. /* show stats for this file */
  637. #ifdef DEBUG
  638. //struct stat st;
  639. //fstat(*((int *)handle), &st);
  640. //fprintf(stdout,"file size = %d\n", st.st_size);
  641. #endif
  642. /****************************/
  643. if (Ok != currentStatus || 0 == size)
  644. return currentStatus;
  645. else
  646. {
  647. long lastBytes;
  648. long *bytes = (NULL == bytesRead) ? &lastBytes : (long *)bytesRead;
  649. if ( (*((U32 *)bytes) = x86UNIXRead(*((int *)handle), dst, size)) == -1)
  650. {
  651. #ifdef DEBUG
  652. // fprintf(stdout,"unsuccessful: %d\n", *((U32 *)bytes));fflush(stdout);
  653. #endif
  654. return setStatus(); // unsuccessful
  655. } else {
  656. // dst[*((U32 *)bytes)] = '\0';
  657. if (*((U32 *)bytes) != size || *((U32 *)bytes) == 0) {
  658. #ifdef DEBUG
  659. // fprintf(stdout,"end of stream: %d\n", *((U32 *)bytes));fflush(stdout);
  660. #endif
  661. return currentStatus = EOS; // end of stream
  662. }
  663. }
  664. }
  665. // dst[*bytesRead] = '\0';
  666. #ifdef DEBUG
  667. //fprintf(stdout, "We read:\n");
  668. //fprintf(stdout, "====================================================\n");
  669. //fprintf(stdout, "%s\n",dst);
  670. //fprintf(stdout, "====================================================\n");
  671. //fprintf(stdout,"read ok: %d\n", *bytesRead);fflush(stdout);
  672. #endif
  673. return currentStatus = Ok; // successfully read size bytes
  674. }
  675. //-----------------------------------------------------------------------------
  676. // Write to a file.
  677. // The number of bytes to write is passed in size, the data is passed in src.
  678. // The number of bytes written is available in bytesWritten if a non-Null
  679. // pointer is provided.
  680. //-----------------------------------------------------------------------------
  681. File::FileStatus File::write(U32 size, const char *src, U32 *bytesWritten)
  682. {
  683. // JMQ: despite the U32 parameters, the maximum filesize supported by this
  684. // function is probably the max value of S32, due to the unix syscall
  685. // api.
  686. AssertFatal(Closed != currentStatus, "File::write: file closed");
  687. AssertFatal(NULL != handle, "File::write: invalid file handle");
  688. AssertFatal(NULL != src, "File::write: NULL source pointer");
  689. AssertFatal(true == hasCapability(FileWrite), "File::write: file lacks capability");
  690. AssertWarn(0 != size, "File::write: size of zero");
  691. if ((Ok != currentStatus && EOS != currentStatus) || 0 == size)
  692. return currentStatus;
  693. else
  694. {
  695. S32 numWritten = x86UNIXWrite(*((int *)handle), src, size);
  696. if (numWritten < 0)
  697. return setStatus();
  698. if (bytesWritten)
  699. *bytesWritten = static_cast<U32>(numWritten);
  700. return currentStatus = Ok;
  701. }
  702. }
  703. //-----------------------------------------------------------------------------
  704. // Self-explanatory. JMQ: No explanation needed. Move along. These aren't
  705. // the droids you're looking for.
  706. //-----------------------------------------------------------------------------
  707. bool File::hasCapability(Capability cap) const
  708. {
  709. return (0 != (U32(cap) & capability));
  710. }
  711. //-----------------------------------------------------------------------------
  712. S32 Platform::compareFileTimes(const FileTime &a, const FileTime &b)
  713. {
  714. if(a > b)
  715. return 1;
  716. if(a < b)
  717. return -1;
  718. return 0;
  719. }
  720. //-----------------------------------------------------------------------------
  721. static bool GetFileTimes(const char *filePath, FileTime *createTime, FileTime *modifyTime)
  722. {
  723. struct stat fStat;
  724. if (stat(filePath, &fStat) == -1)
  725. return false;
  726. if(createTime)
  727. {
  728. // no where does SysV/BSD UNIX keep a record of a file's
  729. // creation time. instead of creation time I'll just use
  730. // changed time for now.
  731. *createTime = fStat.st_ctime;
  732. }
  733. if(modifyTime)
  734. {
  735. *modifyTime = fStat.st_mtime;
  736. }
  737. return true;
  738. }
  739. //-----------------------------------------------------------------------------
  740. bool Platform::getFileTimes(const char *filePath, FileTime *createTime, FileTime *modifyTime)
  741. {
  742. char pathName[MaxPath];
  743. // if it starts with cwd, we need to strip that off so that we can look for
  744. // the file in the pref dir
  745. char cwd[MaxPath];
  746. getcwd(cwd, MaxPath);
  747. if (dStrstr(filePath, cwd) == filePath)
  748. filePath = filePath + dStrlen(cwd) + 1;
  749. // if its relative, first look in the pref dir
  750. if (filePath[0] != '/' && filePath[0] != '\\')
  751. {
  752. MungePath(pathName, MaxPath, filePath, GetPrefDir());
  753. if (GetFileTimes(pathName, createTime, modifyTime))
  754. return true;
  755. }
  756. // here if the path is absolute or not in the pref dir
  757. MungePath(pathName, MaxPath, filePath, cwd);
  758. return GetFileTimes(pathName, createTime, modifyTime);
  759. }
  760. //-----------------------------------------------------------------------------
  761. bool Platform::createPath(const char *file)
  762. {
  763. char pathbuf[MaxPath];
  764. const char *dir;
  765. pathbuf[0] = 0;
  766. U32 pathLen = 0;
  767. // all paths should be created in home directory
  768. char prefPathName[MaxPath];
  769. MungePath(prefPathName, MaxPath, file, GetPrefDir());
  770. file = prefPathName;
  771. // does the directory exist already?
  772. if (DirExists(prefPathName, true)) // true means that the path is a filepath
  773. return true;
  774. while((dir = dStrchr(file, '/')) != NULL)
  775. {
  776. dStrncpy(pathbuf + pathLen, file, dir - file);
  777. pathbuf[pathLen + dir-file] = 0;
  778. bool ret = mkdir(pathbuf, 0700);
  779. pathLen += dir - file;
  780. pathbuf[pathLen++] = '/';
  781. file = dir + 1;
  782. }
  783. return true;
  784. }
  785. // JMQ: Platform:cdFileExists in unimplemented
  786. //------------------------------------------------------------------------------
  787. // bool Platform::cdFileExists(const char *filePath, const char *volumeName,
  788. // S32 serialNum)
  789. // {
  790. // }
  791. //-----------------------------------------------------------------------------
  792. bool Platform::dumpPath(const char *path, Vector<Platform::FileInfo> &fileVector, int depth)
  793. {
  794. const char* pattern = "*";
  795. // if it is not absolute, dump the pref dir first
  796. if (path[0] != '/' && path[0] != '\\')
  797. {
  798. char prefPathName[MaxPath];
  799. MungePath(prefPathName, MaxPath, path, GetPrefDir());
  800. RecurseDumpPath(prefPathName, path, pattern, fileVector, 0, depth);
  801. }
  802. // munge the requested path and dump it
  803. char mungedPath[MaxPath];
  804. char cwd[MaxPath];
  805. getcwd(cwd, MaxPath);
  806. MungePath(mungedPath, MaxPath, path, cwd);
  807. return RecurseDumpPath(mungedPath, path, pattern, fileVector, 0, depth);
  808. }
  809. //-----------------------------------------------------------------------------
  810. StringTableEntry Platform::getCurrentDirectory()
  811. {
  812. char cwd_buf[2048];
  813. getcwd(cwd_buf, 2047);
  814. return StringTable->insert(cwd_buf);
  815. }
  816. //-----------------------------------------------------------------------------
  817. bool Platform::setCurrentDirectory(StringTableEntry newDir)
  818. {
  819. if (Platform::getWebDeployment())
  820. return true;
  821. TempAlloc< UTF8 > buf( dStrlen( newDir ) + 2 );
  822. dStrcpy( buf, newDir, buf.size );
  823. ForwardSlash( buf );
  824. return chdir( buf ) == 0;
  825. }
  826. //-----------------------------------------------------------------------------
  827. const char *Platform::getUserDataDirectory()
  828. {
  829. return StringTable->insert( GetPrefDir() );
  830. }
  831. //-----------------------------------------------------------------------------
  832. StringTableEntry Platform::getUserHomeDirectory()
  833. {
  834. char *home = getenv( "HOME" );
  835. return StringTable->insert( home );
  836. }
  837. StringTableEntry Platform::getExecutablePath()
  838. {
  839. if( !sBinPathName[0] )
  840. {
  841. const char *cpath;
  842. if( (cpath = torque_getexecutablepath()) )
  843. {
  844. dStrncpy(sBinPathName, cpath, sizeof(sBinPathName));
  845. chdir(sBinPathName);
  846. }
  847. else
  848. {
  849. getcwd(sBinPathName, sizeof(sBinPathName)-1);
  850. }
  851. }
  852. return StringTable->insert(sBinPathName);
  853. }
  854. //-----------------------------------------------------------------------------
  855. bool Platform::isFile(const char *pFilePath)
  856. {
  857. if (!pFilePath || !*pFilePath)
  858. return false;
  859. // Get file info
  860. struct stat fStat;
  861. if (stat(pFilePath, &fStat) < 0)
  862. {
  863. // Since file does not exist on disk see if it exists in a zip file loaded
  864. return Torque::FS::IsFile(pFilePath);
  865. }
  866. // if the file is a "regular file" then true
  867. if ( (fStat.st_mode & S_IFMT) == S_IFREG)
  868. return true;
  869. // must be some other file (directory, device, etc.)
  870. return false;
  871. }
  872. //-----------------------------------------------------------------------------
  873. S32 Platform::getFileSize(const char *pFilePath)
  874. {
  875. if (!pFilePath || !*pFilePath)
  876. return -1;
  877. // Get the file info
  878. struct stat fStat;
  879. if (stat(pFilePath, &fStat) < 0)
  880. return -1;
  881. // if the file is a "regular file" then return the size
  882. if ( (fStat.st_mode & S_IFMT) == S_IFREG)
  883. return fStat.st_size;
  884. // Must be something else or we can't read the file.
  885. return -1;
  886. }
  887. //-----------------------------------------------------------------------------
  888. bool Platform::isDirectory(const char *pDirPath)
  889. {
  890. if (!pDirPath || !*pDirPath)
  891. return false;
  892. // Get file info
  893. struct stat fStat;
  894. if (stat(pDirPath, &fStat) < 0)
  895. return false;
  896. // if the file is a Directory then true
  897. if ( (fStat.st_mode & S_IFMT) == S_IFDIR)
  898. return true;
  899. return false;
  900. }
  901. //-----------------------------------------------------------------------------
  902. bool Platform::isSubDirectory(const char *pParent, const char *pDir)
  903. {
  904. if (!pParent || !*pDir)
  905. return false;
  906. // this is somewhat of a brute force method but we need to be 100% sure
  907. // that the user cannot enter things like ../dir or /dir etc,...
  908. DIR *directory;
  909. directory = opendir(pParent);
  910. if (directory == NULL)
  911. return false;
  912. struct dirent *fEntry;
  913. fEntry = readdir(directory);
  914. if ( fEntry == NULL )
  915. {
  916. closedir(directory);
  917. return false;
  918. }
  919. do
  920. {
  921. char dirBuf[MaxPath];
  922. struct stat fStat;
  923. dSprintf(dirBuf, sizeof(dirBuf), "%s/%s", pParent, fEntry->d_name);
  924. if (stat(dirBuf, &fStat) < 0)
  925. continue;
  926. // if it is a directory...
  927. if ( (fStat.st_mode & S_IFMT) == S_IFDIR)
  928. {
  929. // and the names match
  930. if (dStrcmp(pDir, fEntry->d_name ) == 0)
  931. {
  932. // then we have a real sub directory
  933. closedir(directory);
  934. return true;
  935. }
  936. }
  937. } while( (fEntry = readdir(directory)) != NULL );
  938. closedir(directory);
  939. return false;
  940. }
  941. //-----------------------------------------------------------------------------
  942. // This is untested -- BJG
  943. bool Platform::fileTimeToString(FileTime * time, char * string, U32 strLen)
  944. {
  945. if(!time || !string)
  946. return(false);
  947. dSprintf(string, strLen, "%ld", *time);
  948. return(true);
  949. }
  950. bool Platform::stringToFileTime(const char * string, FileTime * time)
  951. {
  952. if(!time || !string)
  953. return(false);
  954. *time = dAtoi(string);
  955. return(true);
  956. }
  957. bool Platform::hasSubDirectory(const char *pPath)
  958. {
  959. if (!pPath)
  960. return false;
  961. struct dirent *d;
  962. DIR *dip;
  963. dip = opendir(pPath);
  964. if (dip == NULL)
  965. return false;
  966. while ((d = readdir(dip)))
  967. {
  968. bool isDir = false;
  969. if (d->d_type == DT_UNKNOWN)
  970. {
  971. char child [1024];
  972. if ((pPath[dStrlen(pPath) - 1] == '/'))
  973. dSprintf(child, 1024, "%s%s", pPath, d->d_name);
  974. else
  975. dSprintf(child, 1024, "%s/%s", pPath, d->d_name);
  976. isDir = Platform::isDirectory (child);
  977. }
  978. else if (d->d_type & DT_DIR)
  979. isDir = true;
  980. if( isDir )
  981. {
  982. // Skip the . and .. directories
  983. if (dStrcmp(d->d_name, ".") == 0 ||dStrcmp(d->d_name, "..") == 0)
  984. continue;
  985. if (Platform::isExcludedDirectory(d->d_name))
  986. continue;
  987. Platform::clearExcludedDirectories();
  988. closedir(dip);
  989. return true;
  990. }
  991. }
  992. closedir(dip);
  993. Platform::clearExcludedDirectories();
  994. return false;
  995. }
  996. bool Platform::fileDelete(const char * name)
  997. {
  998. return ModifyFile(name, DELETE);
  999. }
  1000. static bool recurseDumpDirectories(const char *basePath, const char *subPath, Vector<StringTableEntry> &directoryVector, S32 currentDepth, S32 recurseDepth, bool noBasePath)
  1001. {
  1002. char Path[1024];
  1003. DIR *dip;
  1004. struct dirent *d;
  1005. dsize_t trLen = basePath ? dStrlen(basePath) : 0;
  1006. dsize_t subtrLen = subPath ? dStrlen(subPath) : 0;
  1007. char trail = trLen > 0 ? basePath[trLen - 1] : '\0';
  1008. char subTrail = subtrLen > 0 ? subPath[subtrLen - 1] : '\0';
  1009. char subLead = subtrLen > 0 ? subPath[0] : '\0';
  1010. if (trail == '/')
  1011. {
  1012. if (subPath && (dStrncmp(subPath, "", 1) != 0))
  1013. {
  1014. if (subTrail == '/')
  1015. dSprintf(Path, 1024, "%s%s", basePath, subPath);
  1016. else
  1017. dSprintf(Path, 1024, "%s%s/", basePath, subPath);
  1018. }
  1019. else
  1020. dSprintf(Path, 1024, "%s", basePath);
  1021. }
  1022. else
  1023. {
  1024. if (subPath && (dStrncmp(subPath, "", 1) != 0))
  1025. {
  1026. if (subTrail == '/')
  1027. dSprintf(Path, 1024, "%s%s", basePath, subPath);
  1028. else
  1029. dSprintf(Path, 1024, "%s%s/", basePath, subPath);
  1030. }
  1031. else
  1032. dSprintf(Path, 1024, "%s/", basePath);
  1033. }
  1034. dip = opendir(Path);
  1035. if (dip == NULL)
  1036. return false;
  1037. //////////////////////////////////////////////////////////////////////////
  1038. // add path to our return list ( provided it is valid )
  1039. //////////////////////////////////////////////////////////////////////////
  1040. if (!Platform::isExcludedDirectory(subPath))
  1041. {
  1042. if (noBasePath)
  1043. {
  1044. // We have a path and it's not an empty string or an excluded directory
  1045. if ( (subPath && (dStrncmp (subPath, "", 1) != 0)) )
  1046. directoryVector.push_back(StringTable->insert(subPath));
  1047. }
  1048. else
  1049. {
  1050. if ( (subPath && (dStrncmp(subPath, "", 1) != 0)) )
  1051. {
  1052. char szPath[1024];
  1053. dMemset(szPath, 0, 1024);
  1054. if (trail == '/')
  1055. {
  1056. if ((basePath[dStrlen(basePath) - 1]) != '/')
  1057. dSprintf(szPath, 1024, "%s%s", basePath, &subPath[1]);
  1058. else
  1059. dSprintf(szPath, 1024, "%s%s", basePath, subPath);
  1060. }
  1061. else
  1062. {
  1063. if ((basePath[dStrlen(basePath) - 1]) != '/')
  1064. dSprintf(szPath, 1024, "%s%s", basePath, subPath);
  1065. else
  1066. dSprintf(szPath, 1024, "%s/%s", basePath, subPath);
  1067. }
  1068. directoryVector.push_back(StringTable->insert(szPath));
  1069. }
  1070. else
  1071. directoryVector.push_back(StringTable->insert(basePath));
  1072. }
  1073. }
  1074. //////////////////////////////////////////////////////////////////////////
  1075. // Iterate through and grab valid directories
  1076. //////////////////////////////////////////////////////////////////////////
  1077. while ((d = readdir(dip)))
  1078. {
  1079. bool isDir;
  1080. isDir = false;
  1081. if (d->d_type == DT_UNKNOWN)
  1082. {
  1083. char child [1024];
  1084. if (Path[dStrlen(Path) - 1] == '/')
  1085. dSprintf(child, 1024, "%s%s", Path, d->d_name);
  1086. else
  1087. dSprintf(child, 1024, "%s/%s", Path, d->d_name);
  1088. isDir = Platform::isDirectory (child);
  1089. }
  1090. else if (d->d_type & DT_DIR)
  1091. isDir = true;
  1092. if ( isDir )
  1093. {
  1094. if (dStrcmp(d->d_name, ".") == 0 ||
  1095. dStrcmp(d->d_name, "..") == 0)
  1096. continue;
  1097. if (Platform::isExcludedDirectory(d->d_name))
  1098. continue;
  1099. if ( (subPath && (dStrncmp(subPath, "", 1) != 0)) )
  1100. {
  1101. char child[1024];
  1102. if ((subPath[dStrlen(subPath) - 1] == '/'))
  1103. dSprintf(child, 1024, "%s%s", subPath, d->d_name);
  1104. else
  1105. dSprintf(child, 1024, "%s/%s", subPath, d->d_name);
  1106. if (currentDepth < recurseDepth || recurseDepth == -1 )
  1107. recurseDumpDirectories(basePath, child, directoryVector,
  1108. currentDepth + 1, recurseDepth,
  1109. noBasePath);
  1110. }
  1111. else
  1112. {
  1113. char child[1024];
  1114. if ( (basePath[dStrlen(basePath) - 1]) == '/')
  1115. dStrcpy (child, d->d_name, 1024);
  1116. else
  1117. dSprintf(child, 1024, "/%s", d->d_name);
  1118. if (currentDepth < recurseDepth || recurseDepth == -1)
  1119. recurseDumpDirectories(basePath, child, directoryVector,
  1120. currentDepth + 1, recurseDepth,
  1121. noBasePath);
  1122. }
  1123. }
  1124. }
  1125. closedir(dip);
  1126. return true;
  1127. }
  1128. bool Platform::dumpDirectories(const char *path, Vector<StringTableEntry> &directoryVector, S32 depth, bool noBasePath)
  1129. {
  1130. #ifdef TORQUE_POSIX_PATH_CASE_INSENSITIVE
  1131. dsize_t pathLength = dStrlen(path);
  1132. char* caseSensitivePath = new char[pathLength + 1];
  1133. // Load path into temporary buffer
  1134. dMemcpy(caseSensitivePath, path, pathLength);
  1135. caseSensitivePath[pathLength] = 0x00;
  1136. ResolvePathCaseInsensitive(caseSensitivePath, pathLength, false);
  1137. #else
  1138. const char* caseSensitivePath = path;
  1139. #endif
  1140. bool retVal = recurseDumpDirectories(caseSensitivePath, "", directoryVector, -1, depth, noBasePath);
  1141. clearExcludedDirectories();
  1142. #ifdef TORQUE_POSIX_PATH_CASE_INSENSITIVE
  1143. delete[] caseSensitivePath;
  1144. #endif
  1145. return retVal;
  1146. }
  1147. StringTableEntry Platform::getExecutableName()
  1148. {
  1149. return StringTable->insert(sBinName);
  1150. }
  1151. extern "C"
  1152. {
  1153. void setExePathName(const char* exePathName)
  1154. {
  1155. if (exePathName == NULL)
  1156. sBinPathName[0] = '\0';
  1157. else
  1158. dStrncpy(sBinPathName, exePathName, sizeof(sBinPathName));
  1159. // set the base exe name field
  1160. char *binName = dStrrchr(sBinPathName, '/');
  1161. if( !binName )
  1162. binName = sBinPathName;
  1163. else
  1164. *binName++ = '\0';
  1165. sBinName = binName;
  1166. }
  1167. }
  1168. #endif