42 { |
42 { |
43 void *tid; |
43 void *tid; |
44 PHYSFS_ErrorCode code; |
44 PHYSFS_ErrorCode code; |
45 struct __PHYSFS_ERRSTATETYPE__ *next; |
45 struct __PHYSFS_ERRSTATETYPE__ *next; |
46 } ErrState; |
46 } ErrState; |
47 |
|
48 |
|
49 /* The various i/o drivers...some of these may not be compiled in. */ |
|
50 extern const PHYSFS_Archiver __PHYSFS_Archiver_ZIP; |
|
51 extern const PHYSFS_Archiver __PHYSFS_Archiver_LZMA; |
|
52 extern const PHYSFS_Archiver __PHYSFS_Archiver_GRP; |
|
53 extern const PHYSFS_Archiver __PHYSFS_Archiver_QPAK; |
|
54 extern const PHYSFS_Archiver __PHYSFS_Archiver_HOG; |
|
55 extern const PHYSFS_Archiver __PHYSFS_Archiver_MVL; |
|
56 extern const PHYSFS_Archiver __PHYSFS_Archiver_WAD; |
|
57 extern const PHYSFS_Archiver __PHYSFS_Archiver_DIR; |
|
58 extern const PHYSFS_Archiver __PHYSFS_Archiver_ISO9660; |
|
59 |
|
60 static const PHYSFS_Archiver *staticArchivers[] = |
|
61 { |
|
62 #if PHYSFS_SUPPORTS_ZIP |
|
63 &__PHYSFS_Archiver_ZIP, |
|
64 #endif |
|
65 #if PHYSFS_SUPPORTS_7Z |
|
66 &__PHYSFS_Archiver_LZMA, |
|
67 #endif |
|
68 #if PHYSFS_SUPPORTS_GRP |
|
69 &__PHYSFS_Archiver_GRP, |
|
70 #endif |
|
71 #if PHYSFS_SUPPORTS_QPAK |
|
72 &__PHYSFS_Archiver_QPAK, |
|
73 #endif |
|
74 #if PHYSFS_SUPPORTS_HOG |
|
75 &__PHYSFS_Archiver_HOG, |
|
76 #endif |
|
77 #if PHYSFS_SUPPORTS_MVL |
|
78 &__PHYSFS_Archiver_MVL, |
|
79 #endif |
|
80 #if PHYSFS_SUPPORTS_WAD |
|
81 &__PHYSFS_Archiver_WAD, |
|
82 #endif |
|
83 #if PHYSFS_SUPPORTS_ISO9660 |
|
84 &__PHYSFS_Archiver_ISO9660, |
|
85 #endif |
|
86 NULL |
|
87 }; |
|
88 |
|
89 |
47 |
90 |
48 |
91 /* General PhysicsFS state ... */ |
49 /* General PhysicsFS state ... */ |
92 static int initialized = 0; |
50 static int initialized = 0; |
93 static ErrState *errorStates = NULL; |
51 static ErrState *errorStates = NULL; |
690 |
649 |
691 return NULL; /* no error available. */ |
650 return NULL; /* no error available. */ |
692 } /* findErrorForCurrentThread */ |
651 } /* findErrorForCurrentThread */ |
693 |
652 |
694 |
653 |
695 void __PHYSFS_setError(const PHYSFS_ErrorCode errcode) |
654 /* this doesn't reset the error state. */ |
696 { |
655 static inline PHYSFS_ErrorCode currentErrorCode(void) |
697 ErrState *err; |
656 { |
698 |
657 const ErrState *err = findErrorForCurrentThread(); |
699 if (!errcode) |
658 return err ? err->code : PHYSFS_ERR_OK; |
700 return; |
659 } /* currentErrorCode */ |
701 |
|
702 err = findErrorForCurrentThread(); |
|
703 if (err == NULL) |
|
704 { |
|
705 err = (ErrState *) allocator.Malloc(sizeof (ErrState)); |
|
706 if (err == NULL) |
|
707 return; /* uhh...? */ |
|
708 |
|
709 memset(err, '\0', sizeof (ErrState)); |
|
710 err->tid = __PHYSFS_platformGetThreadID(); |
|
711 |
|
712 if (errorLock != NULL) |
|
713 __PHYSFS_platformGrabMutex(errorLock); |
|
714 |
|
715 err->next = errorStates; |
|
716 errorStates = err; |
|
717 |
|
718 if (errorLock != NULL) |
|
719 __PHYSFS_platformReleaseMutex(errorLock); |
|
720 } /* if */ |
|
721 |
|
722 err->code = errcode; |
|
723 } /* __PHYSFS_setError */ |
|
724 |
660 |
725 |
661 |
726 PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void) |
662 PHYSFS_ErrorCode PHYSFS_getLastErrorCode(void) |
727 { |
663 { |
728 ErrState *err = findErrorForCurrentThread(); |
664 ErrState *err = findErrorForCurrentThread(); |
746 case PHYSFS_ERR_UNSUPPORTED: return "unsupported"; |
682 case PHYSFS_ERR_UNSUPPORTED: return "unsupported"; |
747 case PHYSFS_ERR_PAST_EOF: return "past end of file"; |
683 case PHYSFS_ERR_PAST_EOF: return "past end of file"; |
748 case PHYSFS_ERR_FILES_STILL_OPEN: return "files still open"; |
684 case PHYSFS_ERR_FILES_STILL_OPEN: return "files still open"; |
749 case PHYSFS_ERR_INVALID_ARGUMENT: return "invalid argument"; |
685 case PHYSFS_ERR_INVALID_ARGUMENT: return "invalid argument"; |
750 case PHYSFS_ERR_NOT_MOUNTED: return "not mounted"; |
686 case PHYSFS_ERR_NOT_MOUNTED: return "not mounted"; |
751 case PHYSFS_ERR_NO_SUCH_PATH: return "no such path"; |
687 case PHYSFS_ERR_NOT_FOUND: return "not found"; |
752 case PHYSFS_ERR_SYMLINK_FORBIDDEN: return "symlinks are forbidden"; |
688 case PHYSFS_ERR_SYMLINK_FORBIDDEN: return "symlinks are forbidden"; |
753 case PHYSFS_ERR_NO_WRITE_DIR: return "write directory is not set"; |
689 case PHYSFS_ERR_NO_WRITE_DIR: return "write directory is not set"; |
754 case PHYSFS_ERR_OPEN_FOR_READING: return "file open for reading"; |
690 case PHYSFS_ERR_OPEN_FOR_READING: return "file open for reading"; |
755 case PHYSFS_ERR_OPEN_FOR_WRITING: return "file open for writing"; |
691 case PHYSFS_ERR_OPEN_FOR_WRITING: return "file open for writing"; |
756 case PHYSFS_ERR_NOT_A_FILE: return "not a file"; |
692 case PHYSFS_ERR_NOT_A_FILE: return "not a file"; |
762 case PHYSFS_ERR_NO_SPACE: return "no space available for writing"; |
698 case PHYSFS_ERR_NO_SPACE: return "no space available for writing"; |
763 case PHYSFS_ERR_BAD_FILENAME: return "filename is illegal or insecure"; |
699 case PHYSFS_ERR_BAD_FILENAME: return "filename is illegal or insecure"; |
764 case PHYSFS_ERR_BUSY: return "tried to modify a file the OS needs"; |
700 case PHYSFS_ERR_BUSY: return "tried to modify a file the OS needs"; |
765 case PHYSFS_ERR_DIR_NOT_EMPTY: return "directory isn't empty"; |
701 case PHYSFS_ERR_DIR_NOT_EMPTY: return "directory isn't empty"; |
766 case PHYSFS_ERR_OS_ERROR: return "OS reported an error"; |
702 case PHYSFS_ERR_OS_ERROR: return "OS reported an error"; |
|
703 case PHYSFS_ERR_DUPLICATE: return "duplicate resource"; |
|
704 case PHYSFS_ERR_BAD_PASSWORD: return "bad password"; |
767 } /* switch */ |
705 } /* switch */ |
768 |
706 |
769 return NULL; /* don't know this error code. */ |
707 return NULL; /* don't know this error code. */ |
770 } /* PHYSFS_getErrorByCode */ |
708 } /* PHYSFS_getErrorByCode */ |
771 |
709 |
772 |
710 |
773 void PHYSFS_setErrorCode(PHYSFS_ErrorCode code) |
711 void PHYSFS_setErrorCode(PHYSFS_ErrorCode errcode) |
774 { |
712 { |
775 __PHYSFS_setError(code); |
713 ErrState *err; |
|
714 |
|
715 if (!errcode) |
|
716 return; |
|
717 |
|
718 err = findErrorForCurrentThread(); |
|
719 if (err == NULL) |
|
720 { |
|
721 err = (ErrState *) allocator.Malloc(sizeof (ErrState)); |
|
722 if (err == NULL) |
|
723 return; /* uhh...? */ |
|
724 |
|
725 memset(err, '\0', sizeof (ErrState)); |
|
726 err->tid = __PHYSFS_platformGetThreadID(); |
|
727 |
|
728 if (errorLock != NULL) |
|
729 __PHYSFS_platformGrabMutex(errorLock); |
|
730 |
|
731 err->next = errorStates; |
|
732 errorStates = err; |
|
733 |
|
734 if (errorLock != NULL) |
|
735 __PHYSFS_platformReleaseMutex(errorLock); |
|
736 } /* if */ |
|
737 |
|
738 err->code = errcode; |
776 } /* PHYSFS_setErrorCode */ |
739 } /* PHYSFS_setErrorCode */ |
777 |
740 |
778 |
741 |
779 const char *PHYSFS_getLastError(void) |
742 const char *PHYSFS_getLastError(void) |
780 { |
743 { |
864 static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting) |
827 static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting) |
865 { |
828 { |
866 DirHandle *retval = NULL; |
829 DirHandle *retval = NULL; |
867 const PHYSFS_Archiver **i; |
830 const PHYSFS_Archiver **i; |
868 const char *ext; |
831 const char *ext; |
|
832 int created_io = 0; |
869 |
833 |
870 assert((io != NULL) || (d != NULL)); |
834 assert((io != NULL) || (d != NULL)); |
871 |
835 |
872 if (io == NULL) |
836 if (io == NULL) |
873 { |
837 { |
874 /* DIR gets first shot (unlike the rest, it doesn't deal with files). */ |
838 /* DIR gets first shot (unlike the rest, it doesn't deal with files). */ |
|
839 extern const PHYSFS_Archiver __PHYSFS_Archiver_DIR; |
875 retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting); |
840 retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting); |
876 if (retval != NULL) |
841 if (retval != NULL) |
877 return retval; |
842 return retval; |
878 |
843 |
879 io = __PHYSFS_createNativeIo(d, forWriting ? 'w' : 'r'); |
844 io = __PHYSFS_createNativeIo(d, forWriting ? 'w' : 'r'); |
880 BAIL_IF_MACRO(!io, ERRPASS, 0); |
845 BAIL_IF_MACRO(!io, ERRPASS, 0); |
|
846 created_io = 1; |
881 } /* if */ |
847 } /* if */ |
882 |
848 |
883 ext = find_filename_extension(d); |
849 ext = find_filename_extension(d); |
884 if (ext != NULL) |
850 if (ext != NULL) |
885 { |
851 { |
886 /* Look for archivers with matching file extensions first... */ |
852 /* Look for archivers with matching file extensions first... */ |
887 for (i = archivers; (*i != NULL) && (retval == NULL); i++) |
853 for (i = archivers; (*i != NULL) && (retval == NULL); i++) |
888 { |
854 { |
889 if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) == 0) |
855 if (__PHYSFS_utf8stricmp(ext, (*i)->info.extension) == 0) |
890 retval = tryOpenDir(io, *i, d, forWriting); |
856 retval = tryOpenDir(io, *i, d, forWriting); |
891 } /* for */ |
857 } /* for */ |
892 |
858 |
893 /* failing an exact file extension match, try all the others... */ |
859 /* failing an exact file extension match, try all the others... */ |
894 for (i = archivers; (*i != NULL) && (retval == NULL); i++) |
860 for (i = archivers; (*i != NULL) && (retval == NULL); i++) |
895 { |
861 { |
896 if (__PHYSFS_stricmpASCII(ext, (*i)->info.extension) != 0) |
862 if (__PHYSFS_utf8stricmp(ext, (*i)->info.extension) != 0) |
897 retval = tryOpenDir(io, *i, d, forWriting); |
863 retval = tryOpenDir(io, *i, d, forWriting); |
898 } /* for */ |
864 } /* for */ |
899 } /* if */ |
865 } /* if */ |
900 |
866 |
901 else /* no extension? Try them all. */ |
867 else /* no extension? Try them all. */ |
902 { |
868 { |
903 for (i = archivers; (*i != NULL) && (retval == NULL); i++) |
869 for (i = archivers; (*i != NULL) && (retval == NULL); i++) |
904 retval = tryOpenDir(io, *i, d, forWriting); |
870 retval = tryOpenDir(io, *i, d, forWriting); |
905 } /* else */ |
871 } /* else */ |
|
872 |
|
873 if ((!retval) && (created_io)) |
|
874 io->destroy(io); |
906 |
875 |
907 BAIL_IF_MACRO(!retval, PHYSFS_ERR_UNSUPPORTED, NULL); |
876 BAIL_IF_MACRO(!retval, PHYSFS_ERR_UNSUPPORTED, NULL); |
908 return retval; |
877 return retval; |
909 } /* openDirectory */ |
878 } /* openDirectory */ |
910 |
879 |
1119 errorLock = stateLock = NULL; |
1088 errorLock = stateLock = NULL; |
1120 return 0; /* failed. */ |
1089 return 0; /* failed. */ |
1121 } /* initializeMutexes */ |
1090 } /* initializeMutexes */ |
1122 |
1091 |
1123 |
1092 |
1124 static void setDefaultAllocator(void); |
1093 static int doRegisterArchiver(const PHYSFS_Archiver *_archiver); |
1125 |
1094 |
1126 static int initStaticArchivers(void) |
1095 static int initStaticArchivers(void) |
1127 { |
1096 { |
1128 const size_t numStaticArchivers = __PHYSFS_ARRAYLEN(staticArchivers); |
1097 #define REGISTER_STATIC_ARCHIVER(arc) { \ |
1129 const size_t len = numStaticArchivers * sizeof (void *); |
1098 extern const PHYSFS_Archiver __PHYSFS_Archiver_##arc; \ |
1130 size_t i; |
1099 if (!doRegisterArchiver(&__PHYSFS_Archiver_##arc)) { \ |
1131 |
1100 return 0; \ |
1132 assert(numStaticArchivers > 0); /* seriously, none at all?! */ |
1101 } \ |
1133 assert(staticArchivers[numStaticArchivers - 1] == NULL); |
1102 } |
1134 |
1103 |
1135 archiveInfo = (const PHYSFS_ArchiveInfo **) allocator.Malloc(len); |
1104 #if PHYSFS_SUPPORTS_ZIP |
1136 BAIL_IF_MACRO(!archiveInfo, PHYSFS_ERR_OUT_OF_MEMORY, 0); |
1105 REGISTER_STATIC_ARCHIVER(ZIP); |
1137 archivers = (const PHYSFS_Archiver **) allocator.Malloc(len); |
1106 #endif |
1138 BAIL_IF_MACRO(!archivers, PHYSFS_ERR_OUT_OF_MEMORY, 0); |
1107 #if PHYSFS_SUPPORTS_7Z |
1139 |
1108 REGISTER_STATIC_ARCHIVER(LZMA); |
1140 for (i = 0; i < numStaticArchivers - 1; i++) |
1109 #endif |
1141 archiveInfo[i] = &staticArchivers[i]->info; |
1110 #if PHYSFS_SUPPORTS_GRP |
1142 archiveInfo[numStaticArchivers - 1] = NULL; |
1111 REGISTER_STATIC_ARCHIVER(GRP); |
1143 |
1112 #endif |
1144 memcpy(archivers, staticArchivers, len); |
1113 #if PHYSFS_SUPPORTS_QPAK |
|
1114 REGISTER_STATIC_ARCHIVER(QPAK); |
|
1115 #endif |
|
1116 #if PHYSFS_SUPPORTS_HOG |
|
1117 REGISTER_STATIC_ARCHIVER(HOG); |
|
1118 #endif |
|
1119 #if PHYSFS_SUPPORTS_MVL |
|
1120 REGISTER_STATIC_ARCHIVER(MVL); |
|
1121 #endif |
|
1122 #if PHYSFS_SUPPORTS_WAD |
|
1123 REGISTER_STATIC_ARCHIVER(WAD); |
|
1124 #endif |
|
1125 #if PHYSFS_SUPPORTS_SLB |
|
1126 REGISTER_STATIC_ARCHIVER(SLB); |
|
1127 #endif |
|
1128 #if PHYSFS_SUPPORTS_ISO9660 |
|
1129 REGISTER_STATIC_ARCHIVER(ISO9660); |
|
1130 #endif |
|
1131 |
|
1132 #undef REGISTER_STATIC_ARCHIVER |
1145 |
1133 |
1146 return 1; |
1134 return 1; |
1147 } /* initStaticArchivers */ |
1135 } /* initStaticArchivers */ |
1148 |
1136 |
1149 |
1137 |
|
1138 static void setDefaultAllocator(void); |
1150 static int doDeinit(void); |
1139 static int doDeinit(void); |
1151 |
1140 |
1152 int PHYSFS_init(const char *argv0) |
1141 int PHYSFS_init(const char *argv0) |
1153 { |
1142 { |
1154 BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0); |
1143 BAIL_IF_MACRO(initialized, PHYSFS_ERR_IS_INITIALIZED, 0); |
1237 searchPath = NULL; |
1226 searchPath = NULL; |
1238 } /* if */ |
1227 } /* if */ |
1239 } /* freeSearchPath */ |
1228 } /* freeSearchPath */ |
1240 |
1229 |
1241 |
1230 |
|
1231 /* MAKE SURE you hold stateLock before calling this! */ |
|
1232 static int archiverInUse(const PHYSFS_Archiver *arc, const DirHandle *list) |
|
1233 { |
|
1234 const DirHandle *i; |
|
1235 for (i = list; i != NULL; i = i->next) |
|
1236 { |
|
1237 if (i->funcs == arc) |
|
1238 return 1; |
|
1239 } /* for */ |
|
1240 |
|
1241 return 0; /* not in use */ |
|
1242 } /* archiverInUse */ |
|
1243 |
|
1244 |
|
1245 /* MAKE SURE you hold stateLock before calling this! */ |
|
1246 static int doDeregisterArchiver(const size_t idx) |
|
1247 { |
|
1248 const size_t len = (numArchivers - idx) * sizeof (void *); |
|
1249 const PHYSFS_ArchiveInfo *info = archiveInfo[idx]; |
|
1250 const PHYSFS_Archiver *arc = archivers[idx]; |
|
1251 |
|
1252 /* make sure nothing is still using this archiver */ |
|
1253 if (archiverInUse(arc, searchPath) || archiverInUse(arc, writeDir)) |
|
1254 BAIL_MACRO(PHYSFS_ERR_FILES_STILL_OPEN, 0); |
|
1255 |
|
1256 allocator.Free((void *) info->extension); |
|
1257 allocator.Free((void *) info->description); |
|
1258 allocator.Free((void *) info->author); |
|
1259 allocator.Free((void *) info->url); |
|
1260 allocator.Free((void *) arc); |
|
1261 |
|
1262 memmove(&archiveInfo[idx], &archiveInfo[idx+1], len); |
|
1263 memmove(&archivers[idx], &archivers[idx+1], len); |
|
1264 |
|
1265 assert(numArchivers > 0); |
|
1266 numArchivers--; |
|
1267 |
|
1268 return 1; |
|
1269 } /* doDeregisterArchiver */ |
|
1270 |
|
1271 |
|
1272 /* Does NOT hold the state lock; we're shutting down. */ |
|
1273 static void freeArchivers(void) |
|
1274 { |
|
1275 while (numArchivers > 0) |
|
1276 { |
|
1277 if (!doDeregisterArchiver(numArchivers - 1)) |
|
1278 assert(!"nothing should be mounted during shutdown."); |
|
1279 } /* while */ |
|
1280 |
|
1281 allocator.Free(archivers); |
|
1282 allocator.Free(archiveInfo); |
|
1283 archivers = NULL; |
|
1284 archiveInfo = NULL; |
|
1285 } /* freeArchivers */ |
|
1286 |
|
1287 |
1242 static int doDeinit(void) |
1288 static int doDeinit(void) |
1243 { |
1289 { |
1244 BAIL_IF_MACRO(!__PHYSFS_platformDeinit(), ERRPASS, 0); |
|
1245 |
|
1246 closeFileHandleList(&openWriteList); |
1290 closeFileHandleList(&openWriteList); |
1247 BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), PHYSFS_ERR_FILES_STILL_OPEN, 0); |
1291 BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), PHYSFS_ERR_FILES_STILL_OPEN, 0); |
1248 |
1292 |
1249 freeSearchPath(); |
1293 freeSearchPath(); |
|
1294 freeArchivers(); |
1250 freeErrorStates(); |
1295 freeErrorStates(); |
1251 |
1296 |
1252 if (baseDir != NULL) |
1297 if (baseDir != NULL) |
1253 { |
1298 { |
1254 allocator.Free(baseDir); |
1299 allocator.Free(baseDir); |
1302 |
1351 |
1303 int PHYSFS_isInit(void) |
1352 int PHYSFS_isInit(void) |
1304 { |
1353 { |
1305 return initialized; |
1354 return initialized; |
1306 } /* PHYSFS_isInit */ |
1355 } /* PHYSFS_isInit */ |
|
1356 |
|
1357 |
|
1358 char *__PHYSFS_strdup(const char *str) |
|
1359 { |
|
1360 char *retval = (char *) allocator.Malloc(strlen(str) + 1); |
|
1361 if (retval) |
|
1362 strcpy(retval, str); |
|
1363 return retval; |
|
1364 } /* __PHYSFS_strdup */ |
|
1365 |
|
1366 |
|
1367 PHYSFS_uint32 __PHYSFS_hashString(const char *str, size_t len) |
|
1368 { |
|
1369 PHYSFS_uint32 hash = 5381; |
|
1370 while (len--) |
|
1371 hash = ((hash << 5) + hash) ^ *(str++); |
|
1372 return hash; |
|
1373 } /* __PHYSFS_hashString */ |
|
1374 |
|
1375 |
|
1376 /* MAKE SURE you hold stateLock before calling this! */ |
|
1377 static int doRegisterArchiver(const PHYSFS_Archiver *_archiver) |
|
1378 { |
|
1379 const PHYSFS_uint32 maxver = CURRENT_PHYSFS_ARCHIVER_API_VERSION; |
|
1380 const size_t len = (numArchivers + 2) * sizeof (void *); |
|
1381 PHYSFS_Archiver *archiver = NULL; |
|
1382 PHYSFS_ArchiveInfo *info = NULL; |
|
1383 const char *ext = NULL; |
|
1384 void *ptr = NULL; |
|
1385 size_t i; |
|
1386 |
|
1387 BAIL_IF_MACRO(!_archiver, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1388 BAIL_IF_MACRO(_archiver->version > maxver, PHYSFS_ERR_UNSUPPORTED, 0); |
|
1389 BAIL_IF_MACRO(!_archiver->info.extension, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1390 BAIL_IF_MACRO(!_archiver->info.description, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1391 BAIL_IF_MACRO(!_archiver->info.author, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1392 BAIL_IF_MACRO(!_archiver->info.url, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1393 BAIL_IF_MACRO(!_archiver->openArchive, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1394 BAIL_IF_MACRO(!_archiver->enumerateFiles, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1395 BAIL_IF_MACRO(!_archiver->openRead, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1396 BAIL_IF_MACRO(!_archiver->openWrite, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1397 BAIL_IF_MACRO(!_archiver->openAppend, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1398 BAIL_IF_MACRO(!_archiver->remove, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1399 BAIL_IF_MACRO(!_archiver->mkdir, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1400 BAIL_IF_MACRO(!_archiver->closeArchive, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1401 BAIL_IF_MACRO(!_archiver->stat, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1402 |
|
1403 ext = _archiver->info.extension; |
|
1404 for (i = 0; i < numArchivers; i++) |
|
1405 { |
|
1406 if (__PHYSFS_utf8stricmp(archiveInfo[i]->extension, ext) == 0) |
|
1407 BAIL_MACRO(PHYSFS_ERR_DUPLICATE, 0); /* !!! FIXME: better error? ERR_IN_USE? */ |
|
1408 } /* for */ |
|
1409 |
|
1410 /* make a copy of the data. */ |
|
1411 archiver = (PHYSFS_Archiver *) allocator.Malloc(sizeof (*archiver)); |
|
1412 GOTO_IF_MACRO(!archiver, PHYSFS_ERR_OUT_OF_MEMORY, regfailed); |
|
1413 |
|
1414 /* Must copy sizeof (OLD_VERSION_OF_STRUCT) when version changes! */ |
|
1415 memcpy(archiver, _archiver, sizeof (*archiver)); |
|
1416 |
|
1417 info = (PHYSFS_ArchiveInfo *) &archiver->info; |
|
1418 memset(info, '\0', sizeof (*info)); /* NULL in case an alloc fails. */ |
|
1419 #define CPYSTR(item) \ |
|
1420 info->item = __PHYSFS_strdup(_archiver->info.item); \ |
|
1421 GOTO_IF_MACRO(!info->item, PHYSFS_ERR_OUT_OF_MEMORY, regfailed); |
|
1422 CPYSTR(extension); |
|
1423 CPYSTR(description); |
|
1424 CPYSTR(author); |
|
1425 CPYSTR(url); |
|
1426 info->supportsSymlinks = _archiver->info.supportsSymlinks; |
|
1427 #undef CPYSTR |
|
1428 |
|
1429 ptr = allocator.Realloc(archiveInfo, len); |
|
1430 GOTO_IF_MACRO(!ptr, PHYSFS_ERR_OUT_OF_MEMORY, regfailed); |
|
1431 archiveInfo = (const PHYSFS_ArchiveInfo **) ptr; |
|
1432 |
|
1433 ptr = allocator.Realloc(archivers, len); |
|
1434 GOTO_IF_MACRO(!ptr, PHYSFS_ERR_OUT_OF_MEMORY, regfailed); |
|
1435 archivers = (const PHYSFS_Archiver **) ptr; |
|
1436 |
|
1437 archiveInfo[numArchivers] = info; |
|
1438 archiveInfo[numArchivers + 1] = NULL; |
|
1439 |
|
1440 archivers[numArchivers] = archiver; |
|
1441 archivers[numArchivers + 1] = NULL; |
|
1442 |
|
1443 numArchivers++; |
|
1444 |
|
1445 return 1; |
|
1446 |
|
1447 regfailed: |
|
1448 if (info != NULL) |
|
1449 { |
|
1450 allocator.Free((void *) info->extension); |
|
1451 allocator.Free((void *) info->description); |
|
1452 allocator.Free((void *) info->author); |
|
1453 allocator.Free((void *) info->url); |
|
1454 } /* if */ |
|
1455 allocator.Free(archiver); |
|
1456 |
|
1457 return 0; |
|
1458 } /* doRegisterArchiver */ |
|
1459 |
|
1460 |
|
1461 int PHYSFS_registerArchiver(const PHYSFS_Archiver *archiver) |
|
1462 { |
|
1463 int retval; |
|
1464 BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0); |
|
1465 __PHYSFS_platformGrabMutex(stateLock); |
|
1466 retval = doRegisterArchiver(archiver); |
|
1467 __PHYSFS_platformReleaseMutex(stateLock); |
|
1468 return retval; |
|
1469 } /* PHYSFS_registerArchiver */ |
|
1470 |
|
1471 |
|
1472 int PHYSFS_deregisterArchiver(const char *ext) |
|
1473 { |
|
1474 size_t i; |
|
1475 |
|
1476 BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, 0); |
|
1477 BAIL_IF_MACRO(!ext, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
|
1478 |
|
1479 __PHYSFS_platformGrabMutex(stateLock); |
|
1480 for (i = 0; i < numArchivers; i++) |
|
1481 { |
|
1482 if (__PHYSFS_utf8stricmp(archiveInfo[i]->extension, ext) == 0) |
|
1483 { |
|
1484 const int retval = doDeregisterArchiver(i); |
|
1485 __PHYSFS_platformReleaseMutex(stateLock); |
|
1486 return retval; |
|
1487 } /* if */ |
|
1488 } /* for */ |
|
1489 __PHYSFS_platformReleaseMutex(stateLock); |
|
1490 |
|
1491 BAIL_MACRO(PHYSFS_ERR_NOT_FOUND, 0); |
|
1492 } /* PHYSFS_deregisterArchiver */ |
1307 |
1493 |
1308 |
1494 |
1309 const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void) |
1495 const PHYSFS_ArchiveInfo **PHYSFS_supportedArchiveTypes(void) |
1310 { |
1496 { |
1311 BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL); |
1497 BAIL_IF_MACRO(!initialized, PHYSFS_ERR_NOT_INITIALIZED, NULL); |
1757 { |
1942 { |
1758 size_t mntpntlen = strlen(h->mountPoint); |
1943 size_t mntpntlen = strlen(h->mountPoint); |
1759 size_t len = strlen(fname); |
1944 size_t len = strlen(fname); |
1760 assert(mntpntlen > 1); /* root mount points should be NULL. */ |
1945 assert(mntpntlen > 1); /* root mount points should be NULL. */ |
1761 /* not under the mountpoint, so skip this archive. */ |
1946 /* not under the mountpoint, so skip this archive. */ |
1762 BAIL_IF_MACRO(len < mntpntlen-1, PHYSFS_ERR_NO_SUCH_PATH, 0); |
1947 BAIL_IF_MACRO(len < mntpntlen-1, PHYSFS_ERR_NOT_FOUND, 0); |
1763 /* !!! FIXME: Case insensitive? */ |
1948 /* !!! FIXME: Case insensitive? */ |
1764 retval = strncmp(h->mountPoint, fname, mntpntlen-1); |
1949 retval = strncmp(h->mountPoint, fname, mntpntlen-1); |
1765 BAIL_IF_MACRO(retval != 0, PHYSFS_ERR_NO_SUCH_PATH, 0); |
1950 BAIL_IF_MACRO(retval != 0, PHYSFS_ERR_NOT_FOUND, 0); |
1766 if (len > mntpntlen-1) /* corner case... */ |
1951 if (len > mntpntlen-1) /* corner case... */ |
1767 BAIL_IF_MACRO(fname[mntpntlen-1]!='/', PHYSFS_ERR_NO_SUCH_PATH, 0); |
1952 BAIL_IF_MACRO(fname[mntpntlen-1]!='/', PHYSFS_ERR_NOT_FOUND, 0); |
1768 fname += mntpntlen-1; /* move to start of actual archive path. */ |
1953 fname += mntpntlen-1; /* move to start of actual archive path. */ |
1769 if (*fname == '/') |
1954 if (*fname == '/') |
1770 fname++; |
1955 fname++; |
1771 *_fname = fname; /* skip mountpoint for later use. */ |
1956 *_fname = fname; /* skip mountpoint for later use. */ |
1772 retval = 1; /* may be reset, below. */ |
1957 retval = 1; /* may be reset, below. */ |
2058 callback(data, _fname, ptr); |
2246 callback(data, _fname, ptr); |
2059 __PHYSFS_smallFree(mountPoint); |
2247 __PHYSFS_smallFree(mountPoint); |
2060 } /* enumerateFromMountPoint */ |
2248 } /* enumerateFromMountPoint */ |
2061 |
2249 |
2062 |
2250 |
|
2251 typedef struct SymlinkFilterData |
|
2252 { |
|
2253 PHYSFS_EnumFilesCallback callback; |
|
2254 void *callbackData; |
|
2255 DirHandle *dirhandle; |
|
2256 } SymlinkFilterData; |
|
2257 |
|
2258 /* !!! FIXME: broken if in a virtual mountpoint (stat call fails). */ |
|
2259 static void enumCallbackFilterSymLinks(void *_data, const char *origdir, |
|
2260 const char *fname) |
|
2261 { |
|
2262 const char *trimmedDir = (*origdir == '/') ? (origdir+1) : origdir; |
|
2263 const size_t slen = strlen(trimmedDir) + strlen(fname) + 2; |
|
2264 char *path = (char *) __PHYSFS_smallAlloc(slen); |
|
2265 |
|
2266 if (path != NULL) |
|
2267 { |
|
2268 SymlinkFilterData *data = (SymlinkFilterData *) _data; |
|
2269 const DirHandle *dh = data->dirhandle; |
|
2270 PHYSFS_Stat statbuf; |
|
2271 |
|
2272 sprintf(path, "%s%s%s", trimmedDir, *trimmedDir ? "/" : "", fname); |
|
2273 if (dh->funcs->stat(dh->opaque, path, &statbuf)) |
|
2274 { |
|
2275 /* Pass it on to the application if it's not a symlink. */ |
|
2276 if (statbuf.filetype != PHYSFS_FILETYPE_SYMLINK) |
|
2277 data->callback(data->callbackData, origdir, fname); |
|
2278 } /* if */ |
|
2279 |
|
2280 __PHYSFS_smallFree(path); |
|
2281 } /* if */ |
|
2282 } /* enumCallbackFilterSymLinks */ |
|
2283 |
|
2284 |
2063 /* !!! FIXME: this should report error conditions. */ |
2285 /* !!! FIXME: this should report error conditions. */ |
2064 void PHYSFS_enumerateFilesCallback(const char *_fname, |
2286 void PHYSFS_enumerateFilesCallback(const char *_fname, |
2065 PHYSFS_EnumFilesCallback callback, |
2287 PHYSFS_EnumFilesCallback callback, |
2066 void *data) |
2288 void *data) |
2067 { |
2289 { |
2076 BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, ) /*0*/; |
2298 BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, ) /*0*/; |
2077 |
2299 |
2078 if (sanitizePlatformIndependentPath(_fname, fname)) |
2300 if (sanitizePlatformIndependentPath(_fname, fname)) |
2079 { |
2301 { |
2080 DirHandle *i; |
2302 DirHandle *i; |
2081 int noSyms; |
2303 SymlinkFilterData filterdata; |
2082 |
2304 |
2083 __PHYSFS_platformGrabMutex(stateLock); |
2305 __PHYSFS_platformGrabMutex(stateLock); |
2084 noSyms = !allowSymLinks; |
2306 |
|
2307 if (!allowSymLinks) |
|
2308 { |
|
2309 memset(&filterdata, '\0', sizeof (filterdata)); |
|
2310 filterdata.callback = callback; |
|
2311 filterdata.callbackData = data; |
|
2312 } /* if */ |
|
2313 |
2085 for (i = searchPath; i != NULL; i = i->next) |
2314 for (i = searchPath; i != NULL; i = i->next) |
2086 { |
2315 { |
2087 char *arcfname = fname; |
2316 char *arcfname = fname; |
2088 if (partOfMountPoint(i, arcfname)) |
2317 if (partOfMountPoint(i, arcfname)) |
2089 enumerateFromMountPoint(i, arcfname, callback, _fname, data); |
2318 enumerateFromMountPoint(i, arcfname, callback, _fname, data); |
2090 |
2319 |
2091 else if (verifyPath(i, &arcfname, 0)) |
2320 else if (verifyPath(i, &arcfname, 0)) |
2092 { |
2321 { |
2093 i->funcs->enumerateFiles(i->opaque, arcfname, noSyms, |
2322 if ((!allowSymLinks) && (i->funcs->info.supportsSymlinks)) |
2094 callback, _fname, data); |
2323 { |
|
2324 filterdata.dirhandle = i; |
|
2325 i->funcs->enumerateFiles(i->opaque, arcfname, |
|
2326 enumCallbackFilterSymLinks, |
|
2327 _fname, &filterdata); |
|
2328 } /* if */ |
|
2329 else |
|
2330 { |
|
2331 i->funcs->enumerateFiles(i->opaque, arcfname, |
|
2332 callback, _fname, data); |
|
2333 } /* else */ |
2095 } /* else if */ |
2334 } /* else if */ |
2096 } /* for */ |
2335 } /* for */ |
2097 __PHYSFS_platformReleaseMutex(stateLock); |
2336 __PHYSFS_platformReleaseMutex(stateLock); |
2098 } /* if */ |
2337 } /* if */ |
2099 |
2338 |
2210 fname = (char *) __PHYSFS_smallAlloc(len); |
2449 fname = (char *) __PHYSFS_smallAlloc(len); |
2211 BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); |
2450 BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); |
2212 |
2451 |
2213 if (sanitizePlatformIndependentPath(_fname, fname)) |
2452 if (sanitizePlatformIndependentPath(_fname, fname)) |
2214 { |
2453 { |
2215 int fileExists = 0; |
|
2216 DirHandle *i = NULL; |
2454 DirHandle *i = NULL; |
2217 PHYSFS_Io *io = NULL; |
2455 PHYSFS_Io *io = NULL; |
2218 |
2456 |
2219 __PHYSFS_platformGrabMutex(stateLock); |
2457 __PHYSFS_platformGrabMutex(stateLock); |
2220 |
2458 |
2221 GOTO_IF_MACRO(!searchPath, PHYSFS_ERR_NO_SUCH_PATH, openReadEnd); |
2459 GOTO_IF_MACRO(!searchPath, PHYSFS_ERR_NOT_FOUND, openReadEnd); |
2222 |
2460 |
2223 for (i = searchPath; (i != NULL) && (!fileExists); i = i->next) |
2461 for (i = searchPath; i != NULL; i = i->next) |
2224 { |
2462 { |
2225 char *arcfname = fname; |
2463 char *arcfname = fname; |
2226 if (verifyPath(i, &arcfname, 0)) |
2464 if (verifyPath(i, &arcfname, 0)) |
2227 { |
2465 { |
2228 io = i->funcs->openRead(i->opaque, arcfname, &fileExists); |
2466 io = i->funcs->openRead(i->opaque, arcfname); |
2229 if (io) |
2467 if (io) |
2230 break; |
2468 break; |
2231 } /* if */ |
2469 } /* if */ |
2232 } /* for */ |
2470 } /* for */ |
2233 |
2471 |
2328 if (buffered >= len) /* totally in the buffer, just copy and return! */ |
2566 if (buffered >= len) /* totally in the buffer, just copy and return! */ |
2329 { |
2567 { |
2330 memcpy(buffer, fh->buffer + fh->bufpos, (size_t) len); |
2568 memcpy(buffer, fh->buffer + fh->bufpos, (size_t) len); |
2331 fh->bufpos += (PHYSFS_uint32) len; |
2569 fh->bufpos += (PHYSFS_uint32) len; |
2332 return (PHYSFS_sint64) len; |
2570 return (PHYSFS_sint64) len; |
2333 } /* else if */ |
2571 } /* if */ |
2334 |
2572 |
2335 if (buffered > 0) /* partially in the buffer... */ |
2573 else if (buffered > 0) /* partially in the buffer... */ |
2336 { |
2574 { |
2337 memcpy(buffer, fh->buffer + fh->bufpos, (size_t) buffered); |
2575 memcpy(buffer, fh->buffer + fh->bufpos, (size_t) buffered); |
2338 buffer = ((PHYSFS_uint8 *) buffer) + buffered; |
2576 buffer = ((PHYSFS_uint8 *) buffer) + buffered; |
2339 len -= buffered; |
2577 len -= buffered; |
2340 retval = buffered; |
2578 retval = buffered; |
2341 fh->buffill = fh->bufpos = 0; |
|
2342 } /* if */ |
2579 } /* if */ |
2343 |
2580 |
2344 /* if you got here, the buffer is drained and we still need bytes. */ |
2581 /* if you got here, the buffer is drained and we still need bytes. */ |
2345 assert(len > 0); |
2582 assert(len > 0); |
|
2583 |
|
2584 fh->buffill = fh->bufpos = 0; |
2346 |
2585 |
2347 io = fh->io; |
2586 io = fh->io; |
2348 if (len >= fh->bufsize) /* need more than the buffer takes. */ |
2587 if (len >= fh->bufsize) /* need more than the buffer takes. */ |
2349 { |
2588 { |
2350 /* leave buffer empty, go right to output instead. */ |
2589 /* leave buffer empty, go right to output instead. */ |
2580 /* dump buffer to disk. */ |
2819 /* dump buffer to disk. */ |
2581 io = fh->io; |
2820 io = fh->io; |
2582 rc = io->write(io, fh->buffer + fh->bufpos, fh->buffill - fh->bufpos); |
2821 rc = io->write(io, fh->buffer + fh->bufpos, fh->buffill - fh->bufpos); |
2583 BAIL_IF_MACRO(rc <= 0, ERRPASS, 0); |
2822 BAIL_IF_MACRO(rc <= 0, ERRPASS, 0); |
2584 fh->bufpos = fh->buffill = 0; |
2823 fh->bufpos = fh->buffill = 0; |
2585 return io->flush(io); |
2824 return io->flush ? io->flush(io) : 1; |
2586 } /* PHYSFS_flush */ |
2825 } /* PHYSFS_flush */ |
2587 |
2826 |
2588 |
2827 |
2589 int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) |
2828 int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) |
2590 { |
2829 { |
2591 int retval = 0; |
2830 int retval = 0; |
2592 char *fname; |
2831 char *fname; |
2593 size_t len; |
2832 size_t len; |
2594 |
2833 |
2595 BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, -1); |
2834 BAIL_IF_MACRO(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
2596 BAIL_IF_MACRO(!stat, PHYSFS_ERR_INVALID_ARGUMENT, -1); |
2835 BAIL_IF_MACRO(!stat, PHYSFS_ERR_INVALID_ARGUMENT, 0); |
2597 len = strlen(_fname) + 1; |
2836 len = strlen(_fname) + 1; |
2598 fname = (char *) __PHYSFS_smallAlloc(len); |
2837 fname = (char *) __PHYSFS_smallAlloc(len); |
2599 BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, -1); |
2838 BAIL_IF_MACRO(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); |
2600 |
2839 |
2601 /* set some sane defaults... */ |
2840 /* set some sane defaults... */ |
2602 stat->filesize = -1; |
2841 stat->filesize = -1; |
2603 stat->modtime = -1; |
2842 stat->modtime = -1; |
2604 stat->createtime = -1; |
2843 stat->createtime = -1; |