/
dir.c
360 lines (279 loc) · 9.95 KB
1
2
3
4
5
6
7
8
9
10
/*
* Standard directory I/O support routines for PhysicsFS.
*
* Please see the file LICENSE in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#include <stdio.h>
#include <stdlib.h>
11
12
13
#include <string.h>
#include <errno.h>
#include <fcntl.h>
14
#include "physfs.h"
15
16
17
18
#define __PHYSICSFS_INTERNAL__
#include "physfs_internal.h"
19
20
21
22
23
24
25
26
27
28
29
30
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
static int DIR_read(FileHandle *handle, void *buffer,
unsigned int objSize, unsigned int objCount);
static int DIR_write(FileHandle *handle, void *buffer,
unsigned int objSize, unsigned int objCount);
static int DIR_eof(FileHandle *handle);
static int DIR_tell(FileHandle *handle);
static int DIR_seek(FileHandle *handle, int offset);
static int DIR_fileLength(FileHandle *handle);
static int DIR_fileClose(FileHandle *handle);
static int DIR_isArchive(const char *filename, int forWriting);
static DirHandle *DIR_openArchive(const char *name, int forWriting);
static LinkedStringList *DIR_enumerateFiles(DirHandle *h,
const char *dname,
int omitSymLinks);
static int DIR_exists(DirHandle *h, const char *name);
static int DIR_isDirectory(DirHandle *h, const char *name);
static int DIR_isSymLink(DirHandle *h, const char *name);
static FileHandle *DIR_openRead(DirHandle *h, const char *filename);
static FileHandle *DIR_openWrite(DirHandle *h, const char *filename);
static FileHandle *DIR_openAppend(DirHandle *h, const char *filename);
static int DIR_remove(DirHandle *h, const char *name);
static int DIR_mkdir(DirHandle *h, const char *name);
static void DIR_dirClose(DirHandle *h);
static const FileFunctions __PHYSFS_FileFunctions_DIR =
{
DIR_read, /* read() method */
NULL, /* write() method */
DIR_eof, /* eof() method */
DIR_tell, /* tell() method */
DIR_seek, /* seek() method */
DIR_fileLength, /* fileLength() method */
DIR_fileClose /* fileClose() method */
};
static const FileFunctions __PHYSFS_FileFunctions_DIRW =
{
NULL, /* read() method */
DIR_write, /* write() method */
DIR_eof, /* eof() method */
DIR_tell, /* tell() method */
DIR_seek, /* seek() method */
DIR_fileLength, /* fileLength() method */
DIR_fileClose /* fileClose() method */
};
const DirFunctions __PHYSFS_DirFunctions_DIR =
{
DIR_isArchive, /* isArchive() method */
DIR_openArchive, /* openArchive() method */
DIR_enumerateFiles, /* enumerateFiles() method */
DIR_exists, /* exists() method */
DIR_isDirectory, /* isDirectory() method */
DIR_isSymLink, /* isSymLink() method */
DIR_openRead, /* openRead() method */
DIR_openWrite, /* openWrite() method */
DIR_openAppend, /* openAppend() method */
DIR_remove, /* remove() method */
DIR_mkdir, /* mkdir() method */
DIR_dirClose /* dirClose() method */
};
/* This doesn't get listed, since it's technically not an archive... */
#if 0
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_DIR =
{
"DIR",
"non-archive directory I/O",
91
"Ryan C. Gordon <icculus@clutteredmind.org>",
92
93
94
95
"http://www.icculus.org/physfs/",
};
#endif
96
97
98
99
100
static int DIR_read(FileHandle *handle, void *buffer,
unsigned int objSize, unsigned int objCount)
{
FILE *h = (FILE *) (handle->opaque);
101
size_t retval;
102
103
104
errno = 0;
retval = fread(buffer, objSize, objCount, h);
105
106
BAIL_IF_MACRO((retval < (size_t) objCount) && (ferror(h)),
strerror(errno), (int) retval);
107
108
return((int) retval);
109
110
111
112
113
114
115
} /* DIR_read */
static int DIR_write(FileHandle *handle, void *buffer,
unsigned int objSize, unsigned int objCount)
{
FILE *h = (FILE *) (handle->opaque);
116
size_t retval;
117
118
errno = 0;
119
retval = fwrite(buffer, (size_t) objSize, objCount, h);
120
if ( (retval < (signed int) objCount) && (ferror(h)) )
121
122
__PHYSFS_setError(strerror(errno));
123
return((int) retval);
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
} /* DIR_write */
static int DIR_eof(FileHandle *handle)
{
return(feof((FILE *) (handle->opaque)));
} /* DIR_eof */
static int DIR_tell(FileHandle *handle)
{
return(ftell((FILE *) (handle->opaque)));
} /* DIR_tell */
static int DIR_seek(FileHandle *handle, int offset)
{
return(fseek((FILE *) (handle->opaque), offset, SEEK_SET) == 0);
} /* DIR_seek */
145
146
147
148
149
150
static int DIR_fileLength(FileHandle *handle)
{
return(__PHYSFS_platformFileLength((FILE *) (handle->opaque)));
} /* DIR_fileLength */
151
152
153
154
static int DIR_fileClose(FileHandle *handle)
{
FILE *h = (FILE *) (handle->opaque);
155
#if 0
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
* we manually fflush() the buffer, since that's the place fclose() will
* most likely fail, but that will leave the file handle in an undefined
* state if it fails. fflush() failures we can recover from.
*/
/* keep trying until there's success or an unrecoverable error... */
do {
__PHYSFS_platformTimeslice();
errno = 0;
} while ( (fflush(h) == EOF) && ((errno == EAGAIN) || (errno == EINTR)) );
/* EBADF == "Not open for writing". That's fine. */
BAIL_IF_MACRO((errno != 0) && (errno != EBADF), strerror(errno), 0);
170
#endif
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/* if fclose fails anyhow, we just have to pray that it's still usable. */
errno = 0;
BAIL_IF_MACRO(fclose(h) == EOF, strerror(errno), 0); /* (*shrug*) */
free(handle);
return(1);
} /* DIR_fileClose */
static int DIR_isArchive(const char *filename, int forWriting)
{
/* directories ARE archives in this driver... */
return(__PHYSFS_platformIsDirectory(filename));
} /* DIR_isArchive */
static DirHandle *DIR_openArchive(const char *name, int forWriting)
{
190
const char *dirsep = PHYSFS_getDirSeparator();
191
DirHandle *retval = NULL;
192
193
size_t namelen = strlen(name);
size_t seplen = strlen(dirsep);
194
195
196
BAIL_IF_MACRO(!DIR_isArchive(name, forWriting),
ERR_UNSUPPORTED_ARCHIVE, NULL);
197
198
199
200
201
202
203
retval = malloc(sizeof (DirHandle));
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
retval->opaque = malloc(namelen + seplen + 1);
if (retval->opaque == NULL)
{
free(retval);
204
BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
205
206
207
208
209
210
211
212
213
214
215
} /* if */
/* make sure there's a dir separator at the end of the string */
strcpy((char *) (retval->opaque), name);
if (strcmp((name + namelen) - seplen, dirsep) != 0)
strcat((char *) (retval->opaque), dirsep);
return(retval);
} /* DIR_openArchive */
216
217
218
static LinkedStringList *DIR_enumerateFiles(DirHandle *h,
const char *dname,
int omitSymLinks)
219
220
221
222
223
{
char *d = __PHYSFS_platformCvtToDependent((char *)(h->opaque),dname,NULL);
LinkedStringList *retval;
BAIL_IF_MACRO(d == NULL, NULL, NULL);
224
retval = __PHYSFS_platformEnumerateFiles(d, omitSymLinks);
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
free(d);
return(retval);
} /* DIR_enumerateFiles */
static int DIR_exists(DirHandle *h, const char *name)
{
char *f = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL);
int retval;
BAIL_IF_MACRO(f == NULL, NULL, 0);
retval = __PHYSFS_platformExists(f);
free(f);
return(retval);
} /* DIR_exists */
static int DIR_isDirectory(DirHandle *h, const char *name)
{
char *d = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL);
int retval;
BAIL_IF_MACRO(d == NULL, NULL, 0);
retval = __PHYSFS_platformIsDirectory(d);
free(d);
return(retval);
} /* DIR_isDirectory */
static int DIR_isSymLink(DirHandle *h, const char *name)
{
char *f = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL);
int retval;
BAIL_IF_MACRO(f == NULL, NULL, 0); /* !!! might be a problem. */
retval = __PHYSFS_platformIsSymLink(f);
free(f);
return(retval);
} /* DIR_isSymLink */
static FileHandle *doOpen(DirHandle *h, const char *name, const char *mode)
{
char *f = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL);
FILE *rc;
FileHandle *retval;
char *str;
BAIL_IF_MACRO(f == NULL, NULL, NULL);
retval = (FileHandle *) malloc(sizeof (FileHandle));
if (!retval)
{
free(f);
279
BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
280
281
282
283
284
285
286
287
288
289
} /* if */
errno = 0;
rc = fopen(f, mode);
str = strerror(errno);
free(f);
if (!rc)
{
free(retval);
290
BAIL_IF_MACRO(1, str, NULL);
291
292
293
294
} /* if */
retval->opaque = (void *) rc;
retval->dirHandle = h;
295
296
retval->funcs = (mode[0] == 'r') ?
&__PHYSFS_FileFunctions_DIR : &__PHYSFS_FileFunctions_DIRW;
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
return(retval);
} /* doOpen */
static FileHandle *DIR_openRead(DirHandle *h, const char *filename)
{
return(doOpen(h, filename, "rb"));
} /* DIR_openRead */
static FileHandle *DIR_openWrite(DirHandle *h, const char *filename)
{
return(doOpen(h, filename, "wb"));
} /* DIR_openWrite */
static FileHandle *DIR_openAppend(DirHandle *h, const char *filename)
{
return(doOpen(h, filename, "ab"));
} /* DIR_openAppend */
static int DIR_remove(DirHandle *h, const char *name)
{
char *f = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL);
int retval;
BAIL_IF_MACRO(f == NULL, NULL, 0);
errno = 0;
retval = (remove(f) == 0);
if (!retval)
__PHYSFS_setError(strerror(errno));
free(f);
return(retval);
} /* DIR_remove */
static int DIR_mkdir(DirHandle *h, const char *name)
{
char *f = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL);
int retval;
BAIL_IF_MACRO(f == NULL, NULL, 0);
errno = 0;
344
retval = __PHYSFS_platformMkDir(f);
345
346
347
348
349
350
351
352
353
354
355
356
357
358
if (!retval)
__PHYSFS_setError(strerror(errno));
free(f);
return(retval);
} /* DIR_mkdir */
static void DIR_dirClose(DirHandle *h)
{
free(h->opaque);
free(h);
} /* DIR_dirClose */
359
/* end of dir.c ... */