The MinGW.org Windows System Libraries
リビジョン | 2c98d6af72c886e5821b3717bfa25efea5147e39 (tree) |
---|---|
日時 | 2018-12-05 04:00:29 |
作者 | Keith Marshall <keith@user...> |
コミッター | Keith Marshall |
Reimplement Win9x specific fseek()/fwrite() redirector.
@@ -1,5 +1,28 @@ | ||
1 | 1 | 2018-12-04 Keith Marshall <keith@users.osdn.me> |
2 | 2 | |
3 | + Reimplement Win9x specific fseek()/fwrite() redirector. | |
4 | + | |
5 | + * include/stdio.h [__USE_MINGW_FSEEK]: Deprecate support for direct | |
6 | + user definition; deduce it, as an internal private definition, from... | |
7 | + [_WIN32_WINDOWS]: ...this, when appropriately defined for Win9x. | |
8 | + [__USE_MINGW_FSEEK] (__mingw_fseek): Declare new prototype; map it as | |
9 | + multiple __CRT_ALIAS inline function overrides for each of... | |
10 | + (fseek, _fseeki64, fseeko64): ...these. | |
11 | + [__USE_MINGW_FSEEK] (__mingw_fwrite): Likewise, overriding... | |
12 | + (fwrite): ...this. | |
13 | + (__mingw_fseeko64): Delete all references; it is no longer provided, | |
14 | + nor required. | |
15 | + | |
16 | + * mingwex/stdio/fwrite.c: New file; it reimplements the Win9x | |
17 | + fseek()/fwrite() function redirector interface, and thus replaces... | |
18 | + * mingex/ming-fseek.c: ...this; delete it. | |
19 | + | |
20 | + * Makefile.in (libmingwex.a): Remove dependency on... | |
21 | + (mingw-fseek.$OBJEXT): ...this object module; replace it with... | |
22 | + (fwrite.$OBJEXT): ...this alternative dependency. | |
23 | + | |
24 | +2018-12-04 Keith Marshall <keith@users.osdn.me> | |
25 | + | |
3 | 26 | Implement POSIX.1-1996 linked-list queue management API. |
4 | 27 | |
5 | 28 | * mingwex/insque.c mingwex/remque.c: New files; they implement the |
@@ -446,7 +446,7 @@ $(addsuffix fmt.$(OBJEXT),varo crto geto seto crtn getn setn): %.$(OBJEXT): ofmt | ||
446 | 446 | |
447 | 447 | # Some additional miscellaneous functions, in libmingwex.a |
448 | 448 | # |
449 | -libmingwex.a: $(addsuffix .$(OBJEXT), mingw-aligned-malloc mingw-fseek) | |
449 | +libmingwex.a: $(addsuffix .$(OBJEXT), mingw-aligned-malloc fwrite) | |
450 | 450 | libmingwex.a: $(addsuffix .$(OBJEXT), glob getopt basename dirname nsleep) |
451 | 451 | libmingwex.a: $(addsuffix .$(OBJEXT), clockapi clockres clockset clocktime) |
452 | 452 | libmingwex.a: $(addsuffix .$(OBJEXT), insque remque tdelete tfind tsearch twalk) |
@@ -742,14 +742,37 @@ _CRTIMP __cdecl __MINGW_NOTHROW void rewind (FILE *); | ||
742 | 742 | |
743 | 743 | #ifdef __USE_MINGW_FSEEK |
744 | 744 | /* Workaround for a limitation on Win9x where a file is not zero padded |
745 | - * on write, following a seek beyond the original end of file; these are | |
746 | - * implemented in libmingwex.a | |
745 | + * on write, following a seek beyond the original end of file; supporting | |
746 | + * redirector functions are implemented in libmingwex.a | |
747 | + * | |
748 | + * Note: this is improper usage. __USE_MINGW_FSEEK exhibits the form of a | |
749 | + * private (system reserved) feature test macro; as such, users should not | |
750 | + * define it directly, and thus, it really should not have been defined at | |
751 | + * this point; discourage this practice. | |
747 | 752 | */ |
748 | -__cdecl __MINGW_NOTHROW int __mingw_fseek (FILE *, long, int); | |
749 | -__cdecl __MINGW_NOTHROW size_t __mingw_fwrite (const void *, size_t, size_t, FILE *); | |
753 | +#warning "The __USE_MINGW_FSEEK feature test is deprecated" | |
754 | +#pragma info "Define _WIN32_WINDOWS, instead of __USE_MINGW_FSEEK" | |
755 | + | |
756 | +#elif _WIN32_WINDOWS >= _WIN32_WINDOWS_95 && _WIN32_WINDOWS < _WIN32_WINNT_WIN2K | |
757 | +/* This is correct usage; the private __USE_MINGW_FSEEK feature affects only | |
758 | + * Win9x, so enable it implicitly when the _WIN32_WINDOWS feature is specified, | |
759 | + * thus indicating the user's intent to target a Win9x platform. | |
760 | + */ | |
761 | +#define __USE_MINGW_FSEEK | |
762 | +#endif | |
750 | 763 | |
751 | -#define fwrite(buffer, size, count, fp) __mingw_fwrite(buffer, size, count, fp) | |
752 | -#define fseek(fp, offset, whence) __mingw_fseek(fp, offset, whence) | |
764 | +#ifdef __USE_MINGW_FSEEK | |
765 | +/* Regardless of how it may have become defined, when __USE_MINGW_FSEEK has | |
766 | + * been defined, we must redirect calls to fseek() and fwrite(), so that the | |
767 | + * Win9x zero padding limitation can be mitigated. | |
768 | + */ | |
769 | +__cdecl __MINGW_NOTHROW int __mingw_fseek (FILE *, __off64_t, int); | |
770 | +__CRT_ALIAS int fseek( FILE *__fp, long __offset, int __whence ) | |
771 | +{ return __mingw_fseek( __fp, (__off64_t)(__offset), __whence ); } | |
772 | + | |
773 | +__cdecl __MINGW_NOTHROW size_t __mingw_fwrite (const void *, size_t, size_t, FILE *); | |
774 | +__CRT_ALIAS size_t fwrite( const void *__buf, size_t __len, size_t __cnt, FILE *__fp ) | |
775 | +{ return __mingw_fwrite( __buf, __len, __cnt, __fp ); } | |
753 | 776 | #endif /* __USE_MINGW_FSEEK */ |
754 | 777 | |
755 | 778 | /* An opaque data type used for storing file positions... The contents |
@@ -965,12 +988,11 @@ int __cdecl __MINGW_NOTHROW fseeko64 (FILE *, __off64_t, int); | ||
965 | 988 | * argument, (and both types are effectively 64-bit signed ints anyway), |
966 | 989 | * the same wrapper will suffice for both. |
967 | 990 | */ |
968 | -int __cdecl __MINGW_NOTHROW __mingw_fseeko64 (FILE *, __off64_t, int); | |
969 | -__CRT_ALIAS int __cdecl __MINGW_NOTHROW fseeko64 (FILE *__f, __off64_t __o, int __w) | |
970 | -{ return __mingw_fseeko64 (__f, __o, __w); } | |
991 | +__CRT_ALIAS int _fseeki64( FILE *__fp, __int64 __offset, int __whence ) | |
992 | +{ return __mingw_fseek( __fp, (__off64_t)(__offset), __whence ); } | |
971 | 993 | |
972 | -__CRT_ALIAS int __cdecl __MINGW_NOTHROW _fseeki64 (FILE *__f, __off64_t __o, int __w) | |
973 | -{ return __mingw_fseeko64 (__f, (__off64_t)(__o), __w); } | |
994 | +__CRT_ALIAS int fseeko64( FILE *__fp, __off64_t __offset, int __whence ) | |
995 | +{ return __mingw_fseek( __fp, __offset, __whence ); } | |
974 | 996 | #endif |
975 | 997 | |
976 | 998 | __off64_t __cdecl __MINGW_NOTHROW ftello64 (FILE *); |
@@ -1,138 +0,0 @@ | ||
1 | -/* | |
2 | - * mingw-fseek.c | |
3 | - * | |
4 | - * Workaround for limitations on Win9x where extended file content | |
5 | - * is not zeroed out if you seek past the end and then write. | |
6 | - * | |
7 | - * $Id$ | |
8 | - * | |
9 | - * Written by Mumit Khan <khan@xraylith.wisc.edu> | |
10 | - * Copyright (C) 1999, 2002-2005, 2011, 2015, MinGW.org Project. | |
11 | - * | |
12 | - * Abstracted from MinGW local patch to binutils/bfd/libbfd.c | |
13 | - * | |
14 | - * | |
15 | - * Permission is hereby granted, free of charge, to any person obtaining a | |
16 | - * copy of this software and associated documentation files (the "Software"), | |
17 | - * to deal in the Software without restriction, including without limitation | |
18 | - * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
19 | - * and/or sell copies of the Software, and to permit persons to whom the | |
20 | - * Software is furnished to do so, subject to the following conditions: | |
21 | - * | |
22 | - * The above copyright notice, this permission notice, and the following | |
23 | - * disclaimer shall be included in all copies or substantial portions of | |
24 | - * the Software. | |
25 | - * | |
26 | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
27 | - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
28 | - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
29 | - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
30 | - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
31 | - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER | |
32 | - * DEALINGS IN THE SOFTWARE. | |
33 | - * | |
34 | - */ | |
35 | -#define WIN32_LEAN_AND_MEAN | |
36 | - | |
37 | -#include <windows.h> | |
38 | -#include <stdio.h> | |
39 | -#include <io.h> | |
40 | -#include <stdlib.h> | |
41 | - | |
42 | -#define ZEROBLOCKSIZE 512 | |
43 | -static int __mingw_fseek_called; | |
44 | - | |
45 | -/* The fseek in Win9x runtime does not zero out the file if seeking past | |
46 | - * the end; if you don't want random stuff from your disk included in your | |
47 | - * output DLL/executable, use this version instead. On WinNT/Win2k, it | |
48 | - * just calls runtime fseek(). | |
49 | - * | |
50 | - * CHECK/FIXME: Does this work for both text and binary modes?? | |
51 | - */ | |
52 | -int | |
53 | -__mingw_fseek (FILE *fp, long offset, int whence) | |
54 | -{ | |
55 | -# undef fseek | |
56 | - __mingw_fseek_called = 1; | |
57 | - return fseek (fp, offset, whence); | |
58 | -} | |
59 | - | |
60 | -int | |
61 | -__mingw_fseeko64 (FILE *fp, __off64_t offset, int whence) | |
62 | -{ | |
63 | -# undef fseeko64 | |
64 | - __mingw_fseek_called = 1; | |
65 | - return fseeko64 (fp, offset, whence); | |
66 | -} | |
67 | - | |
68 | -size_t | |
69 | -__mingw_fwrite (const void *buffer, size_t size, size_t count, FILE *fp) | |
70 | -{ | |
71 | -# undef fwrite | |
72 | - if ((_osver & 0x8000) && __mingw_fseek_called) | |
73 | - { | |
74 | - ULARGE_INTEGER actual_length; | |
75 | - LARGE_INTEGER current_position = {{0LL}}; | |
76 | - __mingw_fseek_called = 0; | |
77 | - fflush (fp); | |
78 | - actual_length.u.LowPart = GetFileSize | |
79 | - ( (HANDLE) _get_osfhandle (fileno (fp)), &actual_length.u.HighPart | |
80 | - ); | |
81 | - if (actual_length.u.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR ) | |
82 | - return -1; | |
83 | - current_position.u.LowPart = SetFilePointer | |
84 | - ( (HANDLE) _get_osfhandle (fileno (fp)), current_position.u.LowPart, | |
85 | - ¤t_position.u.HighPart, FILE_CURRENT | |
86 | - ); | |
87 | - if (current_position.u.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR ) | |
88 | - return -1; | |
89 | - | |
90 | -# ifdef DEBUG | |
91 | - printf( "__mingw_fwrite: current %I64u, actual %I64u\n", | |
92 | - current_position.QuadPart, actual_length.QuadPart | |
93 | - ); | |
94 | -# endif /* DEBUG */ | |
95 | - if( current_position.QuadPart > actual_length.QuadPart ) | |
96 | - { | |
97 | - static char __mingw_zeros[ZEROBLOCKSIZE]; | |
98 | - long long numleft; | |
99 | - | |
100 | - SetFilePointer( (HANDLE) _get_osfhandle (fileno (fp)), 0, 0, FILE_END ); | |
101 | - numleft = current_position.QuadPart - actual_length.QuadPart; | |
102 | - | |
103 | -# ifdef DEBUG | |
104 | - printf( "__mingw_fwrite: Seeking %I64d bytes past end\n", numleft ); | |
105 | -# endif /* DEBUG */ | |
106 | - while( numleft > 0LL ) | |
107 | - { | |
108 | - DWORD nzeros = (numleft > ZEROBLOCKSIZE) | |
109 | - ? ZEROBLOCKSIZE | |
110 | - : numleft; | |
111 | - DWORD written; | |
112 | - if( ! WriteFile ((HANDLE) _get_osfhandle (fileno (fp)), | |
113 | - __mingw_zeros, nzeros, &written, NULL) | |
114 | - ) | |
115 | - { /* Best we can hope for, or at least DJ says so. | |
116 | - */ | |
117 | - SetFilePointer( (HANDLE) _get_osfhandle (fileno (fp)), | |
118 | - 0, 0, FILE_BEGIN | |
119 | - ); | |
120 | - return -1; | |
121 | - } | |
122 | - if( written < nzeros ) | |
123 | - { | |
124 | - /* Likewise. */ | |
125 | - SetFilePointer( (HANDLE) _get_osfhandle (fileno (fp)), | |
126 | - 0, 0, FILE_BEGIN | |
127 | - ); | |
128 | - return -1; | |
129 | - } | |
130 | - numleft -= written; | |
131 | - } | |
132 | - FlushFileBuffers ((HANDLE) _get_osfhandle (fileno (fp))); | |
133 | - } | |
134 | - } | |
135 | - return (fwrite)(buffer, size, count, fp); | |
136 | -} | |
137 | - | |
138 | -/* $RCSfile$: end of file */ |
@@ -0,0 +1,275 @@ | ||
1 | +/* | |
2 | + * fwrite.c | |
3 | + * | |
4 | + * Workaround for limitations on Win9x where extended file content | |
5 | + * is not zeroed out if you seek past the end and then write. | |
6 | + * | |
7 | + * | |
8 | + * $Id$ | |
9 | + * | |
10 | + * Written by Keith Marshall <keith@users.osdn.me> | |
11 | + * Copyright (C) 2018, MinGW.org Project. | |
12 | + * | |
13 | + * | |
14 | + * Replaces mingw-fseek.c implementation | |
15 | + * Written by Mumit Khan <khan@xraylith.wisc.edu> | |
16 | + * Copyright (C) 1999, 2002-2005, 2011, 2015, MinGW.org Project. | |
17 | + * | |
18 | + * Originally abstracted from MinGW local patch to binutils/bfd/libbfd.c | |
19 | + * | |
20 | + * | |
21 | + * Permission is hereby granted, free of charge, to any person obtaining a | |
22 | + * copy of this software and associated documentation files (the "Software"), | |
23 | + * to deal in the Software without restriction, including without limitation | |
24 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
25 | + * and/or sell copies of the Software, and to permit persons to whom the | |
26 | + * Software is furnished to do so, subject to the following conditions: | |
27 | + * | |
28 | + * The above copyright notice, this permission notice, and the following | |
29 | + * disclaimer shall be included in all copies or substantial portions of | |
30 | + * the Software. | |
31 | + * | |
32 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
33 | + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
34 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
35 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
36 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
37 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER | |
38 | + * DEALINGS IN THE SOFTWARE. | |
39 | + * | |
40 | + * | |
41 | + * Although specifically providing support for Win9x, we must compile this | |
42 | + * with the associated feature test disabled, so that the wrappers provided | |
43 | + * herein can access the underlying functions which they wrap. | |
44 | + * | |
45 | + */ | |
46 | +#undef _WIN32_WINDOWS | |
47 | +#undef __USE_MINGW_FSEEK | |
48 | + | |
49 | +#include <io.h> | |
50 | +#include <search.h> | |
51 | +#include <stdlib.h> | |
52 | +#include <stdio.h> | |
53 | + | |
54 | +/* The fseek() handler control structures. | |
55 | + */ | |
56 | +static void fseek_handler_init( FILE * ); | |
57 | +struct fseek_pending { struct fseek_pending *fwd, *bkwd; FILE *fp; }; | |
58 | +static struct { struct fseek_pending *avail, *active; void (*action)(FILE *); } | |
59 | +fseek_handler = { NULL, NULL, fseek_handler_init }; | |
60 | + | |
61 | +/* The fseek() handler function redirector implementation. | |
62 | + */ | |
63 | +static __attribute__((__noinline__)) | |
64 | +void *fseek_handler_trap_pending( FILE *fp ) | |
65 | +{ /* Local helper, to check for any pending fseek trap associated | |
66 | + * with "fp"; used from multiple locations, so we prefer to deny | |
67 | + * GCC any choice to in-line it. | |
68 | + * | |
69 | + * Note that, if "fseek_handler.active" is NULL, there are no | |
70 | + * pending stream traps, so there is nothing to check... | |
71 | + */ | |
72 | + if( fseek_handler.active != NULL ) | |
73 | + { /* ...but when there is at least one active trap... | |
74 | + */ | |
75 | + struct fseek_pending *trap = fseek_handler.active; | |
76 | + do { /* ...we walk the queue of active traps, until we find | |
77 | + * (and immediately return) one associated with "fp", or | |
78 | + * we have examined all entries in the circular queue. | |
79 | + */ | |
80 | + if( trap->fp == fp ) return trap; | |
81 | + } while( (trap = trap->fwd) != fseek_handler.active ); | |
82 | + } | |
83 | + /* If we get to here, there is no trap associated with "fp". | |
84 | + */ | |
85 | + return NULL; | |
86 | +} | |
87 | + | |
88 | +/* On WinNT, the fseek() handler is required to take no action; by | |
89 | + * installing the following "no-op" handler, on first-time call, we | |
90 | + * reduce the fseek() and fwrite() wrappers to operate as simple | |
91 | + * pass-through filters... | |
92 | + */ | |
93 | +static void fseek_handler_nop( FILE *fp __attribute__((__unused__)) ){} | |
94 | + | |
95 | +/* ...whereas, on Win9x, we install this active fseek() handler. | |
96 | + */ | |
97 | +static void fseek_handler_set_trap( FILE *fp ) | |
98 | +{ /* This records fseek() requests, on a per-stream basis, such that | |
99 | + * any subsequent fwrite() request can apply corrective action, to | |
100 | + * ensure that any "holes" in the file stream are properly filled | |
101 | + * with zeros, in the event that the fseek() has moved the file | |
102 | + * pointer beyond EOF; however, we never assign more than one | |
103 | + * active trap per stream. | |
104 | + */ | |
105 | + if( fseek_handler_trap_pending( fp ) == NULL ) | |
106 | + { /* There is no active trap currently associated with "fp"; take | |
107 | + * an unused trap record from the "avail" queue... | |
108 | + */ | |
109 | + struct fseek_pending *avail; | |
110 | + if( (avail = fseek_handler.avail) == NULL ) | |
111 | + { /* ...creating a new block of eight such records, if none are | |
112 | + * currently available... | |
113 | + */ | |
114 | + int avail_index = 8; | |
115 | + avail = malloc( 8 * sizeof (struct fseek_pending) ); | |
116 | + | |
117 | + /* ...and linking them into a linear queue. | |
118 | + */ | |
119 | + avail->fwd = avail->bkwd = NULL; | |
120 | + while( --avail_index > 0 ) insque( avail + avail_index, avail ); | |
121 | + } | |
122 | + /* The taken record is popped from the front of the queue; thus | |
123 | + * we must follow its forward link, to update the front-of-queue | |
124 | + * pointer to the next available unused trap record. | |
125 | + */ | |
126 | + remque( avail ); fseek_handler.avail = avail->fwd; | |
127 | + | |
128 | + /* Now, we must insert the "avail" record we've just acquired | |
129 | + * into the "active" queue; this is managed as a circular queue, | |
130 | + * so, if it is currently empty... | |
131 | + */ | |
132 | + if( fseek_handler.active == NULL ) | |
133 | + /* ...then we must assign this new record as its sole entry, | |
134 | + * with both links referring to itself... | |
135 | + */ | |
136 | + fseek_handler.active = avail->fwd = avail->bkwd = avail; | |
137 | + | |
138 | + /* ...otherwise, the POSIX.1 insque() API will take care of it. | |
139 | + */ | |
140 | + else insque( avail, fseek_handler.active ); | |
141 | + | |
142 | + /* Finally, we must associate this new trap record with "fp". | |
143 | + */ | |
144 | + avail->fp = fp; | |
145 | + } | |
146 | +} | |
147 | + | |
148 | +static void fseek_handler_init( FILE *fp ) | |
149 | +{ /* fseek() handler initialization routine; invoked only the first time | |
150 | + * that the fseek() handler itself is invoked, it checks whether we are | |
151 | + * running on Win9x, and if not... | |
152 | + */ | |
153 | + if( (_osver & 0x8000) == 0 ) | |
154 | + /* ...it installs a no-op handler for future calls, (since WinNT | |
155 | + * doesn't require any further handling... | |
156 | + */ | |
157 | + fseek_handler.action = fseek_handler_nop; | |
158 | + | |
159 | + else | |
160 | + { /* ...otherwise, it installs the Win9x specific handler, which | |
161 | + * traps seek requests to enable corrective action, which may be | |
162 | + * required in a subsequent fwrite() call... | |
163 | + */ | |
164 | + fseek_handler.action = fseek_handler_set_trap; | |
165 | + | |
166 | + /* ...and immediately sets a trap for this first-time call. | |
167 | + */ | |
168 | + fseek_handler_set_trap( fp ); | |
169 | + } | |
170 | +} | |
171 | + | |
172 | +/* Public API entry to the Win9x function redirector for the system | |
173 | + * fseek() APIs; implemented in terms of fseeko64(), it is suitable as | |
174 | + * a transparent wrapper for any of the fseek()-alike functions. | |
175 | + */ | |
176 | +int __mingw_fseek( FILE *fp, __off64_t offset, int whence ) | |
177 | +{ fseek_handler.action( fp ); return fseeko64( fp, offset, whence ); } | |
178 | + | |
179 | +static __off64_t fseek_handler_reset( struct fseek_pending *trap ) | |
180 | +{ /* Bridging function, called exclusively by __mingw_fwrite(), to disarm | |
181 | + * any fseek trap which it has identified as being active and associated | |
182 | + * with its target stream; since it is called only from one location, we | |
183 | + * may safely allow GCC to in-line it. | |
184 | + */ | |
185 | + if( trap == fseek_handler.active ) | |
186 | + { /* The active trap is currently the lead entry, in the active trap | |
187 | + * queue, then we must move the lead entry onward; if it continues | |
188 | + * to refer to the same trap, then we must clear the queue... | |
189 | + */ | |
190 | + if( fseek_handler.active->fwd == trap ) fseek_handler.active = NULL; | |
191 | + | |
192 | + /* ...otherwise, we simply remove the trap entry from the queue... | |
193 | + */ | |
194 | + else remque( trap ); | |
195 | + } | |
196 | + /* ...and likewise, if the trap entry is not the queue's lead entry. | |
197 | + */ | |
198 | + else remque( trap ); | |
199 | + | |
200 | + /* Having removed the trap from the "active" queue, we must return it | |
201 | + * to the "avail" queue... | |
202 | + */ | |
203 | + insque( trap, fseek_handler.avail ); | |
204 | + | |
205 | + /* ...and, if that queue was previously empty, update its lead entry | |
206 | + * reference pointer to match. | |
207 | + */ | |
208 | + if( fseek_handler.avail == NULL ) fseek_handler.avail = trap; | |
209 | + | |
210 | + /* Finally, tell fwrite() where it must begin data transfer, after it | |
211 | + * has completed any Win9x corrective action which may be required. | |
212 | + */ | |
213 | + return __mingw_ftelli64( trap->fp ); | |
214 | +} | |
215 | + | |
216 | +size_t __mingw_fwrite( const void *buffer, size_t size, size_t count, FILE *fp ) | |
217 | +{ /* A wrapper around the system fwrite() API; it ensures that padding | |
218 | + * zero bytes are inserted, following EOF, when fwrite() is called on | |
219 | + * Win9x, after any seek request which moves the file pointer to any | |
220 | + * position which lies beyond the existing EOF. | |
221 | + */ | |
222 | + struct fseek_pending *trap; | |
223 | + if( (trap = fseek_handler_trap_pending( fp )) != NULL ) | |
224 | + { /* The fseek handler has determined that we are running on Win9x, | |
225 | + * and that this fwrite operation was preceded by a seek; we don't | |
226 | + * yet know if that seek has moved the position beyond the current | |
227 | + * end of file, in which case Win9x may leave random garbage after | |
228 | + * EOF, in the intervening space, (where ISO-C requires the effect | |
229 | + * of zero bytes); check for this anomaly now. | |
230 | + */ | |
231 | + __off64_t eof_pos, fwrite_pos = fseek_handler_reset( trap ); | |
232 | + if( fwrite_pos > (eof_pos = _lseeki64( fileno( fp ), 0LL, SEEK_END )) ) | |
233 | + { /* The original seek request HAD moved the fwrite position to | |
234 | + * some point beyond EOF! We've now moved it back to EOF, so | |
235 | + * prepare to fill with zeros, to pad out the file until we | |
236 | + * return to the original seek position. | |
237 | + */ | |
238 | + char zero_bytes[BUFSIZ] = {'\0'}; | |
239 | + __int64 fill_len = fwrite_pos - eof_pos; | |
240 | + | |
241 | + /* Emit the requisite number of padding zeros, in blocks of | |
242 | + * no more than BUFSIZ bytes... | |
243 | + */ | |
244 | + while( fill_len > 0LL ) | |
245 | + { size_t len = (fill_len > BUFSIZ) ? BUFSIZ : fill_len; | |
246 | + if( fwrite( zero_bytes, 1, len, fp ) != len ) | |
247 | + { /* ...but, if any block falls short of its expected size, | |
248 | + * then an error has occurred; attempt to restore to the | |
249 | + * original seek position, and abort the fwrite request, | |
250 | + * having written NONE of its requested data. | |
251 | + */ | |
252 | + __mingw_fseeki64( fp, fwrite_pos, SEEK_SET ); | |
253 | + return 0; | |
254 | + } | |
255 | + /* A padding block has been successfully written; adjust | |
256 | + * the residual padding length, to account for it. | |
257 | + */ | |
258 | + fill_len -= len; | |
259 | + } | |
260 | + } | |
261 | + else | |
262 | + /* The preceding seek was not beyond end of file, so there is no | |
263 | + * danger of leaving random garbage, but our check has moved the | |
264 | + * fwrite position to end of file; move it back to the position | |
265 | + * set by the original seek request. | |
266 | + */ | |
267 | + __mingw_fseeki64( fp, fwrite_pos, SEEK_SET ); | |
268 | + } | |
269 | + /* Ultimately, complete the original fwrite request, at the expected | |
270 | + * position within the output file. | |
271 | + */ | |
272 | + return fwrite( buffer, size, count, fp ); | |
273 | +} | |
274 | + | |
275 | +/* $RCSfile$: end of file */ |