Skip to content

Latest commit

 

History

History
451 lines (354 loc) · 11.3 KB

platform_unix.c

File metadata and controls

451 lines (354 loc) · 11.3 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 7, 2001
Jul 7, 2001
14
15
#include <stdio.h>
#include <stdlib.h>
Jul 8, 2001
Jul 8, 2001
16
17
18
19
20
21
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <sys/stat.h>
Jul 16, 2001
Jul 16, 2001
22
#include <sys/param.h>
Jul 8, 2001
Jul 8, 2001
23
24
25
#include <dirent.h>
#include <time.h>
#include <errno.h>
Mar 5, 2002
Mar 5, 2002
26
Feb 15, 2010
Feb 15, 2010
27
#if (!defined PHYSFS_NO_PTHREADS_SUPPORT)
Jul 25, 2002
Jul 25, 2002
28
29
30
#include <pthread.h>
#endif
Jul 20, 2002
Jul 20, 2002
31
32
33
34
#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
35
# include <sys/mount.h>
Jul 20, 2002
Jul 20, 2002
36
# include <sys/ucred.h>
Mar 5, 2002
Mar 5, 2002
37
#endif
Jul 7, 2001
Jul 7, 2001
38
Jul 20, 2002
Jul 20, 2002
39
40
41
#ifdef PHYSFS_HAVE_MNTENT_H
#include <mntent.h>
#endif
Apr 6, 2002
Apr 6, 2002
42
Apr 13, 2009
Apr 13, 2009
43
44
45
46
#ifdef PHYSFS_HAVE_SYS_MNTTAB_H
#include <sys/mnttab.h>
#endif
Jul 7, 2001
Jul 7, 2001
47
48
#include "physfs_internal.h"
Mar 15, 2010
Mar 15, 2010
49
50
51
52
/* !!! FIXME: we should probably remove MAXPATHLEN entirely, if we can. */
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
Mar 5, 2002
Mar 5, 2002
53
Mar 24, 2002
Mar 24, 2002
54
55
int __PHYSFS_platformInit(void)
{
Jan 28, 2010
Jan 28, 2010
56
return 1; /* always succeed. */
Mar 24, 2002
Mar 24, 2002
57
58
59
60
61
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
Jan 28, 2010
Jan 28, 2010
62
return 1; /* always succeed. */
Mar 24, 2002
Mar 24, 2002
63
64
65
} /* __PHYSFS_platformDeinit */
Jul 25, 2002
Jul 25, 2002
66
/* Stub version for platforms without CD-ROM support. */
Sep 29, 2004
Sep 29, 2004
67
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
Jul 25, 2002
Jul 25, 2002
68
{
Apr 13, 2009
Apr 13, 2009
69
70
#if (defined PHYSFS_NO_CDROM_SUPPORT)
/* no-op. */
Jul 25, 2002
Jul 25, 2002
71
May 24, 2003
May 24, 2003
72
#elif (defined PHYSFS_HAVE_SYS_UCRED_H)
Jul 25, 2002
Jul 25, 2002
73
int i;
Sep 29, 2004
Sep 29, 2004
74
75
struct statfs *mntbufp = NULL;
int mounts = getmntinfo(&mntbufp, MNT_WAIT);
Mar 5, 2002
Mar 5, 2002
76
Jul 25, 2002
Jul 25, 2002
77
78
for (i = 0; i < mounts; i++)
{
Mar 5, 2002
Mar 5, 2002
79
80
int add_it = 0;
Jul 25, 2002
Jul 25, 2002
81
if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0)
Mar 5, 2002
Mar 5, 2002
82
add_it = 1;
Jul 25, 2002
Jul 25, 2002
83
else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0)
Apr 6, 2002
Apr 6, 2002
84
add_it = 1;
May 21, 2002
May 21, 2002
85
86
/* add other mount types here */
Mar 5, 2002
Mar 5, 2002
87
88
if (add_it)
Sep 29, 2004
Sep 29, 2004
89
cb(data, mntbufp[i].f_mntonname);
Jul 25, 2002
Jul 25, 2002
90
} /* for */
Mar 5, 2002
Mar 5, 2002
91
May 24, 2003
May 24, 2003
92
#elif (defined PHYSFS_HAVE_MNTENT_H)
Aug 7, 2001
Aug 7, 2001
93
94
95
96
FILE *mounts = NULL;
struct mntent *ent = NULL;
mounts = setmntent("/etc/mtab", "r");
Mar 13, 2005
Mar 13, 2005
97
BAIL_IF_MACRO(mounts == NULL, ERR_IO_ERROR, /*return void*/);
Aug 7, 2001
Aug 7, 2001
98
99
100
101
102
103
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
104
105
106
107
108
109
110
111
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
112
Mar 1, 2010
Mar 1, 2010
113
114
/* !!! FIXME: udf? automount? */
May 21, 2002
May 21, 2002
115
/* add other mount types here */
Aug 7, 2001
Aug 7, 2001
116
117
if (add_it)
Sep 29, 2004
Sep 29, 2004
118
cb(data, ent->mnt_dir);
Aug 7, 2001
Aug 7, 2001
119
120
121
} /* while */
endmntent(mounts);
Apr 13, 2009
Apr 13, 2009
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#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
144
#endif
Apr 13, 2009
Apr 13, 2009
145
} /* __PHYSFS_platformDetectAvailableCDs */
Jul 7, 2001
Jul 7, 2001
146
147
May 24, 2002
May 24, 2002
148
149
/* this is in posix.c ... */
extern char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname);
Jul 8, 2001
Jul 8, 2001
150
151
May 21, 2002
May 21, 2002
152
153
154
155
156
157
/*
* 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
158
* (envr) will be scribbled over, and you are expected to allocator.Free() the
May 21, 2002
May 21, 2002
159
160
161
* return value when you're done with it.
*/
static char *findBinaryInPath(const char *bin, char *envr)
Jul 8, 2001
Jul 8, 2001
162
{
May 21, 2002
May 21, 2002
163
164
165
size_t alloc_size = 0;
char *exe = NULL;
char *start = envr;
Jul 8, 2001
Jul 8, 2001
166
167
char *ptr;
May 21, 2002
May 21, 2002
168
169
BAIL_IF_MACRO(bin == NULL, ERR_INVALID_ARGUMENT, NULL);
BAIL_IF_MACRO(envr == NULL, ERR_INVALID_ARGUMENT, NULL);
Jul 8, 2001
Jul 8, 2001
170
171
172
do
{
May 21, 2002
May 21, 2002
173
174
size_t size;
ptr = strchr(start, ':'); /* find next $PATH separator. */
Jul 8, 2001
Jul 8, 2001
175
176
177
if (ptr)
*ptr = '\0';
May 21, 2002
May 21, 2002
178
179
size = strlen(start) + strlen(bin) + 2;
if (size > alloc_size)
Jul 8, 2001
Jul 8, 2001
180
{
Mar 14, 2005
Mar 14, 2005
181
char *x = (char *) allocator.Realloc(exe, size);
May 21, 2002
May 21, 2002
182
183
184
if (x == NULL)
{
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
185
allocator.Free(exe);
May 21, 2002
May 21, 2002
186
187
188
189
190
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
alloc_size = size;
exe = x;
Jul 8, 2001
Jul 8, 2001
191
} /* if */
May 21, 2002
May 21, 2002
192
193
/* build full binary path... */
Jul 8, 2001
Jul 8, 2001
194
strcpy(exe, start);
Nov 30, 2002
Nov 30, 2002
195
if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
Aug 29, 2001
Aug 29, 2001
196
strcat(exe, "/");
May 21, 2002
May 21, 2002
197
198
199
strcat(exe, bin);
if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */
Jul 8, 2001
Jul 8, 2001
200
{
May 21, 2002
May 21, 2002
201
strcpy(exe, start); /* i'm lazy. piss off. */
Jan 28, 2010
Jan 28, 2010
202
return exe;
May 21, 2002
May 21, 2002
203
} /* if */
Jul 8, 2001
Jul 8, 2001
204
May 21, 2002
May 21, 2002
205
start = ptr + 1; /* start points to beginning of next element. */
Jul 8, 2001
Jul 8, 2001
206
207
} while (ptr != NULL);
May 21, 2002
May 21, 2002
208
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
209
allocator.Free(exe);
May 21, 2002
May 21, 2002
210
Jan 28, 2010
Jan 28, 2010
211
return NULL; /* doesn't exist in path. */
May 21, 2002
May 21, 2002
212
213
214
} /* findBinaryInPath */
Jul 8, 2009
Jul 8, 2009
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
244
245
246
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
247
248
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
Mar 19, 2007
Mar 19, 2007
249
250
251
252
253
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
254
return NULL; /* higher level will parse out real path from argv0. */
May 21, 2002
May 21, 2002
255
Mar 19, 2007
Mar 19, 2007
256
257
258
259
260
/*
* 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
261
retval = readSymLink("/proc/self/exe");
Jul 8, 2009
Jul 8, 2009
262
263
264
265
266
267
268
269
270
271
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
272
if (retval != NULL) /* chop off filename. */
Mar 19, 2007
Mar 19, 2007
273
{
Jul 8, 2009
Jul 8, 2009
274
275
276
char *ptr = strrchr(retval, '/');
if (ptr != NULL)
*ptr = '\0';
Mar 19, 2007
Mar 19, 2007
277
} /* if */
May 21, 2002
May 21, 2002
278
Mar 19, 2007
Mar 19, 2007
279
280
281
282
283
284
285
286
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
287
Jul 8, 2009
Jul 8, 2009
288
289
290
291
292
293
294
295
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
296
return retval;
Jul 8, 2001
Jul 8, 2001
297
298
299
} /* __PHYSFS_platformCalcBaseDir */
Jul 16, 2001
Jul 16, 2001
300
301
302
303
304
305
306
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
307
retval = (char *) allocator.Malloc(strlen(resolved_path) + 1);
Jul 16, 2001
Jul 16, 2001
308
309
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, resolved_path);
Jan 4, 2003
Jan 4, 2003
310
Jan 28, 2010
Jan 28, 2010
311
return retval;
Jul 16, 2001
Jul 16, 2001
312
313
} /* __PHYSFS_platformRealPath */
Aug 23, 2001
Aug 23, 2001
314
Mar 21, 2007
Mar 21, 2007
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
349
350
351
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
352
return retval;
Mar 21, 2007
Mar 21, 2007
353
354
355
} /* __PHYSFS_platformCurrentDir */
Mar 20, 2007
Mar 20, 2007
356
357
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
{
Jan 28, 2010
Jan 28, 2010
358
return 0; /* just use malloc() and friends. */
Mar 20, 2007
Mar 20, 2007
359
360
361
} /* __PHYSFS_platformSetDefaultAllocator */
Feb 15, 2010
Feb 15, 2010
362
#if (defined PHYSFS_NO_PTHREADS_SUPPORT)
Jul 25, 2002
Jul 25, 2002
363
Jan 28, 2010
Jan 28, 2010
364
365
void *__PHYSFS_platformGetThreadID(void) { return ((void *) 0x0001); }
void *__PHYSFS_platformCreateMutex(void) { return ((void *) 0x0001); }
Jul 25, 2002
Jul 25, 2002
366
void __PHYSFS_platformDestroyMutex(void *mutex) {}
Jan 28, 2010
Jan 28, 2010
367
int __PHYSFS_platformGrabMutex(void *mutex) { return 1; }
Jul 25, 2002
Jul 25, 2002
368
369
370
371
void __PHYSFS_platformReleaseMutex(void *mutex) {}
#else
Apr 3, 2007
Apr 3, 2007
372
373
374
375
376
377
378
typedef struct
{
pthread_mutex_t mutex;
pthread_t owner;
PHYSFS_uint32 count;
} PthreadMutex;
Jul 25, 2002
Jul 25, 2002
379
Sep 6, 2009
Sep 6, 2009
380
void *__PHYSFS_platformGetThreadID(void)
Jul 25, 2002
Jul 25, 2002
381
{
Jan 28, 2010
Jan 28, 2010
382
return ( (void *) ((size_t) pthread_self()) );
Jul 25, 2002
Jul 25, 2002
383
384
385
} /* __PHYSFS_platformGetThreadID */
Mar 30, 2002
Mar 30, 2002
386
387
388
void *__PHYSFS_platformCreateMutex(void)
{
int rc;
Apr 3, 2007
Apr 3, 2007
389
390
391
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
392
393
if (rc != 0)
{
Mar 14, 2005
Mar 14, 2005
394
allocator.Free(m);
Mar 30, 2002
Mar 30, 2002
395
396
397
BAIL_MACRO(strerror(rc), NULL);
} /* if */
Apr 3, 2007
Apr 3, 2007
398
399
m->count = 0;
m->owner = (pthread_t) 0xDEADBEEF;
Jan 28, 2010
Jan 28, 2010
400
return ((void *) m);
Mar 30, 2002
Mar 30, 2002
401
402
403
404
405
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
406
407
408
409
410
411
412
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
413
allocator.Free(m);
Mar 30, 2002
Mar 30, 2002
414
415
416
417
418
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
419
420
421
422
423
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
424
return 0;
Apr 3, 2007
Apr 3, 2007
425
426
427
428
m->owner = tid;
} /* if */
m->count++;
Jan 28, 2010
Jan 28, 2010
429
return 1;
Mar 30, 2002
Mar 30, 2002
430
431
432
433
434
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
435
436
437
438
439
440
441
442
443
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
444
445
} /* __PHYSFS_platformReleaseMutex */
Feb 15, 2010
Feb 15, 2010
446
#endif /* !PHYSFS_NO_PTHREADS_SUPPORT */
Jul 25, 2002
Jul 25, 2002
447
Mar 11, 2007
Mar 11, 2007
448
#endif /* PHYSFS_PLATFORM_UNIX */
May 24, 2002
May 24, 2002
449
Jul 7, 2001
Jul 7, 2001
450
/* end of unix.c ... */