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
Line 
1
2/***********************************************************************
3
4 $Id: wrappers.c 1627 2011-08-26 21:48:06Z 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
69APIRET xDosAllocSharedMem(PPVOID ppb,
70 PSZ pszName,
71 ULONG cb,
72 ULONG flag,
73 PCSZ pszSrcFile,
74 UINT uiLineNumber)
75{
76 APIRET rc; ;
77
78 rc = DosAllocSharedMem(ppb, pszName, cb, flag | OBJ_ANY);
79 //DbgMsg(pszSrcFile, __LINE__, "ppb %p", *ppb);
80 if (rc)
81 rc = DosAllocSharedMem(ppb, pszName, cb, flag);
82 if (rc)
83 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
84 return rc;
85}
86
87APIRET xDosAllocMem(PPVOID ppb,
88 ULONG cb,
89 ULONG flag,
90 PCSZ pszSrcFile,
91 UINT uiLineNumber)
92{
93 APIRET rc;
94
95 rc = DosAllocMem(ppb, cb, flag | OBJ_ANY);
96 //DbgMsg(pszSrcFile, uiLineNumber, "ppb %p %x", *ppb, rc);
97 if (rc)
98 rc = DosAllocMem(ppb, cb, flag);
99 if (rc)
100 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
101 //DbgMsg(pszSrcFile, uiLineNumber, "ppb %p", *ppb);
102 return rc;
103}
104
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
120APIRET xDosFindFirst(PSZ pszFileSpec,
121 PHDIR phdir,
122 ULONG flAttribute,
123 PVOID pfindbuf,
124 ULONG cbBuf,
125 PULONG pcFileNames,
126 ULONG ulInfoLevel)
127{
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 }
147 break;
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 }
165 break;
166 default:
167 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
168 rc = ERROR_INVALID_PARAMETER;
169 } // switch
170 }
171 else
172 rc = DosFindFirst(pszFileSpec, phdir, flAttribute, pfindbuf, cbBuf,
173 pcFileNames, ulInfoLevel);
174 return rc;
175}
176
177APIRET xDosFindNext(HDIR hDir,
178 PVOID pfindbuf,
179 ULONG cbfindbuf,
180 PULONG pcFileNames,
181 ULONG ulInfoLevel)
182{
183 APIRET rc;
184 if (fNoLargeFileSupport) {
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
221 }
222 else
223 rc = DosFindNext(hDir, pfindbuf, cbfindbuf, pcFileNames);
224
225 return rc;
226}
227
228/**
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
266 rc = DosQueryPathInfo (pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf);
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 *
275 * Some kernels do not correctly handle FILESTATUS3 and PEAOP2 buffers
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
282 * @param pInfoBuf pointer to FILESTATUS3(L) or EAOP2 buffer
283 * @param ulInfoLevel FIL_STANDARD(L) or FIL_QUERYEASIZE
284 * @returns Same as DosSetPathInfo
285 */
286
287APIRET xDosSetPathInfo(PSZ pszPathName,
288 ULONG ulInfoLevel,
289 PVOID pInfoBuf,
290 ULONG cbInfoBuf,
291 ULONG flOptions)
292{
293 FILESTATUS3 fs3;
294 FILESTATUS3 fs3_a;
295 FILESTATUS3L fs3l;
296 EAOP2 eaop2;
297 APIRET rc;
298 BOOL crosses = ((ULONG)pInfoBuf ^
299 ((ULONG)pInfoBuf + cbInfoBuf - 1)) & ~0xffff;
300 BOOL fResetVerify = FALSE;
301
302 if (fVerify && driveflags[toupper(*pszPathName) - 'A'] & DRIVE_WRITEVERIFYOFF) {
303 DosSetVerify(FALSE);
304 fResetVerify = TRUE;
305 }
306 switch (ulInfoLevel) {
307 case FIL_STANDARD:
308 if (crosses) {
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);
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);
352 }
353 break;
354 default:
355 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
356 rc = ERROR_INVALID_PARAMETER;
357 } // switch
358 if (fResetVerify) {
359 DosSetVerify(fVerify);
360 fResetVerify = FALSE;
361 }
362 return rc;
363}
364
365PSZ xfgets(PSZ pszBuf, size_t cMaxBytes, FILE * fp, PCSZ pszSrcFile,
366 UINT uiLineNumber)
367{
368 PSZ psz = fgets(pszBuf, cMaxBytes, fp);
369
370 if (!psz) {
371 if (ferror(fp))
372 Runtime_Error(pszSrcFile, uiLineNumber, "fgets");
373 }
374 else {
375 size_t c = strlen(psz);
376
377 if (c + 1 > cMaxBytes)
378 Runtime_Error(pszSrcFile, uiLineNumber, "buffer overflow");
379 else if (!c || (psz[c - 1] != '\n' && psz[c - 1] != '\r'))
380 Runtime_Error(pszSrcFile, uiLineNumber, "missing EOL");
381 }
382 return psz;
383}
384
385PSZ xfgets_bstripcr(PSZ pszBuf, size_t cMaxBytes, FILE * fp, PCSZ pszSrcFile,
386 UINT uiLineNumber)
387{
388 PSZ psz = xfgets(pszBuf, cMaxBytes, fp, pszSrcFile, uiLineNumber);
389
390 if (psz)
391 bstripcr(psz);
392 return psz;
393}
394
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
404FILE *xfopen(PCSZ pszFileName, PCSZ pszMode, PCSZ pszSrcFile,
405 UINT uiLineNumber, BOOL fSilent)
406{
407 CHAR FileName[CCHMAXPATH];
408 FILE *fp;
409
410 strcpy(FileName, pszFileName);
411 fp = fopen(FileName, pszMode);
412
413 if (!fp && !fSilent)
414 Runtime_Error(pszSrcFile, uiLineNumber, "fopen");
415 return fp;
416}
417
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
427FILE *xfsopen(PCSZ pszFileName, PCSZ pszMode, INT fSharemode, PCSZ pszSrcFile,
428 UINT uiLineNumber, BOOL fSilent)
429{
430 CHAR FileName[CCHMAXPATH];
431 FILE *fp;
432
433 strcpy(FileName, pszFileName);
434 fp = _fsopen(FileName, pszMode, fSharemode);
435
436 if (!fp && !fSilent)
437 Runtime_Error(pszSrcFile, uiLineNumber, "_fsopen");
438 return fp;
439}
440
441//== xfree - safe free ==
442
443VOID xfree(PVOID pv, PCSZ pszSrcFile, UINT uiLineNumber)
444{
445 if (pv && pv != NullStr) {
446# ifdef FORTIFY
447 Fortify_free(pv, pszSrcFile, uiLineNumber);
448# else
449 free(pv);
450# endif
451
452 }
453}
454
455//== xmalloc() malloc with error checking ==
456
457PVOID xmalloc(size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
458{
459# ifdef FORTIFY
460 PVOID pv = Fortify_malloc(cBytes, pszSrcFile, uiLineNumber);
461# else
462 PVOID pv = malloc(cBytes);
463# endif
464
465 if (!pv)
466 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
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{
475 PVOID pv = xmalloc(cBytes, pszSrcFile, uiLineNumber);
476
477 if (pv)
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{
487 if (pvIn != NullStr) {
488# ifdef FORTIFY
489 PVOID pv = Fortify_realloc(pvIn, cBytes, pszSrcFile, uiLineNumber);
490# else
491 PVOID pv = realloc(pvIn, cBytes);
492# endif
493
494 if (!pv && cBytes)
495 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
496
497 return pv;
498 }
499 else
500 return xmalloc(cBytes, pszSrcFile, uiLineNumber);
501}
502
503//== xstrdup() strdup with error checking ==
504
505PVOID xstrdup(PCSZ pszIn, PCSZ pszSrcFile, UINT uiLineNumber)
506{
507# ifdef FORTIFY
508 PSZ psz = Fortify_strdup(pszIn, pszSrcFile, uiLineNumber);
509# else
510 PSZ psz = strdup(pszIn);
511# endif
512
513 if (!psz)
514 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
515
516 return psz;
517}
518
519
520#pragma alloc_text(WRAPPERS1,xfree,xfopen,xfsopen,xmalloc,xrealloc,xstrdup)
521#pragma alloc_text(WRAPPERS2,xDosSetPathInfo,xDosFindFirst,xDosFindNext)
Note: See TracBrowser for help on using the repository browser.