Skip to content

Latest commit

 

History

History
479 lines (382 loc) · 12.3 KB

platform_posix.c

File metadata and controls

479 lines (382 loc) · 12.3 KB
 
May 24, 2002
May 24, 2002
1
2
3
/*
* Posix-esque support routines for PhysicsFS.
*
Mar 11, 2007
Mar 11, 2007
4
* Please see the file LICENSE.txt in the source's root directory.
May 24, 2002
May 24, 2002
5
6
7
8
*
* This file written by Ryan C. Gordon.
*/
Mar 20, 2012
Mar 20, 2012
9
10
/* !!! FIXME: check for EINTR? */
Mar 11, 2007
Mar 11, 2007
11
12
13
14
#define __PHYSICSFS_INTERNAL__
#include "physfs_platforms.h"
#ifdef PHYSFS_PLATFORM_POSIX
Jun 29, 2002
Jun 29, 2002
15
May 24, 2002
May 24, 2002
16
#include <unistd.h>
Jun 2, 2002
Jun 2, 2002
17
#include <ctype.h>
May 24, 2002
May 24, 2002
18
19
#include <sys/types.h>
#include <sys/stat.h>
Jun 2, 2002
Jun 2, 2002
20
#include <pwd.h>
May 24, 2002
May 24, 2002
21
22
#include <dirent.h>
#include <errno.h>
Jun 2, 2002
Jun 2, 2002
23
#include <fcntl.h>
May 24, 2002
May 24, 2002
24
Jul 25, 2011
Jul 25, 2011
25
26
27
28
#if ((!defined PHYSFS_NO_THREAD_SUPPORT) && (!defined PHYSFS_PLATFORM_BEOS))
#include <pthread.h>
#endif
May 24, 2002
May 24, 2002
29
30
#include "physfs_internal.h"
Mar 20, 2012
Mar 20, 2012
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
static PHYSFS_ErrorCode errcodeFromErrnoError(const int err)
{
switch (err)
{
case 0: return PHYSFS_ERR_OK;
case EACCES: return PHYSFS_ERR_PERMISSION;
case EPERM: return PHYSFS_ERR_PERMISSION;
case EDQUOT: return PHYSFS_ERR_NO_SPACE;
case EIO: return PHYSFS_ERR_IO;
case ELOOP: return PHYSFS_ERR_SYMLINK_LOOP;
case EMLINK: return PHYSFS_ERR_NO_SPACE;
case ENAMETOOLONG: return PHYSFS_ERR_BAD_FILENAME;
case ENOENT: return PHYSFS_ERR_NO_SUCH_PATH;
case ENOSPC: return PHYSFS_ERR_NO_SPACE;
case ENOTDIR: return PHYSFS_ERR_NO_SUCH_PATH;
case EISDIR: return PHYSFS_ERR_NOT_A_FILE;
case EROFS: return PHYSFS_ERR_READ_ONLY;
case ETXTBSY: return PHYSFS_ERR_BUSY;
case EBUSY: return PHYSFS_ERR_BUSY;
case ENOMEM: return PHYSFS_ERR_OUT_OF_MEMORY;
case ENOTEMPTY: return PHYSFS_ERR_DIR_NOT_EMPTY;
default: return PHYSFS_ERR_OS_ERROR;
} /* switch */
} /* errcodeFromErrnoError */
static inline PHYSFS_ErrorCode errcodeFromErrno(void)
{
return errcodeFromErrnoError(errno);
} /* errcodeFromErrno */
May 24, 2002
May 24, 2002
64
65
66
67
68
69
70
static char *getUserDirByUID(void)
{
uid_t uid = getuid();
struct passwd *pw;
char *retval = NULL;
pw = getpwuid(uid);
Mar 24, 2012
Mar 24, 2012
71
if ((pw != NULL) && (pw->pw_dir != NULL) && (*pw->pw_dir != '\0'))
May 24, 2002
May 24, 2002
72
{
Mar 24, 2012
Mar 24, 2012
73
74
75
const size_t dlen = strlen(pw->pw_dir);
const size_t add_dirsep = (pw->pw_dir[dlen-1] != '/') ? 1 : 0;
retval = (char *) allocator.Malloc(dlen + 1 + add_dirsep);
May 24, 2002
May 24, 2002
76
if (retval != NULL)
Mar 24, 2012
Mar 24, 2012
77
{
May 24, 2002
May 24, 2002
78
strcpy(retval, pw->pw_dir);
Mar 24, 2012
Mar 24, 2012
79
80
81
82
83
84
if (add_dirsep)
{
retval[dlen] = '/';
retval[dlen+1] = '\0';
} /* if */
} /* if */
May 24, 2002
May 24, 2002
85
86
} /* if */
Jan 28, 2010
Jan 28, 2010
87
return retval;
May 24, 2002
May 24, 2002
88
89
90
} /* getUserDirByUID */
Mar 22, 2012
Mar 22, 2012
91
char *__PHYSFS_platformCalcUserDir(void)
May 24, 2002
May 24, 2002
92
{
Mar 24, 2012
Mar 24, 2012
93
94
char *retval = NULL;
char *envr = getenv("HOME");
Mar 21, 2010
Mar 21, 2010
95
96
/* if the environment variable was set, make sure it's really a dir. */
Mar 24, 2012
Mar 24, 2012
97
if (envr != NULL)
Mar 21, 2010
Mar 21, 2010
98
99
{
struct stat statbuf;
Mar 24, 2012
Mar 24, 2012
100
if ((stat(envr, &statbuf) != -1) && (S_ISDIR(statbuf.st_mode)))
Mar 21, 2010
Mar 21, 2010
101
{
Mar 24, 2012
Mar 24, 2012
102
103
104
105
106
107
108
109
110
111
112
113
const size_t envrlen = strlen(envr);
const size_t add_dirsep = (envr[envrlen-1] != '/') ? 1 : 0;
retval = allocator.Malloc(envrlen + 1 + add_dirsep);
if (retval)
{
strcpy(retval, envr);
if (add_dirsep)
{
retval[envrlen] = '/';
retval[envrlen+1] = '\0';
} /* if */
} /* if */
Mar 21, 2010
Mar 21, 2010
114
115
116
} /* if */
} /* if */
May 24, 2002
May 24, 2002
117
118
if (retval == NULL)
retval = getUserDirByUID();
Mar 21, 2010
Mar 21, 2010
119
Jan 28, 2010
Jan 28, 2010
120
return retval;
Mar 22, 2012
Mar 22, 2012
121
} /* __PHYSFS_platformCalcUserDir */
May 24, 2002
May 24, 2002
122
123
Sep 29, 2004
Sep 29, 2004
124
125
void __PHYSFS_platformEnumerateFiles(const char *dirname,
int omitSymLinks,
Sep 18, 2005
Sep 18, 2005
126
127
PHYSFS_EnumFilesCallback callback,
const char *origdir,
Sep 29, 2004
Sep 29, 2004
128
void *callbackdata)
May 24, 2002
May 24, 2002
129
130
131
132
133
134
135
{
DIR *dir;
struct dirent *ent;
int bufsize = 0;
char *buf = NULL;
int dlen = 0;
Sep 29, 2004
Sep 29, 2004
136
if (omitSymLinks) /* !!! FIXME: this malloc sucks. */
May 24, 2002
May 24, 2002
137
138
139
{
dlen = strlen(dirname);
bufsize = dlen + 256;
Mar 14, 2005
Mar 14, 2005
140
buf = (char *) allocator.Malloc(bufsize);
Sep 29, 2004
Sep 29, 2004
141
142
if (buf == NULL)
return;
May 24, 2002
May 24, 2002
143
144
145
146
147
148
149
150
151
152
153
154
strcpy(buf, dirname);
if (buf[dlen - 1] != '/')
{
buf[dlen++] = '/';
buf[dlen] = '\0';
} /* if */
} /* if */
errno = 0;
dir = opendir(dirname);
if (dir == NULL)
{
Mar 24, 2007
Mar 24, 2007
155
allocator.Free(buf);
Sep 29, 2004
Sep 29, 2004
156
return;
May 24, 2002
May 24, 2002
157
158
} /* if */
Jul 23, 2002
Jul 23, 2002
159
while ((ent = readdir(dir)) != NULL)
May 24, 2002
May 24, 2002
160
161
162
163
164
165
166
167
168
{
if (strcmp(ent->d_name, ".") == 0)
continue;
if (strcmp(ent->d_name, "..") == 0)
continue;
if (omitSymLinks)
{
Sep 5, 2010
Sep 5, 2010
169
170
PHYSFS_Stat statbuf;
int exists = 0;
May 24, 2002
May 24, 2002
171
172
173
174
char *p;
int len = strlen(ent->d_name) + dlen + 1;
if (len > bufsize)
{
Mar 14, 2005
Mar 14, 2005
175
p = (char *) allocator.Realloc(buf, len);
May 24, 2002
May 24, 2002
176
177
178
179
180
181
182
if (p == NULL)
continue;
buf = p;
bufsize = len;
} /* if */
strcpy(buf + dlen, ent->d_name);
Sep 5, 2010
Sep 5, 2010
183
Mar 9, 2012
Mar 9, 2012
184
185
186
187
188
189
if (!__PHYSFS_platformStat(buf, &exists, &statbuf))
continue;
else if (!exists)
continue; /* probably can't happen, but just in case. */
else if (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK)
continue;
May 24, 2002
May 24, 2002
190
191
} /* if */
Sep 18, 2005
Sep 18, 2005
192
callback(callbackdata, origdir, ent->d_name);
May 24, 2002
May 24, 2002
193
194
} /* while */
Mar 24, 2007
Mar 24, 2007
195
allocator.Free(buf);
May 24, 2002
May 24, 2002
196
197
198
199
200
201
closedir(dir);
} /* __PHYSFS_platformEnumerateFiles */
int __PHYSFS_platformMkDir(const char *path)
{
Mar 20, 2012
Mar 20, 2012
202
203
const int rc = mkdir(path, S_IRWXU);
BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), 0);
Jan 28, 2010
Jan 28, 2010
204
return 1;
May 24, 2002
May 24, 2002
205
206
207
} /* __PHYSFS_platformMkDir */
Jun 2, 2002
Jun 2, 2002
208
static void *doOpen(const char *filename, int mode)
May 24, 2002
May 24, 2002
209
{
Apr 3, 2008
Apr 3, 2008
210
const int appending = (mode & O_APPEND);
Jun 2, 2002
Jun 2, 2002
211
212
int fd;
int *retval;
May 24, 2002
May 24, 2002
213
214
errno = 0;
Apr 3, 2008
Apr 3, 2008
215
216
217
/* O_APPEND doesn't actually behave as we'd like. */
mode &= ~O_APPEND;
Jun 2, 2002
Jun 2, 2002
218
fd = open(filename, mode, S_IRUSR | S_IWUSR);
Mar 20, 2012
Mar 20, 2012
219
BAIL_IF_MACRO(fd < 0, errcodeFromErrno(), NULL);
May 24, 2002
May 24, 2002
220
Apr 3, 2008
Apr 3, 2008
221
222
223
224
if (appending)
{
if (lseek(fd, 0, SEEK_END) < 0)
{
Mar 20, 2012
Mar 20, 2012
225
const int err = errno;
Apr 3, 2008
Apr 3, 2008
226
close(fd);
Mar 20, 2012
Mar 20, 2012
227
BAIL_MACRO(errcodeFromErrnoError(err), NULL);
Apr 3, 2008
Apr 3, 2008
228
229
230
} /* if */
} /* if */
Mar 14, 2005
Mar 14, 2005
231
retval = (int *) allocator.Malloc(sizeof (int));
Mar 20, 2012
Mar 20, 2012
232
if (!retval)
Jun 2, 2002
Jun 2, 2002
233
234
{
close(fd);
Mar 20, 2012
Mar 20, 2012
235
BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Jun 2, 2002
Jun 2, 2002
236
237
238
} /* if */
*retval = fd;
Jan 28, 2010
Jan 28, 2010
239
return ((void *) retval);
May 24, 2002
May 24, 2002
240
241
242
243
244
} /* doOpen */
void *__PHYSFS_platformOpenRead(const char *filename)
{
Jan 28, 2010
Jan 28, 2010
245
return doOpen(filename, O_RDONLY);
May 24, 2002
May 24, 2002
246
247
248
249
250
} /* __PHYSFS_platformOpenRead */
void *__PHYSFS_platformOpenWrite(const char *filename)
{
Jan 28, 2010
Jan 28, 2010
251
return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC);
May 24, 2002
May 24, 2002
252
253
254
255
256
} /* __PHYSFS_platformOpenWrite */
void *__PHYSFS_platformOpenAppend(const char *filename)
{
Jan 28, 2010
Jan 28, 2010
257
return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND);
May 24, 2002
May 24, 2002
258
259
260
261
} /* __PHYSFS_platformOpenAppend */
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
Aug 21, 2010
Aug 21, 2010
262
PHYSFS_uint64 len)
May 24, 2002
May 24, 2002
263
{
Aug 29, 2010
Aug 29, 2010
264
const int fd = *((int *) opaque);
Aug 21, 2010
Aug 21, 2010
265
ssize_t rc = 0;
May 24, 2002
May 24, 2002
266
Mar 20, 2012
Mar 20, 2012
267
268
if (!__PHYSFS_ui64FitsAddressSpace(len))
BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
Jun 2, 2002
Jun 2, 2002
269
Aug 21, 2010
Aug 21, 2010
270
rc = read(fd, buffer, (size_t) len);
Mar 20, 2012
Mar 20, 2012
271
BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), -1);
Aug 21, 2010
Aug 21, 2010
272
273
274
assert(rc >= 0);
assert(rc <= len);
return (PHYSFS_sint64) rc;
May 24, 2002
May 24, 2002
275
276
277
278
} /* __PHYSFS_platformRead */
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
Aug 21, 2010
Aug 21, 2010
279
PHYSFS_uint64 len)
May 24, 2002
May 24, 2002
280
{
Aug 29, 2010
Aug 29, 2010
281
const int fd = *((int *) opaque);
Aug 21, 2010
Aug 21, 2010
282
ssize_t rc = 0;
Jun 2, 2002
Jun 2, 2002
283
Mar 20, 2012
Mar 20, 2012
284
285
if (!__PHYSFS_ui64FitsAddressSpace(len))
BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
Jun 2, 2002
Jun 2, 2002
286
Aug 21, 2010
Aug 21, 2010
287
rc = write(fd, (void *) buffer, (size_t) len);
Mar 20, 2012
Mar 20, 2012
288
BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), rc);
Aug 21, 2010
Aug 21, 2010
289
290
291
assert(rc >= 0);
assert(rc <= len);
return (PHYSFS_sint64) rc;
May 24, 2002
May 24, 2002
292
293
294
295
296
} /* __PHYSFS_platformWrite */
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
{
Aug 29, 2010
Aug 29, 2010
297
const int fd = *((int *) opaque);
Mar 20, 2012
Mar 20, 2012
298
299
const int rc = lseek(fd, (off_t) pos, SEEK_SET);
BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), 0);
Jan 28, 2010
Jan 28, 2010
300
return 1;
May 24, 2002
May 24, 2002
301
302
303
304
305
} /* __PHYSFS_platformSeek */
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
{
Aug 29, 2010
Aug 29, 2010
306
const int fd = *((int *) opaque);
Jun 6, 2002
Jun 6, 2002
307
PHYSFS_sint64 retval;
Mar 18, 2012
Mar 18, 2012
308
retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
Mar 20, 2012
Mar 20, 2012
309
BAIL_IF_MACRO(retval == -1, errcodeFromErrno(), -1);
Jan 28, 2010
Jan 28, 2010
310
return retval;
May 24, 2002
May 24, 2002
311
312
313
314
315
} /* __PHYSFS_platformTell */
PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
{
Aug 29, 2010
Aug 29, 2010
316
const int fd = *((int *) opaque);
May 24, 2002
May 24, 2002
317
struct stat statbuf;
Mar 20, 2012
Mar 20, 2012
318
BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1);
Jan 28, 2010
Jan 28, 2010
319
return ((PHYSFS_sint64) statbuf.st_size);
May 24, 2002
May 24, 2002
320
321
322
323
324
} /* __PHYSFS_platformFileLength */
int __PHYSFS_platformFlush(void *opaque)
{
Aug 29, 2010
Aug 29, 2010
325
const int fd = *((int *) opaque);
Mar 20, 2012
Mar 20, 2012
326
BAIL_IF_MACRO(fsync(fd) == -1, errcodeFromErrno(), 0);
Jan 28, 2010
Jan 28, 2010
327
return 1;
May 24, 2002
May 24, 2002
328
329
330
} /* __PHYSFS_platformFlush */
Aug 30, 2010
Aug 30, 2010
331
void __PHYSFS_platformClose(void *opaque)
May 24, 2002
May 24, 2002
332
{
Aug 30, 2010
Aug 30, 2010
333
334
const int fd = *((int *) opaque);
(void) close(fd); /* we don't check this. You should have used flush! */
Mar 14, 2005
Mar 14, 2005
335
allocator.Free(opaque);
May 24, 2002
May 24, 2002
336
337
338
339
340
} /* __PHYSFS_platformClose */
int __PHYSFS_platformDelete(const char *path)
{
Mar 20, 2012
Mar 20, 2012
341
BAIL_IF_MACRO(remove(path) == -1, errcodeFromErrno(), 0);
Jan 28, 2010
Jan 28, 2010
342
return 1;
May 24, 2002
May 24, 2002
343
344
} /* __PHYSFS_platformDelete */
May 25, 2002
May 25, 2002
345
Feb 15, 2010
Feb 15, 2010
346
347
348
349
int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *st)
{
struct stat statbuf;
Mar 9, 2012
Mar 9, 2012
350
if (lstat(filename, &statbuf) == -1)
Feb 15, 2010
Feb 15, 2010
351
{
Mar 9, 2012
Mar 9, 2012
352
*exists = (errno == ENOENT);
Mar 20, 2012
Mar 20, 2012
353
BAIL_MACRO(errcodeFromErrno(), 0);
Feb 15, 2010
Feb 15, 2010
354
355
} /* if */
Jun 22, 2011
Jun 22, 2011
356
357
*exists = 1;
Feb 15, 2010
Feb 15, 2010
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
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);
Aug 21, 2010
Aug 21, 2010
382
return 1;
Feb 15, 2010
Feb 15, 2010
383
384
} /* __PHYSFS_platformStat */
Jul 25, 2011
Jul 25, 2011
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
#ifndef PHYSFS_PLATFORM_BEOS /* BeOS has its own code in platform_beos.cpp */
#if (defined PHYSFS_NO_THREAD_SUPPORT)
void *__PHYSFS_platformGetThreadID(void) { return ((void *) 0x0001); }
void *__PHYSFS_platformCreateMutex(void) { return ((void *) 0x0001); }
void __PHYSFS_platformDestroyMutex(void *mutex) {}
int __PHYSFS_platformGrabMutex(void *mutex) { return 1; }
void __PHYSFS_platformReleaseMutex(void *mutex) {}
#else
typedef struct
{
pthread_mutex_t mutex;
pthread_t owner;
PHYSFS_uint32 count;
} PthreadMutex;
void *__PHYSFS_platformGetThreadID(void)
{
return ( (void *) ((size_t) pthread_self()) );
} /* __PHYSFS_platformGetThreadID */
void *__PHYSFS_platformCreateMutex(void)
{
int rc;
PthreadMutex *m = (PthreadMutex *) allocator.Malloc(sizeof (PthreadMutex));
Mar 20, 2012
Mar 20, 2012
415
BAIL_IF_MACRO(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Jul 25, 2011
Jul 25, 2011
416
417
418
419
rc = pthread_mutex_init(&m->mutex, NULL);
if (rc != 0)
{
allocator.Free(m);
Mar 20, 2012
Mar 20, 2012
420
BAIL_MACRO(PHYSFS_ERR_OS_ERROR, NULL);
Jul 25, 2011
Jul 25, 2011
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
} /* if */
m->count = 0;
m->owner = (pthread_t) 0xDEADBEEF;
return ((void *) m);
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
PthreadMutex *m = (PthreadMutex *) mutex;
/* Destroying a locked mutex is a bug, but we'll try to be helpful. */
if ((m->owner == pthread_self()) && (m->count > 0))
pthread_mutex_unlock(&m->mutex);
pthread_mutex_destroy(&m->mutex);
allocator.Free(m);
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
PthreadMutex *m = (PthreadMutex *) mutex;
pthread_t tid = pthread_self();
if (m->owner != tid)
{
if (pthread_mutex_lock(&m->mutex) != 0)
return 0;
m->owner = tid;
} /* if */
m->count++;
return 1;
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
PthreadMutex *m = (PthreadMutex *) mutex;
Mar 20, 2012
Mar 20, 2012
461
462
assert(m->owner == pthread_self()); /* catch programming errors. */
assert(m->count > 0); /* catch programming errors. */
Jul 25, 2011
Jul 25, 2011
463
464
465
466
467
468
469
470
471
472
473
474
475
if (m->owner == pthread_self())
{
if (--m->count == 0)
{
m->owner = (pthread_t) 0xDEADBEEF;
pthread_mutex_unlock(&m->mutex);
} /* if */
} /* if */
} /* __PHYSFS_platformReleaseMutex */
#endif /* !PHYSFS_NO_THREAD_SUPPORT */
#endif /* !PHYSFS_PLATFORM_BEOS */
Mar 11, 2007
Mar 11, 2007
476
#endif /* PHYSFS_PLATFORM_POSIX */
Jun 29, 2002
Jun 29, 2002
477
May 24, 2002
May 24, 2002
478
/* end of posix.c ... */