/
unix.c
314 lines (238 loc) · 7.62 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
#if (!defined __BEOS__) /* BeOS uses beos.cpp and posix.c ... */
15
16
17
18
#if (defined WIN32) /* cygwin/mingw32? */
#include "win32.c" /* !!! FIXME: holy friggin' hack. */
#else
19
20
21
22
23
24
#if ((defined __APPLE__) && (defined __MACH__))
# if (!defined __DARWIN__)
# define __DARWIN__
# endif
#endif
25
26
#include <stdio.h>
#include <stdlib.h>
27
28
#include <string.h>
#include <ctype.h>
29
#include <pthread.h>
30
31
32
33
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <sys/stat.h>
34
#include <sys/param.h>
35
36
37
#include <dirent.h>
#include <time.h>
#include <errno.h>
38
39
40
41
#if (!defined __DARWIN__)
#include <mntent.h>
#else
42
43
#include <sys/ucred.h>
#endif
44
45
46
47
#include <sys/mount.h>
48
49
50
51
52
53
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
const char *__PHYSFS_platformDirSeparator = "/";
54
55
56
57
58
59
60
61
62
63
64
65
66
67
int __PHYSFS_platformInit(void)
{
return(1); /* always succeed. */
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
return(1); /* always succeed. */
} /* __PHYSFS_platformDeinit */
68
69
70
71
72
73
74
75
76
77
#if (defined __DARWIN__)
char **__PHYSFS_platformDetectAvailableCDs(void)
{
char **retval = (char **) malloc(sizeof (char *));
int cd_count = 1; /* We count the NULL entry. */
struct statfs* mntbufp = NULL;
int mounts;
int ii;
78
79
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
80
81
82
83
84
85
86
mounts = getmntinfo( &mntbufp, MNT_WAIT );
for ( ii=0; ii < mounts; ++ii ) {
int add_it = 0;
if ( strcmp( mntbufp[ii].f_fstypename, "iso9660") == 0 )
add_it = 1;
87
88
else if ( strcmp( mntbufp[ii].f_fstypename, "cd9660") == 0 )
add_it = 1;
89
90
/* add other mount types here */
91
92
93
if (add_it)
{
94
char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
95
96
97
if (tmp)
{
retval = tmp;
98
99
100
retval[cd_count - 1] = (char *)
malloc(strlen(mntbufp[ii].f_mntonname) + 1);
if (retval[cd_count - 1])
101
{
102
strcpy(retval[cd_count - 1], mntbufp[ii].f_mntonname);
103
104
105
106
107
108
109
110
111
112
113
114
115
116
cd_count++;
} /* if */
} /* if */
} /* if */
}
retval[cd_count - 1] = NULL;
return(retval);
} /* __PHYSFS_platformDetectAvailableCDs */
#else /* non-Darwin implementation... */
117
118
char **__PHYSFS_platformDetectAvailableCDs(void)
{
119
120
121
122
123
char **retval = (char **) malloc(sizeof (char *));
int cd_count = 1; /* We count the NULL entry. */
FILE *mounts = NULL;
struct mntent *ent = NULL;
124
125
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
126
127
128
129
130
131
132
133
134
*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;
135
136
/* add other mount types here */
137
138
139
if (add_it)
{
140
char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
141
142
143
144
if (tmp)
{
retval = tmp;
retval[cd_count-1] = (char *) malloc(strlen(ent->mnt_dir) + 1);
145
if (retval[cd_count - 1])
146
{
147
strcpy(retval[cd_count - 1], ent->mnt_dir);
148
149
150
151
152
153
154
cd_count++;
} /* if */
} /* if */
} /* if */
} /* while */
endmntent(mounts);
155
156
retval[cd_count - 1] = NULL;
157
return(retval);
158
159
160
} /* __PHYSFS_platformDetectAvailableCDs */
#endif
161
162
163
164
/* this is in posix.c ... */
extern char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname);
165
166
167
168
169
170
171
172
173
174
175
176
/*
* 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)
177
{
178
179
180
size_t alloc_size = 0;
char *exe = NULL;
char *start = envr;
181
182
char *ptr;
183
184
BAIL_IF_MACRO(bin == NULL, ERR_INVALID_ARGUMENT, NULL);
BAIL_IF_MACRO(envr == NULL, ERR_INVALID_ARGUMENT, NULL);
185
186
187
do
{
188
189
size_t size;
ptr = strchr(start, ':'); /* find next $PATH separator. */
190
191
192
if (ptr)
*ptr = '\0';
193
194
size = strlen(start) + strlen(bin) + 2;
if (size > alloc_size)
195
{
196
197
198
199
200
201
202
203
204
205
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;
206
} /* if */
207
208
/* build full binary path... */
209
strcpy(exe, start);
210
211
if (exe[strlen(exe) - 1] != '/')
strcat(exe, "/");
212
213
214
strcat(exe, bin);
if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */
215
{
216
217
218
strcpy(exe, start); /* i'm lazy. piss off. */
return(exe);
} /* if */
219
220
start = ptr + 1; /* start points to beginning of next element. */
221
222
} while (ptr != NULL);
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
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);
240
envr = __PHYSFS_platformCopyEnvironmentVariable("PATH");
241
242
BAIL_IF_MACRO(!envr, NULL, NULL);
retval = findBinaryInPath(argv0, envr);
243
244
245
246
247
free(envr);
return(retval);
} /* __PHYSFS_platformCalcBaseDir */
248
PHYSFS_uint64 __PHYSFS_platformGetThreadID(void)
249
{
250
return((PHYSFS_uint64) ((PHYSFS_uint32) pthread_self()));
251
252
253
} /* __PHYSFS_platformGetThreadID */
254
255
256
/* Much like my college days, try to sleep for 10 milliseconds at a time... */
void __PHYSFS_platformTimeslice(void)
{
257
usleep( 10 * 1000 ); /* don't care if it fails. */
258
259
260
} /* __PHYSFS_platformTimeslice */
261
262
263
264
265
266
267
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);
268
retval = (char *) malloc(strlen(resolved_path) + 1);
269
270
271
272
273
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
strcpy(retval, resolved_path);
return(retval);
} /* __PHYSFS_platformRealPath */
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
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 */
309
310
#endif /* win32 check. */
311
312
#endif /* !defined __BEOS__ */
313
/* end of unix.c ... */