Skip to content

Latest commit

 

History

History
443 lines (347 loc) · 11 KB

platform_unix.c

File metadata and controls

443 lines (347 loc) · 11 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;
May 21, 2002
May 21, 2002
104
Mar 1, 2010
Mar 1, 2010
105
106
/* !!! FIXME: udf? automount? */
May 21, 2002
May 21, 2002
107
/* add other mount types here */
Aug 7, 2001
Aug 7, 2001
108
109
if (add_it)
Sep 29, 2004
Sep 29, 2004
110
cb(data, ent->mnt_dir);
Aug 7, 2001
Aug 7, 2001
111
112
113
} /* while */
endmntent(mounts);
Apr 13, 2009
Apr 13, 2009
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#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
136
#endif
Apr 13, 2009
Apr 13, 2009
137
} /* __PHYSFS_platformDetectAvailableCDs */
Jul 7, 2001
Jul 7, 2001
138
139
May 24, 2002
May 24, 2002
140
141
/* this is in posix.c ... */
extern char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname);
Jul 8, 2001
Jul 8, 2001
142
143
May 21, 2002
May 21, 2002
144
145
146
147
148
149
/*
* 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
150
* (envr) will be scribbled over, and you are expected to allocator.Free() the
May 21, 2002
May 21, 2002
151
152
153
* return value when you're done with it.
*/
static char *findBinaryInPath(const char *bin, char *envr)
Jul 8, 2001
Jul 8, 2001
154
{
May 21, 2002
May 21, 2002
155
156
157
size_t alloc_size = 0;
char *exe = NULL;
char *start = envr;
Jul 8, 2001
Jul 8, 2001
158
159
char *ptr;
May 21, 2002
May 21, 2002
160
161
BAIL_IF_MACRO(bin == NULL, ERR_INVALID_ARGUMENT, NULL);
BAIL_IF_MACRO(envr == NULL, ERR_INVALID_ARGUMENT, NULL);
Jul 8, 2001
Jul 8, 2001
162
163
164
do
{
May 21, 2002
May 21, 2002
165
166
size_t size;
ptr = strchr(start, ':'); /* find next $PATH separator. */
Jul 8, 2001
Jul 8, 2001
167
168
169
if (ptr)
*ptr = '\0';
May 21, 2002
May 21, 2002
170
171
size = strlen(start) + strlen(bin) + 2;
if (size > alloc_size)
Jul 8, 2001
Jul 8, 2001
172
{
Mar 14, 2005
Mar 14, 2005
173
char *x = (char *) allocator.Realloc(exe, size);
May 21, 2002
May 21, 2002
174
175
176
if (x == NULL)
{
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
177
allocator.Free(exe);
May 21, 2002
May 21, 2002
178
179
180
181
182
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
alloc_size = size;
exe = x;
Jul 8, 2001
Jul 8, 2001
183
} /* if */
May 21, 2002
May 21, 2002
184
185
/* build full binary path... */
Jul 8, 2001
Jul 8, 2001
186
strcpy(exe, start);
Nov 30, 2002
Nov 30, 2002
187
if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
Aug 29, 2001
Aug 29, 2001
188
strcat(exe, "/");
May 21, 2002
May 21, 2002
189
190
191
strcat(exe, bin);
if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */
Jul 8, 2001
Jul 8, 2001
192
{
May 21, 2002
May 21, 2002
193
strcpy(exe, start); /* i'm lazy. piss off. */
Jan 28, 2010
Jan 28, 2010
194
return exe;
May 21, 2002
May 21, 2002
195
} /* if */
Jul 8, 2001
Jul 8, 2001
196
May 21, 2002
May 21, 2002
197
start = ptr + 1; /* start points to beginning of next element. */
Jul 8, 2001
Jul 8, 2001
198
199
} while (ptr != NULL);
May 21, 2002
May 21, 2002
200
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
201
allocator.Free(exe);
May 21, 2002
May 21, 2002
202
Jan 28, 2010
Jan 28, 2010
203
return NULL; /* doesn't exist in path. */
May 21, 2002
May 21, 2002
204
205
206
} /* findBinaryInPath */
Jul 8, 2009
Jul 8, 2009
207
208
209
210
211
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
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
239
240
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
Mar 19, 2007
Mar 19, 2007
241
242
243
244
245
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
246
return NULL; /* higher level will parse out real path from argv0. */
May 21, 2002
May 21, 2002
247
Mar 19, 2007
Mar 19, 2007
248
249
250
251
252
/*
* 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
253
retval = readSymLink("/proc/self/exe");
Jul 8, 2009
Jul 8, 2009
254
255
256
257
258
259
260
261
262
263
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
264
if (retval != NULL) /* chop off filename. */
Mar 19, 2007
Mar 19, 2007
265
{
Jul 8, 2009
Jul 8, 2009
266
267
268
char *ptr = strrchr(retval, '/');
if (ptr != NULL)
*ptr = '\0';
Mar 19, 2007
Mar 19, 2007
269
} /* if */
May 21, 2002
May 21, 2002
270
Mar 19, 2007
Mar 19, 2007
271
272
273
274
275
276
277
278
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
279
Jul 8, 2009
Jul 8, 2009
280
281
282
283
284
285
286
287
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
288
return retval;
Jul 8, 2001
Jul 8, 2001
289
290
291
} /* __PHYSFS_platformCalcBaseDir */
Jul 16, 2001
Jul 16, 2001
292
293
294
295
296
297
298
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
299
retval = (char *) allocator.Malloc(strlen(resolved_path) + 1);
Jul 16, 2001
Jul 16, 2001
300
301
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, resolved_path);
Jan 4, 2003
Jan 4, 2003
302
Jan 28, 2010
Jan 28, 2010
303
return retval;
Jul 16, 2001
Jul 16, 2001
304
305
} /* __PHYSFS_platformRealPath */
Aug 23, 2001
Aug 23, 2001
306
Mar 21, 2007
Mar 21, 2007
307
308
309
310
311
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
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
344
return retval;
Mar 21, 2007
Mar 21, 2007
345
346
347
} /* __PHYSFS_platformCurrentDir */
Mar 20, 2007
Mar 20, 2007
348
349
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
{
Jan 28, 2010
Jan 28, 2010
350
return 0; /* just use malloc() and friends. */
Mar 20, 2007
Mar 20, 2007
351
352
353
} /* __PHYSFS_platformSetDefaultAllocator */
Feb 15, 2010
Feb 15, 2010
354
#if (defined PHYSFS_NO_PTHREADS_SUPPORT)
Jul 25, 2002
Jul 25, 2002
355
Jan 28, 2010
Jan 28, 2010
356
357
void *__PHYSFS_platformGetThreadID(void) { return ((void *) 0x0001); }
void *__PHYSFS_platformCreateMutex(void) { return ((void *) 0x0001); }
Jul 25, 2002
Jul 25, 2002
358
void __PHYSFS_platformDestroyMutex(void *mutex) {}
Jan 28, 2010
Jan 28, 2010
359
int __PHYSFS_platformGrabMutex(void *mutex) { return 1; }
Jul 25, 2002
Jul 25, 2002
360
361
362
363
void __PHYSFS_platformReleaseMutex(void *mutex) {}
#else
Apr 3, 2007
Apr 3, 2007
364
365
366
367
368
369
370
typedef struct
{
pthread_mutex_t mutex;
pthread_t owner;
PHYSFS_uint32 count;
} PthreadMutex;
Jul 25, 2002
Jul 25, 2002
371
Sep 6, 2009
Sep 6, 2009
372
void *__PHYSFS_platformGetThreadID(void)
Jul 25, 2002
Jul 25, 2002
373
{
Jan 28, 2010
Jan 28, 2010
374
return ( (void *) ((size_t) pthread_self()) );
Jul 25, 2002
Jul 25, 2002
375
376
377
} /* __PHYSFS_platformGetThreadID */
Mar 30, 2002
Mar 30, 2002
378
379
380
void *__PHYSFS_platformCreateMutex(void)
{
int rc;
Apr 3, 2007
Apr 3, 2007
381
382
383
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
384
385
if (rc != 0)
{
Mar 14, 2005
Mar 14, 2005
386
allocator.Free(m);
Mar 30, 2002
Mar 30, 2002
387
388
389
BAIL_MACRO(strerror(rc), NULL);
} /* if */
Apr 3, 2007
Apr 3, 2007
390
391
m->count = 0;
m->owner = (pthread_t) 0xDEADBEEF;
Jan 28, 2010
Jan 28, 2010
392
return ((void *) m);
Mar 30, 2002
Mar 30, 2002
393
394
395
396
397
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
398
399
400
401
402
403
404
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
405
allocator.Free(m);
Mar 30, 2002
Mar 30, 2002
406
407
408
409
410
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
411
412
413
414
415
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
416
return 0;
Apr 3, 2007
Apr 3, 2007
417
418
419
420
m->owner = tid;
} /* if */
m->count++;
Jan 28, 2010
Jan 28, 2010
421
return 1;
Mar 30, 2002
Mar 30, 2002
422
423
424
425
426
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
427
428
429
430
431
432
433
434
435
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
436
437
} /* __PHYSFS_platformReleaseMutex */
Feb 15, 2010
Feb 15, 2010
438
#endif /* !PHYSFS_NO_PTHREADS_SUPPORT */
Jul 25, 2002
Jul 25, 2002
439
Mar 11, 2007
Mar 11, 2007
440
#endif /* PHYSFS_PLATFORM_UNIX */
May 24, 2002
May 24, 2002
441
Jul 7, 2001
Jul 7, 2001
442
/* end of unix.c ... */