/
dir.c
362 lines (280 loc) · 10 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
static int DIR_read(FileHandle *handle, void *buffer,
unsigned int objSize, unsigned int objCount);
21
static int DIR_write(FileHandle *handle, const void *buffer,
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
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
} /* DIR_read */
112
static int DIR_write(FileHandle *handle, const void *buffer,
113
114
115
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
retval = (DirHandle *) malloc(sizeof (DirHandle));
199
200
201
202
203
BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
retval->opaque = malloc(namelen + seplen + 1);
if (retval->opaque == NULL)
{
free(retval);
204
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
205
206
207
208
209
210
211
} /* 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);
212
213
retval->funcs = &__PHYSFS_DirFunctions_DIR;
214
215
216
217
return(retval);
} /* DIR_openArchive */
218
219
220
static LinkedStringList *DIR_enumerateFiles(DirHandle *h,
const char *dname,
int omitSymLinks)
221
222
223
224
225
{
char *d = __PHYSFS_platformCvtToDependent((char *)(h->opaque),dname,NULL);
LinkedStringList *retval;
BAIL_IF_MACRO(d == NULL, NULL, NULL);
226
retval = __PHYSFS_platformEnumerateFiles(d, omitSymLinks);
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
279
280
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);
281
BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
282
283
284
285
286
287
288
289
290
291
} /* if */
errno = 0;
rc = fopen(f, mode);
str = strerror(errno);
free(f);
if (!rc)
{
free(retval);
292
BAIL_IF_MACRO(1, str, NULL);
293
294
295
296
} /* if */
retval->opaque = (void *) rc;
retval->dirHandle = h;
297
298
retval->funcs = (mode[0] == 'r') ?
&__PHYSFS_FileFunctions_DIR : &__PHYSFS_FileFunctions_DIRW;
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
344
345
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;
346
retval = __PHYSFS_platformMkDir(f);
347
348
349
350
351
352
353
354
355
356
357
358
359
360
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 */
361
/* end of dir.c ... */