source: trunk/dll/wrappers.c@ 967

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

Changed xDosSetPathInfo so that it always copies the buffer to a local
(stack) so that it would never cross a 64K boundary. This seems to fix
the problem described in ticket 228.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.0 KB
Line 
1
2/***********************************************************************
3
4 $Id: wrappers.c 967 2008-02-20 22:55:17Z 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
215 switch (ulInfoLevel) {
216 case FIL_STANDARD:
217 fs3 = *(PFILESTATUS3)pInfoBuf; // Copy to buffer that does not cross 64K boundary
218 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3, cbInfoBuf, flOptions);
219 break;
220
221 case FIL_STANDARDL:
222 if (fNoLargeFileSupport) {
223 ulInfoLevel = FIL_STANDARD;
224 fs3 = *(PFILESTATUS3)pInfoBuf; // Copy aligned data
225 // Check size too big to handle
226 if (((PFILESTATUS3L)pInfoBuf)->cbFile >= 1LL << 32 ||
227 ((PFILESTATUS3L)pInfoBuf)->cbFileAlloc >= 2LL << 32)
228 {
229 rc = ERROR_INVALID_PARAMETER;
230 }
231 else {
232 fs3.cbFile = ((PFILESTATUS3L)pInfoBuf)->cbFile; // Copy unaligned data
233 fs3.cbFileAlloc = ((PFILESTATUS3L)pInfoBuf)->cbFileAlloc;
234 fs3.attrFile = ((PFILESTATUS3L)pInfoBuf)->attrFile;
235 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3, sizeof(fs3), flOptions);
236 }
237 if (rc == ERROR_INVALID_NAME) {
238 // fixme to validate counts?
239 fs3_a = fs3; // Copy to buffer that does not cross
240 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3_a, sizeof(fs3_a), flOptions);
241 }
242 }
243 else {
244 rc = DosSetPathInfo(pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf, flOptions);
245 if (rc == ERROR_INVALID_NAME) {
246 fs3l = *(PFILESTATUS3L)pInfoBuf; // Copy to buffer that does not cross
247 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &fs3l, sizeof(fs3l), flOptions);
248 }
249 }
250 break;
251 case FIL_QUERYEASIZE:
252 rc = DosSetPathInfo(pszPathName, ulInfoLevel, pInfoBuf, cbInfoBuf, flOptions);
253 if (rc == ERROR_INVALID_NAME) {
254 // fixme to validate counts?
255 eaop2 = *(PEAOP2)pInfoBuf; // Copy to buffer that does not cross
256 rc = DosSetPathInfo(pszPathName, ulInfoLevel, &eaop2, sizeof(eaop2), flOptions);
257 }
258 break;
259 default:
260 Runtime_Error(pszSrcFile, __LINE__, "ulInfoLevel %u unexpected", ulInfoLevel);
261 rc = ERROR_INVALID_PARAMETER;
262 } // switch
263
264 return rc;
265}
266
267PSZ xfgets(PSZ pszBuf, size_t cMaxBytes, FILE * fp, PCSZ pszSrcFile,
268 UINT uiLineNumber)
269{
270 PSZ psz = fgets(pszBuf, cMaxBytes, fp);
271
272 if (!psz) {
273 if (ferror(fp))
274 Runtime_Error(pszSrcFile, uiLineNumber, "fgets");
275 }
276 else {
277 size_t c = strlen(psz);
278
279 if (c + 1 > cMaxBytes)
280 Runtime_Error(pszSrcFile, uiLineNumber, "buffer overflow");
281 else if (!c || (psz[c - 1] != '\n' && psz[c - 1] != '\r'))
282 Runtime_Error(pszSrcFile, uiLineNumber, "missing EOL");
283 }
284 return psz;
285}
286
287PSZ xfgets_bstripcr(PSZ pszBuf, size_t cMaxBytes, FILE * fp, PCSZ pszSrcFile,
288 UINT uiLineNumber)
289{
290 PSZ psz = xfgets(pszBuf, cMaxBytes, fp, pszSrcFile, uiLineNumber);
291
292 if (psz)
293 bstripcr(psz);
294 return psz;
295}
296
297FILE *xfopen(PCSZ pszFileName, PCSZ pszMode, PCSZ pszSrcFile,
298 UINT uiLineNumber)
299{
300 FILE *fp = fopen(pszFileName, pszMode);
301
302 if (!fp)
303 Runtime_Error(pszSrcFile, uiLineNumber, "fopen");
304 return fp;
305}
306
307FILE *xfsopen(PCSZ pszFileName, PCSZ pszMode, INT fSharemode, PCSZ pszSrcFile,
308 UINT uiLineNumber)
309{
310 FILE *fp = _fsopen((PSZ) pszFileName, (PSZ) pszMode, fSharemode);
311
312 if (!fp)
313 Runtime_Error(pszSrcFile, uiLineNumber, "_fsopen");
314 return fp;
315}
316
317//== xfree - safe free ==
318
319VOID xfree(PVOID pv)
320{
321 if (pv && pv != NullStr)
322 free(pv);
323}
324
325//== xmalloc() malloc with error checking ==
326
327PVOID xmalloc(size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
328{
329 PVOID pv = malloc(cBytes);
330
331 if (!pv)
332 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
333
334 return pv;
335}
336
337//== xmallocz() malloc and zero with error checking ==
338
339PVOID xmallocz(size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
340{
341 PVOID pv = malloc(cBytes);
342
343 if (!pv)
344 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
345 else
346 memset(pv, 0, cBytes);
347
348 return pv;
349}
350
351//== xrealloc() realloc with error checking ==
352
353PVOID xrealloc(PVOID pvIn, size_t cBytes, PCSZ pszSrcFile, UINT uiLineNumber)
354{
355 if (pvIn != NullStr) {
356 PVOID pv = realloc(pvIn, cBytes);
357
358 if (!pv && cBytes)
359 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
360
361 return pv;
362 }
363 else
364 return xmalloc(cBytes, pszSrcFile, uiLineNumber);
365}
366
367//== xstrdup() strdup with error checking ==
368
369PVOID xstrdup(PCSZ pszIn, PCSZ pszSrcFile, UINT uiLineNumber)
370{
371 PSZ psz = strdup(pszIn);
372
373 if (!psz)
374 Runtime_Error(pszSrcFile, uiLineNumber, GetPString(IDS_OUTOFMEMORY));
375
376 return psz;
377}
378
379#pragma alloc_text(WRAPPERS1,xfree,xfopen,xfsopen,xmalloc,xrealloc, xstrdup)
380#pragma alloc_text(WRAPPERS2,xDosSetPathInfo,xDosFindFirst,xDosFindNext)
Note: See TracBrowser for help on using the repository browser.