physfs_platform_macos.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * Mac OS X support routines for PhysicsFS.
  3. *
  4. * Please see the file LICENSE.txt in the source's root directory.
  5. *
  6. * This file written by Ryan C. Gordon.
  7. */
  8. #define __PHYSICSFS_INTERNAL__
  9. #include "physfs_internal.h"
  10. #ifdef PHYSFS_PLATFORM_MACOS
  11. #include <CoreFoundation/CoreFoundation.h>
  12. #if !defined(PHYSFS_NO_CDROM_SUPPORT)
  13. #include <IOKit/IOKitLib.h>
  14. #include <IOKit/storage/IOMedia.h>
  15. #include <IOKit/storage/IOCDMedia.h>
  16. #include <IOKit/storage/IODVDMedia.h>
  17. #include <sys/mount.h>
  18. #endif
  19. int __PHYSFS_platformInit(void)
  20. {
  21. return 1; /* success. */
  22. } /* __PHYSFS_platformInit */
  23. void __PHYSFS_platformDeinit(void)
  24. {
  25. /* no-op */
  26. } /* __PHYSFS_platformDeinit */
  27. /* CD-ROM detection code... */
  28. /*
  29. * Code based on sample from Apple Developer Connection:
  30. * https://developer.apple.com/samplecode/Sample_Code/Devices_and_Hardware/Disks/VolumeToBSDNode/VolumeToBSDNode.c.htm
  31. */
  32. #if !defined(PHYSFS_NO_CDROM_SUPPORT)
  33. static int darwinIsWholeMedia(io_service_t service)
  34. {
  35. int retval = 0;
  36. CFTypeRef wholeMedia;
  37. if (!IOObjectConformsTo(service, kIOMediaClass))
  38. return 0;
  39. wholeMedia = IORegistryEntryCreateCFProperty(service,
  40. CFSTR(kIOMediaWholeKey),
  41. NULL, 0);
  42. if (wholeMedia == NULL)
  43. return 0;
  44. retval = CFBooleanGetValue(wholeMedia);
  45. CFRelease(wholeMedia);
  46. return retval;
  47. } /* darwinIsWholeMedia */
  48. static int darwinIsMountedDisc(char *bsdName, mach_port_t masterPort)
  49. {
  50. int retval = 0;
  51. CFMutableDictionaryRef matchingDict;
  52. kern_return_t rc;
  53. io_iterator_t iter;
  54. io_service_t service;
  55. if ((matchingDict = IOBSDNameMatching(masterPort, 0, bsdName)) == NULL)
  56. return 0;
  57. rc = IOServiceGetMatchingServices(masterPort, matchingDict, &iter);
  58. if ((rc != KERN_SUCCESS) || (!iter))
  59. return 0;
  60. service = IOIteratorNext(iter);
  61. IOObjectRelease(iter);
  62. if (!service)
  63. return 0;
  64. rc = IORegistryEntryCreateIterator(service, kIOServicePlane,
  65. kIORegistryIterateRecursively | kIORegistryIterateParents, &iter);
  66. if (!iter)
  67. return 0;
  68. if (rc != KERN_SUCCESS)
  69. {
  70. IOObjectRelease(iter);
  71. return 0;
  72. } /* if */
  73. IOObjectRetain(service); /* add an extra object reference... */
  74. do
  75. {
  76. if (darwinIsWholeMedia(service))
  77. {
  78. if ( (IOObjectConformsTo(service, kIOCDMediaClass)) ||
  79. (IOObjectConformsTo(service, kIODVDMediaClass)) )
  80. {
  81. retval = 1;
  82. } /* if */
  83. } /* if */
  84. IOObjectRelease(service);
  85. } while ((service = IOIteratorNext(iter)) && (!retval));
  86. IOObjectRelease(iter);
  87. IOObjectRelease(service);
  88. return retval;
  89. } /* darwinIsMountedDisc */
  90. #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
  91. void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
  92. {
  93. #if !defined(PHYSFS_NO_CDROM_SUPPORT)
  94. const char *devPrefix = "/dev/";
  95. const int prefixLen = strlen(devPrefix);
  96. mach_port_t masterPort = 0;
  97. struct statfs *mntbufp;
  98. int i, mounts;
  99. if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
  100. BAIL(PHYSFS_ERR_OS_ERROR, ) /*return void*/;
  101. mounts = getmntinfo(&mntbufp, MNT_WAIT); /* NOT THREAD SAFE! */
  102. for (i = 0; i < mounts; i++)
  103. {
  104. char *dev = mntbufp[i].f_mntfromname;
  105. char *mnt = mntbufp[i].f_mntonname;
  106. if (strncmp(dev, devPrefix, prefixLen) != 0) /* a virtual device? */
  107. continue;
  108. dev += prefixLen;
  109. if (darwinIsMountedDisc(dev, masterPort))
  110. cb(data, mnt);
  111. } /* for */
  112. #endif /* !defined(PHYSFS_NO_CDROM_SUPPORT) */
  113. } /* __PHYSFS_platformDetectAvailableCDs */
  114. static char *convertCFString(CFStringRef cfstr)
  115. {
  116. CFIndex len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
  117. kCFStringEncodingUTF8) + 1;
  118. char *retval = (char *) allocator.Malloc(len);
  119. BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  120. if (CFStringGetCString(cfstr, retval, len, kCFStringEncodingUTF8))
  121. {
  122. /* shrink overallocated buffer if possible... */
  123. CFIndex newlen = strlen(retval) + 1;
  124. if (newlen < len)
  125. {
  126. void *ptr = allocator.Realloc(retval, newlen);
  127. if (ptr != NULL)
  128. retval = (char *) ptr;
  129. } /* if */
  130. } /* if */
  131. else /* probably shouldn't fail, but just in case... */
  132. {
  133. allocator.Free(retval);
  134. BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  135. } /* else */
  136. return retval;
  137. } /* convertCFString */
  138. char *__PHYSFS_platformCalcBaseDir(const char *argv0)
  139. {
  140. CFURLRef cfurl = NULL;
  141. CFStringRef cfstr = NULL;
  142. CFMutableStringRef cfmutstr = NULL;
  143. char *retval = NULL;
  144. cfurl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
  145. BAIL_IF(cfurl == NULL, PHYSFS_ERR_OS_ERROR, NULL);
  146. cfstr = CFURLCopyFileSystemPath(cfurl, kCFURLPOSIXPathStyle);
  147. CFRelease(cfurl);
  148. BAIL_IF(!cfstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  149. cfmutstr = CFStringCreateMutableCopy(NULL, 0, cfstr);
  150. CFRelease(cfstr);
  151. BAIL_IF(!cfmutstr, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  152. CFStringAppendCString(cfmutstr, "/", kCFStringEncodingUTF8);
  153. retval = convertCFString(cfmutstr);
  154. CFRelease(cfmutstr);
  155. return retval; /* whew. */
  156. } /* __PHYSFS_platformCalcBaseDir */
  157. char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
  158. {
  159. /* !!! FIXME: there's a real API to determine this */
  160. const char *userdir = __PHYSFS_getUserDir();
  161. const char *append = "Library/Application Support/";
  162. const size_t len = strlen(userdir) + strlen(append) + strlen(app) + 2;
  163. char *retval = allocator.Malloc(len);
  164. BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
  165. snprintf(retval, len, "%s%s%s/", userdir, append, app);
  166. return retval;
  167. } /* __PHYSFS_platformCalcPrefDir */
  168. #endif /* PHYSFS_PLATFORM_MACOS */
  169. /* end of physfs_platform_macos.c ... */