/
platform_posix.c
468 lines (363 loc) · 11.2 KB
1
2
3
/*
* Posix-esque support routines for PhysicsFS.
*
4
* Please see the file LICENSE.txt in the source's root directory.
5
6
7
8
*
* This file written by Ryan C. Gordon.
*/
9
10
11
12
#define __PHYSICSFS_INTERNAL__
#include "physfs_platforms.h"
#ifdef PHYSFS_PLATFORM_POSIX
13
14
15
16
17
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
18
#include <ctype.h>
19
20
#include <sys/types.h>
#include <sys/stat.h>
21
#include <pwd.h>
22
23
#include <dirent.h>
#include <errno.h>
24
#include <fcntl.h>
25
26
27
28
29
#ifdef PHYSFS_HAVE_LLSEEK
#include <linux/unistd.h>
#endif
30
31
32
#include "physfs_internal.h"
33
34
35
const char *__PHYSFS_platformDirSeparator = "/";
36
37
38
39
40
41
42
char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname)
{
const char *envr = getenv(varname);
char *retval = NULL;
if (envr != NULL)
{
43
retval = (char *) allocator.Malloc(strlen(envr) + 1);
44
45
46
47
if (retval != NULL)
strcpy(retval, envr);
} /* if */
48
return retval;
49
50
51
52
53
54
55
56
57
58
59
60
} /* __PHYSFS_platformCopyEnvironmentVariable */
static char *getUserNameByUID(void)
{
uid_t uid = getuid();
struct passwd *pw;
char *retval = NULL;
pw = getpwuid(uid);
if ((pw != NULL) && (pw->pw_name != NULL))
{
61
retval = (char *) allocator.Malloc(strlen(pw->pw_name) + 1);
62
63
64
65
if (retval != NULL)
strcpy(retval, pw->pw_name);
} /* if */
66
return retval;
67
68
69
70
71
72
73
74
75
76
77
78
} /* getUserNameByUID */
static char *getUserDirByUID(void)
{
uid_t uid = getuid();
struct passwd *pw;
char *retval = NULL;
pw = getpwuid(uid);
if ((pw != NULL) && (pw->pw_dir != NULL))
{
79
retval = (char *) allocator.Malloc(strlen(pw->pw_dir) + 1);
80
81
82
83
if (retval != NULL)
strcpy(retval, pw->pw_dir);
} /* if */
84
return retval;
85
86
87
88
89
90
91
92
} /* getUserDirByUID */
char *__PHYSFS_platformGetUserName(void)
{
char *retval = getUserNameByUID();
if (retval == NULL)
retval = __PHYSFS_platformCopyEnvironmentVariable("USER");
93
return retval;
94
95
96
97
98
99
} /* __PHYSFS_platformGetUserName */
char *__PHYSFS_platformGetUserDir(void)
{
char *retval = __PHYSFS_platformCopyEnvironmentVariable("HOME");
100
101
102
103
104
105
106
107
108
109
110
111
/* if the environment variable was set, make sure it's really a dir. */
if (retval != NULL)
{
struct stat statbuf;
if ((stat(retval, &statbuf) == -1) || (S_ISDIR(statbuf.st_mode) == 0))
{
allocator.Free(retval);
retval = NULL;
} /* if */
} /* if */
112
113
if (retval == NULL)
retval = getUserDirByUID();
114
115
return retval;
116
117
118
119
120
121
} /* __PHYSFS_platformGetUserDir */
int __PHYSFS_platformExists(const char *fname)
{
struct stat statbuf;
122
BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
123
return 1;
124
125
126
127
128
129
} /* __PHYSFS_platformExists */
int __PHYSFS_platformIsSymLink(const char *fname)
{
struct stat statbuf;
130
BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
131
return ( (S_ISLNK(statbuf.st_mode)) ? 1 : 0 );
132
133
134
135
136
137
} /* __PHYSFS_platformIsSymlink */
int __PHYSFS_platformIsDirectory(const char *fname)
{
struct stat statbuf;
138
BAIL_IF_MACRO(stat(fname, &statbuf) == -1, strerror(errno), 0);
139
return ( (S_ISDIR(statbuf.st_mode)) ? 1 : 0 );
140
141
142
143
144
145
146
147
148
149
} /* __PHYSFS_platformIsDirectory */
char *__PHYSFS_platformCvtToDependent(const char *prepend,
const char *dirName,
const char *append)
{
int len = ((prepend) ? strlen(prepend) : 0) +
((append) ? strlen(append) : 0) +
strlen(dirName) + 1;
150
char *retval = (char *) allocator.Malloc(len);
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
/* platform-independent notation is Unix-style already. :) */
if (prepend)
strcpy(retval, prepend);
else
retval[0] = '\0';
strcat(retval, dirName);
if (append)
strcat(retval, append);
166
return retval;
167
168
169
170
} /* __PHYSFS_platformCvtToDependent */
171
172
void __PHYSFS_platformEnumerateFiles(const char *dirname,
int omitSymLinks,
173
174
PHYSFS_EnumFilesCallback callback,
const char *origdir,
175
void *callbackdata)
176
177
178
179
180
181
182
{
DIR *dir;
struct dirent *ent;
int bufsize = 0;
char *buf = NULL;
int dlen = 0;
183
if (omitSymLinks) /* !!! FIXME: this malloc sucks. */
184
185
186
{
dlen = strlen(dirname);
bufsize = dlen + 256;
187
buf = (char *) allocator.Malloc(bufsize);
188
189
if (buf == NULL)
return;
190
191
192
193
194
195
196
197
198
199
200
201
strcpy(buf, dirname);
if (buf[dlen - 1] != '/')
{
buf[dlen++] = '/';
buf[dlen] = '\0';
} /* if */
} /* if */
errno = 0;
dir = opendir(dirname);
if (dir == NULL)
{
202
allocator.Free(buf);
203
return;
204
205
} /* if */
206
while ((ent = readdir(dir)) != NULL)
207
208
209
210
211
212
213
214
215
216
217
218
219
{
if (strcmp(ent->d_name, ".") == 0)
continue;
if (strcmp(ent->d_name, "..") == 0)
continue;
if (omitSymLinks)
{
char *p;
int len = strlen(ent->d_name) + dlen + 1;
if (len > bufsize)
{
220
p = (char *) allocator.Realloc(buf, len);
221
222
223
224
225
226
227
228
229
230
231
if (p == NULL)
continue;
buf = p;
bufsize = len;
} /* if */
strcpy(buf + dlen, ent->d_name);
if (__PHYSFS_platformIsSymLink(buf))
continue;
} /* if */
232
callback(callbackdata, origdir, ent->d_name);
233
234
} /* while */
235
allocator.Free(buf);
236
237
238
239
240
241
242
243
244
245
closedir(dir);
} /* __PHYSFS_platformEnumerateFiles */
int __PHYSFS_platformMkDir(const char *path)
{
int rc;
errno = 0;
rc = mkdir(path, S_IRWXU);
BAIL_IF_MACRO(rc == -1, strerror(errno), 0);
246
return 1;
247
248
249
} /* __PHYSFS_platformMkDir */
250
static void *doOpen(const char *filename, int mode)
251
{
252
const int appending = (mode & O_APPEND);
253
254
int fd;
int *retval;
255
256
errno = 0;
257
258
259
/* O_APPEND doesn't actually behave as we'd like. */
mode &= ~O_APPEND;
260
fd = open(filename, mode, S_IRUSR | S_IWUSR);
261
BAIL_IF_MACRO(fd < 0, strerror(errno), NULL);
262
263
264
265
266
267
268
269
270
271
if (appending)
{
if (lseek(fd, 0, SEEK_END) < 0)
{
close(fd);
BAIL_MACRO(strerror(errno), NULL);
} /* if */
} /* if */
272
retval = (int *) allocator.Malloc(sizeof (int));
273
274
275
276
277
278
279
if (retval == NULL)
{
close(fd);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
*retval = fd;
280
return ((void *) retval);
281
282
283
284
285
} /* doOpen */
void *__PHYSFS_platformOpenRead(const char *filename)
{
286
return doOpen(filename, O_RDONLY);
287
288
289
290
291
} /* __PHYSFS_platformOpenRead */
void *__PHYSFS_platformOpenWrite(const char *filename)
{
292
return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC);
293
294
295
296
297
} /* __PHYSFS_platformOpenWrite */
void *__PHYSFS_platformOpenAppend(const char *filename)
{
298
return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND);
299
300
301
302
} /* __PHYSFS_platformOpenAppend */
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
303
PHYSFS_uint64 len)
304
{
305
int fd = *((int *) opaque);
306
ssize_t rc = 0;
307
308
BAIL_IF_MACRO(!__PHYSFS_ui64FitsAddressSpace(len),ERR_INVALID_ARGUMENT,-1);
309
310
311
312
313
314
rc = read(fd, buffer, (size_t) len);
BAIL_IF_MACRO(rc == -1, strerror(errno), (PHYSFS_sint64) rc);
assert(rc >= 0);
assert(rc <= len);
return (PHYSFS_sint64) rc;
315
316
317
318
} /* __PHYSFS_platformRead */
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
319
PHYSFS_uint64 len)
320
{
321
int fd = *((int *) opaque);
322
ssize_t rc = 0;
323
324
BAIL_IF_MACRO(!__PHYSFS_ui64FitsAddressSpace(len),ERR_INVALID_ARGUMENT,-1);
325
326
327
328
329
330
rc = write(fd, (void *) buffer, (size_t) len);
BAIL_IF_MACRO(rc == -1, strerror(errno), rc);
assert(rc >= 0);
assert(rc <= len);
return (PHYSFS_sint64) rc;
331
332
333
334
335
} /* __PHYSFS_platformWrite */
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
{
336
int fd = *((int *) opaque);
337
338
339
340
341
342
343
344
345
346
#ifdef PHYSFS_HAVE_LLSEEK
unsigned long offset_high = ((pos >> 32) & 0xFFFFFFFF);
unsigned long offset_low = (pos & 0xFFFFFFFF);
loff_t retoffset;
int rc = llseek(fd, offset_high, offset_low, &retoffset, SEEK_SET);
BAIL_IF_MACRO(rc == -1, strerror(errno), 0);
#else
BAIL_IF_MACRO(lseek(fd, (int) pos, SEEK_SET) == -1, strerror(errno), 0);
#endif
347
348
return 1;
349
350
351
352
353
} /* __PHYSFS_platformSeek */
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
{
354
int fd = *((int *) opaque);
355
356
357
358
359
360
361
362
363
364
365
366
PHYSFS_sint64 retval;
#ifdef PHYSFS_HAVE_LLSEEK
loff_t retoffset;
int rc = llseek(fd, 0, &retoffset, SEEK_CUR);
BAIL_IF_MACRO(rc == -1, strerror(errno), -1);
retval = (PHYSFS_sint64) retoffset;
#else
retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
#endif
367
return retval;
368
369
370
371
372
} /* __PHYSFS_platformTell */
PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
{
373
int fd = *((int *) opaque);
374
struct stat statbuf;
375
BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, strerror(errno), -1);
376
return ((PHYSFS_sint64) statbuf.st_size);
377
378
379
380
381
} /* __PHYSFS_platformFileLength */
int __PHYSFS_platformEOF(void *opaque)
{
382
383
PHYSFS_sint64 pos = __PHYSFS_platformTell(opaque);
PHYSFS_sint64 len = __PHYSFS_platformFileLength(opaque);
384
return (pos >= len);
385
386
387
388
389
} /* __PHYSFS_platformEOF */
int __PHYSFS_platformFlush(void *opaque)
{
390
391
int fd = *((int *) opaque);
BAIL_IF_MACRO(fsync(fd) == -1, strerror(errno), 0);
392
return 1;
393
394
395
396
397
} /* __PHYSFS_platformFlush */
int __PHYSFS_platformClose(void *opaque)
{
398
399
int fd = *((int *) opaque);
BAIL_IF_MACRO(close(fd) == -1, strerror(errno), 0);
400
allocator.Free(opaque);
401
return 1;
402
403
404
405
406
407
} /* __PHYSFS_platformClose */
int __PHYSFS_platformDelete(const char *path)
{
BAIL_IF_MACRO(remove(path) == -1, strerror(errno), 0);
408
return 1;
409
410
} /* __PHYSFS_platformDelete */
411
412
413
414
415
416
417
418
PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
{
struct stat statbuf;
BAIL_IF_MACRO(stat(fname, &statbuf) < 0, strerror(errno), -1);
return statbuf.st_mtime;
} /* __PHYSFS_platformGetLastModTime */
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *st)
{
struct stat statbuf;
/* !!! FIXME: lstat()? */
if (stat(filename, &statbuf))
{
if (errno == ENOENT)
{
*exists = 0;
return 0;
} /* if */
else
{
BAIL_MACRO(strerror(errno), -1);
} /* else */
} /* if */
if (S_ISREG(statbuf.st_mode))
{
st->filetype = PHYSFS_FILETYPE_REGULAR;
st->filesize = statbuf.st_size;
} /* if */
else if(S_ISDIR(statbuf.st_mode))
{
st->filetype = PHYSFS_FILETYPE_DIRECTORY;
st->filesize = 0;
} /* else if */
else
{
st->filetype = PHYSFS_FILETYPE_OTHER;
st->filesize = statbuf.st_size;
} /* else */
st->modtime = statbuf.st_mtime;
st->createtime = statbuf.st_ctime;
st->accesstime = statbuf.st_atime;
/* !!! FIXME: maybe we should just report full permissions? */
st->readonly = access(filename, W_OK);
return 0;
} /* __PHYSFS_platformStat */
465
#endif /* PHYSFS_PLATFORM_POSIX */
466
467
/* end of posix.c ... */