physfs.c
changeset 7 07d5e6e8259d
parent 5 055ddaaabf85
child 11 677e01f5109e
equal deleted inserted replaced
6:3662cbc014ef 7:07d5e6e8259d
    12 #include <stdlib.h>
    12 #include <stdlib.h>
    13 #include <string.h>
    13 #include <string.h>
    14 #include <assert.h>
    14 #include <assert.h>
    15 #include "physfs.h"
    15 #include "physfs.h"
    16 
    16 
       
    17 #define __PHYSICSFS_INTERNAL__
       
    18 #include "physfs_internal.h"
       
    19 
    17 typedef struct __PHYSFS_ERRMSGTYPE__
    20 typedef struct __PHYSFS_ERRMSGTYPE__
    18 {
    21 {
    19     int tid;
    22     int tid;
    20     int errorAvailable;
    23     int errorAvailable;
    21     char errorString[80];
    24     char errorString[80];
    22     struct __PHYSFS_ERRMSGTYPE__ *next;
    25     struct __PHYSFS_ERRMSGTYPE__ *next;
    23 } ErrMsg;
    26 } ErrMsg;
    24 
    27 
    25 /* !!!
       
    26 typedef struct __PHYSFS_READER__
       
    27 {
       
    28     
       
    29 } Reader;
       
    30 */
       
    31 
    28 
    32 typedef struct __PHYSFS_SEARCHDIRINFO__
    29 typedef struct __PHYSFS_SEARCHDIRINFO__
    33 {
    30 {
    34     char *dirName;
    31     char *dirName;
    35     Reader *reader;
    32     DirReader *reader;
    36     struct __PHYSFS_SEARCHDIRINFO__ *next;
    33     struct __PHYSFS_SEARCHDIRINFO__ *next;
    37 } SearchDirInfo;
    34 } SearchDirInfo;
    38 
    35 
    39 
    36 
    40 static int initialized = 0;
    37 static int initialized = 0;
    41 static ErrMsg **errorMessages = NULL;  /* uses list functions. */
    38 static ErrMsg *errorMessages = NULL;
    42 static char **searchPath = NULL;  /* uses list functions. */
    39 static char *searchPath = NULL;
    43 static char *baseDir = NULL;
    40 static char *baseDir = NULL;
    44 static char *writeDir = NULL;
    41 static char *writeDir = NULL;
    45 
    42 static int allowSymLinks = 0;
    46 static const PHYSFS_ArchiveInfo *supported_types[] =
    43 
    47 {
       
    48 #if (defined PHYSFS_SUPPORTS_ZIP)
    44 #if (defined PHYSFS_SUPPORTS_ZIP)
    49     { "ZIP", "PkZip/WinZip/Info-Zip compatible" },
    45 extern const __PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ZIP;
       
    46 extern const __PHYSFS_DirReader   __PHYSFS_DirReader_ZIP;
       
    47 extern const __PHYSFS_FileHandle  __PHYSFS_FileHandle_ZIP;
       
    48 #endif
       
    49 
       
    50 
       
    51 static const __PHYSFS_ArchiveInfo *supported_types[] =
       
    52 {
       
    53 #if (defined PHYSFS_SUPPORTS_ZIP)
       
    54     &__PHYSFS_ArchiveInfo_ZIP,
    50 #endif
    55 #endif
    51 
    56 
    52     NULL
    57     NULL
    53 };
    58 };
    54 
    59 
    55 
    60 
    56 /* error messages... */
       
    57 #define ERR_IS_INITIALIZED       "Already initialized"
       
    58 #define ERR_NOT_INITIALIZED      "Not initialized"
       
    59 #define ERR_INVALID_ARGUMENT     "Invalid argument"
       
    60 #define ERR_FILES_OPEN_WRITE     "Files still open for writing"
       
    61 #define ERR_NO_DIR_CREATE        "Failed to create directories"
       
    62 #define ERR_OUT_OF_MEMORY        "Out of memory"
       
    63 #define ERR_NOT_IN_SEARCH_PATH   "No such entry in search path"
       
    64 
       
    65 
       
    66 /* This gets used all over for lessening code clutter. */
       
    67 #define BAIL_IF_MACRO(cond, err, rc) if (cond) { setError(err); return(rc); }
       
    68 
    61 
    69 
    62 
    70 static ErrMsg *findErrorForCurrentThread(void)
    63 static ErrMsg *findErrorForCurrentThread(void)
    71 {
    64 {
    72     ErrMsg *i;
    65     ErrMsg *i;
    85 
    78 
    86     return(NULL);   /* no error available. */
    79     return(NULL);   /* no error available. */
    87 } /* findErrorForCurrentThread */
    80 } /* findErrorForCurrentThread */
    88 
    81 
    89 
    82 
    90 static void setError(char *str)
    83 void __PHYSFS_setError(const char *str)
    91 {
    84 {
    92     ErrMsg *err = findErrorForCurrentThread();
    85     ErrMsg *err = findErrorForCurrentThread();
    93 
    86 
    94     if (err == NULL)
    87     if (err == NULL)
    95     {
    88     {
    96         err = (ErrMsg *) malloc(sizeof (ErrMsg));
    89         err = (ErrMsg *) malloc(sizeof (ErrMsg));
    97         if (err == NULL)
    90         if (err == NULL)
    98             return;   /* uhh...? */
    91             return;   /* uhh...? */
    99 
    92 
       
    93         err->tid = __PHYSFS_platformGetThreadID();
   100         err->next = errorMessages;
    94         err->next = errorMessages;
   101         if (errorMessages == NULL)
    95         errorMessages = err;
   102             errorMessages = err;
       
   103 
       
   104         err->tid = __PHYSFS_platformGetThreadID();
       
   105     } /* if */
    96     } /* if */
   106 
    97 
   107     err->errorAvailable = 1;
    98     err->errorAvailable = 1;
   108     strncpy(err->errorString, str, sizeof (err->errorString));
    99     strncpy(err->errorString, str, sizeof (err->errorString));
   109     err->errorString[sizeof (err->errorString) - 1] = '\0';
   100     err->errorString[sizeof (err->errorString) - 1] = '\0';
   110 } /* setError */
   101 } /* __PHYSFS_setError */
   111 
   102 
   112 
   103 
   113 const char *PHYSFS_getLastError(void)
   104 const char *PHYSFS_getLastError(void)
   114 {
   105 {
   115     ErrMsg *err = findErrorForCurrentThread();
   106     ErrMsg *err = findErrorForCurrentThread();
   145 
   136 
   146 
   137 
   147 static void freeSearchDir(SearchDirInfo *sdi)
   138 static void freeSearchDir(SearchDirInfo *sdi)
   148 {
   139 {
   149     assert(sdi != NULL);
   140     assert(sdi != NULL);
   150     freeReader(sdi->reader);
   141 
       
   142     /* !!! make sure all files in search dir are closed. */
       
   143 
       
   144     sdi->reader->close(sdi->reader);
   151     free(sdi->dirName);
   145     free(sdi->dirName);
   152     free(sdi);
   146     free(sdi);
   153 } /* freeSearchDir */
   147 } /* freeSearchDir */
   154 
   148 
   155 
   149 
   168         searchPath = NULL;
   162         searchPath = NULL;
   169     } /* if */
   163     } /* if */
   170 } /* freeSearchPath */
   164 } /* freeSearchPath */
   171 
   165 
   172 
   166 
       
   167 static void closeAllFiles(void)
       
   168 {
       
   169 } /* closeAllFiles */
       
   170 
       
   171 
   173 void PHYSFS_deinit(void)
   172 void PHYSFS_deinit(void)
   174 {
   173 {
   175     BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
   174     BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
   176 
   175 
   177     /* close/cleanup open handles. */
   176     closeAllFiles();
   178 
       
   179     if (baseDir != NULL)
       
   180         free(baseDir);
       
   181 
   177 
   182     PHYSFS_setWriteDir(NULL);
   178     PHYSFS_setWriteDir(NULL);
   183     freeSearchPath();
   179     freeSearchPath();
   184     freeErrorMessages();
   180     freeErrorMessages();
   185 
   181 
       
   182     if (baseDir != NULL)
       
   183         free(baseDir);
       
   184 
       
   185     allowSymLinks = 0;
   186     initialized = 0;
   186     initialized = 0;
   187     return(1);
   187     return(1);
   188 } /* PHYSFS_deinit */
   188 } /* PHYSFS_deinit */
   189 
   189 
   190 
   190 
   195 
   195 
   196 
   196 
   197 void PHYSFS_freeList(void *list)
   197 void PHYSFS_freeList(void *list)
   198 {
   198 {
   199     void **i;
   199     void **i;
   200 
       
   201     for (i = (void **) list; *i != NULL; i++)
   200     for (i = (void **) list; *i != NULL; i++)
   202         free(*i);
   201         free(*i);
   203 
   202 
   204     free(list);
   203     free(list);
   205 } /* PHYSFS_freeList */
   204 } /* PHYSFS_freeList */
   223 } /* PHYSFS_getBaseDir */
   222 } /* PHYSFS_getBaseDir */
   224 
   223 
   225 
   224 
   226 const char *PHYSFS_getUserDir(void)
   225 const char *PHYSFS_getUserDir(void)
   227 {
   226 {
   228     return(__PHYSFS_platformGetUserDir());
   227     static char *retval = NULL;
       
   228     const char *str = NULL;
       
   229 
       
   230     if (retval != NULL)
       
   231         return(retval);
       
   232 
       
   233     str = __PHYSFS_platformGetUserDir();
       
   234     if (str != NULL)
       
   235         retval = str;
       
   236     else
       
   237     {
       
   238         const char *dirsep = PHYSFS_getDirSeparator();
       
   239         const char *uname;
       
   240 
       
   241         str = getenv("HOME");  /* try a default. */
       
   242         if (str != NULL)
       
   243             retval = str;
       
   244         else
       
   245         {
       
   246             uname = __PHYSFS_platformGetUserName();
       
   247             str = (uname != NULL) ? uname : "default";
       
   248             retval = malloc(strlen(baseDir) + strlen(str) +
       
   249                             (strlen(dirsep) * 2) + 6);
       
   250             if (retval == NULL)
       
   251                 retval = baseDir;  /* (*shrug*) */
       
   252             else
       
   253                 sprintf(retval, "%s%susers%s%s", baseDir, dirsep, dirsep, uname);
       
   254 
       
   255             if (uname != NULL)
       
   256                 free(uname);
       
   257         } /* else */
       
   258     } /* if */
       
   259 
       
   260     return(baseDir);  /* just in case. */
   229 } /* PHYSFS_getUserDir */
   261 } /* PHYSFS_getUserDir */
   230 
   262 
   231 
   263 
   232 const char *PHYSFS_getWriteDir(void)
   264 const char *PHYSFS_getWriteDir(void)
   233 {
   265 {
   243     {
   275     {
   244         free(writeDir);
   276         free(writeDir);
   245         writeDir = NULL;
   277         writeDir = NULL;
   246     } /* if */
   278     } /* if */
   247 
   279 
   248     if (newDir == NULL)   /* we're done already! */
   280     if (newDir != NULL)
   249         return(1);
   281     {
   250 
   282         BAIL_IF_MACRO(!createDirs_dependent(newDir), ERR_NO_DIR_CREATE, 0);
   251     BAIL_IF_MACRO(!createDirs_dependent(newDir), ERR_NO_DIR_CREATE, 0);
   283 
   252 
   284         writeDir = malloc(strlen(newDir) + 1);
   253     writeDir = malloc(strlen(newDir) + 1);
   285         BAIL_IF_MACRO(writeDir == NULL, ERR_OUT_OF_MEMORY, 0);
   254     BAIL_IF_MACRO(writeDir == NULL, ERR_OUT_OF_MEMORY, 0);
   286 
   255 
   287         strcpy(writeDir, newDir);
   256     strcpy(writeDir, newDir);
   288     } /* if */
       
   289 
   257     return(1);
   290     return(1);
   258 } /* PHYSFS_setWriteDir */
   291 } /* PHYSFS_setWriteDir */
   259 
   292 
   260 
   293 
   261 int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
   294 int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
   262 {
   295 {
   263     char *str = NULL;
   296     char *str = NULL;
   264     SearchDirInfo *sdi = NULL;
   297     SearchDirInfo *sdi = NULL;
   265     __PHYSFS_Reader *reader = NULL;
   298     DirReader *dirReader = NULL;
   266 
   299 
   267     BAIL_IF_MACRO(newDir == NULL, ERR_INVALID_ARGUMENT, 0);
   300     BAIL_IF_MACRO(newDir == NULL, ERR_INVALID_ARGUMENT, 0);
   268 
   301 
   269     reader = getReader(newDir); /* This sets the error message. */
   302     reader = getDirReader(newDir); /* This sets the error message. */
   270     if (reader == NULL)
   303     if (reader == NULL)
   271         return(0);
   304         return(0);
   272 
   305 
   273     sdi = (SearchDirInfo *) malloc(sizeof (SearchDirInfo));
   306     sdi = (SearchDirInfo *) malloc(sizeof (SearchDirInfo));
   274     BAIL_IF_MACRO(sdi == NULL, ERR_OUT_OF_MEMORY, 0);
   307     BAIL_IF_MACRO(sdi == NULL, ERR_OUT_OF_MEMORY, 0);
   276     sdi->dirName = (char *) malloc(strlen(newDir) + 1);
   309     sdi->dirName = (char *) malloc(strlen(newDir) + 1);
   277     if (sdi->dirName == NULL)
   310     if (sdi->dirName == NULL)
   278     {
   311     {
   279         free(sdi);
   312         free(sdi);
   280         freeReader(reader);
   313         freeReader(reader);
   281         setError(ERR_OUT_OF_MEMORY);
   314         __PHYSFS_setError(ERR_OUT_OF_MEMORY);
   282         return(0);
   315         return(0);
   283     } /* if */
   316     } /* if */
   284 
   317 
   285     sdi->reader = reader;
   318     sdi->dirReader = dirReader;
   286     strcpy(sdi->dirName, newDir);
   319     strcpy(sdi->dirName, newDir);
   287 
   320 
   288     if (appendToPath)
   321     if (appendToPath)
   289     {
   322     {
   290         sdi->next = searchPath;
   323         sdi->next = searchPath;
   322         {
   355         {
   323             if (prev == NULL)
   356             if (prev == NULL)
   324                 searchPath = i->next;
   357                 searchPath = i->next;
   325             else
   358             else
   326                 prev->next = i->next;
   359                 prev->next = i->next;
       
   360 
       
   361             /* !!! make sure all files in search dir are closed. */
       
   362 
   327             freeSearchDir(i);
   363             freeSearchDir(i);
   328             return(1);
   364             return(1);
   329         } /* if */
   365         } /* if */
   330         prev = i;
   366         prev = i;
   331     } /* for */
   367     } /* for */
   332 
   368 
   333     setError(ERR_NOT_IN_SEARCH_PATH);
   369     __PHYSFS_setError(ERR_NOT_IN_SEARCH_PATH);
   334     return(0);
   370     return(0);
   335 } /* PHYSFS_removeFromSearchPath */
   371 } /* PHYSFS_removeFromSearchPath */
   336 
   372 
   337 
   373 
   338 char **PHYSFS_getSearchPath(void)
   374 char **PHYSFS_getSearchPath(void)
   360                 x--;
   396                 x--;
   361                 free(retval[x]);
   397                 free(retval[x]);
   362             } /* while */
   398             } /* while */
   363 
   399 
   364             free(retval);
   400             free(retval);
   365             setError(ERR_OUT_OF_MEMORY);
   401             __PHYSFS_setError(ERR_OUT_OF_MEMORY);
   366             return(NULL);
   402             return(NULL);
   367         } /* if */
   403         } /* if */
   368 
   404 
   369         strcpy(retval[x], i->dirName);
   405         strcpy(retval[x], i->dirName);
   370     } /* for */
   406     } /* for */
   420  *                         yourself.
   456  *                         yourself.
   421  *
   457  *
   422  *    @param archivesFirst Non-zero to prepend the archives to the search path.
   458  *    @param archivesFirst Non-zero to prepend the archives to the search path.
   423  *                          Zero to append them. Ignored if !(archiveExt).
   459  *                          Zero to append them. Ignored if !(archiveExt).
   424  */
   460  */
   425 void PHYSFS_setSaneConfig(const char *appName, const char *archiveExt,
   461 int PHYSFS_setSaneConfig(const char *appName, const char *archiveExt,
   426                          int includeCdRoms, int archivesFirst)
   462                          int includeCdRoms, int archivesFirst)
   427 {
   463 {
       
   464     const char *basedir = PHYSFS_getBaseDir();
       
   465     const char *userdir = PHYSFS_getUserDir();
       
   466     const char *dirsep = PHYSFS_getDirSeparator();
       
   467     char *str;
       
   468     int rc;
       
   469 
       
   470         /* set write dir... */
       
   471     str = malloc(strlen(userdir) + (strlen(appName) * 2) +
       
   472                  (strlen(dirsep) * 2) + 2);
       
   473     BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
       
   474     sprintf(str, "%s%s.%s", userdir, dirsep, appName);
       
   475     rc = PHYSFS_setWriteDir(str);
       
   476     if (!rc)
       
   477         return(0);  /* error set by PHYSFS_setWriteDir() ... */
       
   478 
       
   479         /* Put write dir related dirs on search path... */
       
   480     PHYSFS_addToSearchPath(str, 1);
       
   481     PHYSFS_mkdir(appName); /* don't care if this fails. */
       
   482     strcat(str, dirSep);
       
   483     strcat(str, appName);
       
   484     PHYSFS_addToSearchPath(str, 1);
       
   485     free(str);
       
   486 
       
   487         /* Put base path stuff on search path... */
       
   488     PHYSFS_addToSearchPath(basedir, 1);
       
   489     str = malloc(strlen(basedir) + (strlen(appName) * 2) +
       
   490                  (strlen(dirsep) * 2) + 2);
       
   491     if (str != NULL)
       
   492     {
       
   493         sprintf(str, "%s%s.%s", basedir, dirsep, appName);
       
   494         PHYSFS_addToSearchPath(str, 1);
       
   495         free(str);
       
   496     } /* if */
       
   497 
       
   498         /* handle CD-ROMs... */
       
   499     if (includeCdRoms)
       
   500     {
       
   501         char **cds = PHYSFS_getCdRomDirs();
       
   502         char **i;
       
   503         for (i = cds; *i != NULL; i++)
       
   504         {
       
   505             PHYSFS_addToSearchPath(*i);
       
   506             str = malloc(strlen(*i) + strlen(appName) + strlen(dirsep) + 1);
       
   507             if (str != NULL)
       
   508             {
       
   509                 sprintf(str, "%s%s%s", *i, dirsep, appName);
       
   510                 PHYSFS_addToSearchPath(str);
       
   511                 free(str);
       
   512             } /* if */
       
   513         } /* for */
       
   514         PHYSFS_freeList(cds);
       
   515     } /* if */
       
   516 
       
   517         /* Root out archives, and add them to search path... */
       
   518     if (archiveExt != NULL)
       
   519     {
       
   520         char **rc = PHYSFS_enumerateFiles("");
       
   521         char **i;
       
   522         int extlen = strlen(archiveExt);
       
   523         char *ext;
       
   524 
       
   525         for (i = rc; *i != NULL; i++)
       
   526         {
       
   527             int l = strlen(*i);
       
   528             if ((l > extlen) && ((*i)[l - extlen - 1] == '.'));
       
   529             {
       
   530                 ext = (*i) + (l - extlen);
       
   531                 if (__PHYSFS_platformStricmp(ext, archiveExt) == 0)
       
   532                 {
       
   533                     const char *d = PHYSFS_getRealDir(*i);
       
   534                     str = malloc(strlen(d) + strlen(dirsep) + l + 1);
       
   535                     if (str != NULL)
       
   536                     {
       
   537                         sprintf(str, "%s%s%s", d, dirsep, *i);
       
   538                         PHYSFS_addToSearchPath(d, str);
       
   539                         free(str);
       
   540                     } /* if */
       
   541                 } /* if */
       
   542             } /* if */
       
   543         } /* for */
       
   544 
       
   545         PHYSFS_freeList(rc);
       
   546     } /* if */
       
   547 
       
   548     return(1);
   428 } /* PHYSFS_setSaneConfig */
   549 } /* PHYSFS_setSaneConfig */
   429 
   550 
   430 
   551 
   431 /**
   552 /* string manipulation in C makes my ass itch. */
   432  * Create a directory. This is specified in platform-independent notation in
   553 /*  be sure to free this crap after you're done with it. */
   433  *  relation to the write path. All missing parent directories are also
   554 static char *convertToDependentNotation(const char *prepend,
   434  *  created if they don't exist.
   555                                         const char *dirName,
   435  *
   556                                         const char *append)
   436  * So if you've got the write path set to "C:\mygame\writepath" and call
   557 {
   437  *  PHYSFS_mkdir("downloads/maps") then the directories
   558     const char *dirsep = PHYSFS_getDirSeparator();
   438  *  "C:\mygame\writepath\downloads" and "C:\mygame\writepath\downloads\maps"
   559     int sepsize = strlen(dirsep);
   439  *  will be created if possible. If the creation of "maps" fails after we
   560     char *str;
   440  *  have successfully created "downloads", then the function leaves the
   561     char *i1;
   441  *  created directory behind and reports failure.
   562     char *i2;
   442  *
   563     size_t allocSize;
   443  *   @param dirName New path to create.
   564 
   444  *  @return nonzero on success, zero on error. Specifics of the error can be
   565     allocSize = strlen(dirName) + strlen(writeDir) + sepsize + 1;
   445  *          gleaned from PHYSFS_getLastError().
   566     if (prepend != NULL)
   446  */
   567         allocSize += strlen(prepend) + sepsize;
       
   568     if (append != NULL)
       
   569         allocSize += strlen(append) + sepsize;
       
   570 
       
   571         /* make sure there's enough space if the dir separator is bigger. */
       
   572     if (sepsize > 1)
       
   573     {
       
   574         for (str = dirName; *str != '\0'; str++)
       
   575         {
       
   576             if (*str == '/')
       
   577                 allocSize += (sepsize - 1);
       
   578         } /* for */
       
   579     } /* if */
       
   580 
       
   581     str = (char *) malloc(allocSize);
       
   582     BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, NULL);
       
   583     *str = '\0';
       
   584 
       
   585     if (prepend)
       
   586     {
       
   587         strcpy(str, prepend);
       
   588         strcat(str, dirsep);
       
   589     } /* if */
       
   590 
       
   591     for (i1 = dirName, i2 = str + strlen(str); *i1 != '\0'; i1++, i2++)
       
   592     {
       
   593         if (*i1 == '/')
       
   594         {
       
   595             strcpy(i2, dirsep);
       
   596             i2 += sepsize;
       
   597         } /* if */
       
   598         else
       
   599         {
       
   600             *i2 = *i1;
       
   601         } /* else */
       
   602     } /* for */
       
   603     *i2 = '\0';
       
   604 
       
   605     if (append)
       
   606     {
       
   607         strcat(str, dirsep);
       
   608         strcpy(str, append);
       
   609     } /* if */
       
   610 
       
   611     return(str);
       
   612 } /* convertToDependentNotation */
       
   613 
       
   614 
   447 int PHYSFS_mkdir(const char *dirName)
   615 int PHYSFS_mkdir(const char *dirName)
   448 {
   616 {
       
   617     char *str;
       
   618     int rc;
       
   619 
       
   620     BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, NULL);
       
   621 
       
   622     str = convertToDependentNotation(writeDir, dirName, NULL);
       
   623     if (str == NULL)  /* __PHYSFS_setError is called in convert call. */
       
   624         return(0);
       
   625 
       
   626     rc = createDirs_dependent(str);
       
   627     free(str);
       
   628     return(rc);
   449 } /* PHYSFS_mkdir */
   629 } /* PHYSFS_mkdir */
   450 
   630 
   451 
   631 
   452 /**
       
   453  * Delete a file or directory. This is specified in platform-independent
       
   454  *  notation in relation to the write path.
       
   455  *
       
   456  * A directory must be empty before this call can delete it.
       
   457  *
       
   458  * So if you've got the write path set to "C:\mygame\writepath" and call
       
   459  *  PHYSFS_delete("downloads/maps/level1.map") then the file
       
   460  *  "C:\mygame\writepath\downloads\maps\level1.map" is removed from the
       
   461  *  physical filesystem, if it exists and the operating system permits the
       
   462  *  deletion.
       
   463  *
       
   464  * Note that on Unix systems, deleting a file may be successful, but the
       
   465  *  actual file won't be removed until all processes that have an open
       
   466  *  filehandle to it (including your program) close their handles.
       
   467  *
       
   468  *   @param filename Filename to delete.
       
   469  *  @return nonzero on success, zero on error. Specifics of the error can be
       
   470  *          gleaned from PHYSFS_getLastError().
       
   471  */
       
   472 int PHYSFS_delete(const char *filename)
   632 int PHYSFS_delete(const char *filename)
   473 {
   633 {
       
   634     char *str;
       
   635     int rc;
       
   636 
       
   637     BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, NULL);
       
   638 
       
   639     str = convertToDependentNotation(writeDir, fileName, NULL);
       
   640     if (str == NULL)  /* __PHYSFS_setError is called in convert call. */
       
   641         return(0);
       
   642 
       
   643     rc = remove(str);
       
   644     free(str);
       
   645 
       
   646     rc = (rc == 0);
       
   647 
       
   648     if (!rc)
       
   649         __PHYSFS_setError(strerror(errno));
       
   650 
       
   651     return(rc);
   474 } /* PHYSFS_delete */
   652 } /* PHYSFS_delete */
   475 
   653 
   476 
   654 
   477 /**
       
   478  * Enable symbolic links. Some physical filesystems and archives contain
       
   479  *  files that are just pointers to other files. On the physical filesystem,
       
   480  *  opening such a link will (transparently) open the file that is pointed to.
       
   481  *
       
   482  * By default, PhysicsFS will check if a file is really a symlink during open
       
   483  *  calls and fail if it is. Otherwise, the link could take you outside the
       
   484  *  write and search paths, and compromise security.
       
   485  *
       
   486  * If you want to take that risk, call this function with a non-zero parameter.
       
   487  *  Note that this is more for sandboxing a program's scripting language, in
       
   488  *  case untrusted scripts try to compromise the system. Generally speaking,
       
   489  *  a user could very well have a legitimate reason to set up a symlink, so
       
   490  *  unless you feel there's a specific danger in allowing them, you should
       
   491  *  permit them.
       
   492  *
       
   493  * Symbolic link permission can be enabled or disabled at any time, and is
       
   494  *  disabled by default.
       
   495  *
       
   496  *   @param allow nonzero to permit symlinks, zero to deny linking.
       
   497  */
       
   498 void PHYSFS_permitSymbolicLinks(int allow)
   655 void PHYSFS_permitSymbolicLinks(int allow)
   499 {
   656 {
       
   657     allowSymLinks = allow;
   500 } /* PHYSFS_permitSymbolicLinks */
   658 } /* PHYSFS_permitSymbolicLinks */
   501 
   659 
   502 
   660 
   503 /**
   661 /**
   504  * Figure out where in the search path a file resides. The file is specified
   662  * Figure out where in the search path a file resides. The file is specified
   619  *  @return nonzero on success, zero on error. Specifics of the error can be
   777  *  @return nonzero on success, zero on error. Specifics of the error can be
   620  *          gleaned from PHYSFS_getLastError().
   778  *          gleaned from PHYSFS_getLastError().
   621  */
   779  */
   622 int PHYSFS_close(PHYSFS_file *handle)
   780 int PHYSFS_close(PHYSFS_file *handle)
   623 {
   781 {
       
   782     FileHandle *h = (FileHandle *) handle->opaque;
       
   783     assert(h != NULL);
       
   784     BAIL_IF_MACRO(h->close == NULL, ERR_NOT_SUPPORTED, -1);
       
   785     rc = h->close(h);
       
   786     if (rc)
       
   787         free(handle);
       
   788     return(rc);
   624 } /* PHYSFS_close */
   789 } /* PHYSFS_close */
   625 
   790 
   626 
   791 
   627 /**
       
   628  * Read data from a PhysicsFS filehandle. The file must be opened for reading.
       
   629  *
       
   630  *   @param handle handle returned from PHYSFS_openRead().
       
   631  *   @param buffer buffer to store read data into.
       
   632  *   @param objSize size in bytes of objects being read from (handle).
       
   633  *   @param objCount number of (objSize) objects to read from (handle).
       
   634  *  @return number of objects read. PHYSFS_getLastError() can shed light on
       
   635  *           the reason this might be < (objCount), as can PHYSFS_eof().
       
   636  */
       
   637 int PHYSFS_read(PHYSFS_file *handle, void *buffer,
   792 int PHYSFS_read(PHYSFS_file *handle, void *buffer,
   638                 unsigned int objSize, unsigned int objCount)
   793                 unsigned int objSize, unsigned int objCount)
   639 {
   794 {
       
   795     FileHandle *h = (FileHandle *) handle->opaque;
       
   796     assert(h != NULL);
       
   797     BAIL_IF_MACRO(h->read == NULL, ERR_NOT_SUPPORTED, -1);
       
   798     return(h->read(h, buffer, objSize, objCount));
   640 } /* PHYSFS_read */
   799 } /* PHYSFS_read */
   641 
   800 
   642 
   801 
   643 /**
       
   644  * Write data to a PhysicsFS filehandle. The file must be opened for writing.
       
   645  *
       
   646  *   @param handle retval from PHYSFS_openWrite() or PHYSFS_openAppend().
       
   647  *   @param buffer buffer to store read data into.
       
   648  *   @param objSize size in bytes of objects being read from (handle).
       
   649  *   @param objCount number of (objSize) objects to read from (handle).
       
   650  *  @return number of objects read. PHYSFS_getLastError() can shed light on
       
   651  *           the reason this might be < (objCount).
       
   652  */
       
   653 int PHYSFS_write(PHYSFS_file *handle, void *buffer,
   802 int PHYSFS_write(PHYSFS_file *handle, void *buffer,
   654                  unsigned int objSize, unsigned int objCount)
   803                  unsigned int objSize, unsigned int objCount)
   655 {
   804 {
       
   805     FileHandle *h = (FileHandle *) handle->opaque;
       
   806     assert(h != NULL);
       
   807     BAIL_IF_MACRO(h->write == NULL, ERR_NOT_SUPPORTED, -1);
       
   808     return(h->write(h, buffer, objSize, objCount));
   656 } /* PHYSFS_write */
   809 } /* PHYSFS_write */
   657 
   810 
   658 
   811 
   659 /**
       
   660  * Determine if the end of file has been reached in a PhysicsFS filehandle.
       
   661  *
       
   662  *   @param handle handle returned from PHYSFS_openRead().
       
   663  *  @return nonzero if EOF, zero if not.
       
   664  */
       
   665 int PHYSFS_eof(PHYSFS_file *handle)
   812 int PHYSFS_eof(PHYSFS_file *handle)
   666 {
   813 {
       
   814     FileHandle *h = (FileHandle *) handle->opaque;
       
   815     assert(h != NULL);
       
   816     BAIL_IF_MACRO(h->eof == NULL, ERR_NOT_SUPPORTED, -1);
       
   817     return(h->eof(h));
   667 } /* PHYSFS_eof */
   818 } /* PHYSFS_eof */
   668 
   819 
   669 
   820 
   670 /**
       
   671  * Determine current position within a PhysicsFS filehandle.
       
   672  *
       
   673  *   @param handle handle returned from PHYSFS_open*().
       
   674  *  @return offset in bytes from start of file. -1 if error occurred.
       
   675  *           Specifics of the error can be gleaned from PHYSFS_getLastError().
       
   676  */
       
   677 int PHYSFS_tell(PHYSFS_file *handle)
   821 int PHYSFS_tell(PHYSFS_file *handle)
   678 {
   822 {
       
   823     FileHandle *h = (FileHandle *) handle->opaque;
       
   824     assert(h != NULL);
       
   825     BAIL_IF_MACRO(h->tell == NULL, ERR_NOT_SUPPORTED, -1);
       
   826     return(h->tell(h));
   679 } /* PHYSFS_tell */
   827 } /* PHYSFS_tell */
   680 
   828 
   681 
   829 
   682 /**
       
   683  * Seek to a new position within a PhysicsFS filehandle. The next read or write
       
   684  *  will occur at that place. Seeking past the beginning or end of the file is
       
   685  *  not allowed.
       
   686  *
       
   687  *   @param handle handle returned from PHYSFS_open*().
       
   688  *   @param pos number of bytes from start of file to seek to.
       
   689  *  @return nonzero on success, zero on error. Specifics of the error can be
       
   690  *          gleaned from PHYSFS_getLastError().
       
   691  */
       
   692 int PHYSFS_seek(PHYSFS_file *handle, int pos)
   830 int PHYSFS_seek(PHYSFS_file *handle, int pos)
   693 {
   831 {
       
   832     FileHandle *h = (FileHandle *) handle->opaque;
       
   833     assert(h != NULL);
       
   834     BAIL_IF_MACRO(h->seek == NULL, ERR_NOT_SUPPORTED, 0);
       
   835     return(h->seek(h, pos));
   694 } /* PHYSFS_seek */
   836 } /* PHYSFS_seek */
   695 
   837 
   696 
   838 /* end of physfs.c ... */
   697 /* end of physfs.h ... */
   839 
   698