Skip to content

Latest commit

 

History

History
448 lines (351 loc) · 11.2 KB

platform_unix.c

File metadata and controls

448 lines (351 loc) · 11.2 KB
 
Jul 7, 2001
Jul 7, 2001
1
2
3
/*
* Unix support routines for PhysicsFS.
*
Mar 11, 2007
Mar 11, 2007
4
* Please see the file LICENSE.txt in the source's root directory.
Jul 7, 2001
Jul 7, 2001
5
6
7
8
*
* This file written by Ryan C. Gordon.
*/
Mar 11, 2007
Mar 11, 2007
9
10
11
12
#define __PHYSICSFS_INTERNAL__
#include "physfs_platforms.h"
#ifdef PHYSFS_PLATFORM_UNIX
Jun 29, 2002
Jun 29, 2002
13
Jul 8, 2001
Jul 8, 2001
14
15
16
17
18
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <sys/stat.h>
Jul 16, 2001
Jul 16, 2001
19
#include <sys/param.h>
Jul 8, 2001
Jul 8, 2001
20
21
22
#include <dirent.h>
#include <time.h>
#include <errno.h>
Mar 5, 2002
Mar 5, 2002
23
Mar 22, 2010
Mar 22, 2010
24
#if (!defined PHYSFS_NO_THREAD_SUPPORT)
Jul 25, 2002
Jul 25, 2002
25
26
27
#include <pthread.h>
#endif
Jul 20, 2002
Jul 20, 2002
28
29
30
31
#ifdef PHYSFS_HAVE_SYS_UCRED_H
# ifdef PHYSFS_HAVE_MNTENT_H
# undef PHYSFS_HAVE_MNTENT_H /* don't do both... */
# endif
May 3, 2009
May 3, 2009
32
# include <sys/mount.h>
Jul 20, 2002
Jul 20, 2002
33
# include <sys/ucred.h>
Mar 5, 2002
Mar 5, 2002
34
#endif
Jul 7, 2001
Jul 7, 2001
35
Jul 20, 2002
Jul 20, 2002
36
37
38
#ifdef PHYSFS_HAVE_MNTENT_H
#include <mntent.h>
#endif
Apr 6, 2002
Apr 6, 2002
39
Apr 13, 2009
Apr 13, 2009
40
41
42
43
#ifdef PHYSFS_HAVE_SYS_MNTTAB_H
#include <sys/mnttab.h>
#endif
Jul 7, 2001
Jul 7, 2001
44
45
#include "physfs_internal.h"
Mar 15, 2010
Mar 15, 2010
46
47
48
49
/* !!! FIXME: we should probably remove MAXPATHLEN entirely, if we can. */
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
Mar 5, 2002
Mar 5, 2002
50
Mar 24, 2002
Mar 24, 2002
51
52
int __PHYSFS_platformInit(void)
{
Jan 28, 2010
Jan 28, 2010
53
return 1; /* always succeed. */
Mar 24, 2002
Mar 24, 2002
54
55
56
57
58
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
Jan 28, 2010
Jan 28, 2010
59
return 1; /* always succeed. */
Mar 24, 2002
Mar 24, 2002
60
61
62
} /* __PHYSFS_platformDeinit */
Jul 25, 2002
Jul 25, 2002
63
/* Stub version for platforms without CD-ROM support. */
Sep 29, 2004
Sep 29, 2004
64
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
Jul 25, 2002
Jul 25, 2002
65
{
Apr 13, 2009
Apr 13, 2009
66
67
#if (defined PHYSFS_NO_CDROM_SUPPORT)
/* no-op. */
Jul 25, 2002
Jul 25, 2002
68
May 24, 2003
May 24, 2003
69
#elif (defined PHYSFS_HAVE_SYS_UCRED_H)
Jul 25, 2002
Jul 25, 2002
70
int i;
Sep 29, 2004
Sep 29, 2004
71
72
struct statfs *mntbufp = NULL;
int mounts = getmntinfo(&mntbufp, MNT_WAIT);
Mar 5, 2002
Mar 5, 2002
73
Jul 25, 2002
Jul 25, 2002
74
75
for (i = 0; i < mounts; i++)
{
Mar 5, 2002
Mar 5, 2002
76
77
int add_it = 0;
Jul 25, 2002
Jul 25, 2002
78
if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0)
Mar 5, 2002
Mar 5, 2002
79
add_it = 1;
Jul 25, 2002
Jul 25, 2002
80
else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0)
Apr 6, 2002
Apr 6, 2002
81
add_it = 1;
May 21, 2002
May 21, 2002
82
83
/* add other mount types here */
Mar 5, 2002
Mar 5, 2002
84
85
if (add_it)
Sep 29, 2004
Sep 29, 2004
86
cb(data, mntbufp[i].f_mntonname);
Jul 25, 2002
Jul 25, 2002
87
} /* for */
Mar 5, 2002
Mar 5, 2002
88
May 24, 2003
May 24, 2003
89
#elif (defined PHYSFS_HAVE_MNTENT_H)
Aug 7, 2001
Aug 7, 2001
90
91
92
93
FILE *mounts = NULL;
struct mntent *ent = NULL;
mounts = setmntent("/etc/mtab", "r");
Mar 13, 2005
Mar 13, 2005
94
BAIL_IF_MACRO(mounts == NULL, ERR_IO_ERROR, /*return void*/);
Aug 7, 2001
Aug 7, 2001
95
96
97
98
99
100
while ( (ent = getmntent(mounts)) != NULL )
{
int add_it = 0;
if (strcmp(ent->mnt_type, "iso9660") == 0)
add_it = 1;
Mar 22, 2010
Mar 22, 2010
101
102
103
104
105
106
107
108
else if (strcmp(ent->mnt_type, "udf") == 0)
add_it = 1;
/* !!! FIXME: these might pick up floppy drives, right? */
else if (strcmp(ent->mnt_type, "auto") == 0)
add_it = 1;
else if (strcmp(ent->mnt_type, "supermount") == 0)
add_it = 1;
May 21, 2002
May 21, 2002
109
Mar 1, 2010
Mar 1, 2010
110
111
/* !!! FIXME: udf? automount? */
May 21, 2002
May 21, 2002
112
/* add other mount types here */
Aug 7, 2001
Aug 7, 2001
113
114
if (add_it)
Sep 29, 2004
Sep 29, 2004
115
cb(data, ent->mnt_dir);
Aug 7, 2001
Aug 7, 2001
116
117
118
} /* while */
endmntent(mounts);
Apr 13, 2009
Apr 13, 2009
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#elif (defined PHYSFS_HAVE_SYS_MNTTAB_H)
FILE *mounts = fopen(MNTTAB, "r");
struct mnttab ent;
BAIL_IF_MACRO(mounts == NULL, ERR_IO_ERROR, /*return void*/);
while (getmntent(mounts, &ent) == 0)
{
int add_it = 0;
if (strcmp(ent.mnt_fstype, "hsfs") == 0)
add_it = 1;
/* add other mount types here */
if (add_it)
cb(data, ent.mnt_mountp);
} /* while */
fclose(mounts);
#else
#error Unknown platform. Should have defined PHYSFS_NO_CDROM_SUPPORT, perhaps.
Mar 5, 2002
Mar 5, 2002
141
#endif
Apr 13, 2009
Apr 13, 2009
142
} /* __PHYSFS_platformDetectAvailableCDs */
Jul 7, 2001
Jul 7, 2001
143
144
May 24, 2002
May 24, 2002
145
146
/* this is in posix.c ... */
extern char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname);
Jul 8, 2001
Jul 8, 2001
147
148
May 21, 2002
May 21, 2002
149
150
151
152
153
154
/*
* See where program (bin) resides in the $PATH specified by (envr).
* returns a copy of the first element in envr that contains it, or NULL
* if it doesn't exist or there were other problems. PHYSFS_SetError() is
* called if we have a problem.
*
Mar 14, 2005
Mar 14, 2005
155
* (envr) will be scribbled over, and you are expected to allocator.Free() the
May 21, 2002
May 21, 2002
156
157
158
* return value when you're done with it.
*/
static char *findBinaryInPath(const char *bin, char *envr)
Jul 8, 2001
Jul 8, 2001
159
{
May 21, 2002
May 21, 2002
160
161
162
size_t alloc_size = 0;
char *exe = NULL;
char *start = envr;
Jul 8, 2001
Jul 8, 2001
163
164
char *ptr;
May 21, 2002
May 21, 2002
165
166
BAIL_IF_MACRO(bin == NULL, ERR_INVALID_ARGUMENT, NULL);
BAIL_IF_MACRO(envr == NULL, ERR_INVALID_ARGUMENT, NULL);
Jul 8, 2001
Jul 8, 2001
167
168
169
do
{
May 21, 2002
May 21, 2002
170
171
size_t size;
ptr = strchr(start, ':'); /* find next $PATH separator. */
Jul 8, 2001
Jul 8, 2001
172
173
174
if (ptr)
*ptr = '\0';
May 21, 2002
May 21, 2002
175
176
size = strlen(start) + strlen(bin) + 2;
if (size > alloc_size)
Jul 8, 2001
Jul 8, 2001
177
{
Mar 14, 2005
Mar 14, 2005
178
char *x = (char *) allocator.Realloc(exe, size);
May 21, 2002
May 21, 2002
179
180
181
if (x == NULL)
{
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
182
allocator.Free(exe);
May 21, 2002
May 21, 2002
183
184
185
186
187
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
alloc_size = size;
exe = x;
Jul 8, 2001
Jul 8, 2001
188
} /* if */
May 21, 2002
May 21, 2002
189
190
/* build full binary path... */
Jul 8, 2001
Jul 8, 2001
191
strcpy(exe, start);
Nov 30, 2002
Nov 30, 2002
192
if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
Aug 29, 2001
Aug 29, 2001
193
strcat(exe, "/");
May 21, 2002
May 21, 2002
194
195
196
strcat(exe, bin);
if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */
Jul 8, 2001
Jul 8, 2001
197
{
May 21, 2002
May 21, 2002
198
strcpy(exe, start); /* i'm lazy. piss off. */
Jan 28, 2010
Jan 28, 2010
199
return exe;
May 21, 2002
May 21, 2002
200
} /* if */
Jul 8, 2001
Jul 8, 2001
201
May 21, 2002
May 21, 2002
202
start = ptr + 1; /* start points to beginning of next element. */
Jul 8, 2001
Jul 8, 2001
203
204
} while (ptr != NULL);
May 21, 2002
May 21, 2002
205
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
206
allocator.Free(exe);
May 21, 2002
May 21, 2002
207
Jan 28, 2010
Jan 28, 2010
208
return NULL; /* doesn't exist in path. */
May 21, 2002
May 21, 2002
209
210
211
} /* findBinaryInPath */
Jul 8, 2009
Jul 8, 2009
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
static char *readSymLink(const char *path)
{
ssize_t len = 64;
ssize_t rc = -1;
char *retval = NULL;
while (1)
{
char *ptr = (char *) allocator.Realloc(retval, (size_t) len);
if (ptr == NULL)
break; /* out of memory. */
retval = ptr;
rc = readlink(path, retval, len);
if (rc == -1)
break; /* not a symlink, i/o error, etc. */
else if (rc < len)
{
retval[rc] = '\0'; /* readlink doesn't null-terminate. */
return retval; /* we're good to go. */
} /* else if */
len *= 2; /* grow buffer, try again. */
} /* while */
if (retval != NULL)
allocator.Free(retval);
return NULL;
} /* readSymLink */
May 21, 2002
May 21, 2002
244
245
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
Mar 19, 2007
Mar 19, 2007
246
247
248
249
250
char *retval = NULL;
char *envr = NULL;
/* fast path: default behaviour can handle this. */
if ( (argv0 != NULL) && (strchr(argv0, '/') != NULL) )
Jan 28, 2010
Jan 28, 2010
251
return NULL; /* higher level will parse out real path from argv0. */
May 21, 2002
May 21, 2002
252
Mar 19, 2007
Mar 19, 2007
253
254
255
256
257
/*
* Try to avoid using argv0 unless forced to. If there's a Linux-like
* /proc filesystem, you can get the full path to the current process from
* the /proc/self/exe symlink.
*/
Jul 8, 2009
Jul 8, 2009
258
retval = readSymLink("/proc/self/exe");
Jul 8, 2009
Jul 8, 2009
259
260
261
262
263
264
265
266
267
268
if (retval == NULL)
{
/* older kernels don't have /proc/self ... try PID version... */
const unsigned long long pid = (unsigned long long) getpid();
char path[64];
const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
if ( (rc > 0) && (rc < sizeof(path)) )
retval = readSymLink(path);
} /* if */
Jul 8, 2009
Jul 8, 2009
269
if (retval != NULL) /* chop off filename. */
Mar 19, 2007
Mar 19, 2007
270
{
Jul 8, 2009
Jul 8, 2009
271
272
273
char *ptr = strrchr(retval, '/');
if (ptr != NULL)
*ptr = '\0';
Mar 19, 2007
Mar 19, 2007
274
} /* if */
May 21, 2002
May 21, 2002
275
Mar 19, 2007
Mar 19, 2007
276
277
278
279
280
281
282
283
if ((retval == NULL) && (argv0 != NULL))
{
/* If there's no dirsep on argv0, then look through $PATH for it. */
envr = __PHYSFS_platformCopyEnvironmentVariable("PATH");
BAIL_IF_MACRO(!envr, NULL, NULL);
retval = findBinaryInPath(argv0, envr);
allocator.Free(envr);
} /* if */
May 21, 2002
May 21, 2002
284
Jul 8, 2009
Jul 8, 2009
285
286
287
288
289
290
291
292
if (retval != NULL)
{
/* try to shrink buffer... */
char *ptr = (char *) allocator.Realloc(retval, strlen(retval) + 1);
if (ptr != NULL)
retval = ptr; /* oh well if it failed. */
} /* if */
Jan 28, 2010
Jan 28, 2010
293
return retval;
Jul 8, 2001
Jul 8, 2001
294
295
296
} /* __PHYSFS_platformCalcBaseDir */
Jul 16, 2001
Jul 16, 2001
297
298
299
300
301
302
303
char *__PHYSFS_platformRealPath(const char *path)
{
char resolved_path[MAXPATHLEN];
char *retval = NULL;
errno = 0;
BAIL_IF_MACRO(!realpath(path, resolved_path), strerror(errno), NULL);
Mar 14, 2005
Mar 14, 2005
304
retval = (char *) allocator.Malloc(strlen(resolved_path) + 1);
Jul 16, 2001
Jul 16, 2001
305
306
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, resolved_path);
Jan 4, 2003
Jan 4, 2003
307
Jan 28, 2010
Jan 28, 2010
308
return retval;
Jul 16, 2001
Jul 16, 2001
309
310
} /* __PHYSFS_platformRealPath */
Aug 23, 2001
Aug 23, 2001
311
Mar 21, 2007
Mar 21, 2007
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
char *__PHYSFS_platformCurrentDir(void)
{
/*
* This can't just do platformRealPath("."), since that would eventually
* just end up calling back into here.
*/
int allocSize = 0;
char *retval = NULL;
char *ptr;
do
{
allocSize += 100;
ptr = (char *) allocator.Realloc(retval, allocSize);
if (ptr == NULL)
{
if (retval != NULL)
allocator.Free(retval);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
retval = ptr;
ptr = getcwd(retval, allocSize);
} while (ptr == NULL && errno == ERANGE);
if (ptr == NULL && errno)
{
/*
* getcwd() failed for some reason, for example current
* directory not existing.
*/
if (retval != NULL)
allocator.Free(retval);
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* if */
Jan 28, 2010
Jan 28, 2010
349
return retval;
Mar 21, 2007
Mar 21, 2007
350
351
352
} /* __PHYSFS_platformCurrentDir */
Mar 20, 2007
Mar 20, 2007
353
354
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
{
Jan 28, 2010
Jan 28, 2010
355
return 0; /* just use malloc() and friends. */
Mar 20, 2007
Mar 20, 2007
356
357
358
} /* __PHYSFS_platformSetDefaultAllocator */
Mar 22, 2010
Mar 22, 2010
359
#if (defined PHYSFS_NO_THREAD_SUPPORT)
Jul 25, 2002
Jul 25, 2002
360
Jan 28, 2010
Jan 28, 2010
361
362
void *__PHYSFS_platformGetThreadID(void) { return ((void *) 0x0001); }
void *__PHYSFS_platformCreateMutex(void) { return ((void *) 0x0001); }
Jul 25, 2002
Jul 25, 2002
363
void __PHYSFS_platformDestroyMutex(void *mutex) {}
Jan 28, 2010
Jan 28, 2010
364
int __PHYSFS_platformGrabMutex(void *mutex) { return 1; }
Jul 25, 2002
Jul 25, 2002
365
366
367
368
void __PHYSFS_platformReleaseMutex(void *mutex) {}
#else
Apr 3, 2007
Apr 3, 2007
369
370
371
372
373
374
375
typedef struct
{
pthread_mutex_t mutex;
pthread_t owner;
PHYSFS_uint32 count;
} PthreadMutex;
Jul 25, 2002
Jul 25, 2002
376
Sep 6, 2009
Sep 6, 2009
377
void *__PHYSFS_platformGetThreadID(void)
Jul 25, 2002
Jul 25, 2002
378
{
Jan 28, 2010
Jan 28, 2010
379
return ( (void *) ((size_t) pthread_self()) );
Jul 25, 2002
Jul 25, 2002
380
381
382
} /* __PHYSFS_platformGetThreadID */
Mar 30, 2002
Mar 30, 2002
383
384
385
void *__PHYSFS_platformCreateMutex(void)
{
int rc;
Apr 3, 2007
Apr 3, 2007
386
387
388
PthreadMutex *m = (PthreadMutex *) allocator.Malloc(sizeof (PthreadMutex));
BAIL_IF_MACRO(m == NULL, ERR_OUT_OF_MEMORY, NULL);
rc = pthread_mutex_init(&m->mutex, NULL);
Mar 30, 2002
Mar 30, 2002
389
390
if (rc != 0)
{
Mar 14, 2005
Mar 14, 2005
391
allocator.Free(m);
Mar 30, 2002
Mar 30, 2002
392
393
394
BAIL_MACRO(strerror(rc), NULL);
} /* if */
Apr 3, 2007
Apr 3, 2007
395
396
m->count = 0;
m->owner = (pthread_t) 0xDEADBEEF;
Jan 28, 2010
Jan 28, 2010
397
return ((void *) m);
Mar 30, 2002
Mar 30, 2002
398
399
400
401
402
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
403
404
405
406
407
408
409
PthreadMutex *m = (PthreadMutex *) mutex;
/* Destroying a locked mutex is a bug, but we'll try to be helpful. */
if ((m->owner == pthread_self()) && (m->count > 0))
pthread_mutex_unlock(&m->mutex);
pthread_mutex_destroy(&m->mutex);
Sep 20, 2005
Sep 20, 2005
410
allocator.Free(m);
Mar 30, 2002
Mar 30, 2002
411
412
413
414
415
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
416
417
418
419
420
PthreadMutex *m = (PthreadMutex *) mutex;
pthread_t tid = pthread_self();
if (m->owner != tid)
{
if (pthread_mutex_lock(&m->mutex) != 0)
Jan 28, 2010
Jan 28, 2010
421
return 0;
Apr 3, 2007
Apr 3, 2007
422
423
424
425
m->owner = tid;
} /* if */
m->count++;
Jan 28, 2010
Jan 28, 2010
426
return 1;
Mar 30, 2002
Mar 30, 2002
427
428
429
430
431
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
432
433
434
435
436
437
438
439
440
PthreadMutex *m = (PthreadMutex *) mutex;
if (m->owner == pthread_self())
{
if (--m->count == 0)
{
m->owner = (pthread_t) 0xDEADBEEF;
pthread_mutex_unlock(&m->mutex);
} /* if */
} /* if */
Mar 30, 2002
Mar 30, 2002
441
442
} /* __PHYSFS_platformReleaseMutex */
Mar 22, 2010
Mar 22, 2010
443
#endif /* !PHYSFS_NO_THREAD_SUPPORT */
Jul 25, 2002
Jul 25, 2002
444
Mar 11, 2007
Mar 11, 2007
445
#endif /* PHYSFS_PLATFORM_UNIX */
May 24, 2002
May 24, 2002
446
Jul 7, 2001
Jul 7, 2001
447
/* end of unix.c ... */