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