/
unix.c
339 lines (257 loc) · 8.37 KB
1
2
3
4
5
6
7
8
/*
* Unix support routines for PhysicsFS.
*
* Please see the file LICENSE in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
9
10
11
12
#if HAVE_CONFIG_H
# include <config.h>
#endif
13
14
/* BeOS uses beos.cpp and posix.c ... Cygwin and such use win32.c ... */
#if ((!defined __BEOS__) && (!defined WIN32))
15
16
17
#include <stdio.h>
#include <stdlib.h>
18
19
20
21
22
23
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <sys/stat.h>
24
#include <sys/param.h>
25
26
27
#include <dirent.h>
#include <time.h>
#include <errno.h>
28
#include <sys/mount.h>
29
30
31
32
33
#if (!defined PHYSFS_NO_PTHREADS_SUPPORT)
#include <pthread.h>
#endif
34
35
36
37
38
#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>
39
#endif
40
41
42
43
#ifdef PHYSFS_HAVE_MNTENT_H
#include <mntent.h>
#endif
44
45
46
47
48
49
50
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
const char *__PHYSFS_platformDirSeparator = "/";
51
52
53
54
55
56
57
58
59
60
61
62
63
int __PHYSFS_platformInit(void)
{
return(1); /* always succeed. */
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
return(1); /* always succeed. */
} /* __PHYSFS_platformDeinit */
64
65
66
67
68
69
70
71
72
73
74
75
76
#ifdef PHYSFS_NO_CDROM_SUPPORT
/* Stub version for platforms without CD-ROM support. */
char **__PHYSFS_platformDetectAvailableCDs(void)
{
char **retval = (char **) malloc(sizeof (char *));
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
*retval = NULL;
return(retval);
} /* __PHYSFS_platformDetectAvailableCDs */
#else
77
78
#ifdef PHYSFS_HAVE_SYS_UCRED_H
79
80
81
82
83
char **__PHYSFS_platformDetectAvailableCDs(void)
{
char **retval = (char **) malloc(sizeof (char *));
int cd_count = 1; /* We count the NULL entry. */
84
struct statfs *mntbufp = NULL;
85
int mounts;
86
int i;
87
88
89
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
90
mounts = getmntinfo(&mntbufp, MNT_WAIT);
91
92
93
for (i = 0; i < mounts; i++)
{
94
95
int add_it = 0;
96
if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0)
97
add_it = 1;
98
else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0)
99
add_it = 1;
100
101
/* add other mount types here */
102
103
104
if (add_it)
{
105
char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
106
107
108
if (tmp)
{
retval = tmp;
109
retval[cd_count - 1] = (char *)
110
malloc(strlen(mntbufp[i].f_mntonname) + 1);
111
if (retval[cd_count - 1])
112
{
113
strcpy(retval[cd_count - 1], mntbufp[i].f_mntonname);
114
115
116
117
cd_count++;
} /* if */
} /* if */
} /* if */
118
} /* for */
119
120
121
122
123
retval[cd_count - 1] = NULL;
return(retval);
} /* __PHYSFS_platformDetectAvailableCDs */
124
#endif
125
126
127
#ifdef PHYSFS_HAVE_MNTENT_H
128
129
130
char **__PHYSFS_platformDetectAvailableCDs(void)
{
131
132
133
134
135
char **retval = (char **) malloc(sizeof (char *));
int cd_count = 1; /* We count the NULL entry. */
FILE *mounts = NULL;
struct mntent *ent = NULL;
136
137
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
138
139
140
141
142
143
144
145
146
*retval = NULL;
mounts = setmntent("/etc/mtab", "r");
BAIL_IF_MACRO(mounts == NULL, ERR_IO_ERROR, retval);
while ( (ent = getmntent(mounts)) != NULL )
{
int add_it = 0;
if (strcmp(ent->mnt_type, "iso9660") == 0)
add_it = 1;
147
148
/* add other mount types here */
149
150
151
if (add_it)
{
152
char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
153
154
155
156
if (tmp)
{
retval = tmp;
retval[cd_count-1] = (char *) malloc(strlen(ent->mnt_dir) + 1);
157
if (retval[cd_count - 1])
158
{
159
strcpy(retval[cd_count - 1], ent->mnt_dir);
160
161
162
163
164
165
166
cd_count++;
} /* if */
} /* if */
} /* if */
} /* while */
endmntent(mounts);
167
168
retval[cd_count - 1] = NULL;
169
return(retval);
170
171
172
} /* __PHYSFS_platformDetectAvailableCDs */
#endif
173
174
175
#endif /* !PHYSFS_NO_CDROM_SUPPORT */
176
177
178
/* this is in posix.c ... */
extern char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname);
179
180
181
182
183
184
185
186
187
188
189
190
/*
* 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.
*
* (envr) will be scribbled over, and you are expected to free() the
* return value when you're done with it.
*/
static char *findBinaryInPath(const char *bin, char *envr)
191
{
192
193
194
size_t alloc_size = 0;
char *exe = NULL;
char *start = envr;
195
196
char *ptr;
197
198
BAIL_IF_MACRO(bin == NULL, ERR_INVALID_ARGUMENT, NULL);
BAIL_IF_MACRO(envr == NULL, ERR_INVALID_ARGUMENT, NULL);
199
200
201
do
{
202
203
size_t size;
ptr = strchr(start, ':'); /* find next $PATH separator. */
204
205
206
if (ptr)
*ptr = '\0';
207
208
size = strlen(start) + strlen(bin) + 2;
if (size > alloc_size)
209
{
210
211
212
213
214
215
216
217
218
219
char *x = (char *) realloc(exe, size);
if (x == NULL)
{
if (exe != NULL)
free(exe);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
alloc_size = size;
exe = x;
220
} /* if */
221
222
/* build full binary path... */
223
strcpy(exe, start);
224
225
if (exe[strlen(exe) - 1] != '/')
strcat(exe, "/");
226
227
228
strcat(exe, bin);
if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */
229
{
230
231
232
strcpy(exe, start); /* i'm lazy. piss off. */
return(exe);
} /* if */
233
234
start = ptr + 1; /* start points to beginning of next element. */
235
236
} while (ptr != NULL);
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
if (exe != NULL)
free(exe);
return(NULL); /* doesn't exist in path. */
} /* findBinaryInPath */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
/* If there isn't a path on argv0, then look through the $PATH for it. */
char *retval;
char *envr;
if (strchr(argv0, '/') != NULL) /* default behaviour can handle this. */
return(NULL);
254
envr = __PHYSFS_platformCopyEnvironmentVariable("PATH");
255
256
BAIL_IF_MACRO(!envr, NULL, NULL);
retval = findBinaryInPath(argv0, envr);
257
258
259
260
261
free(envr);
return(retval);
} /* __PHYSFS_platformCalcBaseDir */
262
263
264
/* Much like my college days, try to sleep for 10 milliseconds at a time... */
void __PHYSFS_platformTimeslice(void)
{
265
usleep( 10 * 1000 ); /* don't care if it fails. */
266
267
268
} /* __PHYSFS_platformTimeslice */
269
270
271
272
273
274
275
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);
276
retval = (char *) malloc(strlen(resolved_path) + 1);
277
278
279
280
281
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, resolved_path);
return(retval);
} /* __PHYSFS_platformRealPath */
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
#if (!defined PHYSFS_NO_PTHREADS_SUPPORT)
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
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
{
return((PHYSFS_uint64) pthread_self());
} /* __PHYSFS_platformGetThreadID */
299
300
301
302
303
304
305
306
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
void *__PHYSFS_platformCreateMutex(void)
{
int rc;
pthread_mutex_t *m = (pthread_mutex_t *) malloc(sizeof (pthread_mutex_t));
BAIL_IF_MACRO(m == NULL, ERR_OUT_OF_MEMORY, NULL);
rc = pthread_mutex_init(m, NULL);
if (rc != 0)
{
free(m);
BAIL_MACRO(strerror(rc), NULL);
} /* if */
return((void *) m);
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
pthread_mutex_destroy((pthread_mutex_t *) mutex);
free(mutex);
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
return(pthread_mutex_lock((pthread_mutex_t *) mutex) == 0);
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
pthread_mutex_unlock((pthread_mutex_t *) mutex);
} /* __PHYSFS_platformReleaseMutex */
333
334
335
#endif /* !PHYSFS_NO_PTHREADS_SUPPORT */
336
#endif /* !defined __BEOS__ && !defined WIN32 */
337
338
/* end of unix.c ... */