Test programs to compare behaviour of MSVCRT.DLL time dependent functions.
Revision | 373ddfbf05122b381083f8e2ca6e139e2ce14f1f (tree) |
---|---|
Zeit | 2016-01-07 04:55:12 |
Autor | Keith Marshall <keithmarshall@user...> |
Commiter | Keith Marshall |
Add "chkfind", "chkstat", and autoconfiscated build system.
@@ -0,0 +1,113 @@ | ||
1 | +# @configure_input@ | |
2 | +# $Id$ | |
3 | +# | |
4 | +# Makefile template for MSVCRT.DLL time_t behavioural test suite. | |
5 | + | |
6 | +PACKAGE = @PACKAGE_TARNAME@ | |
7 | +VERSION = @PACKAGE_VERSION@ | |
8 | + | |
9 | +# Written by Keith Marshall <keithmarshall@users.sourceforge.net> | |
10 | +# Copyright (C) 2016, MinGW.org Project | |
11 | +# | |
12 | +# | |
13 | +# Permission is hereby granted, free of charge, to any person obtaining a | |
14 | +# copy of this software and associated documentation files (the "Software"), | |
15 | +# to deal in the Software without restriction, including without limitation | |
16 | +# the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
17 | +# and/or sell copies of the Software, and to permit persons to whom the | |
18 | +# Software is furnished to do so, subject to the following conditions: | |
19 | +# | |
20 | +# The above copyright notice and this permission notice (including the next | |
21 | +# paragraph) shall be included in all copies or substantial portions of the | |
22 | +# Software. | |
23 | +# | |
24 | +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
25 | +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
26 | +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
27 | +# AUTHORS OR THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
28 | +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
29 | +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
30 | +# DEALINGS IN THE SOFTWARE. | |
31 | + | |
32 | + | |
33 | +# The default target is "all"; declare it early, to avoid any possible | |
34 | +# inadvertent override from any included file. | |
35 | +# | |
36 | +all: | |
37 | + | |
38 | +# The gamut of program files to be built by default. | |
39 | +# | |
40 | +EXEFILES = chktime$(EXEEXT) chkfind$(EXEEXT) chkstat$(EXEEXT) | |
41 | + | |
42 | +# Build time path, for location of source files. | |
43 | +# | |
44 | +vpath % @srcdir@ | |
45 | + | |
46 | +# Command and option specifications for running the C compiler. | |
47 | +# | |
48 | +CC := @CC@ | |
49 | +CFLAGS := @CFLAGS@ | |
50 | +CPPFLAGS := @CPPFLAGS@ | |
51 | +LDFLAGS := @LDFLAGS@ | |
52 | +OBJEXT := @OBJEXT@ | |
53 | +EXEEXT := @EXEEXT@ | |
54 | + | |
55 | +# Actual payload specification for the default build target, | |
56 | +# and how to build the deliverable components. | |
57 | +# | |
58 | +all: $(EXEFILES) | |
59 | +%$(EXEEXT): %.c | |
60 | + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS) | |
61 | + | |
62 | +# Additional object file prerequisites for the deliverables. | |
63 | +# | |
64 | +ADDITIONAL_OBJECTS := tmpfile.$(OBJEXT) hexdump.$(OBJEXT) | |
65 | +chkfind$(EXEEXT) chkstat$(EXEEXT): $(ADDITIONAL_OBJECTS) | |
66 | + | |
67 | + | |
68 | +# Distribution. | |
69 | +# | |
70 | +DISTNAME := $(PACKAGE:mingw32-%=%)-$(VERSION)-mingw32 | |
71 | + | |
72 | +dist: srcdist bindist | |
73 | +srcdist: $(DISTNAME)-src.tar.xz | |
74 | +bindist: $(DISTNAME)-bin.tar.xz | |
75 | + | |
76 | +MKDIR_P := @MKDIR_P@ | |
77 | +LN_S := @LN_S@ | |
78 | + | |
79 | +$(DISTNAME)-%.tar.xz: | |
80 | + mkdir -p $(PACKAGE)-$(VERSION) | |
81 | + $(RM) -r $(PACKAGE)-$(VERSION)/* | |
82 | + cd $(PACKAGE)-$(VERSION); $(LN_S) $(^:%=../%) . | |
83 | + tar chf - $(PACKAGE)-$(VERSION) | xz -c > $@ | |
84 | + $(RM) -r $(PACKAGE)-$(VERSION) | |
85 | + | |
86 | +# Specification of the payload for a source distribution. | |
87 | +# | |
88 | +$(DISTNAME)-src.tar.xz: $(EXEFILES:$(EXEEXT)=.c) | |
89 | +$(DISTNAME)-src.tar.xz: $(ADDITIONAL_OBJECTS:.$(OBJEXT)=.c) | |
90 | +$(DISTNAME)-src.tar.xz: configure.ac Makefile.in | |
91 | +$(DISTNAME)-src.tar.xz: configure install-sh | |
92 | + | |
93 | +# Specification of the payload for a binary distribution. | |
94 | +# | |
95 | +$(DISTNAME)-bin.tar.xz: $(EXEFILES) | |
96 | + | |
97 | + | |
98 | +# Clean-up rules. | |
99 | +# | |
100 | +clean mostlyclean: | |
101 | + $(RM) *.$(OBJEXT) $(EXEFILES) | |
102 | + | |
103 | +distclean realclean: clean | |
104 | + $(RM) -r Makefile autom4te.cache config.* | |
105 | + | |
106 | +maintainer-clean: maintainer-clean-notification distclean | |
107 | + $(RM) configure | |
108 | + | |
109 | +maintainer-clean-notification: | |
110 | + @echo "WARNING: this command is intended for use by project maintainers;" | |
111 | + @echo "it deletes files which may require special tools to rebuild." | |
112 | +# | |
113 | +# $RCSfile$: end of file |
@@ -1,17 +1,50 @@ | ||
1 | 1 | /* |
2 | - * chktim.c | |
2 | + * chkfind.c | |
3 | 3 | * |
4 | 4 | * Program to test the hypothesis that MSVCRT.DLL retains the 32-bit |
5 | - * format for _finddata_t, irrespective of MSDN documentation which | |
6 | - * suggests that it might have become an alias for _finddata64_t. | |
5 | + * time_t format, (equivalent to __time32_t), for its representation | |
6 | + * of file system time stamps within any instance of the _finddata_t | |
7 | + * structure, irrespective of MSDN documentation which suggests that | |
8 | + * _finddata_t may now be equivalent to _finddata64_t, in which the | |
9 | + * time stamps are represented as 64-bit __time64_t. | |
7 | 10 | * |
11 | + * $Id$ | |
8 | 12 | * |
9 | - * All MinGW headers assume that _mingw.h is included; we want to avoid | |
13 | + * Written by Keith Marshall <keithmarshall@users.sourceforge.net> | |
14 | + * Copyright (C) 2014-2016, MinGW.org Project | |
15 | + * | |
16 | + * | |
17 | + * Permission is hereby granted, free of charge, to any person obtaining a | |
18 | + * copy of this software and associated documentation files (the "Software"), | |
19 | + * to deal in the Software without restriction, including without limitation | |
20 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
21 | + * and/or sell copies of the Software, and to permit persons to whom the | |
22 | + * Software is furnished to do so, subject to the following conditions: | |
23 | + * | |
24 | + * The above copyright notice, this permission notice, and the following | |
25 | + * disclaimer shall be included in all copies or substantial portions of | |
26 | + * the Software. | |
27 | + * | |
28 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
29 | + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
30 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
31 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
32 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
33 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER | |
34 | + * DEALINGS IN THE SOFTWARE. | |
35 | + * | |
36 | + * | |
37 | + * All MinGW headers assume that <_mingw.h> is included; we want to avoid | |
10 | 38 | * possible conflicts with typedefs from standard headers, where we want |
11 | - * a customized variant; thus we include _mingw.h directly, and copy any | |
12 | - * fragments from other headers, as appropriate. | |
39 | + * a customized variant; thus, we avoid including as many of the standard | |
40 | + * system headers as practicible. However, we do need <dlfcn.h>, to get | |
41 | + * the inline implementation for dlsym(); we know that it doesn't create | |
42 | + * any unwanted conflicts, so we go ahead and include it, allowing it to | |
43 | + * include <_mingw.h> for us, while we copy any required fragments from | |
44 | + * other system headers, as appropriate. | |
45 | + * | |
13 | 46 | */ |
14 | -#include <_mingw.h> | |
47 | +#include <dlfcn.h> | |
15 | 48 | |
16 | 49 | /* The two possible internal representations of time_t, effectively as |
17 | 50 | * defined by time.h; we want only these from time.h, while excluding any |
@@ -28,146 +61,186 @@ typedef __int64 __time64_t; | ||
28 | 61 | */ |
29 | 62 | #define FILENAME_MAX (260) |
30 | 63 | |
31 | -struct _finddata32_t | |
32 | -{ | |
33 | - /* This is the MSVCR80.DLL and later representation, equivalent to | |
34 | - * the all 32-bit member _finddata_t of earlier runtime versions... | |
35 | - */ | |
36 | - unsigned attrib; | |
37 | - __time32_t time_create; | |
38 | - __time32_t time_access; | |
39 | - __time32_t time_write; | |
40 | - __int32 size; | |
41 | - char name[FILENAME_MAX]; | |
42 | -}; | |
43 | - | |
44 | -struct _finddata64_t | |
45 | -{ | |
46 | - /* ...while this is the all 64-bit member alternative, which is used | |
47 | - * by those function variants which explicitly require 64-bit members; | |
48 | - * (it is NOT equivalent to _finddata_t, when that implicitly adopts | |
49 | - * the 64-bit time_t representation, for that retains a 32-bit file | |
50 | - * size member, and thus the equivalent is _finddata64i32_t). | |
51 | - */ | |
52 | - unsigned attrib; | |
53 | - __time64_t time_create; | |
54 | - __time64_t time_access; | |
55 | - __time64_t time_write; | |
56 | - __int64 size; | |
57 | - char name[FILENAME_MAX]; | |
58 | -}; | |
59 | - | |
60 | 64 | struct _finddata_t |
61 | -{ | |
62 | - /* Not the way it's defined in the headers, but this custom variant | |
65 | +{ /* Not the way it's defined in the headers, but this custom variant | |
63 | 66 | * allows it to represent the equivalent of either of the above. |
64 | 67 | */ |
65 | - union { struct _finddata32_t _32_bit; struct _finddata64_t _64_bit; }; | |
68 | + union | |
69 | + { struct _finddata32_t | |
70 | + { /* This is the MSVCR80.DLL and later representation, equivalent to | |
71 | + * the all 32-bit member _finddata_t of earlier runtime versions... | |
72 | + */ | |
73 | + unsigned attrib; | |
74 | + __time32_t time_create; | |
75 | + __time32_t time_access; | |
76 | + __time32_t time_write; | |
77 | + __int32 size; | |
78 | + char name[FILENAME_MAX]; | |
79 | + } _32bit; | |
80 | + | |
81 | + struct _finddata64_t | |
82 | + { /* ...while this is the all 64-bit member alternative, which is used | |
83 | + * by those function variants which explicitly require 64-bit members; | |
84 | + * (it is NOT equivalent to _finddata_t, when that implicitly adopts | |
85 | + * the 64-bit time_t representation, for that retains a 32-bit file | |
86 | + * size member, and thus the equivalent is _finddata64i32_t). | |
87 | + */ | |
88 | + unsigned attrib; | |
89 | + __time64_t time_create; | |
90 | + __time64_t time_access; | |
91 | + __time64_t time_write; | |
92 | + __int64 size; | |
93 | + char name[FILENAME_MAX]; | |
94 | + } _64bit; | |
95 | + }; | |
66 | 96 | }; |
67 | 97 | |
68 | -/* To determine the default equivalence assumed by the runtime DLL, | |
69 | - * we evaluate variants of the _findfirst() function; which specific | |
70 | - * variant may be specified on the compiling command line, but if it | |
71 | - * is not... | |
72 | - */ | |
73 | -#ifndef EVALUATE | |
74 | -/* | |
75 | - * ...then choose the _findfirst() function itself. | |
76 | - */ | |
77 | -#define EVALUATE _findfirst | |
78 | -#endif | |
79 | - | |
80 | 98 | /* All variants of _findfirst() require a typedef for intptr_t; this |
81 | 99 | * is normally provided in stdint.h, but we prefer not to include it, |
82 | 100 | * and anyway, it's just as convenient to typedef it here. |
83 | 101 | */ |
84 | 102 | typedef __int32 intptr_t; |
85 | 103 | |
86 | -/* The _findfirst() variant prototypes are nominally declared in io.h, | |
87 | - * which we MUST NOT include here; thus, we must declare these locally. | |
88 | - */ | |
89 | -_CRTIMP intptr_t __cdecl __MINGW_NOTHROW _findfirst (const char*, struct _finddata_t*); | |
90 | -_CRTIMP intptr_t __cdecl __MINGW_NOTHROW _findfirst32 (const char*, struct _finddata32_t*); | |
91 | -_CRTIMP intptr_t __cdecl __MINGW_NOTHROW _findfirst64 (const char*, struct _finddata64_t*); | |
92 | - | |
93 | -/* Normally prototyped in io.h, which we want to avoid including, declare | |
94 | - * the prototypes for the functions we will use to save our test results to | |
95 | - * a file, for subsequent inspection using the od command. | |
96 | - */ | |
97 | -_CRTIMP int __cdecl __MINGW_NOTHROW open (const char*, int, ...); | |
98 | -_CRTIMP int __cdecl __MINGW_NOTHROW write (int, const void*, unsigned int); | |
99 | -_CRTIMP int __cdecl __MINGW_NOTHROW close (int); | |
100 | - | |
101 | -/* When opening the results file, we must specify a combination of the | |
102 | - * following attributes, which are normally defined in either of fctrl.h | |
103 | - * or sys/stat.h; once again, we define them locally, to avoid including | |
104 | - * either of these header files. | |
105 | - */ | |
106 | -#define O_RDONLY 0 | |
107 | -#define O_RDONLY 0 | |
108 | -#define O_WRONLY 1 | |
109 | -#define O_RDWR 2 | |
110 | - | |
111 | -#define O_CREAT 0x0100 /* Create the file if it does not exist. */ | |
112 | -#define O_BINARY 0x8000 /* Input and output is not translated. */ | |
113 | - | |
114 | -/* The preceding are from fctrl.h, the following from sys/stat.h | |
115 | - */ | |
116 | -#define S_IRUSR 0x0100 | |
117 | -#define S_IWUSR 0x0080 | |
118 | -#define S_IXUSR 0x0040 | |
119 | -#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) | |
120 | - | |
121 | -/* Before opening the results file, we want to ensure that it is | |
122 | - * created anew, and that its directory entry is committed before | |
123 | - * we attempt to invoke _findfirst() on it; to achieve this we will | |
124 | - * first unlink any existing old file, and the immediately close a | |
125 | - * duplicate file descriptor for the newly opened file. For this, | |
126 | - * we use the following pair of functions, for which we provide | |
127 | - * prototypes here, to avoid including io.h | |
128 | - */ | |
129 | -_CRTIMP int __cdecl __MINGW_NOTHROW unlink (const char*); | |
130 | -_CRTIMP int __cdecl __MINGW_NOTHROW dup (int); | |
131 | - | |
132 | 104 | /* To aid identification of regions of the result buffer which may |
133 | 105 | * not be updated when _findfirst() is called, we will initially fill |
134 | 106 | * the data space with a recurring recognizable pattern; for this we |
135 | 107 | * will use memset(), normally prototyped in string.h, which also |
136 | 108 | * requires the definition of size_t from sys/types.h; to avoid |
137 | 109 | * including these headers, we may conveniently reproduce the |
138 | - * requisite typedef and prototype here. | |
110 | + * requisite typedef and prototype here... | |
139 | 111 | */ |
140 | 112 | typedef unsigned __int32 size_t; |
141 | 113 | _CRTIMP void* __cdecl __MINGW_NOTHROW memset (void *, int, size_t); |
142 | 114 | |
143 | -int main() | |
115 | +/* ...together with these, to avoid including <stdio.h>. | |
116 | + */ | |
117 | +_CRTIMP int __cdecl __MINGW_NOTHROW printf (const char *, ...); | |
118 | +_CRTIMP int __cdecl __MINGW_NOTHROW close (int); | |
119 | + | |
120 | +/* This pair are local to this test suite, but are implemented in | |
121 | + * their own separate translation units. | |
122 | + */ | |
123 | +int __cdecl __MINGW_NOTHROW tmpfile_create (char *); | |
124 | +const void* __cdecl __MINGW_NOTHROW hexdump (void *, size_t); | |
125 | + | |
126 | +static void timdump( const char *fmt, struct _finddata_t *refdata ) | |
127 | +# define TIMESTAMP_VALUES(CLASS) refdata->_32bit.CLASS, refdata->_64bit.CLASS | |
128 | +{ | |
129 | + /* Print the analysis of the timestamp fields, within the | |
130 | + * returned data buffer. | |
131 | + */ | |
132 | + printf( fmt, "Creation time", TIMESTAMP_VALUES( time_create ) ); | |
133 | + printf( fmt, "Last access time", TIMESTAMP_VALUES( time_access ) ); | |
134 | + printf( fmt, "Last write time", TIMESTAMP_VALUES( time_write ) ); | |
135 | +} | |
136 | + | |
137 | +static int chkfind( const char *fname, const char *refname ) | |
144 | 138 | { |
145 | - /* Begin by creating, and opening, a new file in which to store | |
146 | - * the resultant data image; (unlink initially, to ensure that no | |
147 | - * pre-existing file of the same name creates confusion). | |
139 | + /* Evaluate the data returned by a single member of the _findfirst() | |
140 | + * family of functions, treating all as generically similar. | |
148 | 141 | */ |
149 | - int fd; const char *fname; | |
150 | - unlink( fname = "./chkfind.dat" ); | |
151 | - if( (fd = open( fname, O_RDWR | O_CREAT | O_BINARY, S_IRWXU )) >= 0 ) | |
142 | + intptr_t (*fn)( const char *, struct _finddata_t * ); | |
143 | + | |
144 | + /* Define a generic underlining string, which may be used by the | |
145 | + * ULINE macro, (defined below), to underline table column headings | |
146 | + * with a maximum width of 23 characters. | |
147 | + */ | |
148 | + char underline[24]; | |
149 | +# define ULINE(LEN) underline + sizeof(underline) - LEN - 1 | |
150 | + memset( underline, '-', sizeof(underline) ); | |
151 | + underline[sizeof(underline)-1] = '\0'; | |
152 | + | |
153 | + /* First check that the function of interest is actually present, | |
154 | + * in the current runtime environment... | |
155 | + */ | |
156 | + printf( "\nChecking for %s()... ", fname ); | |
157 | + if( (fn = dlsym( RTLD_DEFAULT, fname )) == (void *)(0) ) | |
152 | 158 | { |
153 | - /* File opened successfully; proceed to perform a _findfirst() | |
154 | - * look-up on it, having first closed a duplicate file handle to | |
155 | - * ensure that the directory entry has been committed, and also | |
156 | - * filling the return buffer with a recognizable 0xaa pattern, | |
157 | - * before refilling with the actual _findfirst() result. | |
159 | + /* ...bailing out, if not. | |
158 | 160 | */ |
159 | - intptr_t lookup; struct _finddata_t ref; close( dup( fd ) ); | |
160 | - lookup = EVALUATE( fname, memset( &ref, 0xaa, sizeof( ref ) )); | |
161 | + printf( "no\n%s() is not available in the current run time environment\n\n", | |
162 | + fname | |
163 | + ); | |
164 | + return 0; | |
165 | + } | |
166 | + else | |
167 | + { /* Next, check that the specified function actually works, with | |
168 | + * the return buffer initialized with a predefined pattern... | |
169 | + */ | |
170 | + struct _finddata_t refdata; | |
171 | + printf( "yes\nAnalysing behaviour of function %s()...", fname ); | |
172 | + if( fn( refname, memset( &refdata, 0xaa, sizeof( refdata ) )) == -1 ) | |
173 | + /* | |
174 | + * ...again, bailing out if not. | |
175 | + */ | |
176 | + printf( " failed\n\n" ); | |
177 | + | |
178 | + else | |
179 | + { /* Print a hexdump of the data returned by the working function... | |
180 | + */ | |
181 | + printf( "\n\nContent of returned[*] file data structure is:--\n\n" ); | |
182 | + hexdump( &refdata, sizeof( refdata ) ); | |
183 | + | |
184 | + /* ...followed by a field-by-field analysis, with respect to each | |
185 | + * of the potentially applicable structural layouts, of the time | |
186 | + * valued fields within the returned data. | |
187 | + */ | |
188 | + printf( "\nInterpreting as respectively _finddata32_t and _finddata64_t," | |
189 | + "\nthe embedded file system time stamp values are represented as:--" | |
190 | + "\n\n%32s%22s\n%32s%22s\n", "_finddata32_t", "_finddata64_t", | |
191 | + ULINE(13), ULINE(20) | |
192 | + ); | |
193 | + timdump( "%17s: 0x%08I32x 0x%016I64x\n", &refdata ); | |
194 | + printf( "%17s%15s%22s\n" | |
195 | + "\nWhen expressed as elapsed seconds since the beginning of " | |
196 | + "\nthe unix epoch, these timestamp values represent:--" | |
197 | + "\n\n%32s%22s\n%32s%22s\n", ULINE(17), ULINE(13), ULINE(20), | |
198 | + "_finddata32_t", "_finddata64_t", ULINE(13), ULINE(20) | |
199 | + ); | |
200 | + timdump( "%17s:%+14I32d%+22I64d\n", &refdata ); | |
201 | + printf( "%17s%15s%22s\n\n", ULINE(17), ULINE(13), ULINE(20) ); | |
202 | + | |
203 | + /* Returning non-zero indicates that the specified function did | |
204 | + * exist, and appeared to work as advertised. | |
205 | + */ | |
206 | + return 1; | |
207 | + } | |
208 | + } | |
209 | +} | |
161 | 210 | |
162 | - /* Write an image of the _findfirst() result to file, where we | |
163 | - * may subsequently inspect it using od, noting that any 0xaa | |
164 | - * remnants in the result were likely untouched by returned | |
165 | - * data from the _findfirst() call. | |
211 | +int main() | |
212 | +{ /* Begin by creating, and opening, a new file on which to execute | |
213 | + * the _findfirst() function tests. | |
214 | + */ | |
215 | + int fd; | |
216 | + char fname[] = "./chkfind.XXXXXX"; | |
217 | + if( (fd = tmpfile_create( fname )) >= 0 ) | |
218 | + { | |
219 | + /* Evaluate each of the potentially available functions, in turn... | |
220 | + */ | |
221 | + if( chkfind( "_findfirst", fname ) | |
222 | + | chkfind( "_findfirst32", fname ) | |
223 | + | chkfind( "_findfirst64", fname ) | |
224 | + ) printf( | |
225 | + /* | |
226 | + * ...adding a footnote to the resultant output, when at least | |
227 | + * one of them appears to work as advertised. | |
228 | + */ | |
229 | + "[*] In each case, the return data structure is filled with a\n" | |
230 | + " repeating pattern of 0xaa bytes, before invoking the function\n" | |
231 | + " which is to be analysed. Any byte sequences which continue to\n" | |
232 | + " exhibit this pattern, after the function has returned, may be\n" | |
233 | + " assumed to have remained untouched during the function call.\n" | |
234 | + ); | |
235 | + | |
236 | + /* Closing the temporary file, when we are done with it, causes the | |
237 | + * system to delete it automatically. | |
166 | 238 | */ |
167 | - write( fd, &ref, sizeof( ref ) ); | |
168 | 239 | close( fd ); |
169 | 240 | } |
170 | 241 | /* Always terminate indicating successful completion. |
171 | 242 | */ |
172 | 243 | return 0; |
173 | 244 | } |
245 | + | |
246 | +/* $RCSfile$: end of file */ |
@@ -0,0 +1,342 @@ | ||
1 | +/* | |
2 | + * chkstat.c | |
3 | + * | |
4 | + * Program to test the hypothesis that MSVCRT.DLL retains the 32-bit | |
5 | + * time_t format, (equivalent to __time32_t), for its representation | |
6 | + * of file system time stamps within any instance of the _stat family | |
7 | + * of structures, (other than those which explicitly declare their | |
8 | + * timestamp fields to be of type __time64_t), irrespective of MSDN | |
9 | + * documentation which suggests that __time64_t becomes the default | |
10 | + * unless _USE_32BIT_TIME_T is defined. | |
11 | + * | |
12 | + * $Id$ | |
13 | + * | |
14 | + * Written by Keith Marshall <keithmarshall@users.sourceforge.net> | |
15 | + * Copyright (C) 2016, MinGW.org Project | |
16 | + * | |
17 | + * | |
18 | + * Permission is hereby granted, free of charge, to any person obtaining a | |
19 | + * copy of this software and associated documentation files (the "Software"), | |
20 | + * to deal in the Software without restriction, including without limitation | |
21 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
22 | + * and/or sell copies of the Software, and to permit persons to whom the | |
23 | + * Software is furnished to do so, subject to the following conditions: | |
24 | + * | |
25 | + * The above copyright notice, this permission notice, and the following | |
26 | + * disclaimer shall be included in all copies or substantial portions of | |
27 | + * the Software. | |
28 | + * | |
29 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
30 | + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
31 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
32 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
33 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
34 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER | |
35 | + * DEALINGS IN THE SOFTWARE. | |
36 | + * | |
37 | + * | |
38 | + * All MinGW headers assume that <_mingw.h> is included; we want to avoid | |
39 | + * possible conflicts with typedefs from standard headers, where we want | |
40 | + * a customized variant; thus, we avoid including as many of the standard | |
41 | + * system headers as practicible. However, we do need <dlfcn.h>, to get | |
42 | + * the inline implementation for dlsym(); we know that it doesn't create | |
43 | + * any unwanted conflicts, so we go ahead and include it, allowing it to | |
44 | + * include <_mingw.h> for us, while we copy any required fragments from | |
45 | + * other system headers, as appropriate. | |
46 | + * | |
47 | + */ | |
48 | +#include <dlfcn.h> | |
49 | + | |
50 | +/* The two possible internal representations of time_t, effectively as | |
51 | + * defined by time.h; we want only these from time.h, while excluding any | |
52 | + * possible ambiguity in mapping to time_t itself, so just typedef them | |
53 | + * locally, rather than include the header file. | |
54 | + */ | |
55 | +typedef __int32 __time32_t; | |
56 | +typedef __int64 __time64_t; | |
57 | + | |
58 | +/* Similarly, the following three normally come from <sys/types.h>, but | |
59 | + * it is safer for us to just define them here. | |
60 | + */ | |
61 | +typedef unsigned int _dev_t; | |
62 | +typedef unsigned short _mode_t; | |
63 | +typedef short _ino_t; | |
64 | + | |
65 | +/* Here, we definitely want to avoid <sys/stat.h>, to define our own | |
66 | + * custom variant of the stat structure... | |
67 | + */ | |
68 | +struct _stat | |
69 | +{ union | |
70 | + { /* ...making it a union of the normal structure definitions, with | |
71 | + * totally unambiguous declarations for the sizes of the time and | |
72 | + * file size fields, in each case. | |
73 | + */ | |
74 | + struct __stat32 | |
75 | + { _dev_t st_dev; | |
76 | + _ino_t st_ino; | |
77 | + _mode_t st_mode; | |
78 | + short st_nlink; | |
79 | + short st_uid; | |
80 | + short st_gid; | |
81 | + _dev_t st_rdev; | |
82 | + __int32 st_size; | |
83 | + __time32_t st_atime; | |
84 | + __time32_t st_mtime; | |
85 | + __time32_t st_ctime; | |
86 | + } stat32i32; | |
87 | + | |
88 | + struct _stat32i64 | |
89 | + { _dev_t st_dev; | |
90 | + _ino_t st_ino; | |
91 | + _mode_t st_mode; | |
92 | + short st_nlink; | |
93 | + short st_uid; | |
94 | + short st_gid; | |
95 | + _dev_t st_rdev; | |
96 | + __int64 st_size; | |
97 | + __time32_t st_atime; | |
98 | + __time32_t st_mtime; | |
99 | + __time32_t st_ctime; | |
100 | + } stat32i64; | |
101 | + | |
102 | + struct _stat64i32 | |
103 | + { _dev_t st_dev; | |
104 | + _ino_t st_ino; | |
105 | + _mode_t st_mode; | |
106 | + short st_nlink; | |
107 | + short st_uid; | |
108 | + short st_gid; | |
109 | + _dev_t st_rdev; | |
110 | + __int32 st_size; | |
111 | + __time64_t st_atime; | |
112 | + __time64_t st_mtime; | |
113 | + __time64_t st_ctime; | |
114 | + } stat64i32; | |
115 | + | |
116 | + struct __stat64 | |
117 | + { _dev_t st_dev; | |
118 | + _ino_t st_ino; | |
119 | + _mode_t st_mode; | |
120 | + short st_nlink; | |
121 | + short st_uid; | |
122 | + short st_gid; | |
123 | + _dev_t st_rdev; | |
124 | + __int64 st_size; | |
125 | + __time64_t st_atime; | |
126 | + __time64_t st_mtime; | |
127 | + __time64_t st_ctime; | |
128 | + } stat64i64; | |
129 | + }; | |
130 | +}; | |
131 | + | |
132 | +/* To aid identification of regions of the result buffer which may | |
133 | + * not be updated when _stat(), (or any of its variants), is called, | |
134 | + * we will initially fill the data space with a recurring recognizable | |
135 | + * pattern; for this we will use memset(), which is normally prototyped | |
136 | + * in <string.h>, and which also requires the definition of size_t from | |
137 | + * <stddef.h>; to avoid including these headers, we may conveniently | |
138 | + * reproduce the requisite typedef and prototype here... | |
139 | + */ | |
140 | +typedef unsigned __int32 size_t; | |
141 | +_CRTIMP void* __cdecl __MINGW_NOTHROW memset (void *, int, size_t); | |
142 | + | |
143 | +/* ...together with these, to avoid including <stdio.h>. | |
144 | + */ | |
145 | +_CRTIMP int __cdecl __MINGW_NOTHROW printf (const char *, ...); | |
146 | +_CRTIMP int __cdecl __MINGW_NOTHROW close (int); | |
147 | + | |
148 | +/* This pair are local to this test suite, but are implemented in their | |
149 | + * own separate translation units. | |
150 | + */ | |
151 | +int __cdecl __MINGW_NOTHROW tmpfile_create (char *); | |
152 | +const void* __cdecl __MINGW_NOTHROW hexdump (void *, size_t); | |
153 | + | |
154 | +/* A macro to facilitate underlining of column headings; we initialize | |
155 | + * the content of its static buffer in our main() function. | |
156 | + */ | |
157 | +static char underline[32]; | |
158 | +#define ULINE(LEN) underline + sizeof(underline) - LEN - 1 | |
159 | + | |
160 | +static void first_header( const char *first, const char *second ) | |
161 | +{ | |
162 | + /* Print the table header for the first section of analytical results | |
163 | + * in each single function test... | |
164 | + */ | |
165 | + printf( | |
166 | + "\nInterpreting as respectively %s, and %s return data," | |
167 | + "\nthe embedded file sizes and time stamp values are represented as:--" | |
168 | + "\n\n%43s%26s\n%43s%26s\n", first, second, first, second, | |
169 | + ULINE(24), ULINE(24) | |
170 | + ); | |
171 | +} | |
172 | +/* ...and the footer line, used to separate each analytical section | |
173 | + * from the next. | |
174 | + */ | |
175 | +static void table_footer( void ) | |
176 | +{ printf( "%17s%26s%26s\n", ULINE(17), ULINE(24), ULINE(24) ); } | |
177 | + | |
178 | +/* Macros to specify the format for each table row... | |
179 | + */ | |
180 | +#define DECFMT "%17s:%+25I64d%+26I64d\n" | |
181 | +#define HEXFMT "%17s: 0x%016I64x 0x%016I64x\n" | |
182 | +/* | |
183 | + * ...and to identify the specific content for each row. | |
184 | + */ | |
185 | +#define ATIME(CLASS) (__time64_t)(refdata.CLASS.st_atime) | |
186 | +#define CTIME(CLASS) (__time64_t)(refdata.CLASS.st_ctime) | |
187 | +#define MTIME(CLASS) (__time64_t)(refdata.CLASS.st_mtime) | |
188 | + | |
189 | +#define FSIZE(CLASS) (__int64)(refdata.CLASS.st_size) | |
190 | + | |
191 | +static void epoch_header( const char *first, const char *second ) | |
192 | +{ | |
193 | + /* Print the separator between the first tabulated data section, | |
194 | + * and the following interpretation of time stamp values. | |
195 | + */ | |
196 | + table_footer(); | |
197 | + printf( | |
198 | + "\nWhen expressed as elapsed seconds since the beginning of " | |
199 | + "\nthe unix epoch, the above timestamp values represent:--" | |
200 | + "\n\n%43s%26s\n%43s%26s\n", first, second, | |
201 | + ULINE(24), ULINE(24) | |
202 | + ); | |
203 | +} | |
204 | + | |
205 | +static void fsize_header( const char *first, const char *second ) | |
206 | +{ | |
207 | + /* Print the final table separator, introducing the analysis of | |
208 | + * file size data as decimal values. | |
209 | + */ | |
210 | + table_footer(); | |
211 | + printf( | |
212 | + "\nThe decimal value equivalents for the above file sizes are:--" | |
213 | + "\n\n%43s%26s\n%43s%26s\n", first, second, | |
214 | + ULINE(24), ULINE(24) | |
215 | + ); | |
216 | +} | |
217 | + | |
218 | +static int chkstat( const char *fname, const char *refname ) | |
219 | +{ | |
220 | + /* Evaluate the data returned by a single member of the _stat() | |
221 | + * family of functions, treating all as generically similar. | |
222 | + */ | |
223 | + int (*fn)( const char *, struct _stat * ); | |
224 | + | |
225 | + /* First check that the function of interest is actually present, | |
226 | + * in the current runtime environment... | |
227 | + */ | |
228 | + printf( "\nChecking for %s()... ", fname ); | |
229 | + if( (fn = dlsym( RTLD_DEFAULT, fname )) == (void *)(0) ) | |
230 | + { | |
231 | + /* ...bailing out, if not. | |
232 | + */ | |
233 | + printf( "no\n%s() is not available in the current run time environment\n\n", | |
234 | + fname | |
235 | + ); | |
236 | + return 0; | |
237 | + } | |
238 | + else | |
239 | + { /* Next, check that the specified function actually works, with | |
240 | + * the return buffer initialized with a predefined pattern... | |
241 | + */ | |
242 | + struct _stat refdata; | |
243 | + printf( "yes\nAnalysing behaviour of function %s()...", fname ); | |
244 | + if( fn( refname, memset( &refdata, 0xaa, sizeof( refdata ) )) == -1 ) | |
245 | + /* | |
246 | + * ...again, bailing out if not. | |
247 | + */ | |
248 | + printf( " failed\n\n" ); | |
249 | + | |
250 | + else | |
251 | + { /* Print a hexdump of the data returned by the working function... | |
252 | + */ | |
253 | + printf( "\n\nContent of returned[*] stat data structure is:--\n\n" ); | |
254 | + hexdump( &refdata, sizeof( refdata ) ); | |
255 | + | |
256 | + /* ...followed by a field-by-field analysis, with respect to each | |
257 | + * of the potentially applicable structural layouts. | |
258 | + */ | |
259 | + first_header( "_stat", "_stat32i64" ); | |
260 | + printf( HEXFMT, "Creation time", CTIME(stat32i32), CTIME(stat32i64) ); | |
261 | + printf( HEXFMT, "Last access time", ATIME(stat32i32), ATIME(stat32i64) ); | |
262 | + printf( HEXFMT, "Last write time", MTIME(stat32i32), MTIME(stat32i64) ); | |
263 | + printf( HEXFMT, "File size", FSIZE(stat32i32), FSIZE(stat32i64) ); | |
264 | + | |
265 | + epoch_header( "_stat (__time32_t)", "_stat32i64 (__time32_t)" ); | |
266 | + printf( DECFMT, "Creation time", CTIME(stat32i32), CTIME(stat32i64) ); | |
267 | + printf( DECFMT, "Last access time", ATIME(stat32i32), ATIME(stat32i64) ); | |
268 | + printf( DECFMT, "Last write time", MTIME(stat32i32), MTIME(stat32i64) ); | |
269 | + | |
270 | + fsize_header( "_stat (int32_t)", "_stat32i64 (int64_t)" ); | |
271 | + printf( DECFMT, "File size", FSIZE(stat32i32), FSIZE(stat32i64) ); | |
272 | + table_footer(); | |
273 | + | |
274 | + first_header( "_stat64i32", "_stat64" ); | |
275 | + printf( HEXFMT, "Creation time", CTIME(stat64i32), CTIME(stat64i64) ); | |
276 | + printf( HEXFMT, "Last access time", ATIME(stat64i32), ATIME(stat64i64) ); | |
277 | + printf( HEXFMT, "Last write time", MTIME(stat64i32), MTIME(stat64i64) ); | |
278 | + printf( HEXFMT, "File size", FSIZE(stat64i32), FSIZE(stat64i64) ); | |
279 | + | |
280 | + epoch_header( "_stat64i32 (__time64_t)", "_stat64 (__time64_t)" ); | |
281 | + printf( DECFMT, "Creation time", CTIME(stat64i32), CTIME(stat64i64) ); | |
282 | + printf( DECFMT, "Last access time", ATIME(stat64i32), ATIME(stat64i64) ); | |
283 | + printf( DECFMT, "Last write time", MTIME(stat64i32), MTIME(stat64i64) ); | |
284 | + | |
285 | + fsize_header( "_stat64i32 (int32_t)", "_stat64 (int64_t)" ); | |
286 | + printf( DECFMT, "File size", FSIZE(stat64i32), FSIZE(stat64i64) ); | |
287 | + table_footer(); | |
288 | + | |
289 | + /* Returning non-zero indicates that the specified function did | |
290 | + * exist, and appeared to work as advertised. | |
291 | + */ | |
292 | + return 1; | |
293 | + } | |
294 | + } | |
295 | +} | |
296 | + | |
297 | +int main() | |
298 | +{ /* Begin by creating, and opening, a new file on which to execute | |
299 | + * the stat() function tests. | |
300 | + */ | |
301 | + int fd; | |
302 | + char fname[] = "./chkfind.XXXXXX"; | |
303 | + if( (fd = tmpfile_create( fname )) >= 0 ) | |
304 | + { | |
305 | + /* Define a generic underlining string, which may be used by the | |
306 | + * ULINE macro, (defined above), to underline table column headings | |
307 | + * with a maximum width of 23 characters. | |
308 | + */ | |
309 | + memset( underline, '-', sizeof(underline) ); | |
310 | + underline[sizeof(underline)-1] = '\0'; | |
311 | + | |
312 | + /* Evaluate each of the potentially available functions, in turn... | |
313 | + */ | |
314 | + if( chkstat( "_stat", fname ) | |
315 | + | chkstat( "_stat32", fname ) | |
316 | + | chkstat( "_stat64", fname ) | |
317 | + | chkstat( "_stat32i64", fname ) | |
318 | + | chkstat( "_stat64i32", fname ) | |
319 | + | chkstat( "_stati64", fname ) | |
320 | + ) printf( "\n\n" | |
321 | + /* | |
322 | + * ...adding a footnote to the resultant output, when at least | |
323 | + * one of them appears to work as advertised. | |
324 | + */ | |
325 | + "[*] In each case, the return data structure is filled with a\n" | |
326 | + " repeating pattern of 0xaa bytes, before invoking the function\n" | |
327 | + " which is to be analysed. Any byte sequences which continue to\n" | |
328 | + " exhibit this pattern, after the function has returned, may be\n" | |
329 | + " assumed to have remained untouched during the function call.\n" | |
330 | + ); | |
331 | + | |
332 | + /* Closing the temporary file, when we are done with it, causes the | |
333 | + * system to delete it automatically. | |
334 | + */ | |
335 | + close( fd ); | |
336 | + } | |
337 | + /* Always terminate indicating successful completion. | |
338 | + */ | |
339 | + return 0; | |
340 | +} | |
341 | + | |
342 | +/* $RCSfile$: end of file */ |
@@ -6,14 +6,43 @@ | ||
6 | 6 | * MSVCR80.DLL and later, where time_t becomes equivalent to __time64_t, |
7 | 7 | * unless the user defines the _USE_32BIT_TIME_T macro. |
8 | 8 | * |
9 | + * $Id$ | |
9 | 10 | * |
10 | - * All MinGW headers assume that _mingw.h is included; we want to avoid | |
11 | + * Written by Keith Marshall <keithmarshall@users.sourceforge.net> | |
12 | + * Copyright (C) 2014-2016, MinGW.org Project | |
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 | + * All MinGW headers assume that <_mingw.h> is included; we want to avoid | |
11 | 36 | * possible conflicts with typedefs from standard headers, where we want |
12 | - * a customized variant; thus we include _mingw.h directly, and copy any | |
13 | - * required fragments from other headers, as appropriate. | |
37 | + * a customized variant; thus, we avoid including as many of the standard | |
38 | + * system headers as practicible. However, we do need <dlfcn.h>, to get | |
39 | + * the inline implementation for dlsym(); we know that it doesn't create | |
40 | + * any unwanted conflicts, so we go ahead and include it, allowing it to | |
41 | + * include <_mingw.h> for us, while we copy any required fragments from | |
42 | + * other system headers, as appropriate. | |
14 | 43 | * |
15 | 44 | */ |
16 | -#include <_mingw.h> | |
45 | +#include <dlfcn.h> | |
17 | 46 | |
18 | 47 | /* The two possible internal representations of time_t, effectively as |
19 | 48 | * defined by time.h; we want only these from time.h, while excluding any |
@@ -28,75 +57,91 @@ typedef __int64 __time64_t; | ||
28 | 57 | */ |
29 | 58 | typedef union { __time32_t _32bit; __time64_t _64bit; } time_t; |
30 | 59 | |
31 | -/* Declare protototypes for the functions we plan to evaluate; (note that | |
32 | - * _time32() isn't expected to be present in MSVCRT.DLL, but we declare | |
33 | - * its prototype anyway). | |
60 | +/* We reproduce the definition of size_t from sys/types.h, the prototype | |
61 | + * for memset() from string.h, and the prototype for printf() from stdio.h, | |
62 | + * to avoid including any of these. | |
34 | 63 | */ |
35 | -_CRTIMP time_t __cdecl __MINGW_NOTHROW _time32 (time_t *); | |
36 | -_CRTIMP time_t __cdecl __MINGW_NOTHROW _time64 (time_t *); | |
37 | -_CRTIMP time_t __cdecl __MINGW_NOTHROW time (time_t *); | |
64 | +typedef unsigned __int32 size_t; | |
65 | +_CRTIMP void* __cdecl __MINGW_NOTHROW memset( void *, int, size_t ); | |
66 | +_CRTIMP int __cdecl __MINGW_NOTHROW printf( const char *, ... ); | |
38 | 67 | |
39 | -#ifndef EVALUATE | |
40 | -/* | |
41 | - * In the event that no evaluation method was specified on the compiling | |
42 | - * command line, delegate the test to the time() function. | |
68 | +/* Program implementation begins with this... | |
43 | 69 | */ |
44 | -#define EVALUATE time | |
45 | -#endif | |
70 | +static void eval( const char *fname ) | |
71 | +{ | |
72 | + /* ...helper function to lookup the entry point for the specified | |
73 | + * time() function within the program's (DLL) address space, and to | |
74 | + * invoke it according to a generic time() function template. | |
75 | + */ | |
76 | + time_t (*fp)( time_t * ); | |
77 | + if( (fp = dlsym( RTLD_DEFAULT, fname )) == (void *)(0) ) | |
78 | + /* | |
79 | + * The specified function is not supported in the current | |
80 | + * program runtime environment; simply add a line record to | |
81 | + * the results table, reporting this, instead of attempting | |
82 | + * to invoke a non-existent API function. | |
83 | + */ | |
84 | + printf( "%8s():%47s\n", fname, "*** function not supported ***" ); | |
46 | 85 | |
47 | -/* Normally prototyped in io.h, which we want to avoid including, declare | |
48 | - * the prototypes for the functions we will use to save our test results to | |
49 | - * a file, for subsequent inspection using the od command. | |
50 | - */ | |
51 | -_CRTIMP int __cdecl __MINGW_NOTHROW open (const char *, int, ...); | |
52 | -_CRTIMP int __cdecl __MINGW_NOTHROW write (int, const void *, unsigned int); | |
53 | -_CRTIMP int __cdecl __MINGW_NOTHROW close (int); | |
86 | + else | |
87 | + { /* The specified function is available; we set aside a buffer | |
88 | + * in which to capture its return state, initialize that with | |
89 | + * a recognizable bit pattern, (recurring 0xaa bytes), so that | |
90 | + * we can easily see what is subsequently changed as we invoke | |
91 | + * the specified function... | |
92 | + */ | |
93 | + time_t now; | |
94 | + fp( memset( &now, 0xaa, sizeof( time_t ) )); | |
54 | 95 | |
55 | -/* When opening the results file, we must specify a combination of the | |
56 | - * following attributes, which are normally defined in either of fctrl.h | |
57 | - * or sys/stat.h; once again, we define them locally, to avoid including | |
58 | - * either of these header files. | |
59 | - */ | |
60 | -#define O_RDONLY 0 | |
61 | -#define O_WRONLY 1 | |
62 | -#define O_RDWR 2 | |
96 | + /* ...and tabulate the return state, as a single line record | |
97 | + * in our results table. | |
98 | + */ | |
99 | + printf( "%8s(): 0x%016I64x%+22I32d%+22I64d\n", fname, | |
100 | + now._64bit, now._32bit, now._64bit | |
101 | + ); | |
102 | + } | |
103 | +} | |
63 | 104 | |
64 | -#define O_CREAT 0x0100 /* Create the file if it does not exist. */ | |
65 | -#define O_BINARY 0x8000 /* Input and output is not translated. */ | |
105 | +int main() | |
106 | +{ /* Define a generic underlining string, which may be used by the | |
107 | + * ULINE macro, (defined below), to underline table column headings | |
108 | + * with a maximum width of 23 characters. | |
109 | + */ | |
110 | + char underline[24]; | |
111 | + memset( underline, '-', sizeof(underline) ); | |
112 | + underline[sizeof(underline)-1] = '\0'; | |
66 | 113 | |
67 | -/* The preceding are from fctrl.h, the following from sys/stat.h | |
68 | - */ | |
69 | -#define S_IRUSR 0x0100 | |
70 | -#define S_IWUSR 0x0080 | |
71 | -#define S_IXUSR 0x0040 | |
72 | -#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) | |
114 | + /* Print a table heading. | |
115 | + */ | |
116 | +# define ULINE(LEN) underline + sizeof(underline) - LEN - 1 | |
117 | + printf( "Seconds elapsed since the beginning of the unix epoch,\n" | |
118 | + "as reported by MSVCRT.DLL time functions with time_t interpreted as:--\n" | |
119 | + "\n%30s %-22s%s\n%30s%22s%22s\n", "Uninterpreted [*]", | |
120 | + "32-bit (__time32_t)", "64-bit (__time64_t)", | |
121 | + ULINE(18), ULINE(20), ULINE(20) | |
122 | + ); | |
73 | 123 | |
74 | -/* Similarly, we reproduce the definition of size_t from sys/types.h, and | |
75 | - * the prototype for memset() from string.h, to avoid including these. | |
76 | - */ | |
77 | -typedef unsigned __int32 size_t; | |
78 | -_CRTIMP void* __cdecl __MINGW_NOTHROW memset (void *, int, size_t); | |
124 | + /* Evaluate and tabulate the effect of calling each of the possible | |
125 | + * MSVCRT.DLL implementations of the time() function. | |
126 | + */ | |
127 | + eval( "time" ); | |
128 | + eval( "_time32" ); | |
129 | + eval( "_time64" ); | |
79 | 130 | |
80 | -int main() | |
81 | -{ | |
82 | - /* Begin by initializing the results file; if successful... | |
131 | + /* Close the results table, and print a footnote. | |
83 | 132 | */ |
84 | - int fd = open( "./chktime.dat", O_RDWR | O_CREAT | O_BINARY, S_IRWXU ); | |
85 | - if( fd >= 0 ) | |
86 | - { | |
87 | - /* ...create a results buffer, fill it with a recognizable bit | |
88 | - * pattern, then reassign as many initial bytes as required by | |
89 | - * the function which is to be evaluated... | |
90 | - */ | |
91 | - time_t now; | |
92 | - EVALUATE( memset( &now, 0xaa, sizeof( time_t ) )); | |
93 | - /* | |
94 | - * ...before committing it to the results file. | |
95 | - */ | |
96 | - write( fd, &now, sizeof( time_t ) ); | |
97 | - close( fd ); | |
98 | - } | |
133 | + printf( "%10s%20s%22s%22s\n\n" | |
134 | + "[*] This is a hexadecimal representation of the content of the 64-bit\n" | |
135 | + " results buffer, AFTER the function call; note that this was filled\n" | |
136 | + " with 0xaa bytes BEFORE the function call, and that any bytes which\n" | |
137 | + " retain this value after the call may be assumed to have remained\n" | |
138 | + " untouched, when calling the specified function.\n", | |
139 | + ULINE(9), ULINE(18), ULINE(20), ULINE(20) | |
140 | + ); | |
141 | + | |
99 | 142 | /* Always terminate as if successful. |
100 | 143 | */ |
101 | 144 | return 0; |
102 | 145 | } |
146 | + | |
147 | +/* $RCSfile$: end of file */ |
@@ -0,0 +1,45 @@ | ||
1 | +# configure.ac | |
2 | +# | |
3 | +# Configuration script for MinGW time_t behavioural evaluation | |
4 | +# for various functions exported by MSVCRT.DLL | |
5 | +# | |
6 | + AC_INIT([mingw32-chktime],[1.0.0]) | |
7 | +# | |
8 | +# $Id$ | |
9 | +# | |
10 | +# Written by Keith Marshall <keithmarshall@users.sourceforge.net> | |
11 | +# Copyright (C) 2016, MinGW.org Project | |
12 | +# | |
13 | +# | |
14 | +# Permission is hereby granted, free of charge, to any person obtaining a | |
15 | +# copy of this software and associated documentation files (the "Software"), | |
16 | +# to deal in the Software without restriction, including without limitation | |
17 | +# the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
18 | +# and/or sell copies of the Software, and to permit persons to whom the | |
19 | +# Software is furnished to do so, subject to the following conditions: | |
20 | +# | |
21 | +# The above copyright notice and this permission notice (including the next | |
22 | +# paragraph) shall be included in all copies or substantial portions of the | |
23 | +# Software. | |
24 | +# | |
25 | +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
26 | +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
27 | +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
28 | +# AUTHORS OR THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
29 | +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
30 | +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
31 | +# DEALINGS IN THE SOFTWARE. | |
32 | +# | |
33 | +# | |
34 | +# Tests for build support tools. | |
35 | +# | |
36 | + AC_PROG_CC | |
37 | + AC_PROG_MKDIR_P | |
38 | + AC_PROG_LN_S | |
39 | +# | |
40 | +# Makefile generation. | |
41 | +# | |
42 | + AC_CONFIG_FILES([Makefile]) | |
43 | + AC_OUTPUT | |
44 | +# | |
45 | +# $RCSfile$: end of file |
@@ -0,0 +1,112 @@ | ||
1 | +/* | |
2 | + * hexdump.c | |
3 | + * | |
4 | + * Utility functions to display the content of any memory region, in a | |
5 | + * similar style to the hexadecimal output from the unix od command. | |
6 | + * | |
7 | + * $Id$ | |
8 | + * | |
9 | + * Written by Keith Marshall <keithmarshall@users.sourceforge.net> | |
10 | + * Copyright (C) 2014, 2016, MinGW.org Project | |
11 | + * | |
12 | + * | |
13 | + * Permission is hereby granted, free of charge, to any person obtaining a | |
14 | + * copy of this software and associated documentation files (the "Software"), | |
15 | + * to deal in the Software without restriction, including without limitation | |
16 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
17 | + * and/or sell copies of the Software, and to permit persons to whom the | |
18 | + * Software is furnished to do so, subject to the following conditions: | |
19 | + * | |
20 | + * The above copyright notice, this permission notice, and the following | |
21 | + * disclaimer shall be included in all copies or substantial portions of | |
22 | + * the Software. | |
23 | + * | |
24 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
25 | + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
26 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
27 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
28 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
29 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER | |
30 | + * DEALINGS IN THE SOFTWARE. | |
31 | + * | |
32 | + */ | |
33 | +#include <ctype.h> | |
34 | +#include <stdio.h> | |
35 | + | |
36 | +#define HEXDUMP_INLINE static __inline__ __attribute__((__always_inline__)) | |
37 | + | |
38 | +#ifndef HEXDUMP_OFFSET_FORMAT | |
39 | +#define HEXDUMP_OFFSET_FORMAT "%04x" | |
40 | +#endif | |
41 | + | |
42 | +HEXDUMP_INLINE const unsigned char | |
43 | +*show_bytes( const unsigned char *dp, int count ) | |
44 | +{ | |
45 | + /* Internal helper function: prints a sequence of up to sixteen | |
46 | + * byte values, as stored contiguously in memory, into a display | |
47 | + * field of fifty character positions; this allows for a display | |
48 | + * of two hexadecimal digits per byte value, with a single space | |
49 | + * separating each value from its predecessor, and two further | |
50 | + * padding spaces, before appending a textual representation | |
51 | + * of the printable bytes within the sequence. | |
52 | + * | |
53 | + * Returns the memory address of the byte immediately following | |
54 | + * the last byte in the displayed sequence. | |
55 | + */ | |
56 | + int fw; | |
57 | + for( fw = 50; count-- > 0; fw -= printf( " %02x", *dp++ ) ); | |
58 | + while( fw-- > 0 ) putchar( 0x20 ); | |
59 | + return dp; | |
60 | +} | |
61 | + | |
62 | +HEXDUMP_INLINE const unsigned char | |
63 | +*show_text( const unsigned char *dp, int count ) | |
64 | +{ | |
65 | + /* Internal helper function: prints the textual representation of | |
66 | + * a sequence of up to sixteen contiguous bytes in memory; those | |
67 | + * bytes which represent a printable character are displayed as | |
68 | + * such; all others are replaced by a single '.' for display. | |
69 | + * | |
70 | + * Returns the memory address of the byte immediately following | |
71 | + * the last byte in the displayed sequence. | |
72 | + */ | |
73 | + unsigned int c; | |
74 | + while( count-- > 0 ) putchar( isprint( c = *dp++ ) ? c : '.' ); | |
75 | + return dp; | |
76 | +} | |
77 | + | |
78 | +HEXDUMP_INLINE const unsigned char | |
79 | +*show_hexdump( unsigned offset, const unsigned char *dp, int count ) | |
80 | +{ | |
81 | + /* Internal helper function: combines the effects of show_bytes() | |
82 | + * and show_text() above, to format a single hexdump record for a | |
83 | + * contiguous sequence of up to sixteen bytes in memory; each such | |
84 | + * record is prefixed by a caller specified offset, which is taken | |
85 | + * to represent the offset of the current sequence from the start | |
86 | + * of the data buffer being dumped. | |
87 | + * | |
88 | + * Returns the memory address of the byte immediately following | |
89 | + * the last byte in the displayed sequence. | |
90 | + */ | |
91 | + printf( HEXDUMP_OFFSET_FORMAT " ", offset ); | |
92 | + dp = show_text( dp, show_bytes( dp, ((count > 16) ? 16 : count) ) - dp ); | |
93 | + putchar( '\n' ); | |
94 | + return dp; | |
95 | +} | |
96 | + | |
97 | +const void *hexdump( void *data, size_t len ) | |
98 | +{ | |
99 | + /* Entry point for a general purpose hexdump display function. | |
100 | + * Displays the content of a memory buffer of arbitrary length, | |
101 | + * formatting it as a sequence of records of up to sixteen bytes | |
102 | + * each, in conventional hexdump style. | |
103 | + * | |
104 | + * Returns the memory address of the byte immediately following | |
105 | + * the last byte in the specified data buffer region. | |
106 | + */ | |
107 | + const void *dp = data, *ep = data + len; | |
108 | + while( dp < ep ) dp = show_hexdump( dp - data, dp, ep - dp ); | |
109 | + return dp; | |
110 | +} | |
111 | + | |
112 | +/* $RCSfile$: end of file */ |
@@ -0,0 +1,61 @@ | ||
1 | +/* | |
2 | + * tmpfile.c | |
3 | + * | |
4 | + * Utility function to create a temporary file, which will be automatically | |
5 | + * deleted when it is closed. | |
6 | + * | |
7 | + * $Id$ | |
8 | + * | |
9 | + * Written by Keith Marshall <keithmarshall@users.sourceforge.net> | |
10 | + * Copyright (C) 2014, 2016, MinGW.org Project | |
11 | + * | |
12 | + * | |
13 | + * Permission is hereby granted, free of charge, to any person obtaining a | |
14 | + * copy of this software and associated documentation files (the "Software"), | |
15 | + * to deal in the Software without restriction, including without limitation | |
16 | + * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
17 | + * and/or sell copies of the Software, and to permit persons to whom the | |
18 | + * Software is furnished to do so, subject to the following conditions: | |
19 | + * | |
20 | + * The above copyright notice, this permission notice, and the following | |
21 | + * disclaimer shall be included in all copies or substantial portions of | |
22 | + * the Software. | |
23 | + * | |
24 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
25 | + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
26 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
27 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
28 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
29 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER | |
30 | + * DEALINGS IN THE SOFTWARE. | |
31 | + * | |
32 | + */ | |
33 | +#include <fcntl.h> | |
34 | +#include <stdlib.h> | |
35 | +#include <string.h> | |
36 | +#include <unistd.h> | |
37 | + | |
38 | +int tmpfile_create( char *template ) | |
39 | +{ | |
40 | + int fd; | |
41 | + | |
42 | + /* Create and open a temporary file, scheduling it for | |
43 | + * automatic deletion on final closure. | |
44 | + */ | |
45 | + _MKSTEMP_SETMODE( _O_TEMPORARY ); | |
46 | + if( (fd = mkstemp( template )) >= 0 ) | |
47 | + { | |
48 | + /* Close a duplicate handle on the opened temporary file, | |
49 | + * to ensure that its directory entry is committed, while | |
50 | + * keeping the original handle open to prevent immediate | |
51 | + * deletion of the file itself. | |
52 | + */ | |
53 | + close( dup( fd )); | |
54 | + } | |
55 | + /* Return the handle for the open temporary file, leaving | |
56 | + * the caller to use it as required, and finally close it. | |
57 | + */ | |
58 | + return fd; | |
59 | +} | |
60 | + | |
61 | +/* $RCSfile$: end of file */ |