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