unix.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*
  2. * Unix support routines for PhysicsFS.
  3. *
  4. * Please see the file LICENSE in the source's root directory.
  5. *
  6. * This file written by Ryan C. Gordon.
  7. */
  8. #if (defined __STRICT_ANSI__)
  9. #define __PHYSFS_DOING_STRICT_ANSI__
  10. #endif
  11. /*
  12. * We cheat a little: I want the symlink version of stat() (lstat), and
  13. * GCC/Linux will not declare it if compiled with the -ansi flag.
  14. * If you are really lacking symlink support on your platform,
  15. * you should #define __PHYSFS_NO_SYMLINKS__ before compiling this
  16. * file. That will open a security hole, though, if you really DO have
  17. * symlinks on your platform; it renders PHYSFS_permitSymbolicLinks(0)
  18. * useless, since every symlink will be reported as a regular file/dir.
  19. */
  20. #if (defined __PHYSFS_DOING_STRICT_ANSI__)
  21. #undef __STRICT_ANSI__
  22. #endif
  23. #include <stdio.h>
  24. #if (defined __PHYSFS_DOING_STRICT_ANSI__)
  25. #define __STRICT_ANSI__
  26. #endif
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <ctype.h>
  30. #include <pthread.h>
  31. #include <unistd.h>
  32. #include <sys/types.h>
  33. #include <pwd.h>
  34. #include <sys/stat.h>
  35. #include <dirent.h>
  36. #include <time.h>
  37. #include <errno.h>
  38. #define __PHYSICSFS_INTERNAL__
  39. #include "physfs_internal.h"
  40. const char *__PHYSFS_platformDirSeparator = "/";
  41. char **__PHYSFS_platformDetectAvailableCDs(void)
  42. {
  43. /* !!! write me. */
  44. char **retval = malloc(sizeof (char *));
  45. if (retval != NULL)
  46. *retval = NULL;
  47. return(retval);
  48. } /* __PHYSFS_detectAvailableCDs */
  49. static char *copyEnvironmentVariable(const char *varname)
  50. {
  51. const char *envr = getenv(varname);
  52. char *retval = NULL;
  53. if (envr != NULL)
  54. {
  55. retval = malloc(strlen(envr) + 1);
  56. if (retval != NULL)
  57. strcpy(retval, envr);
  58. } /* if */
  59. return(retval);
  60. } /* copyEnvironmentVariable */
  61. /* !!! this is ugly. */
  62. char *__PHYSFS_platformCalcBaseDir(const char *argv0)
  63. {
  64. /* If there isn't a path on argv0, then look through the $PATH for it. */
  65. char *retval = NULL;
  66. char *envr;
  67. char *start;
  68. char *ptr;
  69. char *exe;
  70. if (strchr(argv0, '/') != NULL) /* default behaviour can handle this. */
  71. return(NULL);
  72. envr = copyEnvironmentVariable("PATH");
  73. BAIL_IF_MACRO(!envr, NULL, NULL);
  74. start = envr;
  75. do
  76. {
  77. ptr = strchr(start, ':');
  78. if (ptr)
  79. *ptr = '\0';
  80. exe = (char *) malloc(strlen(start) + strlen(argv0) + 2);
  81. if (!exe)
  82. {
  83. free(envr);
  84. BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
  85. } /* if */
  86. strcpy(exe, start);
  87. if (start[strlen(start) - 1] != '/')
  88. strcat(start, "/");
  89. strcat(start, argv0);
  90. if (access(exe, X_OK) != 0)
  91. free(exe);
  92. else
  93. {
  94. retval = exe;
  95. strcpy(retval, start); /* i'm lazy. piss off. */
  96. break;
  97. } /* else */
  98. start = ptr + 1;
  99. } while (ptr != NULL);
  100. free(envr);
  101. return(retval);
  102. } /* __PHYSFS_platformCalcBaseDir */
  103. static char *getUserNameByUID(void)
  104. {
  105. uid_t uid = getuid();
  106. struct passwd *pw;
  107. char *retval = NULL;
  108. pw = getpwuid(uid);
  109. if ((pw != NULL) && (pw->pw_name != NULL))
  110. {
  111. retval = malloc(strlen(pw->pw_name) + 1);
  112. if (retval != NULL)
  113. strcpy(retval, pw->pw_name);
  114. } /* if */
  115. return(retval);
  116. } /* getUserNameByUID */
  117. static char *getUserDirByUID(void)
  118. {
  119. uid_t uid = getuid();
  120. struct passwd *pw;
  121. char *retval = NULL;
  122. pw = getpwuid(uid);
  123. if ((pw != NULL) && (pw->pw_dir != NULL))
  124. {
  125. retval = malloc(strlen(pw->pw_dir) + 1);
  126. if (retval != NULL)
  127. strcpy(retval, pw->pw_dir);
  128. } /* if */
  129. return(retval);
  130. } /* getUserDirByUID */
  131. char *__PHYSFS_platformGetUserName(void)
  132. {
  133. char *retval = getUserNameByUID();
  134. if (retval == NULL)
  135. retval = copyEnvironmentVariable("USER");
  136. return(retval);
  137. } /* __PHYSFS_platformGetUserName */
  138. char *__PHYSFS_platformGetUserDir(void)
  139. {
  140. char *retval = copyEnvironmentVariable("HOME");
  141. if (retval == NULL)
  142. retval = getUserDirByUID();
  143. return(retval);
  144. } /* __PHYSFS_platformGetUserDir */
  145. int __PHYSFS_platformGetThreadID(void)
  146. {
  147. return((int) pthread_self());
  148. } /* __PHYSFS_platformGetThreadID */
  149. /* -ansi and -pedantic flags prevent use of strcasecmp() on Linux. */
  150. int __PHYSFS_platformStricmp(const char *x, const char *y)
  151. {
  152. int ux, uy;
  153. do
  154. {
  155. ux = toupper((int) *x);
  156. uy = toupper((int) *y);
  157. if (ux > uy)
  158. return(1);
  159. else if (ux < uy)
  160. return(-1);
  161. x++;
  162. y++;
  163. } while ((ux) && (uy));
  164. return(0);
  165. } /* __PHYSFS_platformStricmp */
  166. int __PHYSFS_platformExists(const char *fname)
  167. {
  168. struct stat statbuf;
  169. return(stat(fname, &statbuf) == 0);
  170. } /* __PHYSFS_platformExists */
  171. int __PHYSFS_platformIsSymLink(const char *fname)
  172. {
  173. #if (defined __PHYSFS_NO_SYMLINKS__)
  174. return(0);
  175. #else
  176. struct stat statbuf;
  177. int retval = 0;
  178. if (lstat(fname, &statbuf) == 0)
  179. {
  180. if (S_ISLNK(statbuf.st_mode))
  181. retval = 1;
  182. } /* if */
  183. return(retval);
  184. #endif
  185. } /* __PHYSFS_platformIsSymlink */
  186. int __PHYSFS_platformIsDirectory(const char *fname)
  187. {
  188. struct stat statbuf;
  189. int retval = 0;
  190. if (stat(fname, &statbuf) == 0)
  191. {
  192. if (S_ISDIR(statbuf.st_mode))
  193. retval = 1;
  194. } /* if */
  195. return(retval);
  196. } /* __PHYSFS_platformIsDirectory */
  197. char *__PHYSFS_platformCvtToDependent(const char *prepend,
  198. const char *dirName,
  199. const char *append)
  200. {
  201. int len = ((prepend) ? strlen(prepend) : 0) +
  202. ((append) ? strlen(append) : 0) +
  203. strlen(dirName) + 1;
  204. char *retval = malloc(len);
  205. BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
  206. /* platform-independent notation is Unix-style already. :) */
  207. if (prepend)
  208. strcpy(retval, prepend);
  209. else
  210. retval[0] = '\0';
  211. strcat(retval, dirName);
  212. if (append)
  213. strcat(retval, append);
  214. return(retval);
  215. } /* __PHYSFS_platformCvtToDependent */
  216. /* Much like my college days, try to sleep for 10 milliseconds at a time... */
  217. void __PHYSFS_platformTimeslice(void)
  218. {
  219. struct timespec napTime;
  220. napTime.tv_sec = 0;
  221. napTime.tv_nsec = 10 * 1000 * 1000; /* specified in nanoseconds. */
  222. nanosleep(&napTime, NULL); /* don't care if it fails. */
  223. } /* __PHYSFS_platformTimeslice */
  224. LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname)
  225. {
  226. LinkedStringList *retval = NULL;
  227. LinkedStringList *l = NULL;
  228. LinkedStringList *prev = NULL;
  229. DIR *dir;
  230. struct dirent *ent;
  231. errno = 0;
  232. dir = opendir(dirname);
  233. BAIL_IF_MACRO(dir == NULL, strerror(errno), NULL);
  234. while (1)
  235. {
  236. ent = readdir(dir);
  237. if (ent == NULL) /* we're done. */
  238. break;
  239. l = (LinkedStringList *) malloc(sizeof (LinkedStringList));
  240. if (l != NULL)
  241. break;
  242. l->str = (char *) malloc(strlen(ent->d_name) + 1);
  243. if (l->str == NULL)
  244. {
  245. free(l);
  246. break;
  247. } /* if */
  248. if (retval == NULL)
  249. retval = l;
  250. else
  251. prev->next = l;
  252. prev = l;
  253. l->next = NULL;
  254. } /* while */
  255. closedir(dir);
  256. return(retval);
  257. } /* __PHYSFS_platformEnumerateFiles */
  258. int __PHYSFS_platformFileLength(FILE *handle)
  259. {
  260. struct stat statbuf;
  261. errno = 0;
  262. BAIL_IF_MACRO(fstat(fileno(handle), &statbuf) == -1, strerror(errno), -1);
  263. return(statbuf.st_size);
  264. } /* __PHYSFS_platformFileLength */
  265. /* end of unix.c ... */