Skip to content

Latest commit

 

History

History
449 lines (359 loc) · 11.4 KB

physfs_platform_posix.c

File metadata and controls

449 lines (359 loc) · 11.4 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 11, 2007
Mar 11, 2007
9
10
11
12
#define __PHYSICSFS_INTERNAL__
#include "physfs_platforms.h"
#ifdef PHYSFS_PLATFORM_POSIX
Jun 29, 2002
Jun 29, 2002
13
May 24, 2002
May 24, 2002
14
#include <unistd.h>
Jun 2, 2002
Jun 2, 2002
15
#include <ctype.h>
May 24, 2002
May 24, 2002
16
17
#include <sys/types.h>
#include <sys/stat.h>
Jun 2, 2002
Jun 2, 2002
18
#include <pwd.h>
May 24, 2002
May 24, 2002
19
20
#include <dirent.h>
#include <errno.h>
Jun 2, 2002
Jun 2, 2002
21
#include <fcntl.h>
Jul 25, 2011
Jul 25, 2011
22
23
#include <pthread.h>
May 24, 2002
May 24, 2002
24
25
#include "physfs_internal.h"
Mar 20, 2012
Mar 20, 2012
26
27
28
29
30
31
32
33
34
35
36
37
38
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
39
case ENOENT: return PHYSFS_ERR_NOT_FOUND;
Mar 20, 2012
Mar 20, 2012
40
case ENOSPC: return PHYSFS_ERR_NO_SPACE;
Nov 28, 2012
Nov 28, 2012
41
case ENOTDIR: return PHYSFS_ERR_NOT_FOUND;
Mar 20, 2012
Mar 20, 2012
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
59
60
61
62
63
64
65
static char *getUserDirByUID(void)
{
uid_t uid = getuid();
struct passwd *pw;
char *retval = NULL;
pw = getpwuid(uid);
Mar 24, 2012
Mar 24, 2012
66
if ((pw != NULL) && (pw->pw_dir != NULL) && (*pw->pw_dir != '\0'))
May 24, 2002
May 24, 2002
67
{
Mar 24, 2012
Mar 24, 2012
68
69
70
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
71
if (retval != NULL)
Mar 24, 2012
Mar 24, 2012
72
{
May 24, 2002
May 24, 2002
73
strcpy(retval, pw->pw_dir);
Mar 24, 2012
Mar 24, 2012
74
75
76
77
78
79
if (add_dirsep)
{
retval[dlen] = '/';
retval[dlen+1] = '\0';
} /* if */
} /* if */
May 24, 2002
May 24, 2002
80
81
} /* if */
Jan 28, 2010
Jan 28, 2010
82
return retval;
May 24, 2002
May 24, 2002
83
84
85
} /* getUserDirByUID */
Mar 22, 2012
Mar 22, 2012
86
char *__PHYSFS_platformCalcUserDir(void)
May 24, 2002
May 24, 2002
87
{
Mar 24, 2012
Mar 24, 2012
88
89
char *retval = NULL;
char *envr = getenv("HOME");
Mar 21, 2010
Mar 21, 2010
90
91
/* if the environment variable was set, make sure it's really a dir. */
Mar 24, 2012
Mar 24, 2012
92
if (envr != NULL)
Mar 21, 2010
Mar 21, 2010
93
94
{
struct stat statbuf;
Mar 24, 2012
Mar 24, 2012
95
if ((stat(envr, &statbuf) != -1) && (S_ISDIR(statbuf.st_mode)))
Mar 21, 2010
Mar 21, 2010
96
{
Mar 24, 2012
Mar 24, 2012
97
98
99
100
101
102
103
104
105
106
107
108
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
109
110
111
} /* if */
} /* if */
May 24, 2002
May 24, 2002
112
113
if (retval == NULL)
retval = getUserDirByUID();
Mar 21, 2010
Mar 21, 2010
114
Jan 28, 2010
Jan 28, 2010
115
return retval;
Mar 22, 2012
Mar 22, 2012
116
} /* __PHYSFS_platformCalcUserDir */
May 24, 2002
May 24, 2002
117
118
Aug 19, 2017
Aug 19, 2017
119
PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname,
Aug 12, 2017
Aug 12, 2017
120
121
PHYSFS_EnumerateCallback callback,
const char *origdir, void *callbackdata)
May 24, 2002
May 24, 2002
122
123
124
{
DIR *dir;
struct dirent *ent;
Aug 19, 2017
Aug 19, 2017
125
PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK;
May 24, 2002
May 24, 2002
126
127
dir = opendir(dirname);
Aug 19, 2017
Aug 19, 2017
128
BAIL_IF(dir == NULL, errcodeFromErrno(), PHYSFS_ENUM_ERROR);
May 24, 2002
May 24, 2002
129
Aug 19, 2017
Aug 19, 2017
130
while ((retval == PHYSFS_ENUM_OK) && ((ent = readdir(dir)) != NULL))
May 24, 2002
May 24, 2002
131
{
Aug 12, 2017
Aug 12, 2017
132
133
134
135
136
137
const char *name = ent->d_name;
if (name[0] == '.') /* ignore "." and ".." */
{
if ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0')))
continue;
} /* if */
May 24, 2002
May 24, 2002
138
Aug 12, 2017
Aug 12, 2017
139
retval = callback(callbackdata, origdir, name);
Aug 19, 2017
Aug 19, 2017
140
if (retval == PHYSFS_ENUM_ERROR)
Aug 12, 2017
Aug 12, 2017
141
PHYSFS_setErrorCode(PHYSFS_ERR_APP_CALLBACK);
May 24, 2002
May 24, 2002
142
143
144
} /* while */
closedir(dir);
Aug 12, 2017
Aug 12, 2017
145
146
147
return retval;
} /* __PHYSFS_platformEnumerate */
May 24, 2002
May 24, 2002
148
149
150
151
int __PHYSFS_platformMkDir(const char *path)
{
Mar 20, 2012
Mar 20, 2012
152
const int rc = mkdir(path, S_IRWXU);
Jul 6, 2017
Jul 6, 2017
153
BAIL_IF(rc == -1, errcodeFromErrno(), 0);
Jan 28, 2010
Jan 28, 2010
154
return 1;
May 24, 2002
May 24, 2002
155
156
157
} /* __PHYSFS_platformMkDir */
Jun 16, 2022
Jun 16, 2022
158
159
160
161
162
163
164
165
166
167
#if !defined(O_CLOEXEC) && defined(FD_CLOEXEC)
static inline void set_CLOEXEC(int fildes)
{
int flags = fcntl(fildes, F_GETFD);
if (flags != -1) {
fcntl(fildes, F_SETFD, flags | FD_CLOEXEC);
}
}
#endif
Jun 2, 2002
Jun 2, 2002
168
static void *doOpen(const char *filename, int mode)
May 24, 2002
May 24, 2002
169
{
Apr 3, 2008
Apr 3, 2008
170
const int appending = (mode & O_APPEND);
Jun 2, 2002
Jun 2, 2002
171
172
int fd;
int *retval;
Jun 16, 2022
Jun 16, 2022
173
May 24, 2002
May 24, 2002
174
175
errno = 0;
Apr 3, 2008
Apr 3, 2008
176
177
/* O_APPEND doesn't actually behave as we'd like. */
mode &= ~O_APPEND;
Jun 16, 2022
Jun 16, 2022
178
Jul 12, 2021
Jul 12, 2021
179
180
181
182
#ifdef O_CLOEXEC
/* Add O_CLOEXEC if defined */
mode |= O_CLOEXEC;
#endif
Apr 3, 2008
Apr 3, 2008
183
Jul 12, 2021
Jul 12, 2021
184
185
186
do {
fd = open(filename, mode, S_IRUSR | S_IWUSR);
} while ((fd < 0) && (errno == EINTR));
Jul 6, 2017
Jul 6, 2017
187
BAIL_IF(fd < 0, errcodeFromErrno(), NULL);
May 24, 2002
May 24, 2002
188
Jul 12, 2021
Jul 12, 2021
189
#if !defined(O_CLOEXEC) && defined(FD_CLOEXEC)
Jun 16, 2022
Jun 16, 2022
190
set_CLOEXEC(fd);
Jul 12, 2021
Jul 12, 2021
191
192
#endif
Apr 3, 2008
Apr 3, 2008
193
194
195
196
if (appending)
{
if (lseek(fd, 0, SEEK_END) < 0)
{
Mar 20, 2012
Mar 20, 2012
197
const int err = errno;
Apr 3, 2008
Apr 3, 2008
198
close(fd);
Jul 6, 2017
Jul 6, 2017
199
BAIL(errcodeFromErrnoError(err), NULL);
Apr 3, 2008
Apr 3, 2008
200
201
202
} /* if */
} /* if */
Mar 14, 2005
Mar 14, 2005
203
retval = (int *) allocator.Malloc(sizeof (int));
Mar 20, 2012
Mar 20, 2012
204
if (!retval)
Jun 2, 2002
Jun 2, 2002
205
206
{
close(fd);
Jul 6, 2017
Jul 6, 2017
207
BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Jun 2, 2002
Jun 2, 2002
208
209
210
} /* if */
*retval = fd;
Jan 28, 2010
Jan 28, 2010
211
return ((void *) retval);
May 24, 2002
May 24, 2002
212
213
214
215
216
} /* doOpen */
void *__PHYSFS_platformOpenRead(const char *filename)
{
Jan 28, 2010
Jan 28, 2010
217
return doOpen(filename, O_RDONLY);
May 24, 2002
May 24, 2002
218
219
220
221
222
} /* __PHYSFS_platformOpenRead */
void *__PHYSFS_platformOpenWrite(const char *filename)
{
Jan 28, 2010
Jan 28, 2010
223
return doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC);
May 24, 2002
May 24, 2002
224
225
226
227
228
} /* __PHYSFS_platformOpenWrite */
void *__PHYSFS_platformOpenAppend(const char *filename)
{
Jan 28, 2010
Jan 28, 2010
229
return doOpen(filename, O_WRONLY | O_CREAT | O_APPEND);
May 24, 2002
May 24, 2002
230
231
232
233
} /* __PHYSFS_platformOpenAppend */
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buffer,
Aug 21, 2010
Aug 21, 2010
234
PHYSFS_uint64 len)
May 24, 2002
May 24, 2002
235
{
Aug 29, 2010
Aug 29, 2010
236
const int fd = *((int *) opaque);
Aug 21, 2010
Aug 21, 2010
237
ssize_t rc = 0;
May 24, 2002
May 24, 2002
238
Mar 20, 2012
Mar 20, 2012
239
if (!__PHYSFS_ui64FitsAddressSpace(len))
Jul 6, 2017
Jul 6, 2017
240
BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1);
Jun 2, 2002
Jun 2, 2002
241
Jul 12, 2021
Jul 12, 2021
242
243
244
do {
rc = read(fd, buffer, (size_t) len);
} while ((rc == -1) && (errno == EINTR));
Jul 6, 2017
Jul 6, 2017
245
BAIL_IF(rc == -1, errcodeFromErrno(), -1);
Aug 21, 2010
Aug 21, 2010
246
247
248
assert(rc >= 0);
assert(rc <= len);
return (PHYSFS_sint64) rc;
May 24, 2002
May 24, 2002
249
250
251
252
} /* __PHYSFS_platformRead */
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer,
Aug 21, 2010
Aug 21, 2010
253
PHYSFS_uint64 len)
May 24, 2002
May 24, 2002
254
{
Aug 29, 2010
Aug 29, 2010
255
const int fd = *((int *) opaque);
Aug 21, 2010
Aug 21, 2010
256
ssize_t rc = 0;
Jun 2, 2002
Jun 2, 2002
257
Mar 20, 2012
Mar 20, 2012
258
if (!__PHYSFS_ui64FitsAddressSpace(len))
Jul 6, 2017
Jul 6, 2017
259
BAIL(PHYSFS_ERR_INVALID_ARGUMENT, -1);
Jun 2, 2002
Jun 2, 2002
260
Jul 12, 2021
Jul 12, 2021
261
262
263
do {
rc = write(fd, (void *) buffer, (size_t) len);
} while ((rc == -1) && (errno == EINTR));
Jul 6, 2017
Jul 6, 2017
264
BAIL_IF(rc == -1, errcodeFromErrno(), rc);
Aug 21, 2010
Aug 21, 2010
265
266
267
assert(rc >= 0);
assert(rc <= len);
return (PHYSFS_sint64) rc;
May 24, 2002
May 24, 2002
268
269
270
271
272
} /* __PHYSFS_platformWrite */
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
{
Aug 29, 2010
Aug 29, 2010
273
const int fd = *((int *) opaque);
Aug 14, 2017
Aug 14, 2017
274
const off_t rc = lseek(fd, (off_t) pos, SEEK_SET);
Jul 6, 2017
Jul 6, 2017
275
BAIL_IF(rc == -1, errcodeFromErrno(), 0);
Jan 28, 2010
Jan 28, 2010
276
return 1;
May 24, 2002
May 24, 2002
277
278
279
280
281
} /* __PHYSFS_platformSeek */
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
{
Aug 29, 2010
Aug 29, 2010
282
const int fd = *((int *) opaque);
Jun 6, 2002
Jun 6, 2002
283
PHYSFS_sint64 retval;
Mar 18, 2012
Mar 18, 2012
284
retval = (PHYSFS_sint64) lseek(fd, 0, SEEK_CUR);
Jul 6, 2017
Jul 6, 2017
285
BAIL_IF(retval == -1, errcodeFromErrno(), -1);
Jan 28, 2010
Jan 28, 2010
286
return retval;
May 24, 2002
May 24, 2002
287
288
289
290
291
} /* __PHYSFS_platformTell */
PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
{
Aug 29, 2010
Aug 29, 2010
292
const int fd = *((int *) opaque);
May 24, 2002
May 24, 2002
293
struct stat statbuf;
Jul 6, 2017
Jul 6, 2017
294
BAIL_IF(fstat(fd, &statbuf) == -1, errcodeFromErrno(), -1);
Jan 28, 2010
Jan 28, 2010
295
return ((PHYSFS_sint64) statbuf.st_size);
May 24, 2002
May 24, 2002
296
297
298
299
300
} /* __PHYSFS_platformFileLength */
int __PHYSFS_platformFlush(void *opaque)
{
Aug 29, 2010
Aug 29, 2010
301
const int fd = *((int *) opaque);
Jul 12, 2021
Jul 12, 2021
302
303
304
305
306
307
308
int rc = -1;
if ((fcntl(fd, F_GETFL) & O_ACCMODE) != O_RDONLY) {
do {
rc = fsync(fd);
} while ((rc == -1) && (errno == EINTR));
BAIL_IF(rc == -1, errcodeFromErrno(), 0);
}
Jan 28, 2010
Jan 28, 2010
309
return 1;
May 24, 2002
May 24, 2002
310
311
312
} /* __PHYSFS_platformFlush */
Aug 30, 2010
Aug 30, 2010
313
void __PHYSFS_platformClose(void *opaque)
May 24, 2002
May 24, 2002
314
{
Aug 30, 2010
Aug 30, 2010
315
const int fd = *((int *) opaque);
Jul 12, 2021
Jul 12, 2021
316
317
318
319
int rc = -1;
do {
rc = close(fd); /* we don't check this. You should have used flush! */
} while ((rc == -1) && (errno == EINTR));
Mar 14, 2005
Mar 14, 2005
320
allocator.Free(opaque);
May 24, 2002
May 24, 2002
321
322
323
324
325
} /* __PHYSFS_platformClose */
int __PHYSFS_platformDelete(const char *path)
{
Jul 6, 2017
Jul 6, 2017
326
BAIL_IF(remove(path) == -1, errcodeFromErrno(), 0);
Jan 28, 2010
Jan 28, 2010
327
return 1;
May 24, 2002
May 24, 2002
328
329
} /* __PHYSFS_platformDelete */
May 25, 2002
May 25, 2002
330
Oct 26, 2017
Oct 26, 2017
331
int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st, const int follow)
Feb 15, 2010
Feb 15, 2010
332
333
{
struct stat statbuf;
Oct 26, 2017
Oct 26, 2017
334
335
const int rc = follow ? stat(fname, &statbuf) : lstat(fname, &statbuf);
BAIL_IF(rc == -1, errcodeFromErrno(), 0);
Jun 22, 2011
Jun 22, 2011
336
Feb 15, 2010
Feb 15, 2010
337
338
339
340
341
342
343
344
345
346
347
348
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
349
350
351
352
353
354
else if(S_ISLNK(statbuf.st_mode))
{
st->filetype = PHYSFS_FILETYPE_SYMLINK;
st->filesize = 0;
} /* else if */
Feb 15, 2010
Feb 15, 2010
355
356
357
358
359
360
361
362
363
364
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;
Oct 26, 2017
Oct 26, 2017
365
st->readonly = (access(fname, W_OK) == -1);
Aug 21, 2010
Aug 21, 2010
366
return 1;
Feb 15, 2010
Feb 15, 2010
367
368
} /* __PHYSFS_platformStat */
Jul 25, 2011
Jul 25, 2011
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
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));
Jul 6, 2017
Jul 6, 2017
388
BAIL_IF(!m, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
Jul 25, 2011
Jul 25, 2011
389
390
391
392
rc = pthread_mutex_init(&m->mutex, NULL);
if (rc != 0)
{
allocator.Free(m);
Jul 6, 2017
Jul 6, 2017
393
BAIL(PHYSFS_ERR_OS_ERROR, NULL);
Jul 25, 2011
Jul 25, 2011
394
395
396
397
398
399
400
401
402
403
404
405
406
407
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
} /* 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
434
435
assert(m->owner == pthread_self()); /* catch programming errors. */
assert(m->count > 0); /* catch programming errors. */
Jul 25, 2011
Jul 25, 2011
436
437
438
439
440
441
442
443
444
445
if (m->owner == pthread_self())
{
if (--m->count == 0)
{
m->owner = (pthread_t) 0xDEADBEEF;
pthread_mutex_unlock(&m->mutex);
} /* if */
} /* if */
} /* __PHYSFS_platformReleaseMutex */
Mar 11, 2007
Mar 11, 2007
446
#endif /* PHYSFS_PLATFORM_POSIX */
Jun 29, 2002
Jun 29, 2002
447
Jul 22, 2017
Jul 22, 2017
448
/* end of physfs_platform_posix.c ... */