source: trunk/dll/wrappers.c@ 1570

Last change on this file since 1570 was 1544, checked in by Gregg Young, 15 years ago

Changes to fopen and _fsopen to allow FM2 to be loaded in high memory

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