Skip to content

Latest commit

 

History

History
395 lines (310 loc) · 10 KB

unix.c

File metadata and controls

395 lines (310 loc) · 10 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>
Jul 20, 2002
Jul 20, 2002
26
#include <sys/mount.h>
Mar 5, 2002
Mar 5, 2002
27
Jul 25, 2002
Jul 25, 2002
28
29
30
31
#if (!defined PHYSFS_NO_PTHREADS_SUPPORT)
#include <pthread.h>
#endif
Jul 20, 2002
Jul 20, 2002
32
33
34
35
36
#ifdef PHYSFS_HAVE_SYS_UCRED_H
# ifdef PHYSFS_HAVE_MNTENT_H
# undef PHYSFS_HAVE_MNTENT_H /* don't do both... */
# endif
# 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
Jul 7, 2001
Jul 7, 2001
43
44
#include "physfs_internal.h"
Mar 5, 2002
Mar 5, 2002
45
Mar 24, 2002
Mar 24, 2002
46
47
48
49
50
51
52
53
54
55
56
57
int __PHYSFS_platformInit(void)
{
return(1); /* always succeed. */
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
return(1); /* always succeed. */
} /* __PHYSFS_platformDeinit */
Jul 25, 2002
Jul 25, 2002
58
59
60
#ifdef PHYSFS_NO_CDROM_SUPPORT
/* Stub version for platforms without CD-ROM support. */
Sep 29, 2004
Sep 29, 2004
61
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
Jul 25, 2002
Jul 25, 2002
62
63
64
{
} /* __PHYSFS_platformDetectAvailableCDs */
May 24, 2003
May 24, 2003
65
#elif (defined PHYSFS_HAVE_SYS_UCRED_H)
Mar 5, 2002
Mar 5, 2002
66
Sep 29, 2004
Sep 29, 2004
67
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
Mar 5, 2002
Mar 5, 2002
68
{
Jul 25, 2002
Jul 25, 2002
69
int i;
Sep 29, 2004
Sep 29, 2004
70
71
struct statfs *mntbufp = NULL;
int mounts = getmntinfo(&mntbufp, MNT_WAIT);
Mar 5, 2002
Mar 5, 2002
72
Jul 25, 2002
Jul 25, 2002
73
74
for (i = 0; i < mounts; i++)
{
Mar 5, 2002
Mar 5, 2002
75
76
int add_it = 0;
Jul 25, 2002
Jul 25, 2002
77
if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0)
Mar 5, 2002
Mar 5, 2002
78
add_it = 1;
Jul 25, 2002
Jul 25, 2002
79
else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0)
Apr 6, 2002
Apr 6, 2002
80
add_it = 1;
May 21, 2002
May 21, 2002
81
82
/* add other mount types here */
Mar 5, 2002
Mar 5, 2002
83
84
if (add_it)
Sep 29, 2004
Sep 29, 2004
85
cb(data, mntbufp[i].f_mntonname);
Jul 25, 2002
Jul 25, 2002
86
} /* for */
Mar 5, 2002
Mar 5, 2002
87
88
} /* __PHYSFS_platformDetectAvailableCDs */
May 24, 2003
May 24, 2003
89
#elif (defined PHYSFS_HAVE_MNTENT_H)
Mar 5, 2002
Mar 5, 2002
90
Sep 29, 2004
Sep 29, 2004
91
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
Jul 7, 2001
Jul 7, 2001
92
{
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
105
/* add other mount types here */
Aug 7, 2001
Aug 7, 2001
106
107
if (add_it)
Sep 29, 2004
Sep 29, 2004
108
cb(data, ent->mnt_dir);
Aug 7, 2001
Aug 7, 2001
109
110
111
} /* while */
endmntent(mounts);
Jul 8, 2001
Jul 8, 2001
112
Mar 5, 2002
Mar 5, 2002
113
114
115
} /* __PHYSFS_platformDetectAvailableCDs */
#endif
Jul 7, 2001
Jul 7, 2001
116
117
May 24, 2002
May 24, 2002
118
119
/* this is in posix.c ... */
extern char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname);
Jul 8, 2001
Jul 8, 2001
120
121
May 21, 2002
May 21, 2002
122
123
124
125
126
127
/*
* 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
128
* (envr) will be scribbled over, and you are expected to allocator.Free() the
May 21, 2002
May 21, 2002
129
130
131
* return value when you're done with it.
*/
static char *findBinaryInPath(const char *bin, char *envr)
Jul 8, 2001
Jul 8, 2001
132
{
May 21, 2002
May 21, 2002
133
134
135
size_t alloc_size = 0;
char *exe = NULL;
char *start = envr;
Jul 8, 2001
Jul 8, 2001
136
137
char *ptr;
May 21, 2002
May 21, 2002
138
139
BAIL_IF_MACRO(bin == NULL, ERR_INVALID_ARGUMENT, NULL);
BAIL_IF_MACRO(envr == NULL, ERR_INVALID_ARGUMENT, NULL);
Jul 8, 2001
Jul 8, 2001
140
141
142
do
{
May 21, 2002
May 21, 2002
143
144
size_t size;
ptr = strchr(start, ':'); /* find next $PATH separator. */
Jul 8, 2001
Jul 8, 2001
145
146
147
if (ptr)
*ptr = '\0';
May 21, 2002
May 21, 2002
148
149
size = strlen(start) + strlen(bin) + 2;
if (size > alloc_size)
Jul 8, 2001
Jul 8, 2001
150
{
Mar 14, 2005
Mar 14, 2005
151
char *x = (char *) allocator.Realloc(exe, size);
May 21, 2002
May 21, 2002
152
153
154
if (x == NULL)
{
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
155
allocator.Free(exe);
May 21, 2002
May 21, 2002
156
157
158
159
160
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
alloc_size = size;
exe = x;
Jul 8, 2001
Jul 8, 2001
161
} /* if */
May 21, 2002
May 21, 2002
162
163
/* build full binary path... */
Jul 8, 2001
Jul 8, 2001
164
strcpy(exe, start);
Nov 30, 2002
Nov 30, 2002
165
if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
Aug 29, 2001
Aug 29, 2001
166
strcat(exe, "/");
May 21, 2002
May 21, 2002
167
168
169
strcat(exe, bin);
if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */
Jul 8, 2001
Jul 8, 2001
170
{
May 21, 2002
May 21, 2002
171
172
173
strcpy(exe, start); /* i'm lazy. piss off. */
return(exe);
} /* if */
Jul 8, 2001
Jul 8, 2001
174
May 21, 2002
May 21, 2002
175
start = ptr + 1; /* start points to beginning of next element. */
Jul 8, 2001
Jul 8, 2001
176
177
} while (ptr != NULL);
May 21, 2002
May 21, 2002
178
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
179
allocator.Free(exe);
May 21, 2002
May 21, 2002
180
181
182
183
184
185
186
return(NULL); /* doesn't exist in path. */
} /* findBinaryInPath */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
Mar 19, 2007
Mar 19, 2007
187
188
189
190
191
192
193
194
const char *PROC_SELF_EXE = "/proc/self/exe";
char *retval = NULL;
char *envr = NULL;
struct stat stbuf;
/* fast path: default behaviour can handle this. */
if ( (argv0 != NULL) && (strchr(argv0, '/') != NULL) )
return(NULL); /* higher level will parse out real path from argv0. */
May 21, 2002
May 21, 2002
195
Mar 19, 2007
Mar 19, 2007
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/*
* 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.
*/
if ((lstat(PROC_SELF_EXE, &stbuf) != -1) && (S_ISLNK(stbuf.st_mode)))
{
const size_t len = stbuf.st_size;
char *buf = (char *) allocator.Malloc(len+1);
if (buf != NULL) /* if NULL, maybe you'll get lucky later. */
{
if (readlink(PROC_SELF_EXE, buf, len) != len)
allocator.Free(buf);
else
{
buf[len] = '\0'; /* readlink doesn't null-terminate. */
retval = buf; /* we're good to go. */
} /* else */
} /* if */
} /* if */
May 21, 2002
May 21, 2002
216
Mar 19, 2007
Mar 19, 2007
217
218
219
220
221
222
223
224
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
225
Jul 8, 2001
Jul 8, 2001
226
227
228
229
return(retval);
} /* __PHYSFS_platformCalcBaseDir */
Jul 16, 2001
Jul 16, 2001
230
231
232
233
234
235
236
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
237
retval = (char *) allocator.Malloc(strlen(resolved_path) + 1);
Jul 16, 2001
Jul 16, 2001
238
239
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, resolved_path);
Jan 4, 2003
Jan 4, 2003
240
Jul 16, 2001
Jul 16, 2001
241
242
243
return(retval);
} /* __PHYSFS_platformRealPath */
Aug 23, 2001
Aug 23, 2001
244
Mar 21, 2007
Mar 21, 2007
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
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 */
return(retval);
} /* __PHYSFS_platformCurrentDir */
Mar 20, 2007
Mar 20, 2007
286
287
288
289
290
291
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
{
return(0); /* just use malloc() and friends. */
} /* __PHYSFS_platformSetDefaultAllocator */
Jul 25, 2002
Jul 25, 2002
292
#if (defined PHYSFS_NO_PTHREADS_SUPPORT)
Jul 25, 2002
Jul 25, 2002
293
294
295
296
297
298
299
300
301
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void) { return(0x0001); }
void *__PHYSFS_platformCreateMutex(void) { return((void *) 0x0001); }
void __PHYSFS_platformDestroyMutex(void *mutex) {}
int __PHYSFS_platformGrabMutex(void *mutex) { return(1); }
void __PHYSFS_platformReleaseMutex(void *mutex) {}
#else
Apr 3, 2007
Apr 3, 2007
302
303
304
305
306
307
308
typedef struct
{
pthread_mutex_t mutex;
pthread_t owner;
PHYSFS_uint32 count;
} PthreadMutex;
Aug 9, 2002
Aug 9, 2002
309
310
311
312
313
314
315
316
317
318
319
320
321
322
/* Just in case; this is a panic value. */
#if ((!defined SIZEOF_INT) || (SIZEOF_INT <= 0))
# define SIZEOF_INT 4
#endif
#if (SIZEOF_INT == 4)
# define PHTREAD_TO_UI64(thr) ( (PHYSFS_uint64) ((PHYSFS_uint32) (thr)) )
#elif (SIZEOF_INT == 2)
# define PHTREAD_TO_UI64(thr) ( (PHYSFS_uint64) ((PHYSFS_uint16) (thr)) )
#elif (SIZEOF_INT == 1)
# define PHTREAD_TO_UI64(thr) ( (PHYSFS_uint64) ((PHYSFS_uint8) (thr)) )
#else
# define PHTREAD_TO_UI64(thr) ((PHYSFS_uint64) (thr))
#endif
Jul 25, 2002
Jul 25, 2002
323
Jul 25, 2002
Jul 25, 2002
324
325
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
{
Jul 25, 2002
Jul 25, 2002
326
return(PHTREAD_TO_UI64(pthread_self()));
Jul 25, 2002
Jul 25, 2002
327
328
329
} /* __PHYSFS_platformGetThreadID */
Mar 30, 2002
Mar 30, 2002
330
331
332
void *__PHYSFS_platformCreateMutex(void)
{
int rc;
Apr 3, 2007
Apr 3, 2007
333
334
335
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
336
337
if (rc != 0)
{
Mar 14, 2005
Mar 14, 2005
338
allocator.Free(m);
Mar 30, 2002
Mar 30, 2002
339
340
341
BAIL_MACRO(strerror(rc), NULL);
} /* if */
Apr 3, 2007
Apr 3, 2007
342
343
m->count = 0;
m->owner = (pthread_t) 0xDEADBEEF;
Mar 30, 2002
Mar 30, 2002
344
345
346
347
348
349
return((void *) m);
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
350
351
352
353
354
355
356
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
357
allocator.Free(m);
Mar 30, 2002
Mar 30, 2002
358
359
360
361
362
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
363
364
365
366
367
368
369
370
371
372
PthreadMutex *m = (PthreadMutex *) mutex;
pthread_t tid = pthread_self();
if (m->owner != tid)
{
if (pthread_mutex_lock(&m->mutex) != 0)
return(0);
m->owner = tid;
} /* if */
m->count++;
Sep 20, 2005
Sep 20, 2005
373
return(1);
Mar 30, 2002
Mar 30, 2002
374
375
376
377
378
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
Apr 3, 2007
Apr 3, 2007
379
380
381
382
383
384
385
386
387
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
388
389
} /* __PHYSFS_platformReleaseMutex */
Jul 25, 2002
Jul 25, 2002
390
391
#endif /* !PHYSFS_NO_PTHREADS_SUPPORT */
Mar 11, 2007
Mar 11, 2007
392
#endif /* PHYSFS_PLATFORM_UNIX */
May 24, 2002
May 24, 2002
393
Jul 7, 2001
Jul 7, 2001
394
/* end of unix.c ... */