Skip to content

Latest commit

 

History

History
369 lines (300 loc) · 9.81 KB

physfs_platform_unix.c

File metadata and controls

369 lines (300 loc) · 9.81 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 8, 2001
Jul 8, 2001
14
15
#include <ctype.h>
#include <unistd.h>
Aug 24, 2013
Aug 24, 2013
16
#include <stdlib.h>
Jul 8, 2001
Jul 8, 2001
17
18
19
#include <sys/types.h>
#include <pwd.h>
#include <sys/stat.h>
Jul 16, 2001
Jul 16, 2001
20
#include <sys/param.h>
Jul 8, 2001
Jul 8, 2001
21
22
23
#include <dirent.h>
#include <time.h>
#include <errno.h>
Aug 24, 2013
Aug 24, 2013
24
#include <limits.h>
Mar 5, 2002
Mar 5, 2002
25
Jul 12, 2017
Jul 12, 2017
26
#if PHYSFS_NO_CDROM_SUPPORT
Jul 12, 2017
Jul 12, 2017
27
#elif PHYSFS_PLATFORM_LINUX
Jul 12, 2017
Jul 12, 2017
28
# define PHYSFS_HAVE_MNTENT_H 1
Jul 12, 2017
Jul 12, 2017
29
30
31
#elif defined __CYGWIN__
# define PHYSFS_HAVE_MNTENT_H 1
#elif PHYSFS_PLATFORM_SOLARIS
Jul 12, 2017
Jul 12, 2017
32
# define PHYSFS_HAVE_SYS_MNTTAB_H 1
Jul 12, 2017
Jul 12, 2017
33
#elif PHYSFS_PLATFORM_BSD
Jul 12, 2017
Jul 12, 2017
34
35
36
37
# define PHYSFS_HAVE_SYS_UCRED_H 1
#else
# warning No CD-ROM support included. Either define your platform here,
# warning or define PHYSFS_NO_CDROM_SUPPORT=1 to confirm this is intentional.
Mar 20, 2012
Mar 20, 2012
38
39
#endif
Jul 20, 2002
Jul 20, 2002
40
41
42
43
#ifdef PHYSFS_HAVE_SYS_UCRED_H
# ifdef PHYSFS_HAVE_MNTENT_H
# undef PHYSFS_HAVE_MNTENT_H /* don't do both... */
# endif
May 3, 2009
May 3, 2009
44
# include <sys/mount.h>
Jul 20, 2002
Jul 20, 2002
45
# include <sys/ucred.h>
Mar 5, 2002
Mar 5, 2002
46
#endif
Jul 7, 2001
Jul 7, 2001
47
Jul 20, 2002
Jul 20, 2002
48
49
50
#ifdef PHYSFS_HAVE_MNTENT_H
#include <mntent.h>
#endif
Apr 6, 2002
Apr 6, 2002
51
Apr 13, 2009
Apr 13, 2009
52
53
54
55
#ifdef PHYSFS_HAVE_SYS_MNTTAB_H
#include <sys/mnttab.h>
#endif
Jul 9, 2017
Jul 9, 2017
56
57
58
59
#if PHYSFS_PLATFORM_FREEBSD
#include <sys/sysctl.h>
#endif
Jul 7, 2001
Jul 7, 2001
60
61
#include "physfs_internal.h"
Mar 24, 2002
Mar 24, 2002
62
63
int __PHYSFS_platformInit(void)
{
Jan 28, 2010
Jan 28, 2010
64
return 1; /* always succeed. */
Mar 24, 2002
Mar 24, 2002
65
66
67
68
69
} /* __PHYSFS_platformInit */
int __PHYSFS_platformDeinit(void)
{
Jan 28, 2010
Jan 28, 2010
70
return 1; /* always succeed. */
Mar 24, 2002
Mar 24, 2002
71
72
73
} /* __PHYSFS_platformDeinit */
Jul 25, 2002
Jul 25, 2002
74
/* Stub version for platforms without CD-ROM support. */
Sep 29, 2004
Sep 29, 2004
75
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
Jul 25, 2002
Jul 25, 2002
76
{
Apr 13, 2009
Apr 13, 2009
77
78
#if (defined PHYSFS_NO_CDROM_SUPPORT)
/* no-op. */
Jul 25, 2002
Jul 25, 2002
79
May 24, 2003
May 24, 2003
80
#elif (defined PHYSFS_HAVE_SYS_UCRED_H)
Jul 25, 2002
Jul 25, 2002
81
int i;
Sep 29, 2004
Sep 29, 2004
82
83
struct statfs *mntbufp = NULL;
int mounts = getmntinfo(&mntbufp, MNT_WAIT);
Mar 5, 2002
Mar 5, 2002
84
Jul 25, 2002
Jul 25, 2002
85
86
for (i = 0; i < mounts; i++)
{
Mar 5, 2002
Mar 5, 2002
87
88
int add_it = 0;
Jul 25, 2002
Jul 25, 2002
89
if (strcmp(mntbufp[i].f_fstypename, "iso9660") == 0)
Mar 5, 2002
Mar 5, 2002
90
add_it = 1;
Jul 25, 2002
Jul 25, 2002
91
else if (strcmp( mntbufp[i].f_fstypename, "cd9660") == 0)
Apr 6, 2002
Apr 6, 2002
92
add_it = 1;
May 21, 2002
May 21, 2002
93
94
/* add other mount types here */
Mar 5, 2002
Mar 5, 2002
95
96
if (add_it)
Sep 29, 2004
Sep 29, 2004
97
cb(data, mntbufp[i].f_mntonname);
Jul 25, 2002
Jul 25, 2002
98
} /* for */
Mar 5, 2002
Mar 5, 2002
99
May 24, 2003
May 24, 2003
100
#elif (defined PHYSFS_HAVE_MNTENT_H)
Aug 7, 2001
Aug 7, 2001
101
102
103
104
FILE *mounts = NULL;
struct mntent *ent = NULL;
mounts = setmntent("/etc/mtab", "r");
Jul 6, 2017
Jul 6, 2017
105
BAIL_IF(mounts == NULL, PHYSFS_ERR_IO, /*return void*/);
Aug 7, 2001
Aug 7, 2001
106
107
108
109
110
111
while ( (ent = getmntent(mounts)) != NULL )
{
int add_it = 0;
if (strcmp(ent->mnt_type, "iso9660") == 0)
add_it = 1;
Mar 22, 2010
Mar 22, 2010
112
113
114
115
116
117
118
119
else if (strcmp(ent->mnt_type, "udf") == 0)
add_it = 1;
/* !!! FIXME: these might pick up floppy drives, right? */
else if (strcmp(ent->mnt_type, "auto") == 0)
add_it = 1;
else if (strcmp(ent->mnt_type, "supermount") == 0)
add_it = 1;
May 21, 2002
May 21, 2002
120
Mar 1, 2010
Mar 1, 2010
121
122
/* !!! FIXME: udf? automount? */
May 21, 2002
May 21, 2002
123
/* add other mount types here */
Aug 7, 2001
Aug 7, 2001
124
125
if (add_it)
Sep 29, 2004
Sep 29, 2004
126
cb(data, ent->mnt_dir);
Aug 7, 2001
Aug 7, 2001
127
128
129
} /* while */
endmntent(mounts);
Apr 13, 2009
Apr 13, 2009
130
131
132
133
134
#elif (defined PHYSFS_HAVE_SYS_MNTTAB_H)
FILE *mounts = fopen(MNTTAB, "r");
struct mnttab ent;
Jul 6, 2017
Jul 6, 2017
135
BAIL_IF(mounts == NULL, PHYSFS_ERR_IO, /*return void*/);
Apr 13, 2009
Apr 13, 2009
136
137
138
139
140
141
142
143
144
145
146
147
148
while (getmntent(mounts, &ent) == 0)
{
int add_it = 0;
if (strcmp(ent.mnt_fstype, "hsfs") == 0)
add_it = 1;
/* add other mount types here */
if (add_it)
cb(data, ent.mnt_mountp);
} /* while */
fclose(mounts);
Mar 5, 2002
Mar 5, 2002
149
#endif
Apr 13, 2009
Apr 13, 2009
150
} /* __PHYSFS_platformDetectAvailableCDs */
Jul 7, 2001
Jul 7, 2001
151
152
May 21, 2002
May 21, 2002
153
154
155
156
157
158
/*
* 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
159
* (envr) will be scribbled over, and you are expected to allocator.Free() the
May 21, 2002
May 21, 2002
160
161
162
* return value when you're done with it.
*/
static char *findBinaryInPath(const char *bin, char *envr)
Jul 8, 2001
Jul 8, 2001
163
{
May 21, 2002
May 21, 2002
164
165
166
size_t alloc_size = 0;
char *exe = NULL;
char *start = envr;
Jul 8, 2001
Jul 8, 2001
167
168
char *ptr;
Mar 20, 2012
Mar 20, 2012
169
170
assert(bin != NULL);
assert(envr != NULL);
Jul 8, 2001
Jul 8, 2001
171
172
173
do
{
May 21, 2002
May 21, 2002
174
size_t size;
Mar 23, 2012
Mar 23, 2012
175
176
size_t binlen;
May 21, 2002
May 21, 2002
177
ptr = strchr(start, ':'); /* find next $PATH separator. */
Jul 8, 2001
Jul 8, 2001
178
179
180
if (ptr)
*ptr = '\0';
Mar 23, 2012
Mar 23, 2012
181
182
binlen = strlen(bin);
size = strlen(start) + binlen + 2;
Aug 19, 2014
Aug 19, 2014
183
if (size >= alloc_size)
Jul 8, 2001
Jul 8, 2001
184
{
Mar 14, 2005
Mar 14, 2005
185
char *x = (char *) allocator.Realloc(exe, size);
Mar 20, 2012
Mar 20, 2012
186
if (!x)
May 21, 2002
May 21, 2002
187
188
{
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
189
allocator.Free(exe);
Jul 6, 2017
Jul 6, 2017
190
BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
May 21, 2002
May 21, 2002
191
192
193
194
} /* if */
alloc_size = size;
exe = x;
Jul 8, 2001
Jul 8, 2001
195
} /* if */
May 21, 2002
May 21, 2002
196
197
/* build full binary path... */
Jul 8, 2001
Jul 8, 2001
198
strcpy(exe, start);
Nov 30, 2002
Nov 30, 2002
199
if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
Aug 29, 2001
Aug 29, 2001
200
strcat(exe, "/");
May 21, 2002
May 21, 2002
201
202
203
strcat(exe, bin);
if (access(exe, X_OK) == 0) /* Exists as executable? We're done. */
Jul 8, 2001
Jul 8, 2001
204
{
Jul 16, 2013
Jul 16, 2013
205
exe[(size - binlen) - 1] = '\0'; /* chop off filename, leave '/' */
Jan 28, 2010
Jan 28, 2010
206
return exe;
May 21, 2002
May 21, 2002
207
} /* if */
Jul 8, 2001
Jul 8, 2001
208
May 21, 2002
May 21, 2002
209
start = ptr + 1; /* start points to beginning of next element. */
Jul 8, 2001
Jul 8, 2001
210
211
} while (ptr != NULL);
May 21, 2002
May 21, 2002
212
if (exe != NULL)
Mar 14, 2005
Mar 14, 2005
213
allocator.Free(exe);
May 21, 2002
May 21, 2002
214
Jan 28, 2010
Jan 28, 2010
215
return NULL; /* doesn't exist in path. */
May 21, 2002
May 21, 2002
216
217
218
} /* findBinaryInPath */
Jul 8, 2009
Jul 8, 2009
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
static char *readSymLink(const char *path)
{
ssize_t len = 64;
ssize_t rc = -1;
char *retval = NULL;
while (1)
{
char *ptr = (char *) allocator.Realloc(retval, (size_t) len);
if (ptr == NULL)
break; /* out of memory. */
retval = ptr;
rc = readlink(path, retval, len);
if (rc == -1)
break; /* not a symlink, i/o error, etc. */
else if (rc < len)
{
retval[rc] = '\0'; /* readlink doesn't null-terminate. */
return retval; /* we're good to go. */
} /* else if */
len *= 2; /* grow buffer, try again. */
} /* while */
if (retval != NULL)
allocator.Free(retval);
return NULL;
} /* readSymLink */
May 21, 2002
May 21, 2002
251
252
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
{
Mar 19, 2007
Mar 19, 2007
253
char *retval = NULL;
Mar 24, 2012
Mar 24, 2012
254
const char *envr = NULL;
Mar 19, 2007
Mar 19, 2007
255
Aug 24, 2013
Aug 24, 2013
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/* Try to avoid using argv0 unless forced to. Try system-specific stuff. */
#if PHYSFS_PLATFORM_FREEBSD
{
char fullpath[PATH_MAX];
size_t buflen = sizeof (fullpath);
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
if (sysctl(mib, 4, fullpath, &buflen, NULL, 0) != -1)
retval = __PHYSFS_strdup(fullpath);
}
#elif PHYSFS_PLATFORM_SOLARIS
{
const char *path = getexecname();
if ((path != NULL) && (path[0] == '/')) /* must be absolute path... */
retval = __PHYSFS_strdup(path);
}
#endif
/* If there's a Linux-like /proc filesystem, you can get the full path to
* the current process from a symlink in there.
Mar 19, 2007
Mar 19, 2007
276
*/
Aug 24, 2013
Aug 24, 2013
277
Jul 13, 2017
Jul 13, 2017
278
if (!retval && (access("/proc", F_OK) == 0))
Jul 8, 2009
Jul 8, 2009
279
{
Aug 24, 2013
Aug 24, 2013
280
281
282
283
284
285
286
287
288
289
290
291
retval = readSymLink("/proc/self/exe");
if (!retval) retval = readSymLink("/proc/curproc/file");
if (!retval) retval = readSymLink("/proc/curproc/exe");
if (retval == NULL)
{
/* older kernels don't have /proc/self ... try PID version... */
const unsigned long long pid = (unsigned long long) getpid();
char path[64];
const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
if ( (rc > 0) && (rc < sizeof(path)) )
retval = readSymLink(path);
} /* if */
Jul 8, 2009
Jul 8, 2009
292
293
} /* if */
Jul 8, 2009
Jul 8, 2009
294
if (retval != NULL) /* chop off filename. */
Mar 19, 2007
Mar 19, 2007
295
{
Jul 8, 2009
Jul 8, 2009
296
297
char *ptr = strrchr(retval, '/');
if (ptr != NULL)
Mar 23, 2012
Mar 23, 2012
298
*(ptr+1) = '\0';
Mar 24, 2012
Mar 24, 2012
299
300
301
302
303
else /* shouldn't happen, but just in case... */
{
allocator.Free(retval);
retval = NULL;
} /* else */
Mar 19, 2007
Mar 19, 2007
304
} /* if */
May 21, 2002
May 21, 2002
305
Aug 24, 2013
Aug 24, 2013
306
/* No /proc/self/exe, etc, but we have an argv[0] we can parse? */
Mar 19, 2007
Mar 19, 2007
307
308
if ((retval == NULL) && (argv0 != NULL))
{
Mar 23, 2012
Mar 23, 2012
309
310
311
312
/* fast path: default behaviour can handle this. */
if (strchr(argv0, '/') != NULL)
return NULL; /* higher level parses out real path from argv0. */
Mar 19, 2007
Mar 19, 2007
313
/* If there's no dirsep on argv0, then look through $PATH for it. */
Mar 24, 2012
Mar 24, 2012
314
315
316
317
envr = getenv("PATH");
if (envr != NULL)
{
char *path = (char *) __PHYSFS_smallAlloc(strlen(envr) + 1);
Jul 6, 2017
Jul 6, 2017
318
BAIL_IF(!path, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Mar 24, 2012
Mar 24, 2012
319
320
321
322
strcpy(path, envr);
retval = findBinaryInPath(argv0, path);
__PHYSFS_smallFree(path);
} /* if */
Mar 19, 2007
Mar 19, 2007
323
} /* if */
May 21, 2002
May 21, 2002
324
Jul 8, 2009
Jul 8, 2009
325
326
327
328
329
330
331
332
if (retval != NULL)
{
/* try to shrink buffer... */
char *ptr = (char *) allocator.Realloc(retval, strlen(retval) + 1);
if (ptr != NULL)
retval = ptr; /* oh well if it failed. */
} /* if */
Jan 28, 2010
Jan 28, 2010
333
return retval;
Jul 8, 2001
Jul 8, 2001
334
335
336
} /* __PHYSFS_platformCalcBaseDir */
Mar 22, 2012
Mar 22, 2012
337
338
339
340
341
342
343
char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
{
/*
* We use XDG's base directory spec, even if you're not on Linux.
* This isn't strictly correct, but the results are relatively sane
* in any case.
*
Feb 25, 2016
Feb 25, 2016
344
* https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
Mar 22, 2012
Mar 22, 2012
345
346
347
348
349
350
351
352
353
354
*/
const char *envr = getenv("XDG_DATA_HOME");
const char *append = "/";
char *retval = NULL;
size_t len = 0;
if (!envr)
{
/* You end up with "$HOME/.local/share/Game Name 2" */
envr = __PHYSFS_getUserDir();
Jul 6, 2017
Jul 6, 2017
355
BAIL_IF_ERRPASS(!envr, NULL); /* oh well. */
Mar 22, 2012
Mar 22, 2012
356
357
358
append = ".local/share/";
} /* if */
Mar 22, 2012
Mar 22, 2012
359
len = strlen(envr) + strlen(append) + strlen(app) + 2;
Mar 22, 2012
Mar 22, 2012
360
retval = (char *) allocator.Malloc(len);
Jul 6, 2017
Jul 6, 2017
361
BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Mar 22, 2012
Mar 22, 2012
362
snprintf(retval, len, "%s%s%s/", envr, append, app);
Mar 22, 2012
Mar 22, 2012
363
364
365
return retval;
} /* __PHYSFS_platformCalcPrefDir */
Mar 11, 2007
Mar 11, 2007
366
#endif /* PHYSFS_PLATFORM_UNIX */
May 24, 2002
May 24, 2002
367
Jul 22, 2017
Jul 22, 2017
368
/* end of platform_unix.c ... */