source: trunk/dll/wrappers.c@ 968

Last change on this file since 968 was 968, checked in by John Small, 18 years ago

Improved version of fix for ticket 228.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.3 KB
Line 
1
2/***********************************************************************
3
4 $Id: wrappers.c 968 2008-02-21 03:22:55Z jbs $
5
6 Wrappers with error checking
7
8 Copyright (c) 2006 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
17***********************************************************************/
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#define INCL_WIN
24#define INCL_DOS
25#define INCL_DOSERRORS
26#define INCL_LONGLONG
27#include <os2.h>
28
29#include "fm3dll.h"
30#include "fm3str.h"
31#include "errutil.h" // Dos_Error...
32#include "strutil.h" // GetPString
33
34static PSZ pszSrcFile = __FILE__;
35
36APIRET xDosFindFirst(PSZ pszFileSpec,
37 PHDIR phdir,
38 ULONG flAttribute,
39 PVOID pfindbuf,
40 ULONG cbBuf,
41 PULONG pcFileNames,
42 ULONG ulInfoLevel)
43{
44 APIRET rc;
45 if (fNoLargeFileSupport) {
46 switch (ulInfoLevel) {
47 case FIL_STANDARDL:
48 {
49 FILEFINDBUF3 ffb3;
50 ulInfoLevel = FIL_STANDARD;
51 *pcFileNames = 1; // fixme to support larger counts
52 rc = DosFindFirst(pszFileSpec, phdir, flAttribute, &ffb3, sizeof(ffb3),
53 pcFileNames, ulInfoLevel);
54 if (!rc) {
55 *(PFILEFINDBUF3)pfindbuf = ffb3; // Copy aligned data
56 ((PFILEFINDBUF3L)pfindbuf)->cbFile = ffb3.cbFile; // Copy unaligned data
57 ((PFILEFINDBUF3L)pfindbuf)->cbFileAlloc = ffb3.cbFileAlloc;
58 ((PFILEFINDBUF3L)pfindbuf)->attrFile = ffb3.attrFile;
59 ((PFILEFINDBUF3L)pfindbuf)->cchName = ffb3.cchName;
60 memcpy(((PFILEFINDBUF3L)pfindbuf)->achName, ffb3.achName, ffb3.cchName + 1);
61 }
62 }
63 break;
64 case FIL_QUERYEASIZEL:
65 {
66 FILEFINDBUF4 ffb4;
67 *pcFileNames = 1; // fixme to support larger counts
68 ulInfoLevel = FIL_QUERYEASIZE;
69 rc = DosFindFirst(pszFileSpec, phdir, flAttribute, &ffb4, sizeof(ffb4),
70 pcFileNames, ulInfoLevel);
71 if (!rc) {
72 *(PFILEFINDBUF4)pfindbuf = ffb4; // Copy aligned data
73 ((PFILEFINDBUF4L)pfindbuf)->cbFile = ffb4.cbFile; // Copy unaligned data
74 ((PFILEFINDBUF4L)pfindbuf)->cbFileAlloc = ffb4.cbFileAlloc;
75 ((PFILEFINDBUF4L)pfindbuf)->attrFile = ffb4.attrFile;
76 ((PFILEFINDBUF4L)pfindbuf)->cbList = ffb4.cbList;
77 ((PFILEFINDBUF4L)pfindbuf)->cchName = ffb4.cchName;
78 memcpy(((PFILEFINDBUF4L)pfindbuf)->achName, ffb4.achName, ffb4.cchName + 1);
79 }
80 }
81 break;
82 default:
83 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
84 rc = ERROR_INVALID_PARAMETER;
85 } // switch
86 }
87 else
88 rc = DosFindFirst(pszFileSpec, phdir, flAttribute, pfindbuf, cbBuf,
89 pcFileNames, ulInfoLevel);
90 return rc;
91}
92
93APIRET xDosFindNext(HDIR hDir,
94 PVOID pfindbuf,
95 ULONG cbfindbuf,
96 PULONG pcFileNames,
97 ULONG ulInfoLevel)
98{
99 APIRET rc;
100 if (fNoLargeFileSupport) {
101 switch (ulInfoLevel) {
102 case FIL_STANDARDL:
103 {
104 FILEFINDBUF3 ffb3;
105 *pcFileNames = 1; // fixme to support larger counts
106 rc = DosFindNext(hDir, &ffb3, sizeof(ffb3), pcFileNames);
107 if (!rc) {
108 *(PFILEFINDBUF3)pfindbuf = ffb3; // Copy aligned data
109 ((PFILEFINDBUF3L)pfindbuf)->cbFile = ffb3.cbFile; // Copy unaligned data
110 ((PFILEFINDBUF3L)pfindbuf)->cbFileAlloc = ffb3.cbFileAlloc;
111 ((PFILEFINDBUF3L)pfindbuf)->attrFile = ffb3.attrFile;
112 ((PFILEFINDBUF3L)pfindbuf)->cchName = ffb3.cchName;
113 memcpy(((PFILEFINDBUF3L)pfindbuf)->achName, ffb3.achName, ffb3.cchName + 1);
114 }
115 }
116 break;
117 case FIL_QUERYEASIZEL:
118 {
119 FILEFINDBUF4 ffb4;
120 *pcFileNames = 1; // fixme to support larger counts
121 rc = DosFindNext(hDir, &ffb4, sizeof(ffb4), pcFileNames);
122 if (!rc) {
123 *(PFILEFINDBUF4)pfindbuf = ffb4; // Copy aligned data
124 ((PFILEFINDBUF4L)pfindbuf)->cbFile = ffb4.cbFile; // Copy unaligned data
125 ((PFILEFINDBUF4L)pfindbuf)->cbFileAlloc = ffb4.cbFileAlloc;
126 ((PFILEFINDBUF4L)pfindbuf)->attrFile = ffb4.attrFile;
127 ((PFILEFINDBUF4L)pfindbuf)->cbList = ffb4.cbList;
128 ((PFILEFINDBUF4L)pfindbuf)->cchName = ffb4.cchName;
129 memcpy(((PFILEFINDBUF4L)pfindbuf)->achName, ffb4.achName, ffb4.cchName + 1);
130 }
131 }
132 break;
133 default:
134 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
135 rc = ERROR_INVALID_PARAMETER;
136 } // switch
137 }
138 else
139 rc = DosFindNext(hDir, pfindbuf, cbfindbuf, pcFileNames);
140
141 return rc;
142}
143
144/**
145 * DosQueryPathInfo wrapper
146 * Translate request for systems without large file support
147 */
148
149APIRET xDosQueryPathInfo (PSZ pszPathName, ULONG ulInfoLevel, PVOID pInfoBuf, ULONG cbInfoBuf)
150{
151 FILESTATUS3 fs3;
152 FILESTATUS4 fs4;
153 APIRET rc;
154
155 if (fNoLargeFileSupport) {
156 switch (ulInfoLevel) {
157 case FIL_STANDARDL:
158 rc = DosQueryPathInfo(pszPathName, ulInfoLevel, &fs3, sizeof(fs3));
159 if (!rc) {
160 *(PFILESTATUS3)pInfoBuf = fs3; // Copy aligned data
161 ((PFILESTATUS3L)pInfoBuf)->cbFile = fs3.cbFile; // Copy unaligned data
162 ((PFILESTATUS3L)pInfoBuf)->cbFileAlloc = fs3.cbFileAlloc;
163 ((PFILESTATUS3L)pInfoBuf)->attrFile = fs3.attrFile;
164 }
165 break;
166 case FIL_QUERYEASIZEL:
167 rc = DosQueryPathInfo(pszPathName, ulInfoLevel, &fs4, sizeof(fs4));
168 if (!rc) {
169 *(PFILESTATUS4)pInfoBuf = fs4; // Copy aligned data
170 ((PFILESTATUS4L)pInfoBuf)->cbFile = fs4.cbFile; // Copy unaligned data
171 ((PFILESTATUS4L)pInfoBuf)->cbFileAlloc = fs4.cbFileAlloc;
172 ((PFILESTATUS4L)pInfoBuf)->attrFile = fs4.attrFile;
173 ((PFILESTATUS4L)pInfoBuf)->cbList = fs4.cbList;
174 }
175 break;
176 default:
177 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
178 rc = ERROR_INVALID_PARAMETER;
179 } // switch
180 }
181 else
182 DosQueryPathInfo (pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf);
183
184 return rc;
185}
186
187/**
188 * Wrap DosSetPathInfo to avoid spurious ERROR_INVALID_NAME returns and
189 * support systems without large file support
190 *
191 * Some kernels to do not correctly handle FILESTATUS3 and PEAOP2 buffers
192 * that cross a 64K boundary.
193 * When this occurs, they return ERROR_INVALID_NAME.
194 * This code works around the problem because if the passed buffer crosses
195 * the boundary the alternate buffer will not because both are on the stack
196 * and we don't put enough additional data on the stack for this to occur.
197 * It is caller's responsitibility to report errors
198 * @param pInfoBuf pointer to FILESTATUS3(L) or EAOP2 buffer
199 * @param ulInfoLevel FIL_STANDARD(L) or FIL_QUERYEASIZE
200 * @returns Same as DosSetPathInfo
201 */
202
203APIRET xDosSetPathInfo(PSZ pszPathName,
204 ULONG ulInfoLevel,
205 PVOID pInfoBuf,
206 ULONG cbInfoBuf,
207 ULONG flOptions)
208{
209 FILESTATUS3 fs3;
210 FILESTATUS3 fs3_a;
211 FILESTATUS3L fs3l;
212 EAOP2 eaop2;
213 APIRET rc;
214 BOOL crosses = ((ULONG)pInfoBuf ^
215 ((ULONG)pInfoBuf + cbInfoBuf - 1)) &
216 ~0xffff;
217
218 switch (ulInfoLevel) {
219 case FIL_STANDARD:
220 if (crosses)
221 {
222 fs3 = *(PFILESTATUS3)pInfoBuf; // Copy to buffer that does not cross 64K boundary
223 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3, cbInfoBuf, flOptions);
224 }
225 else
226 {
227 rc = DosSetPathInfo(pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf, flOptions);
228 }
229 break;
230
231 case FIL_STANDARDL:
232 if (fNoLargeFileSupport) {
233 ulInfoLevel = FIL_STANDARD;
234 fs3 = *(PFILESTATUS3)pInfoBuf; // Copy aligned data
235 // Check size too big to handle
236 if (((PFILESTATUS3L)pInfoBuf)->cbFile >= 1LL << 32 ||
237 ((PFILESTATUS3L)pInfoBuf)->cbFileAlloc >= 2LL << 32)
238 {
239 rc = ERROR_INVALID_PARAMETER;
240 }
241 else {
242 fs3.cbFile = ((PFILESTATUS3L)pInfoBuf)->cbFile; // Copy unaligned data
243 fs3.cbFileAlloc = ((PFILESTATUS3L)pInfoBuf)->cbFileAlloc;
244 fs3.attrFile = ((PFILESTATUS3L)pInfoBuf)->attrFile;
245 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3, sizeof(fs3), flOptions);
246 }
247 if (rc == ERROR_INVALID_NAME) {
248 // fixme to validate counts?
249 fs3_a = fs3; // Copy to buffer that does not cross
250 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3_a, sizeof(fs3_a), flOptions);
251 }
252 }
253 else {
254 rc = DosSetPathInfo(pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf, flOptions);
255 if (rc == ERROR_INVALID_NAME) {
256 fs3l = *(PFILESTATUS3L)pInfoBuf; // Copy to buffer that does not cross
257 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3l, sizeof(fs3l), flOptions);
258 }
259 }
260 break;
261 case FIL_QUERYEASIZE:
262 rc = DosSetPathInfo(pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf, flOptions);
263 if (rc == ERROR_INVALID_NAME) {
264 // fixme to validate counts?
265 eaop2 = *(PEAOP2)pInfoBuf; // Copy to buffer that does not cross
266 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &eaop2, sizeof(eaop2), flOptions);
267 }
268 break;
269 default:
270 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
271 rc = ERROR_INVALID_PARAMETER;
272 } // switch
273
274 return rc;
275}
276
277PSZ xfgets(PSZ pszBuf, size_t cMaxBytes, FILE * fp, PCSZ pszSrcFile,
278 UINT uiLineNumber)
279{
280 PSZ psz = fgets(pszBuf, cMaxBytes, fp);
281
282 if (!psz) {
283 if (ferror(fp))
284 Runtime_Error(pszSrcFile, uiLineNumber, "fgets");
285 }
286 else {
287 size_t c = strlen(psz);
288
289 if (c + 1 > cMaxBytes)
290 Runtime_Error(pszSrcFile, uiLineNumber, "buffer overflow");
291 else if (!c || (psz[c - 1] != '\n' && psz[c - 1] != '\r'))
292 Runtime_Error(pszSrcFile, uiLineNumber, "missing EOL");
293 }
294 return psz;
295}
296
297PSZ xfgets_bstripcr(PSZ pszBuf, size_t cMaxBytes, FILE * fp, PCSZ pszSrcFile,
298 UINT uiLineNumber)
299{
300 PSZ psz = xfgets(pszBuf, cMaxBytes, fp, pszSrcFile, uiLineNumber);
301
302 if (psz)
303 bstripcr(psz);
304 return psz;
305}
306
307FILE *xfopen(PCSZ pszFileName, PCSZ pszMode, PCSZ pszSrcFile,
308 UINT uiLineNumber)
309{
310 FILE *fp = fopen(pszFileName, pszMode);
311
312 if (!fp)
313 Runtime_Error(pszSrcFile, uiLineNumber, "fopen");
314 return fp;
315}
316
317FILE *xfsopen(PCSZ pszFileName, PCSZ pszMode, INT fSharemode, PCSZ pszSrcFile,
318 UINT uiLineNumber)
319{
320 FILE *fp = _fsopen((PSZ) pszFileName, (PSZ) pszMode, fSharemode);
321
322 if (!fp)
323 Runtime_Error(pszSrcFile, uiLineNumber, "_fsopen");
324 return fp;
325}
326
327//== xfree - safe free ==
328
329VOID xfree(PVOID pv)
330{
331 if (pv && pv != NullStr)
332 free(pv);
333}
334
335//== xmalloc() malloc with error checking ==
336
337PVOID xmalloc(size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
338{
339 PVOID pv = malloc(cBytes);
340
341 if (!pv)
342 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
343
344 return pv;
345}
346
347//== xmallocz() malloc and zero with error checking ==
348
349PVOID xmallocz(size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
350{
351 PVOID pv = malloc(cBytes);
352
353 if (!pv)
354 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
355 else
356 memset(pv, 0, cBytes);
357
358 return pv;
359}
360
361//== xrealloc() realloc with error checking ==
362
363PVOID xrealloc(PVOID pvIn, size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
364{
365 if (pvIn != NullStr) {
366 PVOID pv = realloc(pvIn, cBytes);
367
368 if (!pv && cBytes)
369 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
370
371 return pv;
372 }
373 else
374 return xmalloc(cBytes, pszSrcFile, uiLineNumber);
375}
376
377//== xstrdup() strdup with error checking ==
378
379PVOID xstrdup(PCSZ pszIn, PCSZ pszSrcFile, UINT uiLineNumber)
380{
381 PSZ psz = strdup(pszIn);
382
383 if (!psz)
384 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
385
386 return psz;
387}
388
389#pragma alloc_text(WRAPPERS1,xfree,xfopen,xfsopen,xmalloc,xrealloc, xstrdup)
390#pragma alloc_text(WRAPPERS2,xDosSetPathInfo,xDosFindFirst,xDosFindNext)
Note: See TracBrowser for help on using the repository browser.