source: trunk/dll/wrappers.c@ 1627

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

Add a low mem version of xDosAlloc* wrappers; move error checking into all the xDosAlloc* wrappers. Ticket 471

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