/
posix.c
470 lines (360 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
33
34
35
36
37
38
39
#include "physfs_internal.h"
char *__PHYSFS_platformCopyEnvironmentVariable(const char *varname)
{
const char *envr = getenv(varname);
char *retval = NULL;
if (envr != NULL)
{
40
retval = (char *) allocator.Malloc(strlen(envr) + 1);
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
if (retval != NULL)
strcpy(retval, envr);
} /* if */
return(retval);
} /* __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))
{
58
retval = (char *) allocator.Malloc(strlen(pw->pw_name) + 1);
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
if (retval != NULL)
strcpy(retval, pw->pw_name);
} /* if */
return(retval);
} /* 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))
{
76
retval = (char *) allocator.Malloc(strlen(pw->pw_dir) + 1);
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
if (retval != NULL)
strcpy(retval, pw->pw_dir);
} /* if */
return(retval);
} /* getUserDirByUID */
char *__PHYSFS_platformGetUserName(void)
{
char *retval = getUserNameByUID();
if (retval == NULL)
retval = __PHYSFS_platformCopyEnvironmentVariable("USER");
return(retval);
} /* __PHYSFS_platformGetUserName */
char *__PHYSFS_platformGetUserDir(void)
{
char *retval = __PHYSFS_platformCopyEnvironmentVariable("HOME");
if (retval == NULL)
retval = getUserDirByUID();
return(retval);
} /* __PHYSFS_platformGetUserDir */
int __PHYSFS_platformExists(const char *fname)
{
struct stat statbuf;
106
BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
107
return(1);
108
109
110
111
112
113
} /* __PHYSFS_platformExists */
int __PHYSFS_platformIsSymLink(const char *fname)
{
struct stat statbuf;
114
115
BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
return( (S_ISLNK(statbuf.st_mode)) ? 1 : 0 );
116
117
118
119
120
121
} /* __PHYSFS_platformIsSymlink */
int __PHYSFS_platformIsDirectory(const char *fname)
{
struct stat statbuf;
122
123
BAIL_IF_MACRO(stat(fname, &statbuf) == -1, strerror(errno), 0);
return( (S_ISDIR(statbuf.st_mode)) ? 1 : 0 );
124
125
126
127
128
129
130
131
132
133
} /* __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;
134
char *retval = (char *) allocator.Malloc(len);
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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);
return(retval);
} /* __PHYSFS_platformCvtToDependent */
155
156
void __PHYSFS_platformEnumerateFiles(const char *dirname,
int omitSymLinks,
157
158
PHYSFS_EnumFilesCallback callback,
const char *origdir,
159
void *callbackdata)
160
161
162
163
164
165
166
{
DIR *dir;
struct dirent *ent;
int bufsize = 0;
char *buf = NULL;
int dlen = 0;
167
if (omitSymLinks) /* !!! FIXME: this malloc sucks. */
168
169
170
{
dlen = strlen(dirname);
bufsize = dlen + 256;
171
buf = (char *) allocator.Malloc(bufsize);
172
173
if (buf == NULL)
return;
174
175
176
177
178
179
180
181
182
183
184
185
186
strcpy(buf, dirname);
if (buf[dlen - 1] != '/')
{
buf[dlen++] = '/';
buf[dlen] = '\0';
} /* if */
} /* if */
errno = 0;
dir = opendir(dirname);
if (dir == NULL)
{
if (buf != NULL)
187
allocator.Free(buf);
188
return;
189
190
} /* if */
191
while ((ent = readdir(dir)) != NULL)
192
193
194
195
196
197
198
199
200
201
202
203
204
{
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)
{
205
p = (char *) allocator.Realloc(buf, len);
206
207
208
209
210
211
212
213
214
215
216
if (p == NULL)
continue;
buf = p;
bufsize = len;
} /* if */
strcpy(buf + dlen, ent->d_name);
if (__PHYSFS_platformIsSymLink(buf))
continue;
} /* if */
217
callback(callbackdata, origdir, ent->d_name);
218
219
220
} /* while */
if (buf != NULL)
221
allocator.Free(buf);
222
223
224
225
226
227
228
229
230
231
232
233
234
235
closedir(dir);
} /* __PHYSFS_platformEnumerateFiles */
char *__PHYSFS_platformCurrentDir(void)
{
int allocSize = 0;
char *retval = NULL;
char *ptr;
do
{
allocSize += 100;
236
ptr = (char *) allocator.Realloc(retval, allocSize);
237
238
239
if (ptr == NULL)
{
if (retval != NULL)
240
allocator.Free(retval);
241
242
243
244
245
246
247
248
249
250
251
252
253
254
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
retval = ptr;
ptr = getcwd(retval, allocSize);
} while (ptr == NULL && errno == ERANGE);
if (ptr == NULL && errno)
{
/*
* getcwd() failed for some reason, for example current
* directory not existing.
*/
if (retval != NULL)
255
allocator.Free(retval);
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
BAIL_MACRO(ERR_NO_SUCH_FILE, NULL);
} /* if */
return(retval);
} /* __PHYSFS_platformCurrentDir */
int __PHYSFS_platformMkDir(const char *path)
{
int rc;
errno = 0;
rc = mkdir(path, S_IRWXU);
BAIL_IF_MACRO(rc == -1, strerror(errno), 0);
return(1);
} /* __PHYSFS_platformMkDir */
274
static void *doOpen(const char *filename, int mode)
275
{
276
277
int fd;
int *retval;
278
279
errno = 0;
280
fd = open(filename, mode, S_IRUSR | S_IWUSR);
281
BAIL_IF_MACRO(fd < 0, strerror(errno), NULL);
282
283
retval = (int *) allocator.Malloc(sizeof (int));
284
285
286
287
288
289
290
if (retval == NULL)
{
close(fd);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
*retval = fd;
291
292
293
294
295
296
return((void *) retval);
} /* doOpen */
void *__PHYSFS_platformOpenRead(const char *filename)
{
297
return(doOpen(filename, O_RDONLY));
298
299
300
301
302
} /* __PHYSFS_platformOpenRead */
void *__PHYSFS_platformOpenWrite(const char *filename)
{
303
return(doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC));
304
305
306
307
308
} /* __PHYSFS_platformOpenWrite */
void *__PHYSFS_platformOpenAppend(const char *filename)
{
309
return(doOpen(filename, O_WRONLY | O_CREAT | O_APPEND));
310
311
312
313
314
315
} /* __PHYSFS_platformOpenAppend */
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
316
317
318
int fd = *((int *) opaque);
int max = size * count;
int rc = read(fd, buffer, max);
319
320
321
322
323
324
325
326
BAIL_IF_MACRO(rc == -1, strerror(errno), rc);
assert(rc <= max);
if ((rc < max) && (size > 1))
lseek(fd, -(rc % size), SEEK_CUR); /* rollback to object boundary. */
return(rc / size);
327
328
329
330
331
332
} /* __PHYSFS_platformRead */
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
333
334
335
336
337
338
339
340
341
int fd = *((int *) opaque);
int max = size * count;
int rc = write(fd, (void *) buffer, max);
BAIL_IF_MACRO(rc == -1, strerror(errno), rc);
assert(rc <= max);
if ((rc < max) && (size > 1))
lseek(fd, -(rc % size), SEEK_CUR); /* rollback to object boundary. */
342
343
return(rc / size);
344
345
346
347
348
} /* __PHYSFS_platformWrite */
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
{
349
int fd = *((int *) opaque);
350
351
352
353
354
355
356
357
358
359
#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
360
361
362
363
364
365
366
return(1);
} /* __PHYSFS_platformSeek */
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
{
367
int fd = *((int *) opaque);
368
369
370
371
372
373
374
375
376
377
378
379
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
380
381
382
383
384
385
return(retval);
} /* __PHYSFS_platformTell */
PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
{
386
int fd = *((int *) opaque);
387
struct stat statbuf;
388
BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, strerror(errno), -1);
389
390
391
392
393
394
return((PHYSFS_sint64) statbuf.st_size);
} /* __PHYSFS_platformFileLength */
int __PHYSFS_platformEOF(void *opaque)
{
395
396
397
PHYSFS_sint64 pos = __PHYSFS_platformTell(opaque);
PHYSFS_sint64 len = __PHYSFS_platformFileLength(opaque);
return(pos >= len);
398
399
400
401
402
} /* __PHYSFS_platformEOF */
int __PHYSFS_platformFlush(void *opaque)
{
403
404
int fd = *((int *) opaque);
BAIL_IF_MACRO(fsync(fd) == -1, strerror(errno), 0);
405
406
407
408
409
410
return(1);
} /* __PHYSFS_platformFlush */
int __PHYSFS_platformClose(void *opaque)
{
411
412
int fd = *((int *) opaque);
BAIL_IF_MACRO(close(fd) == -1, strerror(errno), 0);
413
allocator.Free(opaque);
414
415
416
417
418
419
420
421
422
423
return(1);
} /* __PHYSFS_platformClose */
int __PHYSFS_platformDelete(const char *path)
{
BAIL_IF_MACRO(remove(path) == -1, strerror(errno), 0);
return(1);
} /* __PHYSFS_platformDelete */
424
425
426
427
428
429
430
431
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 */
432
433
int __PHYSFS_platformAllocatorInit(void)
434
{
435
436
return(1); /* always succeeds. */
} /* __PHYSFS_platformAllocatorInit */
437
438
439
void __PHYSFS_platformAllocatorDeinit(void)
440
{
441
442
/* no-op */
} /* __PHYSFS_platformAllocatorInit */
443
444
445
void *__PHYSFS_platformAllocatorMalloc(PHYSFS_uint64 s)
446
{
447
BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
448
#undef malloc
449
return(malloc((size_t) s));
450
} /* __PHYSFS_platformMalloc */
451
452
453
void *__PHYSFS_platformAllocatorRealloc(void *ptr, PHYSFS_uint64 s)
454
{
455
BAIL_IF_MACRO(__PHYSFS_ui64FitsAddressSpace(s), ERR_OUT_OF_MEMORY, NULL);
456
#undef realloc
457
return(realloc(ptr, (size_t) s));
458
} /* __PHYSFS_platformRealloc */
459
460
461
void __PHYSFS_platformAllocatorFree(void *ptr)
462
{
463
#undef free
464
465
free(ptr);
} /* __PHYSFS_platformAllocatorFree */
466
467
#endif /* PHYSFS_PLATFORM_POSIX */
468
469
/* end of posix.c ... */