source: trunk/dll/wrappers.c@ 1628

Last change on this file since 1628 was 1628, checked in by Gregg Young, 14 years ago

Hard coded the flags for the xDosAlloc* wrappers and added a description for each of them.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.1 KB
Line 
1
2/***********************************************************************
3
4 $Id: wrappers.c 1628 2011-08-27 19:35:39Z gyoung $
5
6 Wrappers with error checking
7
8 Copyright (c) 2006, 2008 Steven H.Levine
9
10 22 Jul 06 SHL Baseline
11 29 Jul 06 SHL Add xgets_stripped
12 18 Aug 06 SHL Correct Runtime_Error line number report
13 20 Aug 07 GKY Move #pragma alloc_text to end for OpenWatcom compat
14 01 Sep 07 GKY Add xDosSetPathInfo to fix case where FS3 buffer crosses 64k boundry
15 06 Oct 07 SHL Add xDos...() wrappers to support systems wo/large file support (Gregg, Steven)
16 05 May 08 SHL Add FORTIFY support
17 25 Dec 08 GKY Add code to allow write verify to be turned off on a per drive basis
18 17 Jun 09 SHL Correct missing rc set
19 12 Jul 09 GKY Add xDosQueryAppType and xDosAlloc... to allow FM/2 to load in high memory
20 15 Nov 09 GKY Rework xDosQueryAppType to remove HIMEM ifdefs
21 26 Aug 11 GKY Add a low mem version of xDosAlloc* wrappers; move error checking into all the
22 xDosAlloc* wrappers.
23
24***********************************************************************/
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <ctype.h>
30
31#define INCL_WIN
32#define INCL_DOS
33#define INCL_DOSERRORS
34#define INCL_LONGLONG
35#include <os2.h>
36
37#include "fm3dll.h"
38#include "init.h" // Data declaration(s)
39#include "wrappers.h"
40#include "fm3str.h"
41#include "errutil.h" // Dos_Error...
42#include "strutil.h" // GetPString
43#include "command.h"
44#include "tools.h"
45#include "avl.h"
46#include "strips.h" // bstrip
47
48#include "fortify.h" // GetPString
49#include "info.h" // driveflags
50#include "notebook.h" // fVerify
51#include "pathutil.h" // MaxComLineStrg
52
53// Data definitions
54static PSZ pszSrcFile = __FILE__;
55
56#pragma data_seg(GLOBAL1)
57BOOL fNoLargeFileSupport;
58
59APIRET xDosQueryAppType(PCSZ pszName, PULONG pFlags)
60{
61 APIRET rc;
62 CHAR szPgm[CCHMAXPATH];
63
64 strcpy(szPgm, pszName);
65 rc = DosQueryAppType(szPgm, pFlags);
66 return rc;
67}
68
69/**
70 * xDosAllocSharedMem uses OBJ_ANY on systems that support high memory use
71 * and falls back to low memory allocation where it is not supported.
72 * Flags are hard coded PAG_COMMIT | OBJ_GIVEABLE | PAG_READ | PAG_WRITE
73 * The wrapper provides error checking.
74 */
75
76APIRET xDosAllocSharedMem(PPVOID ppb,
77 PSZ pszName,
78 ULONG cb,
79 PCSZ pszSrcFile,
80 UINT uiLineNumber)
81{
82 APIRET rc; ;
83
84 rc = DosAllocSharedMem(ppb, pszName, cb,
85 PAG_COMMIT | OBJ_GIVEABLE | PAG_READ | PAG_WRITE | OBJ_ANY);
86 //DbgMsg(pszSrcFile, __LINE__, "ppb %p", *ppb);
87 if (rc)
88 rc = DosAllocSharedMem(ppb, pszName, cb, PAG_COMMIT | OBJ_GIVEABLE | PAG_READ | PAG_WRITE);
89 if (rc)
90 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
91 return rc;
92}
93
94/**
95 * xDosAllocMem uses OBJ_ANY on systems that support high memory use
96 * and falls back to low memory allocation where it is not supported.
97 * Flags are hard coded PAG_COMMIT | PAG_READ | PAG_WRITE.
98 * The wrapper provides error checking.
99 */
100
101APIRET xDosAllocMem(PPVOID ppb,
102 ULONG cb,
103 PCSZ pszSrcFile,
104 UINT uiLineNumber)
105{
106 APIRET rc;
107
108 rc = DosAllocMem(ppb, cb, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY);
109 //DbgMsg(pszSrcFile, uiLineNumber, "ppb %p %x", *ppb, rc);
110 if (rc)
111 rc = DosAllocMem(ppb, cb, PAG_COMMIT | PAG_READ | PAG_WRITE);
112 if (rc)
113 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
114 //DbgMsg(pszSrcFile, uiLineNumber, "ppb %p", *ppb);
115 return rc;
116}
117
118/**
119 * xDosAllocMemLow doesn't use OBJ_ANY. It should be used when the buffer
120 * is going to be used by 16 functions that fail to thunk high memory addresses properly
121 * such as DosQueryAppType, DosOpenL, DosGetMessage and DosReadQueue (probably others)
122 * Flags are hard coded PAG_COMMIT | PAG_READ | PAG_WRITE.
123 * The wrapper provides error checking.
124 */
125
126APIRET xDosAllocMemLow(PPVOID ppb,
127 ULONG cb,
128 PCSZ pszSrcFile,
129 UINT uiLineNumber)
130{
131 APIRET rc;
132
133 rc = DosAllocMem(ppb, cb, PAG_COMMIT | PAG_READ | PAG_WRITE);
134 if (rc)
135 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
136 //DbgMsg(pszSrcFile, uiLineNumber, "ppb %p", *ppb);
137 return rc;
138}
139
140APIRET xDosFindFirst(PSZ pszFileSpec,
141 PHDIR phdir,
142 ULONG flAttribute,
143 PVOID pfindbuf,
144 ULONG cbBuf,
145 PULONG pcFileNames,
146 ULONG ulInfoLevel)
147{
148 APIRET rc;
149 if (fNoLargeFileSupport) {
150 switch (ulInfoLevel) {
151 case FIL_STANDARDL:
152 {
153 FILEFINDBUF3 ffb3;
154 ulInfoLevel = FIL_STANDARD;
155 *pcFileNames = 1; // fixme to support larger counts
156 rc = DosFindFirst(pszFileSpec, phdir, flAttribute, &ffb3, sizeof(ffb3),
157 pcFileNames, ulInfoLevel);
158 if (!rc) {
159 *(PFILEFINDBUF3)pfindbuf = ffb3; // Copy aligned data
160 ((PFILEFINDBUF3L)pfindbuf)->cbFile = ffb3.cbFile; // Copy unaligned data
161 ((PFILEFINDBUF3L)pfindbuf)->cbFileAlloc = ffb3.cbFileAlloc;
162 ((PFILEFINDBUF3L)pfindbuf)->attrFile = ffb3.attrFile;
163 ((PFILEFINDBUF3L)pfindbuf)->cchName = ffb3.cchName;
164 memcpy(((PFILEFINDBUF3L)pfindbuf)->achName, ffb3.achName, ffb3.cchName + 1);
165 }
166 }
167 break;
168 case FIL_QUERYEASIZEL:
169 {
170 FILEFINDBUF4 ffb4;
171 *pcFileNames = 1; // fixme to support larger counts
172 ulInfoLevel = FIL_QUERYEASIZE;
173 rc = DosFindFirst(pszFileSpec, phdir, flAttribute, &ffb4, sizeof(ffb4),
174 pcFileNames, ulInfoLevel);
175 if (!rc) {
176 *(PFILEFINDBUF4)pfindbuf = ffb4; // Copy aligned data
177 ((PFILEFINDBUF4L)pfindbuf)->cbFile = ffb4.cbFile; // Copy unaligned data
178 ((PFILEFINDBUF4L)pfindbuf)->cbFileAlloc = ffb4.cbFileAlloc;
179 ((PFILEFINDBUF4L)pfindbuf)->attrFile = ffb4.attrFile;
180 ((PFILEFINDBUF4L)pfindbuf)->cbList = ffb4.cbList;
181 ((PFILEFINDBUF4L)pfindbuf)->cchName = ffb4.cchName;
182 memcpy(((PFILEFINDBUF4L)pfindbuf)->achName, ffb4.achName, ffb4.cchName + 1);
183 }
184 }
185 break;
186 default:
187 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
188 rc = ERROR_INVALID_PARAMETER;
189 } // switch
190 }
191 else
192 rc = DosFindFirst(pszFileSpec, phdir, flAttribute, pfindbuf, cbBuf,
193 pcFileNames, ulInfoLevel);
194 return rc;
195}
196
197APIRET xDosFindNext(HDIR hDir,
198 PVOID pfindbuf,
199 ULONG cbfindbuf,
200 PULONG pcFileNames,
201 ULONG ulInfoLevel)
202{
203 APIRET rc;
204 if (fNoLargeFileSupport) {
205 switch (ulInfoLevel) {
206 case FIL_STANDARDL:
207 {
208 FILEFINDBUF3 ffb3;
209 *pcFileNames = 1; // fixme to support larger counts
210 rc = DosFindNext(hDir, &ffb3, sizeof(ffb3), pcFileNames);
211 if (!rc) {
212 *(PFILEFINDBUF3)pfindbuf = ffb3; // Copy aligned data
213 ((PFILEFINDBUF3L)pfindbuf)->cbFile = ffb3.cbFile; // Copy unaligned data
214 ((PFILEFINDBUF3L)pfindbuf)->cbFileAlloc = ffb3.cbFileAlloc;
215 ((PFILEFINDBUF3L)pfindbuf)->attrFile = ffb3.attrFile;
216 ((PFILEFINDBUF3L)pfindbuf)->cchName = ffb3.cchName;
217 memcpy(((PFILEFINDBUF3L)pfindbuf)->achName, ffb3.achName, ffb3.cchName + 1);
218 }
219 }
220 break;
221 case FIL_QUERYEASIZEL:
222 {
223 FILEFINDBUF4 ffb4;
224 *pcFileNames = 1; // fixme to support larger counts
225 rc = DosFindNext(hDir, &ffb4, sizeof(ffb4), pcFileNames);
226 if (!rc) {
227 *(PFILEFINDBUF4)pfindbuf = ffb4; // Copy aligned data
228 ((PFILEFINDBUF4L)pfindbuf)->cbFile = ffb4.cbFile; // Copy unaligned data
229 ((PFILEFINDBUF4L)pfindbuf)->cbFileAlloc = ffb4.cbFileAlloc;
230 ((PFILEFINDBUF4L)pfindbuf)->attrFile = ffb4.attrFile;
231 ((PFILEFINDBUF4L)pfindbuf)->cbList = ffb4.cbList;
232 ((PFILEFINDBUF4L)pfindbuf)->cchName = ffb4.cchName;
233 memcpy(((PFILEFINDBUF4L)pfindbuf)->achName, ffb4.achName, ffb4.cchName + 1);
234 }
235 }
236 break;
237 default:
238 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
239 rc = ERROR_INVALID_PARAMETER;
240 } // switch
241 }
242 else
243 rc = DosFindNext(hDir, pfindbuf, cbfindbuf, pcFileNames);
244
245 return rc;
246}
247
248/**
249 * DosQueryPathInfo wrapper
250 * Translate request for systems without large file support
251 */
252
253APIRET xDosQueryPathInfo (PSZ pszPathName, ULONG ulInfoLevel, PVOID pInfoBuf, ULONG cbInfoBuf)
254{
255 FILESTATUS3 fs3;
256 FILESTATUS4 fs4;
257 APIRET rc;
258
259 if (fNoLargeFileSupport) {
260 switch (ulInfoLevel) {
261 case FIL_STANDARDL:
262 rc = DosQueryPathInfo(pszPathName, ulInfoLevel, &fs3, sizeof(fs3));
263 if (!rc) {
264 *(PFILESTATUS3)pInfoBuf = fs3; // Copy aligned data
265 ((PFILESTATUS3L)pInfoBuf)->cbFile = fs3.cbFile; // Copy unaligned data
266 ((PFILESTATUS3L)pInfoBuf)->cbFileAlloc = fs3.cbFileAlloc;
267 ((PFILESTATUS3L)pInfoBuf)->attrFile = fs3.attrFile;
268 }
269 break;
270 case FIL_QUERYEASIZEL:
271 rc = DosQueryPathInfo(pszPathName, ulInfoLevel, &fs4, sizeof(fs4));
272 if (!rc) {
273 *(PFILESTATUS4)pInfoBuf = fs4; // Copy aligned data
274 ((PFILESTATUS4L)pInfoBuf)->cbFile = fs4.cbFile; // Copy unaligned data
275 ((PFILESTATUS4L)pInfoBuf)->cbFileAlloc = fs4.cbFileAlloc;
276 ((PFILESTATUS4L)pInfoBuf)->attrFile = fs4.attrFile;
277 ((PFILESTATUS4L)pInfoBuf)->cbList = fs4.cbList;
278 }
279 break;
280 default:
281 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
282 rc = ERROR_INVALID_PARAMETER;
283 } // switch
284 }
285 else
286 rc = DosQueryPathInfo (pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf);
287
288 return rc;
289}
290
291/**
292 * Wrap DosSetPathInfo to avoid spurious ERROR_INVALID_NAME returns and
293 * support systems without large file support
294 *
295 * Some kernels do not correctly handle FILESTATUS3 and PEAOP2 buffers
296 * that cross a 64K boundary.
297 * When this occurs, they return ERROR_INVALID_NAME.
298 * This code works around the problem because if the passed buffer crosses
299 * the boundary the alternate buffer will not because both are on the stack
300 * and we don't put enough additional data on the stack for this to occur.
301 * It is caller's responsitibility to report errors
302 * @param pInfoBuf pointer to FILESTATUS3(L) or EAOP2 buffer
303 * @param ulInfoLevel FIL_STANDARD(L) or FIL_QUERYEASIZE
304 * @returns Same as DosSetPathInfo
305 */
306
307APIRET xDosSetPathInfo(PSZ pszPathName,
308 ULONG ulInfoLevel,
309 PVOID pInfoBuf,
310 ULONG cbInfoBuf,
311 ULONG flOptions)
312{
313 FILESTATUS3 fs3;
314 FILESTATUS3 fs3_a;
315 FILESTATUS3L fs3l;
316 EAOP2 eaop2;
317 APIRET rc;
318 BOOL crosses = ((ULONG)pInfoBuf ^
319 ((ULONG)pInfoBuf + cbInfoBuf - 1)) & ~0xffff;
320 BOOL fResetVerify = FALSE;
321
322 if (fVerify && driveflags[toupper(*pszPathName) - 'A'] & DRIVE_WRITEVERIFYOFF) {
323 DosSetVerify(FALSE);
324 fResetVerify = TRUE;
325 }
326 switch (ulInfoLevel) {
327 case FIL_STANDARD:
328 if (crosses) {
329 fs3 = *(PFILESTATUS3)pInfoBuf; // Copy to buffer that does not cross 64K boundary
330 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3, cbInfoBuf, flOptions);
331 }
332 else
333 rc = DosSetPathInfo(pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf, flOptions);
334 break;
335
336 case FIL_STANDARDL:
337 if (fNoLargeFileSupport) {
338 ulInfoLevel = FIL_STANDARD;
339 fs3 = *(PFILESTATUS3)pInfoBuf; // Copy aligned data
340 // Check size too big to handle
341 if (((PFILESTATUS3L)pInfoBuf)->cbFile >= 1LL << 32 ||
342 ((PFILESTATUS3L)pInfoBuf)->cbFileAlloc >= 2LL << 32)
343 {
344 rc = ERROR_INVALID_PARAMETER;
345 }
346 else {
347 fs3.cbFile = ((PFILESTATUS3L)pInfoBuf)->cbFile; // Copy unaligned data
348 fs3.cbFileAlloc = ((PFILESTATUS3L)pInfoBuf)->cbFileAlloc;
349 fs3.attrFile = ((PFILESTATUS3L)pInfoBuf)->attrFile;
350 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3, sizeof(fs3), flOptions);
351 }
352 if (rc == ERROR_INVALID_NAME) {
353 // fixme to validate counts?
354 fs3_a = fs3; // Copy to buffer that does not cross
355 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3_a, sizeof(fs3_a), flOptions);
356 }
357 }
358 else {
359 rc = DosSetPathInfo(pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf, flOptions);
360 if (rc == ERROR_INVALID_NAME) {
361 fs3l = *(PFILESTATUS3L)pInfoBuf; // Copy to buffer that does not cross
362 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3l, sizeof(fs3l), flOptions);
363 }
364 }
365 break;
366 case FIL_QUERYEASIZE:
367 rc = DosSetPathInfo(pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf, flOptions);
368 if (rc == ERROR_INVALID_NAME) {
369 // fixme to validate counts?
370 eaop2 = *(PEAOP2)pInfoBuf; // Copy to buffer that does not cross
371 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &eaop2, sizeof(eaop2), flOptions);
372 }
373 break;
374 default:
375 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
376 rc = ERROR_INVALID_PARAMETER;
377 } // switch
378 if (fResetVerify) {
379 DosSetVerify(fVerify);
380 fResetVerify = FALSE;
381 }
382 return rc;
383}
384
385PSZ xfgets(PSZ pszBuf, size_t cMaxBytes, FILE * fp, PCSZ pszSrcFile,
386 UINT uiLineNumber)
387{
388 PSZ psz = fgets(pszBuf, cMaxBytes, fp);
389
390 if (!psz) {
391 if (ferror(fp))
392 Runtime_Error(pszSrcFile, uiLineNumber, "fgets");
393 }
394 else {
395 size_t c = strlen(psz);
396
397 if (c + 1 > cMaxBytes)
398 Runtime_Error(pszSrcFile, uiLineNumber, "buffer overflow");
399 else if (!c || (psz[c - 1] != '\n' && psz[c - 1] != '\r'))
400 Runtime_Error(pszSrcFile, uiLineNumber, "missing EOL");
401 }
402 return psz;
403}
404
405PSZ xfgets_bstripcr(PSZ pszBuf, size_t cMaxBytes, FILE * fp, PCSZ pszSrcFile,
406 UINT uiLineNumber)
407{
408 PSZ psz = xfgets(pszBuf, cMaxBytes, fp, pszSrcFile, uiLineNumber);
409
410 if (psz)
411 bstripcr(psz);
412 return psz;
413}
414
415/**
416 * Wrapper for fopen it works around DosOpenL's failure to
417 * thunk properly so that fm2 can be loaded in high memory
418 * It also gives the option of reporting file open errors
419 * If fSilent is TRUE it fails silently; if FALSE it produces a
420 * runtime error dialog. Note pszMode must be passed on the stack
421 * to xfopen to avoid the thunking problem.
422 */
423
424FILE *xfopen(PCSZ pszFileName, PCSZ pszMode, PCSZ pszSrcFile,
425 UINT uiLineNumber, BOOL fSilent)
426{
427 CHAR FileName[CCHMAXPATH];
428 FILE *fp;
429
430 strcpy(FileName, pszFileName);
431 fp = fopen(FileName, pszMode);
432
433 if (!fp && !fSilent)
434 Runtime_Error(pszSrcFile, uiLineNumber, "fopen");
435 return fp;
436}
437
438/**
439 * Wrapper for _fsopen it works around DosOpenL's failure to
440 * thunk properly so that fm2 can be loaded in high memory
441 * It also gives the option of reporting file open errors
442 * If fSilent is TRUE it fails silently; if FALSE it produces a
443 * runtime error dialog. Note pszMode must be passed on the stack
444 * to xfopen to avoid the thunking problem
445 */
446
447FILE *xfsopen(PCSZ pszFileName, PCSZ pszMode, INT fSharemode, PCSZ pszSrcFile,
448 UINT uiLineNumber, BOOL fSilent)
449{
450 CHAR FileName[CCHMAXPATH];
451 FILE *fp;
452
453 strcpy(FileName, pszFileName);
454 fp = _fsopen(FileName, pszMode, fSharemode);
455
456 if (!fp && !fSilent)
457 Runtime_Error(pszSrcFile, uiLineNumber, "_fsopen");
458 return fp;
459}
460
461//== xfree - safe free ==
462
463VOID xfree(PVOID pv, PCSZ pszSrcFile, UINT uiLineNumber)
464{
465 if (pv && pv != NullStr) {
466# ifdef FORTIFY
467 Fortify_free(pv, pszSrcFile, uiLineNumber);
468# else
469 free(pv);
470# endif
471
472 }
473}
474
475//== xmalloc() malloc with error checking ==
476
477PVOID xmalloc(size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
478{
479# ifdef FORTIFY
480 PVOID pv = Fortify_malloc(cBytes, pszSrcFile, uiLineNumber);
481# else
482 PVOID pv = malloc(cBytes);
483# endif
484
485 if (!pv)
486 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
487
488 return pv;
489}
490
491//== xmallocz() malloc and zero with error checking ==
492
493PVOID xmallocz(size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
494{
495 PVOID pv = xmalloc(cBytes, pszSrcFile, uiLineNumber);
496
497 if (pv)
498 memset(pv, 0, cBytes);
499
500 return pv;
501}
502
503//== xrealloc() realloc with error checking ==
504
505PVOID xrealloc(PVOID pvIn, size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
506{
507 if (pvIn != NullStr) {
508# ifdef FORTIFY
509 PVOID pv = Fortify_realloc(pvIn, cBytes, pszSrcFile, uiLineNumber);
510# else
511 PVOID pv = realloc(pvIn, cBytes);
512# endif
513
514 if (!pv && cBytes)
515 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
516
517 return pv;
518 }
519 else
520 return xmalloc(cBytes, pszSrcFile, uiLineNumber);
521}
522
523//== xstrdup() strdup with error checking ==
524
525PVOID xstrdup(PCSZ pszIn, PCSZ pszSrcFile, UINT uiLineNumber)
526{
527# ifdef FORTIFY
528 PSZ psz = Fortify_strdup(pszIn, pszSrcFile, uiLineNumber);
529# else
530 PSZ psz = strdup(pszIn);
531# endif
532
533 if (!psz)
534 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
535
536 return psz;
537}
538
539
540#pragma alloc_text(WRAPPERS1,xfree,xfopen,xfsopen,xmalloc,xrealloc,xstrdup)
541#pragma alloc_text(WRAPPERS2,xDosSetPathInfo,xDosFindFirst,xDosFindNext)
Note: See TracBrowser for help on using the repository browser.