Skip to content

Latest commit

 

History

History
436 lines (344 loc) · 11.1 KB

platform_posix.c

File metadata and controls

436 lines (344 loc) · 11.1 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
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;
Nov 28, 2012
Nov 28, 2012
44
case ENOENT: return PHYSFS_ERR_NOT_FOUND;
Mar 20, 2012
Mar 20, 2012
45
case ENOSPC: return PHYSFS_ERR_NO_SPACE;
Nov 28, 2012
Nov 28, 2012
46
case ENOTDIR: return PHYSFS_ERR_NOT_FOUND;
Mar 20, 2012
Mar 20, 2012
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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
void __PHYSFS_platformEnumerateFiles(const char *dirname,
Sep 18, 2005
Sep 18, 2005
125
126
PHYSFS_EnumFilesCallback callback,
const char *origdir,
Sep 29, 2004
Sep 29, 2004
127
void *callbackdata)
May 24, 2002
May 24, 2002
128
129
130
131
132
133
134
135
136
{
DIR *dir;
struct dirent *ent;
char *buf = NULL;
errno = 0;
dir = opendir(dirname);
if (dir == NULL)
{
Mar 24, 2007
Mar 24, 2007
137
allocator.Free(buf);
Sep 29, 2004
Sep 29, 2004
138
return;
May 24, 2002
May 24, 2002
139
140
} /* if */
Jul 23, 2002
Jul 23, 2002
141
while ((ent = readdir(dir)) != NULL)
May 24, 2002
May 24, 2002
142
143
144
{
if (strcmp(ent->d_name, ".") == 0)
continue;
Nov 29, 2012
Nov 29, 2012
145
else if (strcmp(ent->d_name, "..") == 0)
May 24, 2002
May 24, 2002
146
147
continue;
Sep 18, 2005
Sep 18, 2005
148
callback(callbackdata, origdir, ent->d_name);
May 24, 2002
May 24, 2002
149
150
} /* while */
Mar 24, 2007
Mar 24, 2007
151
allocator.Free(buf);
May 24, 2002
May 24, 2002
152
153
154
155
156
157
closedir(dir);
} /* __PHYSFS_platformEnumerateFiles */
int __PHYSFS_platformMkDir(const char *path)
{
Mar 20, 2012
Mar 20, 2012
158
159
const int rc = mkdir(path, S_IRWXU);
BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), 0);
Jan 28, 2010
Jan 28, 2010
160
return 1;
May 24, 2002
May 24, 2002
161
162
163
} /* __PHYSFS_platformMkDir */
Jun 2, 2002
Jun 2, 2002
164
static void *doOpen(const char *filename, int mode)
May 24, 2002
May 24, 2002
165
{
Apr 3, 2008
Apr 3, 2008
166
const int appending = (mode & O_APPEND);
Jun 2, 2002
Jun 2, 2002
167
168
int fd;
int *retval;
May 24, 2002
May 24, 2002
169
170
errno = 0;
Apr 3, 2008
Apr 3, 2008
171
172
173
/* O_APPEND doesn't actually behave as we'd like. */
mode &= ~O_APPEND;
Jun 2, 2002
Jun 2, 2002
174
fd = open(filename, mode, S_IRUSR | S_IWUSR);
Mar 20, 2012
Mar 20, 2012
175
BAIL_IF_MACRO(fd < 0, errcodeFromErrno(), NULL);
May 24, 2002
May 24, 2002
176
Apr 3, 2008
Apr 3, 2008
177
178
179
180
if (appending)
{
if (lseek(fd, 0, SEEK_END) < 0)
{
Mar 20, 2012
Mar 20, 2012
181
const int err = errno;
Apr 3, 2008
Apr 3, 2008
182
close(fd);
Mar 20, 2012
Mar 20, 2012
183
BAIL_MACRO(errcodeFromErrnoError(err), NULL);
Apr 3, 2008
Apr 3, 2008
184
185
186
} /* if */
} /* if */
Mar 14, 2005
Mar 14, 2005
187
retval = (int *) allocator.Malloc(sizeof (int));
Mar 20, 2012
Mar 20, 2012
188
if (!retval)
Jun 2, 2002
Jun 2, 2002
189
190
{
close(fd);
Mar 20, 2012
Mar 20, 2012
191
BAIL_MACRO(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Jun 2, 2002
Jun 2, 2002
192
193
194
} /* if */
*retval = fd;
Jan 28, 2010
Jan 28, 2010
195
return ((void *) retval);
May 24, 2002
May 24, 2002
196
197
198
199
200
} /* doOpen */
void *__PHYSFS_platformOpenRead(const char *filename)
{
Jan 28, 2010
Jan 28, 2010
201
return doOpen(filename, O_RDONLY);
May 24, 2002
May 24, 2002
202
203
204
205
206
} /* __PHYSFS_platformOpenRead */
void *__PHYSFS_platformOpenWrite(const char *filename)
{
Jan 28, 2010
Jan 28, 2010
207
return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC);
May 24, 2002
May 24, 2002
208
209
210
211
212
} /* __PHYSFS_platformOpenWrite */
void *__PHYSFS_platformOpenAppend(const char *filename)
{
Jan 28, 2010
Jan 28, 2010
213
return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND);
May 24, 2002
May 24, 2002
214
215
216
217
} /* __PHYSFS_platformOpenAppend */
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
Aug 21, 2010
Aug 21, 2010
218
PHYSFS_uint64 len)
May 24, 2002
May 24, 2002
219
{
Aug 29, 2010
Aug 29, 2010
220
const int fd = *((int *) opaque);
Aug 21, 2010
Aug 21, 2010
221
ssize_t rc = 0;
May 24, 2002
May 24, 2002
222
Mar 20, 2012
Mar 20, 2012
223
224
if (!__PHYSFS_ui64FitsAddressSpace(len))
BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
Jun 2, 2002
Jun 2, 2002
225
Aug 21, 2010
Aug 21, 2010
226
rc = read(fd, buffer, (size_t) len);
Mar 20, 2012
Mar 20, 2012
227
BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), -1);
Aug 21, 2010
Aug 21, 2010
228
229
230
assert(rc >= 0);
assert(rc <= len);
return (PHYSFS_sint64) rc;
May 24, 2002
May 24, 2002
231
232
233
234
} /* __PHYSFS_platformRead */
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
Aug 21, 2010
Aug 21, 2010
235
PHYSFS_uint64 len)
May 24, 2002
May 24, 2002
236
{
Aug 29, 2010
Aug 29, 2010
237
const int fd = *((int *) opaque);
Aug 21, 2010
Aug 21, 2010
238
ssize_t rc = 0;
Jun 2, 2002
Jun 2, 2002
239
Mar 20, 2012
Mar 20, 2012
240
241
if (!__PHYSFS_ui64FitsAddressSpace(len))
BAIL_MACRO(PHYSFS_ERR_INVALID_ARGUMENT, -1);
Jun 2, 2002
Jun 2, 2002
242
Aug 21, 2010
Aug 21, 2010
243
rc = write(fd, (void *) buffer, (size_t) len);
Mar 20, 2012
Mar 20, 2012
244
BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), rc);
Aug 21, 2010
Aug 21, 2010
245
246
247
assert(rc >= 0);
assert(rc <= len);
return (PHYSFS_sint64) rc;
May 24, 2002
May 24, 2002
248
249
250
251
252
} /* __PHYSFS_platformWrite */
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
{
Aug 29, 2010
Aug 29, 2010
253
const int fd = *((int *) opaque);
Mar 20, 2012
Mar 20, 2012
254
255
const int rc = lseek(fd, (off_t) pos, SEEK_SET);
BAIL_IF_MACRO(rc == -1, errcodeFromErrno(), 0);
Jan 28, 2010
Jan 28, 2010
256
return 1;
May 24, 2002
May 24, 2002
257
258
259
260
261
} /* __PHYSFS_platformSeek */
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
{
Aug 29, 2010
Aug 29, 2010
262
const int fd = *((int *) opaque);
Jun 6, 2002
Jun 6, 2002
263
PHYSFS_sint64 retval;
Mar 18, 2012
Mar 18, 2012
264
retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
Mar 20, 2012
Mar 20, 2012
265
BAIL_IF_MACRO(retval == -1, errcodeFromErrno(), -1);
Jan 28, 2010
Jan 28, 2010
266
return retval;
May 24, 2002
May 24, 2002
267
268
269
270
271
} /* __PHYSFS_platformTell */
PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
{
Aug 29, 2010
Aug 29, 2010
272
const int fd = *((int *) opaque);
May 24, 2002
May 24, 2002
273
struct stat statbuf;
Mar 20, 2012
Mar 20, 2012
274
BAIL_IF_MACRO(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1);
Jan 28, 2010
Jan 28, 2010
275
return ((PHYSFS_sint64) statbuf.st_size);
May 24, 2002
May 24, 2002
276
277
278
279
280
} /* __PHYSFS_platformFileLength */
int __PHYSFS_platformFlush(void *opaque)
{
Aug 29, 2010
Aug 29, 2010
281
const int fd = *((int *) opaque);
Aug 22, 2013
Aug 22, 2013
282
283
if ((fcntl(fd, F_GETFL) & O_ACCMODE) != O_RDONLY)
BAIL_IF_MACRO(fsync(fd) == -1, errcodeFromErrno(), 0);
Jan 28, 2010
Jan 28, 2010
284
return 1;
May 24, 2002
May 24, 2002
285
286
287
} /* __PHYSFS_platformFlush */
Aug 30, 2010
Aug 30, 2010
288
void __PHYSFS_platformClose(void *opaque)
May 24, 2002
May 24, 2002
289
{
Aug 30, 2010
Aug 30, 2010
290
291
const int fd = *((int *) opaque);
(void) close(fd); /* we don't check this. You should have used flush! */
Mar 14, 2005
Mar 14, 2005
292
allocator.Free(opaque);
May 24, 2002
May 24, 2002
293
294
295
296
297
} /* __PHYSFS_platformClose */
int __PHYSFS_platformDelete(const char *path)
{
Mar 20, 2012
Mar 20, 2012
298
BAIL_IF_MACRO(remove(path) == -1, errcodeFromErrno(), 0);
Jan 28, 2010
Jan 28, 2010
299
return 1;
May 24, 2002
May 24, 2002
300
301
} /* __PHYSFS_platformDelete */
May 25, 2002
May 25, 2002
302
Nov 30, 2012
Nov 30, 2012
303
int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *st)
Feb 15, 2010
Feb 15, 2010
304
305
306
{
struct stat statbuf;
Nov 30, 2012
Nov 30, 2012
307
BAIL_IF_MACRO(lstat(filename, &statbuf) == -1, errcodeFromErrno(), 0);
Jun 22, 2011
Jun 22, 2011
308
Feb 15, 2010
Feb 15, 2010
309
310
311
312
313
314
315
316
317
318
319
320
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 */
Nov 29, 2012
Nov 29, 2012
321
322
323
324
325
326
else if(S_ISLNK(statbuf.st_mode))
{
st->filetype = PHYSFS_FILETYPE_SYMLINK;
st->filesize = 0;
} /* else if */
Feb 15, 2010
Feb 15, 2010
327
328
329
330
331
332
333
334
335
336
337
338
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
339
return 1;
Feb 15, 2010
Feb 15, 2010
340
341
} /* __PHYSFS_platformStat */
Jul 25, 2011
Jul 25, 2011
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
#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
372
BAIL_IF_MACRO(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Jul 25, 2011
Jul 25, 2011
373
374
375
376
rc = pthread_mutex_init(&m->mutex, NULL);
if (rc != 0)
{
allocator.Free(m);
Mar 20, 2012
Mar 20, 2012
377
BAIL_MACRO(PHYSFS_ERR_OS_ERROR, NULL);
Jul 25, 2011
Jul 25, 2011
378
379
380
381
382
383
384
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
415
416
417
} /* 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
418
419
assert(m->owner == pthread_self()); /* catch programming errors. */
assert(m->count > 0); /* catch programming errors. */
Jul 25, 2011
Jul 25, 2011
420
421
422
423
424
425
426
427
428
429
430
431
432
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
433
#endif /* PHYSFS_PLATFORM_POSIX */
Jun 29, 2002
Jun 29, 2002
434
May 24, 2002
May 24, 2002
435
/* end of posix.c ... */