Skip to content

Latest commit

 

History

History
2865 lines (2350 loc) · 89.1 KB

doscalls.c

File metadata and controls

2865 lines (2350 loc) · 89.1 KB
 
Oct 27, 2016
Oct 27, 2016
1
2
3
#include "os2native.h"
#include "doscalls.h"
Sep 30, 2016
Sep 30, 2016
4
5
#include <unistd.h>
#include <limits.h>
Sep 30, 2016
Sep 30, 2016
6
#include <time.h>
Oct 6, 2016
Oct 6, 2016
7
8
#include <dirent.h>
#include <fcntl.h>
Sep 30, 2016
Sep 30, 2016
9
#include <sys/types.h>
Oct 14, 2016
Oct 14, 2016
10
#include <sys/wait.h>
Oct 6, 2016
Oct 6, 2016
11
#include <sys/stat.h>
Sep 30, 2016
Sep 30, 2016
12
13
#include <sys/sysinfo.h>
#include <sys/time.h>
Oct 2, 2016
Oct 2, 2016
14
#include <sys/resource.h>
Oct 9, 2016
Oct 9, 2016
15
#include <sys/stat.h>
Sep 30, 2016
Sep 30, 2016
16
Oct 27, 2016
Oct 27, 2016
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// DosQueryHeaderInfo() is an undocumented OS/2 API that is exported from DOSCALLS. Java uses it.
// This isn't mentioned in the docs or the SDK (beyond the ordinal being listed). I got the basic details
// from Odin32, which lists it in their os2newapi.h header.
enum
{
QHINF_EXEINFO = 1,
QHINF_READRSRCTBL,
QHINF_READFILE,
QHINF_LIBPATHLENGTH,
QHINF_LIBPATH,
QHINF_FIXENTRY,
QHINF_STE,
QHINF_MAPSEL
};
APIRET OS2API DosQueryHeaderInfo(HMODULE hmod, ULONG ulIndex, PVOID pvBuffer, ULONG cbBuffer, ULONG ulSubFunction);
// This is also undocumented (thanks, EDM/2!). Of course, Java uses it.
APIRET OS2API DosQuerySysState(ULONG func, ULONG arg1, ULONG pid, ULONG _res_, PVOID buf, ULONG bufsz);
// This is also undocumented (no idea about this at all, including function params). Of course, Java uses it.
APIRET DosR3ExitAddr(void);
Sep 30, 2016
Sep 30, 2016
39
Oct 14, 2016
Oct 14, 2016
40
41
static pthread_mutex_t GMutexDosCalls;
Sep 30, 2016
Sep 30, 2016
42
43
typedef struct ExitListItem
{
Sep 30, 2016
Sep 30, 2016
44
PFNEXITLIST fn;
Sep 30, 2016
Sep 30, 2016
45
46
47
48
49
50
uint32 priority;
struct ExitListItem *next;
} ExitListItem;
static ExitListItem *GExitList = NULL;
Oct 5, 2016
Oct 5, 2016
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
// Flags returned for character devices from DosQueryHType()...
enum {
DAW_STDIN = (1 << 0),
DAW_STDOUT = (1 << 1),
DAW_NUL = (1 << 2),
DAW_CLOCK = (1 << 3),
DAW_SPEC = (1 << 4),
DAW_ADD_ON = (1 << 5),
DAW_GIOCTL = (1 << 6),
DAW_LEVEL0 = 0,
DAW_LEVEL1 = (1 << 7),
DAW_LEVEL2 = (1 << 8),
DAW_LEVEL3 = (1 << 7) | (1 << 8),
DAW_FCNLEV = (1 << 7) | (1 << 8) | (1 << 9),
// ((1 << 10) is reserved, I think.)
DAW_OPENCLOSE = (1 << 11),
DAW_SHARE = (1 << 12),
DAW_NONIBM = (1 << 13),
DAW_IDC = (1 << 14),
DAW_CHARACTER = (1 << 15)
};
typedef struct HFileInfo
{
Oct 27, 2016
Oct 27, 2016
78
79
80
81
int fd; // unix file descriptor.
ULONG type; // file, pipe, device, etc.
ULONG attr; // for character devices, DAW_*
ULONG flags; // OPEN_FLAGS_*
Oct 5, 2016
Oct 5, 2016
82
} HFileInfo;
Oct 2, 2016
Oct 2, 2016
83
Oct 5, 2016
Oct 5, 2016
84
85
static HFileInfo *HFiles = NULL;
static uint32 MaxHFiles = 0;
Oct 2, 2016
Oct 2, 2016
86
Oct 14, 2016
Oct 14, 2016
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
typedef struct Thread
{
pthread_t thread;
size_t stacklen;
PFNTHREAD fn;
ULONG fnarg;
struct Thread *prev;
struct Thread *next;
} Thread;
static Thread *GDeadThreads = NULL;
typedef struct
{
pthread_mutex_t mutex;
pthread_cond_t condition;
volatile int posted;
volatile int waiting;
} EventSem;
Oct 17, 2016
Oct 17, 2016
108
109
110
111
112
113
114
115
116
117
118
119
typedef struct
{
DIR *dirp;
ULONG attr;
ULONG level;
char pattern[CCHMAXPATHCOMP];
} DirFinder;
static DirFinder GHDir1;
Oct 2, 2016
Oct 2, 2016
120
LX_NATIVE_MODULE_DEINIT({
Oct 28, 2016
Oct 28, 2016
121
122
GLoaderState->dosExit = NULL;
Oct 2, 2016
Oct 2, 2016
123
124
ExitListItem *next = GExitList;
GExitList = NULL;
Oct 14, 2016
Oct 14, 2016
125
Oct 2, 2016
Oct 2, 2016
126
127
128
129
for (ExitListItem *item = next; item; item = next) {
next = item->next;
free(item);
} // for
Oct 14, 2016
Oct 14, 2016
130
131
132
133
134
for (uint32 i = 0; i < MaxHFiles; i++) {
if (HFiles[i].fd != -1)
close(HFiles[i].fd);
} // for
Oct 2, 2016
Oct 2, 2016
135
136
free(HFiles);
HFiles = NULL;
Oct 5, 2016
Oct 5, 2016
137
MaxHFiles = 0;
Oct 14, 2016
Oct 14, 2016
138
139
pthread_mutex_destroy(&GMutexDosCalls);
Oct 2, 2016
Oct 2, 2016
140
141
})
Oct 27, 2016
Oct 27, 2016
142
static int initDoscalls(void)
Oct 5, 2016
Oct 5, 2016
143
{
Oct 28, 2016
Oct 28, 2016
144
145
GLoaderState->dosExit = DosExit;
Oct 14, 2016
Oct 14, 2016
146
147
148
149
150
if (pthread_mutex_init(&GMutexDosCalls, NULL) == -1) {
fprintf(stderr, "pthread_mutex_init failed!\n");
return 0;
} // if
Oct 5, 2016
Oct 5, 2016
151
152
153
154
155
156
157
158
159
160
161
162
MaxHFiles = 20; // seems to be OS/2's default.
HFiles = (HFileInfo *) malloc(sizeof (HFileInfo) * MaxHFiles);
if (!HFiles) {
fprintf(stderr, "Out of memory!\n");
return 0;
} // if
HFileInfo *info = HFiles;
for (uint32 i = 0; i < MaxHFiles; i++, info++) {
info->fd = -1;
info->type = 0;
info->attr = 0;
Oct 27, 2016
Oct 27, 2016
163
info->flags = 0;
Oct 5, 2016
Oct 5, 2016
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
} // for
// launching a Hello World program from CMD.EXE seems to inherit several
// file handles. 0, 1, 2 seem to map to stdin, stdout, stderr (and will
// be character devices (maybe CON?) by default, unless you redirect
// to a file in which case they're physical files, and using '|' in
// CMD.EXE will make handle 1 into a Pipe, of course.
// Handles, 4, 6 and 9 were also in use (all character devices, attributes
// 51585, 51392, 51392), but I don't know what these are, if they are
// inherited from CMD.EXE or supplied by OS/2 for whatever purpose.
// For now, we just wire up stdio.
for (int i = 0; i <= 2; i++) {
HFiles[i].fd = i;
HFiles[i].type = 1; // !!! FIXME: could be a pipe or file.
HFiles[i].attr = DAW_STDIN | DAW_STDOUT | DAW_LEVEL1 | DAW_CHARACTER;
} // for
return 1;
} // initDoscalls
Oct 27, 2016
Oct 27, 2016
185
186
LX_NATIVE_MODULE_INIT({ if (!initDoscalls()) return NULL; })
LX_NATIVE_EXPORT(DosSetMaxFH, 209),
Oct 14, 2016
Oct 14, 2016
187
LX_NATIVE_EXPORT(DosSetPathInfo, 219),
Oct 9, 2016
Oct 9, 2016
188
LX_NATIVE_EXPORT(DosQueryPathInfo, 223),
Oct 2, 2016
Oct 2, 2016
189
190
LX_NATIVE_EXPORT(DosQueryHType, 224),
LX_NATIVE_EXPORT(DosScanEnv, 227),
Oct 19, 2016
Oct 19, 2016
191
LX_NATIVE_EXPORT(DosSleep, 229),
Oct 6, 2016
Oct 6, 2016
192
LX_NATIVE_EXPORT(DosGetDateTime, 230),
Oct 17, 2016
Oct 17, 2016
193
LX_NATIVE_EXPORT(DosDevConfig, 231),
Oct 2, 2016
Oct 2, 2016
194
LX_NATIVE_EXPORT(DosExit, 234),
Oct 17, 2016
Oct 17, 2016
195
LX_NATIVE_EXPORT(DosResetBuffer, 254),
Oct 9, 2016
Oct 9, 2016
196
197
LX_NATIVE_EXPORT(DosSetFilePtr, 256),
LX_NATIVE_EXPORT(DosClose, 257),
Oct 14, 2016
Oct 14, 2016
198
LX_NATIVE_EXPORT(DosDelete, 259),
Oct 17, 2016
Oct 17, 2016
199
200
201
LX_NATIVE_EXPORT(DosFindClose, 263),
LX_NATIVE_EXPORT(DosFindFirst, 264),
LX_NATIVE_EXPORT(DosFindNext, 265),
Oct 6, 2016
Oct 6, 2016
202
LX_NATIVE_EXPORT(DosOpen, 273),
Oct 14, 2016
Oct 14, 2016
203
LX_NATIVE_EXPORT(DosQueryCurrentDir, 274),
Oct 17, 2016
Oct 17, 2016
204
LX_NATIVE_EXPORT(DosQueryCurrentDisk, 275),
Oct 27, 2016
Oct 27, 2016
205
LX_NATIVE_EXPORT(DosQueryFHState, 276),
Oct 9, 2016
Oct 9, 2016
206
LX_NATIVE_EXPORT(DosQueryFileInfo, 279),
Oct 14, 2016
Oct 14, 2016
207
LX_NATIVE_EXPORT(DosWaitChild, 280),
Oct 9, 2016
Oct 9, 2016
208
LX_NATIVE_EXPORT(DosRead, 281),
Oct 2, 2016
Oct 2, 2016
209
LX_NATIVE_EXPORT(DosWrite, 282),
Oct 14, 2016
Oct 14, 2016
210
LX_NATIVE_EXPORT(DosExecPgm, 283),
Oct 16, 2016
Oct 16, 2016
211
LX_NATIVE_EXPORT(DosQueryCp, 291),
Oct 2, 2016
Oct 2, 2016
212
213
LX_NATIVE_EXPORT(DosExitList, 296),
LX_NATIVE_EXPORT(DosAllocMem, 299),
Oct 14, 2016
Oct 14, 2016
214
LX_NATIVE_EXPORT(DosFreeMem, 304),
Oct 2, 2016
Oct 2, 2016
215
LX_NATIVE_EXPORT(DosSetMem, 305),
Oct 14, 2016
Oct 14, 2016
216
LX_NATIVE_EXPORT(DosCreateThread, 311),
Oct 2, 2016
Oct 2, 2016
217
LX_NATIVE_EXPORT(DosGetInfoBlocks, 312),
Oct 17, 2016
Oct 17, 2016
218
LX_NATIVE_EXPORT(DosLoadModule, 318),
Oct 16, 2016
Oct 16, 2016
219
LX_NATIVE_EXPORT(DosQueryModuleHandle, 319),
Oct 2, 2016
Oct 2, 2016
220
LX_NATIVE_EXPORT(DosQueryModuleName, 320),
Oct 16, 2016
Oct 16, 2016
221
LX_NATIVE_EXPORT(DosQueryProcAddr, 321),
Oct 17, 2016
Oct 17, 2016
222
LX_NATIVE_EXPORT(DosQueryAppType, 323),
Oct 2, 2016
Oct 2, 2016
223
LX_NATIVE_EXPORT(DosCreateEventSem, 324),
Oct 14, 2016
Oct 14, 2016
224
225
226
227
228
LX_NATIVE_EXPORT(DosCloseEventSem, 326),
LX_NATIVE_EXPORT(DosResetEventSem, 327),
LX_NATIVE_EXPORT(DosPostEventSem, 328),
LX_NATIVE_EXPORT(DosWaitEventSem, 329),
LX_NATIVE_EXPORT(DosQueryEventSem, 330),
Oct 2, 2016
Oct 2, 2016
229
LX_NATIVE_EXPORT(DosCreateMutexSem, 331),
Oct 9, 2016
Oct 9, 2016
230
231
LX_NATIVE_EXPORT(DosRequestMutexSem, 334),
LX_NATIVE_EXPORT(DosReleaseMutexSem, 335),
Oct 2, 2016
Oct 2, 2016
232
233
LX_NATIVE_EXPORT(DosSubSetMem, 344),
LX_NATIVE_EXPORT(DosSubAllocMem, 345),
Oct 14, 2016
Oct 14, 2016
234
LX_NATIVE_EXPORT(DosSubFreeMem, 346),
Oct 2, 2016
Oct 2, 2016
235
236
LX_NATIVE_EXPORT(DosQuerySysInfo, 348),
LX_NATIVE_EXPORT(DosSetExceptionHandler, 354),
Oct 27, 2016
Oct 27, 2016
237
LX_NATIVE_EXPORT(DosQuerySysState, 368),
Oct 2, 2016
Oct 2, 2016
238
LX_NATIVE_EXPORT(DosSetSignalExceptionFocus, 378),
Oct 9, 2016
Oct 9, 2016
239
240
LX_NATIVE_EXPORT(DosEnterMustComplete, 380),
LX_NATIVE_EXPORT(DosExitMustComplete, 381),
Oct 2, 2016
Oct 2, 2016
241
LX_NATIVE_EXPORT(DosSetRelMaxFH, 382),
Oct 16, 2016
Oct 16, 2016
242
LX_NATIVE_EXPORT(DosFlatToSel, 425),
Oct 29, 2016
Oct 29, 2016
243
LX_NATIVE_EXPORT(DosSelToFlat, 426),
Oct 19, 2016
Oct 19, 2016
244
245
LX_NATIVE_EXPORT(DosAllocThreadLocalMemory, 454),
LX_NATIVE_EXPORT(DosFreeThreadLocalMemory, 455),
Oct 27, 2016
Oct 27, 2016
246
247
248
249
LX_NATIVE_EXPORT(DosR3ExitAddr, 553),
LX_NATIVE_EXPORT(DosQueryHeaderInfo, 582),
LX_NATIVE_EXPORT(DosQueryExtLIBPATH, 874),
LX_NATIVE_EXPORT(DosQueryThreadContext, 877),
Oct 16, 2016
Oct 16, 2016
250
LX_NATIVE_EXPORT(DosOpenL, 981)
Oct 2, 2016
Oct 2, 2016
251
252
253
LX_NATIVE_MODULE_INIT_END()
Oct 14, 2016
Oct 14, 2016
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
static int grabLock(pthread_mutex_t *lock)
{
return (pthread_mutex_lock(lock) == 0);
} // grabLock
static void ungrabLock(pthread_mutex_t *lock)
{
pthread_mutex_unlock(lock);
} // ungrabLock
static void timespecNowPlusMilliseconds(struct timespec *waittime, const ULONG ulTimeout)
{
clock_gettime(CLOCK_REALTIME, waittime);
waittime->tv_sec += ulTimeout / 1000;
waittime->tv_nsec += (ulTimeout % 1000) * 1000000;
if (waittime->tv_nsec >= 1000000000) {
waittime->tv_sec++;
waittime->tv_nsec -= 1000000000;
assert(waittime->tv_nsec < 1000000000);
} // if
} // timespecNowPlusMilliseconds
Oct 9, 2016
Oct 9, 2016
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
static PTIB2 getTib2(void)
{
// just read the FS register, since we have to stick it there anyhow...
PTIB2 ptib2;
__asm__ __volatile__ ( "movl %%fs:0xC, %0 \n\t" : "=r" (ptib2) );
return ptib2;
} // getTib2
static PTIB getTib(void)
{
// we store the TIB2 struct right after the TIB struct on the stack,
// so get the TIB2's linear address from %fs:0xC, then step back
// to the TIB's linear address.
uint8 *ptib2 = (uint8 *) getTib2();
return (PTIB) (ptib2 - sizeof (TIB));
} // getTib
Sep 30, 2016
Sep 30, 2016
294
APIRET DosGetInfoBlocks(PTIB *pptib, PPIB *pppib)
Sep 30, 2016
Sep 30, 2016
295
{
Sep 30, 2016
Sep 30, 2016
296
297
TRACE_NATIVE("DosGetInfoBlocks(%p, %p)", pptib, pppib);
Oct 17, 2016
Oct 17, 2016
298
if (pptib != NULL)
Oct 9, 2016
Oct 9, 2016
299
*pptib = getTib();
Sep 30, 2016
Sep 30, 2016
300
Oct 17, 2016
Oct 17, 2016
301
302
if (pppib != NULL)
*pppib = (PPIB) &GLoaderState->pib;
Sep 30, 2016
Sep 30, 2016
303
304
305
306
return 0;
} // DosGetInfoBlocks
Sep 30, 2016
Sep 30, 2016
307
APIRET DosQuerySysInfo(ULONG first, ULONG last, PVOID _buf, ULONG buflen)
Sep 30, 2016
Sep 30, 2016
308
{
Sep 30, 2016
Sep 30, 2016
309
310
TRACE_NATIVE("DosQuerySysInfo(%u, %u, %p, %u)", (uint) first, (uint) last, _buf, (uint) buflen);
Sep 30, 2016
Sep 30, 2016
311
uint32 *buf = (uint32 *) _buf;
Sep 30, 2016
Sep 30, 2016
312
313
if (last < first) return ERROR_INVALID_PARAMETER;
if ( (buflen / sizeof (uint32)) < ((last - first) + 1) ) return ERROR_BUFFER_OVERFLOW;
Sep 30, 2016
Sep 30, 2016
314
315
316
317
318
319
320
321
322
323
324
325
for (uint32 varid = first; varid <= last; varid++) {
switch (varid) {
case QSV_MAX_PATH_LENGTH: *(buf++) = PATH_MAX; break;
case QSV_MAX_TEXT_SESSIONS: *(buf++) = 999999; break;
case QSV_MAX_PM_SESSIONS: *(buf++) = 999999; break;
case QSV_MAX_VDM_SESSIONS: *(buf++) = 0; break;
case QSV_BOOT_DRIVE: *(buf++) = 3; break; // "C:"
case QSV_DYN_PRI_VARIATION: *(buf++) = 1; break;
case QSV_MAX_WAIT: *(buf++) = 1; break;
case QSV_MIN_SLICE: *(buf++) = 1; break;
case QSV_MAX_SLICE: *(buf++) = 10; break;
case QSV_PAGE_SIZE: *(buf++) = 4096; break;
Sep 30, 2016
Sep 30, 2016
326
// !!! FIXME: change the version number in some way so apps can know this isn't actually OS/2.
Sep 30, 2016
Sep 30, 2016
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
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
372
373
374
375
376
377
378
case QSV_VERSION_MAJOR: *(buf++) = 20; break; // OS/2 Warp 4.0
case QSV_VERSION_MINOR: *(buf++) = 40; break; // OS/2 Warp 4.0
case QSV_VERSION_REVISION: *(buf++) = 0; break; // OS/2 Warp 4.0
case QSV_MS_COUNT: {
static long startoffset = 0;
if (startoffset == 0) {
struct timespec ts;
struct sysinfo info;
sysinfo(&info);
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
startoffset = info.uptime - ((long) ts.tv_sec);
} // if
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
*(buf++) = (uint32) (((long) ts.tv_sec) - startoffset);
break;
} // case
case QSV_TIME_LOW: *(buf++) = (uint32) time(NULL); break;
case QSV_TIME_HIGH: *(buf++) = 0; break; // !!! FIXME: 32-bit Linux time_t is 32-bits!
case QSV_TOTPHYSMEM: {
struct sysinfo info;
sysinfo(&info);
*(buf++) = (uint32) info.totalram;
break;
} // case
case QSV_TOTRESMEM: {
struct sysinfo info;
sysinfo(&info);
*(buf++) = (uint32) info.totalram - info.freeram; // !!! FIXME: probably not right?
break;
} // case
case QSV_TOTAVAILMEM: {
struct sysinfo info;
sysinfo(&info);
*(buf++) = (uint32) info.freeram;
break;
} // case
case QSV_MAXPRMEM: *(buf++) = 0x7FFFFFFF; break; // !!! FIXME: should I list all 4 gigs? Also: what about machines with < 2 gigs?
case QSV_MAXSHMEM: *(buf++) = 0x7FFFFFFF; break; // !!! FIXME: should I list all 4 gigs? Also: what about machines with < 2 gigs?
case QSV_TIMER_INTERVAL: *(buf++) = 10; break;
case QSV_MAX_COMP_LENGTH: *(buf++) = NAME_MAX; break;
case QSV_FOREGROUND_FS_SESSION: *(buf++) = 1; break; // !!! FIXME
case QSV_FOREGROUND_PROCESS: *(buf++) = 1; break; // !!! FIXME
Sep 30, 2016
Sep 30, 2016
379
default: return ERROR_INVALID_PARAMETER;
Sep 30, 2016
Sep 30, 2016
380
381
382
} // switch
} // for
Sep 30, 2016
Sep 30, 2016
383
return NO_ERROR;
Sep 30, 2016
Sep 30, 2016
384
385
386
} // DosQuerySysInfo
Sep 30, 2016
Sep 30, 2016
387
APIRET DosQueryModuleName(HMODULE hmod, ULONG buflen, PCHAR buf)
Sep 30, 2016
Sep 30, 2016
388
{
Sep 30, 2016
Sep 30, 2016
389
390
TRACE_NATIVE("DosQueryModuleName(%u, %u, %p)", (uint) hmod, (uint) buflen, buf);
Sep 30, 2016
Sep 30, 2016
391
392
const LxModule *lxmod = (LxModule *) hmod;
// !!! FIXME: error 6 ERROR_INVALID_HANDLE
Oct 27, 2016
Oct 27, 2016
393
if (strlen(lxmod->os2path) >= buflen)
Sep 30, 2016
Sep 30, 2016
394
return ERROR_BAD_LENGTH;
Sep 30, 2016
Sep 30, 2016
395
strcpy(buf, lxmod->os2path);
Sep 30, 2016
Sep 30, 2016
396
return NO_ERROR;
Sep 30, 2016
Sep 30, 2016
397
398
} // DosQueryModuleName
Sep 30, 2016
Sep 30, 2016
399
400
APIRET DosScanEnv(PSZ name, PSZ *outval)
Sep 30, 2016
Sep 30, 2016
401
{
Sep 30, 2016
Sep 30, 2016
402
403
TRACE_NATIVE("DosScanEnv('%s', %p)", name, outval);
Oct 17, 2016
Oct 17, 2016
404
char *env = GLoaderState->pib.pib_pchenv;
Sep 30, 2016
Sep 30, 2016
405
406
407
408
const size_t len = strlen(name);
while (*env) {
if ((strncmp(env, name, len) == 0) && (env[len] == '=')) {
*outval = env + len + 1;
Sep 30, 2016
Sep 30, 2016
409
return NO_ERROR;
Sep 30, 2016
Sep 30, 2016
410
411
412
413
} // if
env += strlen(env) + 1;
} // while
Sep 30, 2016
Sep 30, 2016
414
return ERROR_ENVVAR_NOT_FOUND;
Sep 30, 2016
Sep 30, 2016
415
416
} // DosScanEnv
Oct 14, 2016
Oct 14, 2016
417
418
419
420
421
422
423
424
425
426
static int getHFileUnixDescriptor(HFILE h)
{
grabLock(&GMutexDosCalls);
const int fd = (h < MaxHFiles) ? HFiles[h].fd : -1;
ungrabLock(&GMutexDosCalls);
return fd;
} // getHFileUnixDescriptor
Sep 30, 2016
Sep 30, 2016
427
APIRET DosWrite(HFILE h, PVOID buf, ULONG buflen, PULONG actual)
Sep 30, 2016
Sep 30, 2016
428
{
Sep 30, 2016
Sep 30, 2016
429
TRACE_NATIVE("DosWrite(%u, %p, %u, %p)", (uint) h, buf, (uint) buflen, actual);
Oct 5, 2016
Oct 5, 2016
430
Oct 14, 2016
Oct 14, 2016
431
432
const int fd = getHFileUnixDescriptor(h);
if (fd == -1)
Oct 5, 2016
Oct 5, 2016
433
434
return ERROR_INVALID_HANDLE;
Oct 14, 2016
Oct 14, 2016
435
436
// !!! FIXME: writing to a terminal should probably convert CR/LF to LF.
const int rc = write(fd, buf, buflen);
Oct 5, 2016
Oct 5, 2016
437
438
if (rc < 0) {
*actual = 0;
Sep 30, 2016
Sep 30, 2016
439
return ERROR_DISK_FULL; // !!! FIXME: map these errors.
Oct 5, 2016
Oct 5, 2016
440
} // if
Sep 30, 2016
Sep 30, 2016
441
442
*actual = (uint32) rc;
Sep 30, 2016
Sep 30, 2016
443
return NO_ERROR;
Sep 30, 2016
Sep 30, 2016
444
445
446
447
448
449
450
451
} // DosWrite
static void runDosExitList(const uint32 why)
{
ExitListItem *next = NULL;
for (ExitListItem *item = GExitList; item; item = next) {
// don't run any of these more than once:
// http://www.verycomputer.com/3_c1f6e02c06ed108e_1.htm
Sep 30, 2016
Sep 30, 2016
452
PFNEXITLIST fn = item->fn;
Sep 30, 2016
Sep 30, 2016
453
454
455
456
457
458
459
next = item->next;
GExitList = next;
free(item);
fn(why);
} // for
} // runDosExitList
Sep 30, 2016
Sep 30, 2016
460
VOID DosExit(ULONG action, ULONG exitcode)
Sep 30, 2016
Sep 30, 2016
461
{
Sep 30, 2016
Sep 30, 2016
462
463
TRACE_NATIVE("DosExit(%u, %u)", (uint) action, (uint) exitcode);
Sep 30, 2016
Sep 30, 2016
464
// !!! FIXME: what does a value other than 0 or 1 do here?
Sep 30, 2016
Sep 30, 2016
465
if (action == EXIT_THREAD) {
Sep 30, 2016
Sep 30, 2016
466
// !!! FIXME: terminate thread. If last thread: terminate process.
Oct 14, 2016
Oct 14, 2016
467
FIXME("DosExit(0) should terminate thread, not process");
Sep 30, 2016
Sep 30, 2016
468
469
470
} // if
// terminate the process.
Sep 30, 2016
Sep 30, 2016
471
runDosExitList(TC_EXIT);
Sep 30, 2016
Sep 30, 2016
472
Oct 28, 2016
Oct 28, 2016
473
GLoaderState->terminate(exitcode);
Sep 30, 2016
Sep 30, 2016
474
475
} // DosExit
Sep 30, 2016
Sep 30, 2016
476
APIRET DosExitList(ULONG ordercode, PFNEXITLIST fn)
Sep 30, 2016
Sep 30, 2016
477
{
Sep 30, 2016
Sep 30, 2016
478
479
TRACE_NATIVE("DosExitList(%u, %p)", (uint) ordercode, fn);
Sep 30, 2016
Sep 30, 2016
480
if (fn == NULL)
Sep 30, 2016
Sep 30, 2016
481
return ERROR_INVALID_FUNCTION;
Sep 30, 2016
Sep 30, 2016
482
483
484
485
486
487
488
489
const uint8 cmd = ordercode & 0xFF;
const uint8 arg = (ordercode >> 8) & 0xFF;
ExitListItem *prev = NULL;
ExitListItem *item = NULL;
// !!! FIXME: docs say this is illegal, but have to check what OS/2 actually does here.
if ((cmd != 1) && (arg != 0))
Sep 30, 2016
Sep 30, 2016
490
return ERROR_INVALID_DATA;
Sep 30, 2016
Sep 30, 2016
491
492
switch (cmd) {
Sep 30, 2016
Sep 30, 2016
493
case EXLST_ADD: {
Sep 30, 2016
Sep 30, 2016
494
495
ExitListItem *newitem = (ExitListItem *) malloc(sizeof (ExitListItem));
if (!newitem)
Sep 30, 2016
Sep 30, 2016
496
return ERROR_NOT_ENOUGH_MEMORY;
Oct 2, 2016
Oct 2, 2016
497
newitem->fn = fn;
Sep 30, 2016
Sep 30, 2016
498
499
500
501
502
503
504
505
506
507
508
509
for (item = GExitList; item; item = item->next) {
if (item->priority >= ((uint32) arg))
break;
prev = item;
} // for
if (prev) {
prev->next = newitem;
newitem->next = item;
} else {
newitem->next = GExitList;
GExitList = newitem;
} // else
Sep 30, 2016
Sep 30, 2016
510
return NO_ERROR;
Sep 30, 2016
Sep 30, 2016
511
512
} // case
Sep 30, 2016
Sep 30, 2016
513
case EXLST_REMOVE: {
Sep 30, 2016
Sep 30, 2016
514
515
516
517
518
519
520
for (item = GExitList; item; item = item->next) {
if (item->fn == fn) {
if (prev)
prev->next = item->next;
else
GExitList = item->next;
free(item);
Sep 30, 2016
Sep 30, 2016
521
return NO_ERROR;
Sep 30, 2016
Sep 30, 2016
522
523
524
} // if
prev = item;
} // for
Sep 30, 2016
Sep 30, 2016
525
return ERROR_INVALID_FUNCTION; // !!! FIXME: yeah?
Sep 30, 2016
Sep 30, 2016
526
527
} // case
Sep 30, 2016
Sep 30, 2016
528
529
case EXLST_EXIT:
return NO_ERROR; // ... just treat this as a no-op, I guess...?
Sep 30, 2016
Sep 30, 2016
530
Sep 30, 2016
Sep 30, 2016
531
default: return ERROR_INVALID_DATA;
Sep 30, 2016
Sep 30, 2016
532
533
} // switch
Sep 30, 2016
Sep 30, 2016
534
return NO_ERROR;
Sep 30, 2016
Sep 30, 2016
535
536
} // DosExitList
Sep 30, 2016
Sep 30, 2016
537
APIRET DosCreateEventSem(PSZ name, PHEV phev, ULONG attr, BOOL32 state)
Sep 30, 2016
Sep 30, 2016
538
{
Sep 30, 2016
Sep 30, 2016
539
TRACE_NATIVE("DosCreateEventSem('%s', %p, %u, %u)", name, phev, (uint) attr, (uint) state);
Oct 14, 2016
Oct 14, 2016
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
if (name != NULL) {
FIXME("implement named semaphores");
return ERROR_NOT_ENOUGH_MEMORY;
} // if
if (attr & DC_SEM_SHARED) {
FIXME("implement shared semaphores");
} // if
assert(sizeof (HEV) == sizeof (EventSem *));
EventSem *sem = (EventSem *) malloc(sizeof (EventSem));
if (sem == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
if (pthread_mutex_init(&sem->mutex, NULL) == -1) {
free(sem);
return ERROR_NOT_ENOUGH_MEMORY;
} // if
if (pthread_cond_init(&sem->condition, NULL) == -1) {
pthread_mutex_destroy(&sem->mutex);
free(sem);
return ERROR_NOT_ENOUGH_MEMORY;
} // if
sem->posted = state ? 1 : 0;
*phev = (HEV) sem;
Sep 30, 2016
Sep 30, 2016
570
return NO_ERROR;
Sep 30, 2016
Sep 30, 2016
571
572
} // DosCreateEventSem
Sep 30, 2016
Sep 30, 2016
573
APIRET DosCreateMutexSem(PSZ name, PHMTX phmtx, ULONG attr, BOOL32 state)
Sep 30, 2016
Sep 30, 2016
574
{
Sep 30, 2016
Sep 30, 2016
575
TRACE_NATIVE("DosCreateMutexSem('%s', %p, %u, %u)", name, phmtx, (uint) attr, (uint) state);
Oct 14, 2016
Oct 14, 2016
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
if (name != NULL) {
FIXME("implement named mutexes");
return ERROR_NOT_ENOUGH_MEMORY;
} // if
if (attr & DC_SEM_SHARED) {
FIXME("implement shared mutexes");
} // if
assert(sizeof (HMTX) == sizeof (pthread_mutex_t *));
pthread_mutex_t *mtx = (pthread_mutex_t *) malloc(sizeof (pthread_mutex_t));
if (mtx == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
// OS/2 mutexes are recursive.
pthread_mutexattr_t muxattr;
pthread_mutexattr_init(&muxattr);
pthread_mutexattr_settype(&muxattr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutexattr_setrobust(&muxattr, PTHREAD_MUTEX_ROBUST);
const int rc = pthread_mutex_init(mtx, &muxattr);
pthread_mutexattr_destroy(&muxattr);
if (rc == -1) {
free(mtx);
return ERROR_NOT_ENOUGH_MEMORY;
} // if
if (state)
pthread_mutex_lock(mtx);
*phmtx = (HMTX) mtx;
Sep 30, 2016
Sep 30, 2016
610
return NO_ERROR;
Sep 30, 2016
Sep 30, 2016
611
612
613
} // DosCreateMutexSem
// !!! FIXME: this is obviously not correct.
Sep 30, 2016
Sep 30, 2016
614
APIRET DosSetExceptionHandler(PEXCEPTIONREGISTRATIONRECORD rec)
Sep 30, 2016
Sep 30, 2016
615
{
Sep 30, 2016
Sep 30, 2016
616
617
TRACE_NATIVE("DosSetExceptionHandler(%p)", rec);
return NO_ERROR;
Sep 30, 2016
Sep 30, 2016
618
619
} // DosSetExceptionHandler
Oct 27, 2016
Oct 27, 2016
620
ULONG _DosFlatToSel(PVOID ptr)
Sep 30, 2016
Sep 30, 2016
621
{
Oct 9, 2016
Oct 9, 2016
622
TRACE_NATIVE("DosFlatToSel(%p)", ptr);
Oct 29, 2016
Oct 29, 2016
623
return GLoaderState->convert32to1616(ptr);
Oct 27, 2016
Oct 27, 2016
624
625
626
627
628
629
630
631
632
633
634
635
636
} // _DosFlatToSel
// DosFlatToSel() passes its argument in %eax, so a little asm to bridge that...
__asm__ (
".globl DosFlatToSel \n\t"
".type DosFlatToSel, @function \n\t"
"DosFlatToSel: \n\t"
" pushl %eax \n\t"
" call _DosFlatToSel \n\t"
" addl $4, %esp \n\t"
" ret \n\t"
".size _DosFlatToSel, .-_DosFlatToSel \n\t"
);
Sep 30, 2016
Sep 30, 2016
637
Sep 30, 2016
Sep 30, 2016
638
APIRET DosSetSignalExceptionFocus(BOOL32 flag, PULONG pulTimes)
Sep 30, 2016
Sep 30, 2016
639
{
Sep 30, 2016
Sep 30, 2016
640
641
TRACE_NATIVE("DosSetSignalExceptionFocus(%u, %p)", (uint) flag, pulTimes);
Sep 30, 2016
Sep 30, 2016
642
643
if (flag == 0) {
if (GLoaderState->main_module->signal_exception_focus_count == 0)
Sep 30, 2016
Sep 30, 2016
644
return ERROR_ALREADY_RESET;
Sep 30, 2016
Sep 30, 2016
645
646
647
GLoaderState->main_module->signal_exception_focus_count--;
} else if (flag == 1) {
if (GLoaderState->main_module->signal_exception_focus_count == 0xFFFFFFFF)
Sep 30, 2016
Sep 30, 2016
648
return ERROR_NESTING_TOO_DEEP;
Sep 30, 2016
Sep 30, 2016
649
650
651
652
653
654
655
656
657
658
GLoaderState->main_module->signal_exception_focus_count++;
} else {
// !!! FIXME: does OS/2 do something if flag != 0 or 1?
} // else
if (pulTimes)
*pulTimes = GLoaderState->main_module->signal_exception_focus_count;
// !!! FIXME: I guess enable/disable SIGINT handler here?
Sep 30, 2016
Sep 30, 2016
659
return NO_ERROR;
Sep 30, 2016
Sep 30, 2016
660
661
} // DosSetSignalExceptionFocus
Oct 5, 2016
Oct 5, 2016
662
APIRET DosSetRelMaxFH(PLONG pincr, PULONG pcurrent)
Oct 2, 2016
Oct 2, 2016
663
{
Oct 5, 2016
Oct 5, 2016
664
TRACE_NATIVE("DosSetRelMaxFH(%p, %p)", pincr, pcurrent);
Oct 2, 2016
Oct 2, 2016
665
Oct 5, 2016
Oct 5, 2016
666
#if 0
Oct 2, 2016
Oct 2, 2016
667
668
669
670
671
672
struct rlimit rlim;
int rc = getrlimit(RLIMIT_NOFILE, &rlim);
assert(rc == 0); // this shouldn't fail...right?
if (pcurrent)
*pcurrent = (ULONG) rlim.rlim_cur;
Oct 5, 2016
Oct 5, 2016
673
674
if (pincr) {
rlim.rlim_cur = (rlim_t) (((LONG) rlim.rlim_cur) + *pincr);
Oct 2, 2016
Oct 2, 2016
675
676
677
678
679
if (setrlimit(RLIMIT_NOFILE, &rlim) == 0) {
if (pcurrent)
*pcurrent = (ULONG) rlim.rlim_cur;
} // if
} // if
Oct 5, 2016
Oct 5, 2016
680
681
682
683
684
685
686
#endif
if (pincr != NULL) {
const LONG incr = *pincr;
// OS/2 API docs say reductions in file handles are advisory, so we
// ignore them outright. Fight me.
if (incr > 0) {
Oct 14, 2016
Oct 14, 2016
687
grabLock(&GMutexDosCalls);
Oct 5, 2016
Oct 5, 2016
688
689
690
691
692
693
694
HFileInfo *info = (HFileInfo *) realloc(HFiles, sizeof (HFileInfo) * (MaxHFiles + incr));
if (info != NULL) {
HFiles = info;
for (LONG i = 0; i < incr; i++, info++) {
info->fd = -1;
info->type = 0;
info->attr = 0;
Oct 27, 2016
Oct 27, 2016
695
info->flags = 0;
Oct 5, 2016
Oct 5, 2016
696
697
698
} // for
MaxHFiles += incr;
} // if
Oct 14, 2016
Oct 14, 2016
699
ungrabLock(&GMutexDosCalls);
Oct 5, 2016
Oct 5, 2016
700
701
702
703
} // if
} // if
if (pcurrent != NULL) {
Oct 14, 2016
Oct 14, 2016
704
grabLock(&GMutexDosCalls);
Oct 5, 2016
Oct 5, 2016
705
*pcurrent = MaxHFiles;
Oct 14, 2016
Oct 14, 2016
706
ungrabLock(&GMutexDosCalls);
Oct 5, 2016
Oct 5, 2016
707
} // if
Oct 2, 2016
Oct 2, 2016
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
return NO_ERROR; // always returns NO_ERROR even if it fails.
} // DosSetRelMaxFH
APIRET DosAllocMem(PPVOID ppb, ULONG cb, ULONG flag)
{
TRACE_NATIVE("DosAllocMem(%p, %u, %u)", ppb, (uint) cb, (uint) flag);
// !!! FIXME: this API is actually much more complicated than this.
*ppb = malloc(cb);
if (!*ppb)
return ERROR_NOT_ENOUGH_MEMORY;
return NO_ERROR;
} // DosAllocMem
Oct 2, 2016
Oct 2, 2016
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
APIRET DosSubSetMem(PVOID pbBase, ULONG flag, ULONG cb)
{
TRACE_NATIVE("DosSubSetMem(%p, %u, %u)", pbBase, (uint) flag, (uint) cb);
return NO_ERROR; // !!! FIXME: obviously wrong
} // DosSubSetMem
APIRET DosSubAllocMem(PVOID pbBase, PPVOID ppb, ULONG cb)
{
TRACE_NATIVE("DosSubAllocMem(%p, %p, %u)", pbBase, ppb, (uint) cb);
*ppb = malloc(cb); // !!! FIXME: obviously wrong
if (!*ppb)
return ERROR_NOT_ENOUGH_MEMORY;
return NO_ERROR;
} // DosSubAllocMem
APIRET DosQueryHType(HFILE hFile, PULONG pType, PULONG pAttr)
{
TRACE_NATIVE("DosQueryHType(%u, %p, %p)", (uint) hFile, pType, pAttr);
Oct 5, 2016
Oct 5, 2016
744
Oct 14, 2016
Oct 14, 2016
745
APIRET retval = NO_ERROR;
Oct 5, 2016
Oct 5, 2016
746
Oct 14, 2016
Oct 14, 2016
747
748
749
750
751
752
753
754
755
grabLock(&GMutexDosCalls);
if ((hFile >= MaxHFiles) || (HFiles[hFile].fd == -1))
retval = ERROR_INVALID_HANDLE;
else {
// OS/2 will dereference a NULL pointer here, but I can't do it...!!!
if (pType) *pType = HFiles[hFile].type;
if (pAttr) *pAttr = HFiles[hFile].attr;
} // else
ungrabLock(&GMutexDosCalls);
Oct 5, 2016
Oct 5, 2016
756
Oct 14, 2016
Oct 14, 2016
757
return retval;
Oct 2, 2016
Oct 2, 2016
758
759
760
761
762
763
764
} // DosQueryHType
APIRET DosSetMem(PVOID pb, ULONG cb, ULONG flag)
{
TRACE_NATIVE("DosSetMem(%p, %u, %u)", pb, (uint) cb, (uint) flag);
return NO_ERROR; // !!! FIXME: obviously wrong.
} // DosSetMem
Oct 6, 2016
Oct 6, 2016
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
APIRET DosGetDateTime(PDATETIME pdt)
{
TRACE_NATIVE("DosGetDateTime(%p)", pdt);
// we can't use time() for this, since we need sub-second resolution.
struct timeval tv;
gettimeofday(&tv, NULL);
struct tm ltm;
localtime_r(&tv.tv_sec, &ltm);
pdt->hours = ltm.tm_hour;
pdt->minutes = ltm.tm_min;
pdt->seconds = (ltm.tm_sec == 60) ? 59 : ltm.tm_sec; // !!! FIXME: I assume OS/2 doesn't support leap seconds...
pdt->hundredths = tv.tv_usec / 10000000; // microseconds to hundreths.
pdt->day = ltm.tm_mday;
pdt->month = ltm.tm_mon + 1;
pdt->year = ltm.tm_year + 1900;
pdt->timezone = -(ltm.tm_gmtoff / 60); // OS/2 is minutes west of GMT, Unix is seconds east. Convert and flip!
pdt->weekday = ltm.tm_wday;
return NO_ERROR; // never returns failure.
} // DosGetDateTime
static char *makeUnixPath(const char *os2path, APIRET *err)
{
Oct 18, 2016
Oct 18, 2016
792
return GLoaderState->makeUnixPath(os2path, (uint32 *) err);
Oct 6, 2016
Oct 6, 2016
793
794
} // makeUnixPath
Oct 16, 2016
Oct 16, 2016
795
static APIRET doDosOpen(PSZ pszFileName, PHFILE pHf, PULONG pulAction, LONGLONG cbFile, ULONG ulAttribute, ULONG fsOpenFlags, ULONG fsOpenMode, PEAOP2 peaop2)
Oct 6, 2016
Oct 6, 2016
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
{
int isReadOnly = 0;
int flags = 0;
const ULONG access_mask = OPEN_ACCESS_READONLY | OPEN_ACCESS_WRITEONLY | OPEN_ACCESS_READWRITE;
switch (fsOpenMode & access_mask) {
case OPEN_ACCESS_READONLY: isReadOnly = 1; flags |= O_RDONLY; break;
case OPEN_ACCESS_WRITEONLY: flags |= O_WRONLY; break;
case OPEN_ACCESS_READWRITE: flags |= O_RDWR; break;
default: return ERROR_INVALID_PARAMETER;
} // switch
if (isReadOnly && (cbFile != 0))
return ERROR_INVALID_PARAMETER;
else if (ulAttribute & FILE_DIRECTORY)
return ERROR_INVALID_PARAMETER; // !!! FIXME: I assume you can't create a directory with DosOpen...right?
else if (isReadOnly && ((fsOpenFlags & 0xF0) == OPEN_ACTION_CREATE_IF_NEW))
return ERROR_INVALID_PARAMETER; // !!! FIXME: is this invalid on OS/2?
else if (isReadOnly && ((fsOpenFlags & 0x0F) == OPEN_ACTION_REPLACE_IF_EXISTS))
return ERROR_INVALID_PARAMETER; // !!! FIXME: is this invalid on OS/2?
else if (fsOpenFlags & 0xfffffe00) // bits (1<<8) through (1<<31) are reserved, must be zero.
return ERROR_INVALID_PARAMETER;
else if (fsOpenFlags & OPEN_FLAGS_DASD) // no good is going to come of this.
return ERROR_OPEN_FAILED;
else if (fsOpenMode & 0xffff0000) // bits (1<<16) through (1<<31) are reserved, must be zero.
return ERROR_INVALID_PARAMETER;
if (peaop2 != NULL) {
FIXME("EAs not yet implemented");
return ERROR_OPEN_FAILED;
}
switch (fsOpenFlags & 0xF0) {
case OPEN_ACTION_FAIL_IF_NEW:
break; // just don't O_CREAT and you're fine.
case OPEN_ACTION_CREATE_IF_NEW:
flags |= O_CREAT | O_EXCL; // the O_EXCL is intentional! see below.
break;
} // switch
int mustNotExist = 0;
int isExclusive = 0;
int isReplacing = 0;
switch (fsOpenFlags & 0x0F) {
case OPEN_ACTION_FAIL_IF_EXISTS:
if (isReadOnly)
mustNotExist = 1;
else {
isExclusive = 1;
flags |= O_CREAT | O_EXCL;
} // else
break;
case OPEN_ACTION_OPEN_IF_EXISTS:
break; // nothing to do here.
case OPEN_ACTION_REPLACE_IF_EXISTS: // right now, we already failed above if readonly.
isReplacing = 1;
flags |= O_TRUNC; // have the open call nuke it, and then we'll ftruncate to grow it if necessary.
break;
} // switch
if (fsOpenMode & OPEN_FLAGS_WRITE_THROUGH)
flags |= O_SYNC; // !!! FIXME: this flag is supposed to drop when inherited by children, but fcntl() can't do that on Linux.
if (fsOpenMode & OPEN_FLAGS_NOINHERIT)
flags |= O_CLOEXEC;
if (fsOpenMode & OPEN_FLAGS_FAIL_ON_ERROR)
FIXME("need other file i/o APIs to do a system dialog box if this handle has i/o failures!");
// O_DIRECT isn't supported on ZFS-on-Linux, so I'm already not on board,
// but also: do we care if programs intended to run on a system with a
// few megabytes of RAM--on an OS that didn't have a resizeable file
// cache!--writes into a multi-gigabyte machine's flexible cache? I don't!
//if (fsOpenMode & OPEN_FLAGS_NO_CACHE)
// flags |= O_DIRECT;
FIXME("There are fsOpenMode flags we currently ignore (like sharing support)");
const mode_t mode = S_IRUSR | ((ulAttribute & FILE_READONLY) ? 0 : S_IWUSR);
FIXME("Most of the file attributes don't make sense on Unix, but we could stuff them in EAs");
HFileInfo *info = HFiles;
uint32 i;
Oct 14, 2016
Oct 14, 2016
883
884
885
if (!grabLock(&GMutexDosCalls))
return ERROR_SYS_INTERNAL;
Oct 6, 2016
Oct 6, 2016
886
for (i = 0; i < MaxHFiles; i++, info++) {
Oct 14, 2016
Oct 14, 2016
887
888
if (info->fd == -1) { // available?
info->fd = -2;
Oct 6, 2016
Oct 6, 2016
889
break;
Oct 14, 2016
Oct 14, 2016
890
} // if
Oct 6, 2016
Oct 6, 2016
891
892
} // for
Oct 14, 2016
Oct 14, 2016
893
894
895
ungrabLock(&GMutexDosCalls);
if (i == MaxHFiles) {
Oct 6, 2016
Oct 6, 2016
896
return ERROR_TOO_MANY_OPEN_FILES;
Oct 14, 2016
Oct 14, 2016
897
}
Oct 6, 2016
Oct 6, 2016
898
899
900
901
902
903
904
905
906
907
const HFILE hf = i;
APIRET err = NO_ERROR;
char *unixpath = makeUnixPath(pszFileName, &err);
if (!unixpath) {
info->fd = -1;
return err;
} // if
Oct 14, 2016
Oct 14, 2016
908
//if (strcmp(pszFileName, unixpath) != 0) { fprintf(stderr, "DosOpen: converted '%s' to '%s'\n", pszFileName, unixpath); }
Oct 6, 2016
Oct 6, 2016
909
Oct 14, 2016
Oct 14, 2016
910
int fd = open(unixpath, flags, mode);
Oct 6, 2016
Oct 6, 2016
911
912
913
914
915
916
// if failed trying exclusive-create because file already exists, but we
// didn't explicitly _need_ exclusivity, retry without O_EXCL. We always
// try O_EXCL at first when using O_CREAT, so we can tell atomically if
// we were the one that created the file, to satisfy pulAction.
int existed = 0;
Oct 14, 2016
Oct 14, 2016
917
if ((fd == -1) && (flags & (O_CREAT|O_EXCL)) && (errno == EEXIST) && !isExclusive) {
Oct 6, 2016
Oct 6, 2016
918
existed = 1;
Oct 14, 2016
Oct 14, 2016
919
920
fd = open(unixpath, flags & ~O_EXCL, mode);
} else if (fd != -1) {
Oct 6, 2016
Oct 6, 2016
921
922
923
924
existed = 1;
} // else if
free(unixpath);
Oct 14, 2016
Oct 14, 2016
925
if (fd != -1) {
Oct 6, 2016
Oct 6, 2016
926
if (mustNotExist) {
Oct 14, 2016
Oct 14, 2016
927
close(fd);
Oct 6, 2016
Oct 6, 2016
928
929
930
931
932
info->fd = -1;
return ERROR_OPEN_FAILED; // !!! FIXME: what error does OS/2 return for this?
} else if ( (!existed || isReplacing) && (cbFile > 0) ) {
if (ftruncate(info->fd, cbFile) == -1) {
const int e = errno;
Oct 14, 2016
Oct 14, 2016
933
close(fd);
Oct 6, 2016
Oct 6, 2016
934
935
936
937
938
939
info->fd = -1;
errno = e; // let the switch below sort out the OS/2 error code.
} // if
} // else if
} // if
Oct 14, 2016
Oct 14, 2016
940
if (fd != -1) {
Oct 6, 2016
Oct 6, 2016
941
942
943
944
if (isReplacing)
FIXME("Replacing a file should delete all its EAs, too");
} // if
Oct 14, 2016
Oct 14, 2016
945
946
947
info->fd = fd;
if (fd == -1) {
Oct 6, 2016
Oct 6, 2016
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
switch (errno) {
case EACCES: return ERROR_ACCESS_DENIED;
case EDQUOT: return ERROR_CANNOT_MAKE;
case EEXIST: return ERROR_CANNOT_MAKE;
case EISDIR: return ERROR_ACCESS_DENIED;
case EMFILE: return ERROR_TOO_MANY_OPEN_FILES;
case ENFILE: return ERROR_TOO_MANY_OPEN_FILES;
case ENAMETOOLONG: return ERROR_FILENAME_EXCED_RANGE;
case ENOSPC: return ERROR_DISK_FULL;
case ENOMEM: return ERROR_NOT_ENOUGH_MEMORY;
case ENOENT: return ERROR_FILE_NOT_FOUND; // !!! FIXME: could be PATH_NOT_FOUND too, depending on circumstances.
case ENOTDIR: return ERROR_PATH_NOT_FOUND;
case EPERM: return ERROR_ACCESS_DENIED;
case EROFS: return ERROR_ACCESS_DENIED;
case ETXTBSY: return ERROR_ACCESS_DENIED;
default: return ERROR_OPEN_FAILED; // !!! FIXME: debug logging about missin errno case.
} // switch
__builtin_unreachable();
} // if
Oct 27, 2016
Oct 27, 2016
968
969
info->flags = fsOpenFlags;
Oct 6, 2016
Oct 6, 2016
970
971
972
973
974
975
976
977
978
if (isReplacing)
*pulAction = FILE_TRUNCATED;
else if (existed)
*pulAction = FILE_EXISTED;
else
*pulAction = FILE_CREATED;
*pHf = hf;
return NO_ERROR;
Oct 16, 2016
Oct 16, 2016
979
980
981
982
983
984
} // doDosOpen
APIRET DosOpen(PSZ pszFileName, PHFILE pHf, PULONG pulAction, ULONG cbFile, ULONG ulAttribute, ULONG fsOpenFlags, ULONG fsOpenMode, PEAOP2 peaop2)
{
TRACE_NATIVE("DosOpen('%s', %p, %p, %u, %u, %u, %u, %p)", pszFileName, pHf, pulAction, (uint) cbFile, (uint) ulAttribute, (uint) fsOpenFlags, (uint) fsOpenMode, peaop2);
return doDosOpen(pszFileName, pHf, pulAction, (LONGLONG) cbFile, ulAttribute, fsOpenFlags, fsOpenMode, peaop2);
Oct 6, 2016
Oct 6, 2016
985
986
} // DosOpen
Oct 9, 2016
Oct 9, 2016
987
988
989
APIRET DosRequestMutexSem(HMTX hmtx, ULONG ulTimeout)
{
TRACE_NATIVE("DosRequestMutexSem(%u, %u)", (uint) hmtx, (uint) ulTimeout);
Oct 14, 2016
Oct 14, 2016
990
991
992
993
994
995
996
997
998
999
1000
if (!hmtx)
return ERROR_INVALID_HANDLE;
pthread_mutex_t *mutex = (pthread_mutex_t *) hmtx;
int rc;
if (ulTimeout == SEM_IMMEDIATE_RETURN) {
rc = pthread_mutex_trylock(mutex);
} else if (ulTimeout == SEM_INDEFINITE_WAIT) {
rc = pthread_mutex_lock(mutex);