/
platform_posix.c
457 lines (353 loc) · 10.9 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
100
101
} /* __PHYSFS_platformGetUserName */
char *__PHYSFS_platformGetUserDir(void)
{
char *retval = __PHYSFS_platformCopyEnvironmentVariable("HOME");
if (retval == NULL)
retval = getUserDirByUID();
102
return retval;
103
104
105
106
107
108
} /* __PHYSFS_platformGetUserDir */
int __PHYSFS_platformExists(const char *fname)
{
struct stat statbuf;
109
BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
110
return 1;
111
112
113
114
115
116
} /* __PHYSFS_platformExists */
int __PHYSFS_platformIsSymLink(const char *fname)
{
struct stat statbuf;
117
BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
118
return ( (S_ISLNK(statbuf.st_mode)) ? 1 : 0 );
119
120
121
122
123
124
} /* __PHYSFS_platformIsSymlink */
int __PHYSFS_platformIsDirectory(const char *fname)
{
struct stat statbuf;
125
BAIL_IF_MACRO(stat(fname, &statbuf) == -1, strerror(errno), 0);
126
return ( (S_ISDIR(statbuf.st_mode)) ? 1 : 0 );
127
128
129
130
131
132
133
134
135
136
} /* __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;
137
char *retval = (char *) allocator.Malloc(len);
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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);
153
return retval;
154
155
156
157
} /* __PHYSFS_platformCvtToDependent */
158
159
void __PHYSFS_platformEnumerateFiles(const char *dirname,
int omitSymLinks,
160
161
PHYSFS_EnumFilesCallback callback,
const char *origdir,
162
void *callbackdata)
163
164
165
166
167
168
169
{
DIR *dir;
struct dirent *ent;
int bufsize = 0;
char *buf = NULL;
int dlen = 0;
170
if (omitSymLinks) /* !!! FIXME: this malloc sucks. */
171
172
173
{
dlen = strlen(dirname);
bufsize = dlen + 256;
174
buf = (char *) allocator.Malloc(bufsize);
175
176
if (buf == NULL)
return;
177
178
179
180
181
182
183
184
185
186
187
188
strcpy(buf, dirname);
if (buf[dlen - 1] != '/')
{
buf[dlen++] = '/';
buf[dlen] = '\0';
} /* if */
} /* if */
errno = 0;
dir = opendir(dirname);
if (dir == NULL)
{
189
allocator.Free(buf);
190
return;
191
192
} /* if */
193
while ((ent = readdir(dir)) != NULL)
194
195
196
197
198
199
200
201
202
203
204
205
206
{
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)
{
207
p = (char *) allocator.Realloc(buf, len);
208
209
210
211
212
213
214
215
216
217
218
if (p == NULL)
continue;
buf = p;
bufsize = len;
} /* if */
strcpy(buf + dlen, ent->d_name);
if (__PHYSFS_platformIsSymLink(buf))
continue;
} /* if */
219
callback(callbackdata, origdir, ent->d_name);
220
221
} /* while */
222
allocator.Free(buf);
223
224
225
226
227
228
229
230
231
232
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);
233
return 1;
234
235
236
} /* __PHYSFS_platformMkDir */
237
static void *doOpen(const char *filename, int mode)
238
{
239
const int appending = (mode & O_APPEND);
240
241
int fd;
int *retval;
242
243
errno = 0;
244
245
246
/* O_APPEND doesn't actually behave as we'd like. */
mode &= ~O_APPEND;
247
fd = open(filename, mode, S_IRUSR | S_IWUSR);
248
BAIL_IF_MACRO(fd < 0, strerror(errno), NULL);
249
250
251
252
253
254
255
256
257
258
if (appending)
{
if (lseek(fd, 0, SEEK_END) < 0)
{
close(fd);
BAIL_MACRO(strerror(errno), NULL);
} /* if */
} /* if */
259
retval = (int *) allocator.Malloc(sizeof (int));
260
261
262
263
264
265
266
if (retval == NULL)
{
close(fd);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */
*retval = fd;
267
return ((void *) retval);
268
269
270
271
272
} /* doOpen */
void *__PHYSFS_platformOpenRead(const char *filename)
{
273
return doOpen(filename, O_RDONLY);
274
275
276
277
278
} /* __PHYSFS_platformOpenRead */
void *__PHYSFS_platformOpenWrite(const char *filename)
{
279
return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC);
280
281
282
283
284
} /* __PHYSFS_platformOpenWrite */
void *__PHYSFS_platformOpenAppend(const char *filename)
{
285
return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND);
286
287
288
289
290
291
} /* __PHYSFS_platformOpenAppend */
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
292
293
294
int fd = *((int *) opaque);
int max = size * count;
int rc = read(fd, buffer, max);
295
296
297
298
299
300
301
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. */
302
return (rc / size);
303
304
305
306
307
308
} /* __PHYSFS_platformRead */
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
PHYSFS_uint32 size, PHYSFS_uint32 count)
{
309
310
311
312
313
314
315
316
317
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. */
318
319
return (rc / size);
320
321
322
323
324
} /* __PHYSFS_platformWrite */
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
{
325
int fd = *((int *) opaque);
326
327
328
329
330
331
332
333
334
335
#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
336
337
return 1;
338
339
340
341
342
} /* __PHYSFS_platformSeek */
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
{
343
int fd = *((int *) opaque);
344
345
346
347
348
349
350
351
352
353
354
355
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
356
return retval;
357
358
359
360
361
} /* __PHYSFS_platformTell */
PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
{
362
int fd = *((int *) opaque);
363
struct stat statbuf;
364
BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, strerror(errno), -1);
365
return ((PHYSFS_sint64) statbuf.st_size);
366
367
368
369
370
} /* __PHYSFS_platformFileLength */
int __PHYSFS_platformEOF(void *opaque)
{
371
372
PHYSFS_sint64 pos = __PHYSFS_platformTell(opaque);
PHYSFS_sint64 len = __PHYSFS_platformFileLength(opaque);
373
return (pos >= len);
374
375
376
377
378
} /* __PHYSFS_platformEOF */
int __PHYSFS_platformFlush(void *opaque)
{
379
380
int fd = *((int *) opaque);
BAIL_IF_MACRO(fsync(fd) == -1, strerror(errno), 0);
381
return 1;
382
383
384
385
386
} /* __PHYSFS_platformFlush */
int __PHYSFS_platformClose(void *opaque)
{
387
388
int fd = *((int *) opaque);
BAIL_IF_MACRO(close(fd) == -1, strerror(errno), 0);
389
allocator.Free(opaque);
390
return 1;
391
392
393
394
395
396
} /* __PHYSFS_platformClose */
int __PHYSFS_platformDelete(const char *path)
{
BAIL_IF_MACRO(remove(path) == -1, strerror(errno), 0);
397
return 1;
398
399
} /* __PHYSFS_platformDelete */
400
401
402
403
404
405
406
407
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 */
408
409
410
411
412
413
414
415
416
417
418
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
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 */
454
#endif /* PHYSFS_PLATFORM_POSIX */
455
456
/* end of posix.c ... */