/
physfs_platform_os2.c
812 lines (669 loc) · 24.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
* OS/2 support routines for PhysicsFS.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
#define __PHYSICSFS_INTERNAL__
#include "physfs_platforms.h"
#ifdef PHYSFS_PLATFORM_OS2
14
#define INCL_DOSMODULEMGR
15
16
17
18
19
20
21
22
23
24
#define INCL_DOSSEMAPHORES
#define INCL_DOSDATETIME
#define INCL_DOSFILEMGR
#define INCL_DOSMODULEMGR
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
#define INCL_DOSDEVICES
#define INCL_DOSDEVIOCTL
#define INCL_DOSMISC
#include <os2.h>
25
#include <uconv.h>
26
27
28
29
30
31
32
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include "physfs_internal.h"
33
34
35
36
37
38
static HMODULE uconvdll = 0;
static UconvObject uconv = 0;
static int (_System *pUniCreateUconvObject)(UniChar *, UconvObject *) = NULL;
static int (_System *pUniFreeUconvObject)(UconvObject *) = NULL;
static int (_System *pUniUconvToUcs)(UconvObject,void **,size_t *, UniChar**, size_t *, size_t *) = NULL;
static int (_System *pUniUconvFromUcs)(UconvObject,UniChar **,size_t *,void **,size_t *,size_t *) = NULL;
39
40
41
42
43
44
45
46
static PHYSFS_ErrorCode errcodeFromAPIRET(const APIRET rc)
{
switch (rc)
{
case NO_ERROR: return PHYSFS_ERR_OK; /* not an error. */
case ERROR_INTERRUPT: return PHYSFS_ERR_OK; /* not an error. */
case ERROR_TIMEOUT: return PHYSFS_ERR_OK; /* not an error. */
47
case ERROR_NOT_ENOUGH_MEMORY: return PHYSFS_ERR_OUT_OF_MEMORY;
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
91
92
93
94
95
case ERROR_FILE_NOT_FOUND: return PHYSFS_ERR_NOT_FOUND;
case ERROR_PATH_NOT_FOUND: return PHYSFS_ERR_NOT_FOUND;
case ERROR_ACCESS_DENIED: return PHYSFS_ERR_PERMISSION;
case ERROR_NOT_DOS_DISK: return PHYSFS_ERR_NOT_FOUND;
case ERROR_SHARING_VIOLATION: return PHYSFS_ERR_PERMISSION;
case ERROR_CANNOT_MAKE: return PHYSFS_ERR_IO; /* maybe this is wrong? */
case ERROR_DEVICE_IN_USE: return PHYSFS_ERR_BUSY;
case ERROR_OPEN_FAILED: return PHYSFS_ERR_IO; /* maybe this is wrong? */
case ERROR_DISK_FULL: return PHYSFS_ERR_NO_SPACE;
case ERROR_PIPE_BUSY: return PHYSFS_ERR_BUSY;
case ERROR_SHARING_BUFFER_EXCEEDED: return PHYSFS_ERR_IO;
case ERROR_FILENAME_EXCED_RANGE: return PHYSFS_ERR_BAD_FILENAME;
case ERROR_META_EXPANSION_TOO_LONG: return PHYSFS_ERR_BAD_FILENAME;
case ERROR_TOO_MANY_HANDLES: return PHYSFS_ERR_IO;
case ERROR_TOO_MANY_OPEN_FILES: return PHYSFS_ERR_IO;
case ERROR_NO_MORE_SEARCH_HANDLES: return PHYSFS_ERR_IO;
case ERROR_SEEK_ON_DEVICE: return PHYSFS_ERR_IO;
case ERROR_NEGATIVE_SEEK: return PHYSFS_ERR_INVALID_ARGUMENT;
case ERROR_WRITE_PROTECT: return PHYSFS_ERR_PERMISSION;
case ERROR_WRITE_FAULT: return PHYSFS_ERR_IO;
case ERROR_UNCERTAIN_MEDIA: return PHYSFS_ERR_IO;
case ERROR_PROTECTION_VIOLATION: return PHYSFS_ERR_IO;
case ERROR_BROKEN_PIPE: return PHYSFS_ERR_IO;
/* !!! FIXME: some of these might be PHYSFS_ERR_BAD_FILENAME, etc */
case ERROR_LOCK_VIOLATION:
case ERROR_GEN_FAILURE:
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_NAME:
case ERROR_INVALID_DRIVE:
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_FUNCTION:
case ERROR_INVALID_LEVEL:
case ERROR_INVALID_CATEGORY:
case ERROR_DUPLICATE_NAME:
case ERROR_BUFFER_OVERFLOW:
case ERROR_BAD_LENGTH:
case ERROR_BAD_DRIVER_LEVEL:
case ERROR_DIRECT_ACCESS_HANDLE:
case ERROR_NOT_OWNER:
return PHYSFS_ERR_OS_ERROR;
default: break;
} /* switch */
return PHYSFS_ERR_OTHER_ERROR;
} /* errcodeFromAPIRET */
96
static char *cvtUtf8ToCodepage(const char *utf8str)
97
{
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
const size_t len = strlen(utf8str) + 1;
const size_t uc2buflen = len * sizeof (UniChar);
UniChar *uc2ptr = (UniChar *) __PHYSFS_smallAlloc(uc2buflen);
UniChar *uc2str = uc2ptr;
char *cpptr = NULL;
char *cpstr = NULL;
size_t subs = 0;
size_t unilen;
BAIL_IF(!uc2str, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
PHYSFS_utf8ToUcs2(utf8str, (PHYSFS_uint16 *) uc2str, uc2buflen);
for (unilen = 0; uc2str[unilen]; unilen++) { /* spin */ }
unilen++; /* null terminator. */
if (!uconvdll)
{
/* There's really not much we can do on older OS/2s except pray this
is latin1-compatible. */
size_t i;
cpptr = (char *) allocator.Malloc(unilen);
cpstr = cpptr;
GOTO_IF(!cpptr, PHYSFS_ERR_OUT_OF_MEMORY, failed);
for (i = 0; i < unilen; i++)
{
const UniChar ch = uc2str[i];
GOTO_IF(ch > 0xFF, PHYSFS_ERR_BAD_FILENAME, failed);
cpptr[i] = (char) ((unsigned char) ch);
} /* for */
__PHYSFS_smallFree(uc2ptr);
return cpstr;
} /* if */
else
131
132
{
int rc;
133
size_t cplen = unilen * 4; /* overallocate, just in case. */
134
135
136
137
cpptr = (char *) allocator.Malloc(cplen);
GOTO_IF(!cpptr, PHYSFS_ERR_OUT_OF_MEMORY, failed);
cpstr = cpptr;
138
rc = pUniUconvFromUcs(uconv, &uc2str, &unilen, (void **) &cpstr, &cplen, &subs);
139
140
141
142
GOTO_IF(rc != ULS_SUCCESS, PHYSFS_ERR_BAD_FILENAME, failed);
GOTO_IF(subs > 0, PHYSFS_ERR_BAD_FILENAME, failed);
assert(unilen == 0);
143
__PHYSFS_smallFree(uc2ptr);
144
return cpptr;
145
} /* else */
146
147
148
149
failed:
__PHYSFS_smallFree(uc2ptr);
allocator.Free(cpptr);
150
151
152
153
return NULL;
} /* cvtUtf8ToCodepage */
154
155
static char *cvtCodepageToUtf8(const char *cpstr)
{
156
157
const size_t len = strlen(cpstr) + 1;
char *retvalbuf = (char *) allocator.Malloc(len * 4);
158
char *retval = NULL;
159
160
161
162
163
164
165
166
167
168
169
BAIL_IF(!retvalbuf, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
if (!uconvdll)
{
/* There's really not much we can do on older OS/2s except pray this
is latin1-compatible. */
retval = retvalbuf;
PHYSFS_utf8FromLatin1(cpstr, retval, len * 4);
} /* if */
else
170
171
172
173
174
{
int rc;
size_t cplen = len;
size_t unilen = len;
size_t subs = 0;
175
176
177
178
179
UniChar *uc2ptr = __PHYSFS_smallAlloc(len * sizeof (UniChar));
UniChar *uc2str = uc2ptr;
BAIL_IF(!uc2ptr, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
rc = pUniUconvToUcs(uconv, (void **) &cpstr, &cplen, &uc2str, &unilen, &subs);
180
181
GOTO_IF(rc != ULS_SUCCESS, PHYSFS_ERR_BAD_FILENAME, done);
GOTO_IF(subs > 0, PHYSFS_ERR_BAD_FILENAME, done);
182
assert(cplen == 0);
183
retval = retvalbuf;
184
PHYSFS_utf8FromUcs2((const PHYSFS_uint16 *) uc2ptr, retval, len * 4);
185
done:
186
__PHYSFS_smallFree(uc2ptr);
187
} /* else */
188
189
190
191
return retval;
} /* cvtCodepageToUtf8 */
192
193
/* (be gentle, this function isn't very robust.) */
194
static char *cvtPathToCorrectCase(char *buf)
195
{
196
char *retval = buf;
197
198
199
200
201
202
203
204
205
206
207
208
char *fname = buf + 3; /* point to first element. */
char *ptr = strchr(fname, '\\'); /* find end of first element. */
buf[0] = toupper(buf[0]); /* capitalize drive letter. */
/*
* Go through each path element, and enumerate its parent dir until
* a case-insensitive match is found. If one is (and it SHOULD be)
* then overwrite the original element with the correct case.
* If there's an error, or the path has vanished for some reason, it
* won't hurt to have the original case, so we just keep going.
*/
209
while ((fname != NULL) && (*fname != '\0'))
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
{
char spec[CCHMAXPATH];
FILEFINDBUF3 fb;
HDIR hdir = HDIR_CREATE;
ULONG count = 1;
APIRET rc;
*(fname - 1) = '\0'; /* isolate parent dir string. */
strcpy(spec, buf); /* copy isolated parent dir... */
strcat(spec, "\\*.*"); /* ...and add wildcard search spec. */
if (ptr != NULL) /* isolate element to find (fname is the start). */
*ptr = '\0';
rc = DosFindFirst((unsigned char *) spec, &hdir, FILE_DIRECTORY,
&fb, sizeof (fb), &count, FIL_STANDARD);
if (rc == NO_ERROR)
{
while (count == 1) /* while still entries to enumerate... */
{
231
232
int cmp;
char *utf8 = cvtCodepageToUtf8(fb.achName);
233
if (!utf8) /* ugh, maybe we'll get lucky with the C runtime. */
234
cmp = stricmp(fb.achName, fname);
235
236
else
{
237
cmp = PHYSFS_utf8stricmp(utf8, fname);
238
239
240
241
allocator.Free(utf8);
} /* else */
if (cmp == 0)
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
{
strcpy(fname, fb.achName);
break; /* there it is. Overwrite and stop searching. */
} /* if */
DosFindNext(hdir, &fb, sizeof (fb), &count);
} /* while */
DosFindClose(hdir);
} /* if */
*(fname - 1) = '\\'; /* unisolate parent dir. */
fname = ptr; /* point to next element. */
if (ptr != NULL)
{
*ptr = '\\'; /* unisolate element. */
ptr = strchr(++fname, '\\'); /* find next element. */
} /* if */
} /* while */
260
261
262
263
264
265
266
267
return retval;
} /* cvtPathToCorrectCase */
static void prepUnicodeSupport(void)
{
/* really old OS/2 might not have Unicode support _at all_, so load
the system library and do without if it doesn't exist. */
268
int ok = 0;
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
char buf[CCHMAXPATH];
UniChar defstr[] = { 0 };
if (DosLoadModule(buf, sizeof (buf) - 1, "uconv", &uconvdll) == NO_ERROR)
{
#define LOAD(x) (DosQueryProcAddr(uconvdll,0,#x,(PFN*)&p##x)==NO_ERROR)
ok = LOAD(UniCreateUconvObject) &&
LOAD(UniFreeUconvObject) &&
LOAD(UniUconvToUcs) &&
LOAD(UniUconvFromUcs);
#undef LOAD
} /* else */
if (!ok || (pUniCreateUconvObject(defstr, &uconv) != ULS_SUCCESS))
{
/* oh well, live without it. */
if (uconvdll)
{
if (uconv)
pUniFreeUconvObject(uconv);
DosFreeModule(uconvdll);
uconvdll = 0;
} /* if */
} /* if */
} /* prepUnicodeSupport */
293
294
295
296
int __PHYSFS_platformInit(void)
{
297
298
prepUnicodeSupport();
return 1; /* ready to go! */
299
300
301
} /* __PHYSFS_platformInit */
302
void __PHYSFS_platformDeinit(void)
303
{
304
305
306
307
308
309
310
if (uconvdll)
{
pUniFreeUconvObject(uconv);
uconv = 0;
DosFreeModule(uconvdll);
uconvdll = 0;
} /* if */
311
312
313
} /* __PHYSFS_platformDeinit */
314
static int discIsInserted(ULONG drive)
315
316
317
318
319
320
321
322
323
324
325
326
327
{
int rc;
char buf[20];
DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
rc = DosQueryFSInfo(drive + 1, FSIL_VOLSER, buf, sizeof (buf));
DosError(FERR_ENABLEHARDERR | FERR_ENABLEEXCEPTION);
return (rc == NO_ERROR);
} /* is_cdrom_inserted */
/* looks like "CD01" in ASCII (littleendian)...used for an ioctl. */
#define CD01 0x31304443
328
static int isCdRomDrive(ULONG drive)
329
330
331
332
333
{
PHYSFS_uint32 param, data;
ULONG ul1, ul2;
APIRET rc;
HFILE hfile = NULLHANDLE;
334
unsigned char drivename[3] = { 0, ':', '\0' };
335
336
337
drivename[0] = 'A' + drive;
338
339
340
341
rc = DosOpen(drivename, &hfile, &ul1, 0, 0,
OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
OPEN_FLAGS_DASD | OPEN_FLAGS_FAIL_ON_ERROR |
OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE, NULL);
342
343
if (rc != NO_ERROR)
return 0;
344
345
346
347
348
349
350
351
352
data = 0;
param = PHYSFS_swapULE32(CD01);
ul1 = ul2 = sizeof (PHYSFS_uint32);
rc = DosDevIOCtl(hfile, IOCTL_CDROMDISK, CDROMDISK_GETDRIVER,
¶m, sizeof (param), &ul1, &data, sizeof (data), &ul2);
DosClose(hfile);
return ((rc == NO_ERROR) && (PHYSFS_swapULE32(data) == CD01));
353
} /* isCdRomDrive */
354
355
356
357
358
359
360
361
void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
{
ULONG dummy = 0;
ULONG drivemap = 0;
ULONG i, bit;
const APIRET rc = DosQueryCurrentDisk(&dummy, &drivemap);
362
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc),);
363
364
365
366
367
for (i = 0, bit = 1; i < 26; i++, bit <<= 1)
{
if (drivemap & bit) /* this logical drive exists. */
{
368
if ((isCdRomDrive(i)) && (discIsInserted(i)))
369
370
371
372
373
374
375
376
377
378
379
{
char drive[4] = "x:\\";
drive[0] = ('A' + i);
cb(data, drive);
} /* if */
} /* if */
} /* for */
} /* __PHYSFS_platformDetectAvailableCDs */
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
380
381
382
383
384
385
386
{
char *retval = NULL;
char buf[CCHMAXPATH];
APIRET rc;
PTIB ptib;
PPIB ppib;
PHYSFS_sint32 len;
387
388
rc = DosGetInfoBlocks(&ptib, &ppib);
389
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), 0);
390
rc = DosQueryModuleName(ppib->pib_hmte, sizeof (buf), (PCHAR) buf);
391
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), 0);
392
393
retval = cvtCodepageToUtf8(buf);
BAIL_IF_ERRPASS(!retval, NULL);
394
395
/* chop off filename, leave path. */
396
for (len = strlen(retval) - 1; len >= 0; len--)
397
{
398
if (retval[len] == '\\')
399
{
400
retval[len + 1] = '\0';
401
402
403
break;
} /* if */
} /* for */
404
405
assert(len > 0); /* should have been a "x:\\" on the front on string. */
406
407
/* The string is capitalized! Figure out the REAL case... */
408
return cvtPathToCorrectCase(retval);
409
410
} /* __PHYSFS_platformCalcBaseDir */
411
char *__PHYSFS_platformCalcUserDir(void)
412
{
413
return __PHYSFS_platformCalcBaseDir(NULL); /* !!! FIXME: ? */
414
} /* __PHYSFS_platformCalcUserDir */
415
416
417
char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
{
418
return __PHYSFS_platformCalcBaseDir(NULL); /* !!! FIXME: ? */
419
} /* __PHYSFS_platformCalcPrefDir */
420
421
PHYSFS_EnumerateCallbackResult __PHYSFS_platformEnumerate(const char *dirname,
422
423
PHYSFS_EnumerateCallback callback,
const char *origdir, void *callbackdata)
424
{
425
PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK;
426
size_t utf8len = strlen(dirname);
427
428
char *utf8 = (char *) __PHYSFS_smallAlloc(utf8len + 5);
char *cpspec = NULL;
429
430
431
432
433
FILEFINDBUF3 fb;
HDIR hdir = HDIR_CREATE;
ULONG count = 1;
APIRET rc;
434
BAIL_IF(!utf8, PHYSFS_ERR_OUT_OF_MEMORY, PHYSFS_ENUM_ERROR);
435
436
437
438
439
440
strcpy(utf8, dirname);
if (utf8[utf8len - 1] != '\\')
strcpy(utf8 + utf8len, "\\*.*");
else
strcpy(utf8 + utf8len, "*.*");
441
442
443
cpspec = cvtUtf8ToCodepage(utf8);
__PHYSFS_smallFree(utf8);
444
BAIL_IF_ERRPASS(!cpspec, PHYSFS_ENUM_ERROR);
445
446
rc = DosFindFirst((unsigned char *) cpspec, &hdir,
447
448
449
FILE_DIRECTORY | FILE_ARCHIVED |
FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM,
&fb, sizeof (fb), &count, FIL_STANDARD);
450
allocator.Free(cpspec);
451
452
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), PHYSFS_ENUM_ERROR);
453
454
455
456
while (count == 1)
{
if ((strcmp(fb.achName, ".") != 0) && (strcmp(fb.achName, "..") != 0))
457
458
{
utf8 = cvtCodepageToUtf8(fb.achName);
459
if (!utf8)
460
retval = PHYSFS_ENUM_ERROR;
461
else
462
{
463
retval = callback(callbackdata, origdir, utf8);
464
allocator.Free(utf8);
465
if (retval == PHYSFS_ENUM_ERROR)
466
PHYSFS_setErrorCode(PHYSFS_ERR_APP_CALLBACK);
467
} /* else */
468
} /* if */
469
470
if (retval != PHYSFS_ENUM_OK)
471
472
break;
473
474
475
476
DosFindNext(hdir, &fb, sizeof (fb), &count);
} /* while */
DosFindClose(hdir);
477
478
479
return retval;
} /* __PHYSFS_platformEnumerate */
480
481
482
483
484
char *__PHYSFS_platformCurrentDir(void)
{
char *retval;
485
486
char *cpstr;
char *utf8;
487
488
489
490
491
492
493
ULONG currentDisk;
ULONG dummy;
ULONG pathSize = 0;
APIRET rc;
BYTE byte;
rc = DosQueryCurrentDisk(¤tDisk, &dummy);
494
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), NULL);
495
496
497
498
/* The first call just tells us how much space we need for the string. */
rc = DosQueryCurrentDir(currentDisk, &byte, &pathSize);
pathSize++; /* Add space for null terminator. */
499
500
cpstr = (char *) __PHYSFS_smallAlloc(pathSize);
BAIL_IF(cpstr == NULL, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
501
502
/* Actually get the string this time. */
503
rc = DosQueryCurrentDir(currentDisk, (PBYTE) cpstr, &pathSize);
504
505
if (rc != NO_ERROR)
{
506
__PHYSFS_smallFree(cpstr);
507
BAIL(errcodeFromAPIRET(rc), NULL);
508
509
} /* if */
510
511
512
513
514
515
516
517
518
519
520
521
utf8 = cvtCodepageToUtf8(cpstr);
__PHYSFS_smallFree(cpstr);
BAIL_IF_ERRPASS(utf8 == NULL, NULL);
/* +4 for "x:\\" drive selector and null terminator. */
retval = (char *) allocator.Malloc(strlen(utf8) + 4);
if (retval == NULL)
{
allocator.Free(utf8);
BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
} /* if */
522
523
524
retval[0] = ('A' + (currentDisk - 1));
retval[1] = ':';
retval[2] = '\\';
525
strcpy(retval + 3, utf8);
526
527
allocator.Free(utf8);
528
529
return retval;
530
} /* __PHYSFS_platformCurrentDir */
531
532
533
int __PHYSFS_platformMkDir(const char *filename)
534
{
535
536
537
538
539
APIRET rc;
char *cpstr = cvtUtf8ToCodepage(filename);
BAIL_IF_ERRPASS(!cpstr, 0);
rc = DosCreateDir((unsigned char *) cpstr, NULL);
allocator.Free(cpstr);
540
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), 0);
541
542
543
544
return 1;
} /* __PHYSFS_platformMkDir */
545
static HFILE openFile(const char *filename, const ULONG flags, const ULONG mode)
546
{
547
548
char *cpfname = cvtUtf8ToCodepage(filename);
ULONG action = 0;
549
HFILE hfile = NULLHANDLE;
550
APIRET rc;
551
552
BAIL_IF_ERRPASS(!cpfname, 0);
553
554
555
556
rc = DosOpen(cpfname, &hfile, &action, 0, FILE_NORMAL, flags, mode, NULL);
allocator.Free(cpfname);
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), 0);
557
558
559
return hfile;
} /* openFile */
560
561
void *__PHYSFS_platformOpenRead(const char *filename)
562
563
{
/*
564
* File must be opened SHARE_DENYWRITE and ACCESS_READONLY, otherwise
565
566
* DosQueryFileInfo() will fail if we try to get a file length, etc.
*/
567
568
569
570
571
572
return (void *) openFile(filename,
OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW,
OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE |
OPEN_ACCESS_READONLY);
} /* __PHYSFS_platformOpenRead */
573
574
575
576
577
578
579
580
581
void *__PHYSFS_platformOpenWrite(const char *filename)
{
return (void *) openFile(filename,
OPEN_ACTION_REPLACE_IF_EXISTS |
OPEN_ACTION_CREATE_IF_NEW,
OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE);
582
583
584
} /* __PHYSFS_platformOpenWrite */
585
void *__PHYSFS_platformOpenAppend(const char *filename)
586
587
{
APIRET rc;
588
589
ULONG dummy = 0;
HFILE hfile;
590
591
592
593
594
/*
* File must be opened SHARE_DENYWRITE and ACCESS_READWRITE, otherwise
* DosQueryFileInfo() will fail if we try to get a file length, etc.
*/
595
596
597
598
599
600
hfile = openFile(filename,
OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW,
OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_LOCALITY |
OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE |
OPEN_ACCESS_READWRITE);
BAIL_IF_ERRPASS(!hfile, NULL);
601
602
603
604
605
rc = DosSetFilePtr(hfile, 0, FILE_END, &dummy);
if (rc != NO_ERROR)
{
DosClose(hfile);
606
BAIL(errcodeFromAPIRET(rc), NULL);
607
608
609
610
611
612
613
614
615
616
} /* if */
return ((void *) hfile);
} /* __PHYSFS_platformOpenAppend */
PHYSFS_sint64 __PHYSFS_platformRead(void *opaque, void *buf, PHYSFS_uint64 len)
{
ULONG br = 0;
APIRET rc;
617
BAIL_IF(!__PHYSFS_ui64FitsAddressSpace(len),PHYSFS_ERR_INVALID_ARGUMENT,-1);
618
rc = DosRead((HFILE) opaque, buf, (ULONG) len, &br);
619
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), (br > 0) ? ((PHYSFS_sint64) br) : -1);
620
621
622
623
624
625
626
627
628
return (PHYSFS_sint64) br;
} /* __PHYSFS_platformRead */
PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buf,
PHYSFS_uint64 len)
{
ULONG bw = 0;
APIRET rc;
629
BAIL_IF(!__PHYSFS_ui64FitsAddressSpace(len),PHYSFS_ERR_INVALID_ARGUMENT,-1);
630
rc = DosWrite((HFILE) opaque, (void *) buf, (ULONG) len, &bw);
631
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), (bw > 0) ? ((PHYSFS_sint64) bw) : -1);
632
633
634
635
636
637
638
639
640
641
642
643
return (PHYSFS_sint64) bw;
} /* __PHYSFS_platformWrite */
int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos)
{
ULONG dummy;
HFILE hfile = (HFILE) opaque;
LONG dist = (LONG) pos;
APIRET rc;
/* hooray for 32-bit filesystem limits! :) */
644
BAIL_IF((PHYSFS_uint64) dist != pos, PHYSFS_ERR_INVALID_ARGUMENT, 0);
645
rc = DosSetFilePtr(hfile, dist, FILE_BEGIN, &dummy);
646
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), 0);
647
648
649
650
651
652
653
654
655
return 1;
} /* __PHYSFS_platformSeek */
PHYSFS_sint64 __PHYSFS_platformTell(void *opaque)
{
ULONG pos;
HFILE hfile = (HFILE) opaque;
const APIRET rc = DosSetFilePtr(hfile, 0, FILE_CURRENT, &pos);
656
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), -1);
657
658
659
660
661
662
663
664
665
return ((PHYSFS_sint64) pos);
} /* __PHYSFS_platformTell */
PHYSFS_sint64 __PHYSFS_platformFileLength(void *opaque)
{
FILESTATUS3 fs;
HFILE hfile = (HFILE) opaque;
const APIRET rc = DosQueryFileInfo(hfile, FIL_STANDARD, &fs, sizeof (fs));
666
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), -1);
667
668
669
670
671
672
673
return ((PHYSFS_sint64) fs.cbFile);
} /* __PHYSFS_platformFileLength */
int __PHYSFS_platformFlush(void *opaque)
{
const APIRET rc = DosResetBuffer((HFILE) opaque);
674
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), 0);
675
676
677
678
679
680
681
682
683
684
return 1;
} /* __PHYSFS_platformFlush */
void __PHYSFS_platformClose(void *opaque)
{
DosClose((HFILE) opaque); /* ignore errors. You should have flushed! */
} /* __PHYSFS_platformClose */
685
int __PHYSFS_platformDelete(const char *path)
686
{
687
char *cppath = cvtUtf8ToCodepage(path);
688
FILESTATUS3 fs;
689
690
691
692
693
694
APIRET rc;
int retval = 0;
BAIL_IF_ERRPASS(!cppath, 0);
rc = DosQueryPathInfo(cppath, FIL_STANDARD, &fs, sizeof (fs));
GOTO_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), done);
695
rc = (fs.attrFile & FILE_DIRECTORY) ? DosDeleteDir(path) : DosDelete(path);
696
697
698
699
700
701
GOTO_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), done);
retval = 1; /* success */
done:
allocator.Free(cppath);
return retval;
702
703
704
705
706
707
708
709
} /* __PHYSFS_platformDelete */
/* Convert to a format PhysicsFS can grok... */
PHYSFS_sint64 os2TimeToUnixTime(const FDATE *date, const FTIME *time)
{
struct tm tm;
710
tm.tm_sec = ((PHYSFS_uint32) time->twosecs) * 2;
711
712
713
714
715
716
717
718
719
720
721
722
723
tm.tm_min = time->minutes;
tm.tm_hour = time->hours;
tm.tm_mday = date->day;
tm.tm_mon = date->month;
tm.tm_year = ((PHYSFS_uint32) date->year) + 80;
tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
tm.tm_yday = -1;
tm.tm_isdst = -1;
return (PHYSFS_sint64) mktime(&tm);
} /* os2TimeToUnixTime */
724
int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *stat)
725
{
726
char *cpfname = cvtUtf8ToCodepage(filename);
727
FILESTATUS3 fs;
728
729
730
int retval = 0;
APIRET rc;
731
BAIL_IF_ERRPASS(!cpfname, 0);
732
733
734
rc = DosQueryPathInfo(cpfname, FIL_STANDARD, &fs, sizeof (fs));
GOTO_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), done);
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
if (fs.attrFile & FILE_DIRECTORY)
{
stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
stat->filesize = 0;
} /* if */
else
{
stat->filetype = PHYSFS_FILETYPE_REGULAR;
stat->filesize = fs.cbFile;
} /* else */
stat->modtime = os2TimeToUnixTime(&fs.fdateLastWrite, &fs.ftimeLastWrite);
if (stat->modtime < 0)
stat->modtime = 0;
stat->accesstime = os2TimeToUnixTime(&fs.fdateLastAccess, &fs.ftimeLastAccess);
if (stat->accesstime < 0)
stat->accesstime = 0;
stat->createtime = os2TimeToUnixTime(&fs.fdateCreation, &fs.ftimeCreation);
if (stat->createtime < 0)
stat->createtime = 0;
stat->readonly = ((fs.attrFile & FILE_READONLY) == FILE_READONLY);
760
return 1; /* success */
761
762
done:
763
allocator.Free(cpfname);
764
return retval;
765
766
767
768
769
770
771
772
773
774
775
776
777
} /* __PHYSFS_platformStat */
void *__PHYSFS_platformGetThreadID(void)
{
PTIB ptib;
PPIB ppib;
/*
* Allegedly, this API never fails, but we'll punt and return a
* default value (zero might as well do) if it does.
*/
const APIRET rc = DosGetInfoBlocks(&ptib, &ppib);
778
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), 0);
779
780
781
782
783
784
785
786
return ((void *) ptib->tib_ordinal);
} /* __PHYSFS_platformGetThreadID */
void *__PHYSFS_platformCreateMutex(void)
{
HMTX hmtx = NULLHANDLE;
const APIRET rc = DosCreateMutexSem(NULL, &hmtx, 0, 0);
787
BAIL_IF(rc != NO_ERROR, errcodeFromAPIRET(rc), NULL);
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
return ((void *) hmtx);
} /* __PHYSFS_platformCreateMutex */
void __PHYSFS_platformDestroyMutex(void *mutex)
{
DosCloseMutexSem((HMTX) mutex);
} /* __PHYSFS_platformDestroyMutex */
int __PHYSFS_platformGrabMutex(void *mutex)
{
/* Do _NOT_ set the physfs error message in here! */
return (DosRequestMutexSem((HMTX) mutex, SEM_INDEFINITE_WAIT) == NO_ERROR);
} /* __PHYSFS_platformGrabMutex */
void __PHYSFS_platformReleaseMutex(void *mutex)
{
DosReleaseMutexSem((HMTX) mutex);
} /* __PHYSFS_platformReleaseMutex */
#endif /* PHYSFS_PLATFORM_OS2 */
812
/* end of physfs_platform_os2.c ... */