Torque3D Documentation / _generateds / x86UNIXFileio.cpp

x86UNIXFileio.cpp

Engine/source/platformX86UNIX/x86UNIXFileio.cpp

More...

Public Enumerations

enum
_Anonymous_ {
  TOUCH 
  DELETE 
}

Public Variables

char
sgPrefDir [MaxPath]

Public Functions

bool
CopyFile(const char * src, const char * dest)
bool
dFileDelete(const char * name)
bool
dFileRename(const char * oldName, const char * newName)
bool
dFileTouch(const char * name)
bool
DirExists(char * pathname, bool isFile)
bool
dPathCopy(const char * fromName, const char * toName, bool nooverwrite)
ForwardSlash(char * str)
bool
GetFileTimes(const char * filePath, FileTime * createTime, FileTime * modifyTime)
const char *
bool
ModifyFile(const char * name, S32 modType)
MungeCase(char * pathName, S32 pathNameSize)
MungePath(char * dest, S32 destSize, const char * src, const char * absolutePrefix)
bool
recurseDumpDirectories(const char * basePath, const char * subPath, Vector< StringTableEntry > & directoryVector, S32 currentDepth, S32 recurseDepth, bool noBasePath)
bool
RecurseDumpPath(const char * path, const char * relativePath, const char * pattern, Vector< Platform::FileInfo > & fileVector)
setExePathName(const char * exePathName)
int
x86UNIXClose(int fd)
int
x86UNIXOpen(const char * path, int oflag)
ssize_t
x86UNIXRead(int fd, void * buf, size_t nbytes)
ssize_t
x86UNIXWrite(int fd, const void * buf, size_t nbytes)

Detailed Description

Public Enumerations

@99

Enumerator

TOUCH
DELETE

Public Variables

const int MaxPath 
char sgPrefDir [MaxPath]
bool sgPrefDirInitialized 

Public Functions

CopyFile(const char * src, const char * dest)

dFileDelete(const char * name)

dFileRename(const char * oldName, const char * newName)

dFileTouch(const char * name)

DirExists(char * pathname, bool isFile)

dPathCopy(const char * fromName, const char * toName, bool nooverwrite)

ForwardSlash(char * str)

GetFileTimes(const char * filePath, FileTime * createTime, FileTime * modifyTime)

GetPrefDir()

ModifyFile(const char * name, S32 modType)

MungeCase(char * pathName, S32 pathNameSize)

MungePath(char * dest, S32 destSize, const char * src, const char * absolutePrefix)

osGetTemporaryDirectory()

recurseDumpDirectories(const char * basePath, const char * subPath, Vector< StringTableEntry > & directoryVector, S32 currentDepth, S32 recurseDepth, bool noBasePath)

RecurseDumpPath(const char * path, const char * relativePath, const char * pattern, Vector< Platform::FileInfo > & fileVector)

setExePathName(const char * exePathName)

x86UNIXClose(int fd)

x86UNIXOpen(const char * path, int oflag)

x86UNIXRead(int fd, void * buf, size_t nbytes)

x86UNIXWrite(int fd, const void * buf, size_t nbytes)

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