source: trunk/dll/wrappers.c@ 1639

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

Fix list file creation failure when file doesn't exist. Ticket 477

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