# HG changeset patch # Parent 3ab1e813729600c700d5efd92d0439242f2b0b74 Address several gratuitous GCC-9.x dependencies. * include/stdlib.h (_get_errno, _set_errno): Declare prototypes; implement them in-line, for Windows versions which may lack them. * include/unistd.h (ftruncate64): Declare prototype; implement it... * mingwex/ftruncate.c: ...in this new file; it will delegate to... (_chsize_s): ...this MSVCRT.DLL function, if available. * Makefile.in (libmingwex.a): Add dependency on... (ftruncate.$OBJEXT): ...this. * msvcrt-xref/msvcrt.def.in (_chsize_s): Require dlsym look-up. diff --git a/mingwrt/Makefile.in b/mingwrt/Makefile.in --- a/mingwrt/Makefile.in +++ b/mingwrt/Makefile.in @@ -457,16 +457,16 @@ LIBMINGWEX_MEMALIGN_OBJECTS = $(addsuffi libmingwex.a: $(LIBMINGWEX_MEMALIGN_OBJECTS) # Some additional miscellaneous functions, in libmingwex.a # +libmingwex.a: $(addsuffix .$(OBJEXT), ftruncate getdelim gettimeofday) libmingwex.a: $(addsuffix .$(OBJEXT), glob getopt basename dirname nsleep) libmingwex.a: $(addsuffix .$(OBJEXT), clockapi clockres clockset clocktime) libmingwex.a: $(addsuffix .$(OBJEXT), insque remque tdelete tfind tsearch twalk) libmingwex.a: $(addsuffix .$(OBJEXT), dirent wdirent dlfcn strerror_r strtok_r) libmingwex.a: $(addsuffix .$(OBJEXT), mkstemp mkdtemp cryptnam setenv) -libmingwex.a: $(addsuffix .$(OBJEXT), getdelim gettimeofday) vpath %.s ${mingwrt_srcdir}/mingwex vpath %.sx ${mingwrt_srcdir}/mingwex libmingwex.a: $(addsuffix .$(OBJEXT), codeset fwide mbrtowc mbsinit strnlen \ wcharmap wcrtomb wcsrtombs wcsnlen wcstof wcstold wctob wctrans wctype wmemchr \ diff --git a/mingwrt/include/stdlib.h b/mingwrt/include/stdlib.h --- a/mingwrt/include/stdlib.h +++ b/mingwrt/include/stdlib.h @@ -164,10 +164,38 @@ extern char ***_imp____argv_dll; extern int errno; #else _CRTIMP __cdecl __MINGW_NOTHROW int *_errno(void); # define errno (*_errno()) #endif + +/* In MSVCR80.DLL, Microsoft introduced the following pair of errno + * accessor functions; they subsequently became available in MSVCRT.DLL + * from Vista onward. Although they are not required by ISO-C, and they + * are more cumbersome to use, than referring to errno directly, the GCC + * developers have gratuitously chosen to assume, in GCC-9.x, that they + * are always supported on MS-Windows, regardless of Windows version; + * thus, we will declare them unconditionally here ... + */ +__cdecl __MINGW_NOTHROW int _get_errno(int *); +__cdecl __MINGW_NOTHROW int _set_errno(int); + +/* ... then provide in-line implementations, (depending on gratuitous + * exposure of EINVAL, which strictly belongs in ), which will + * allow them to be used, even on legacy Windows versions pre-dating + * Vista, and without requiring non-free MSVCRT80.DLL or later. + */ +#if __MSVCRT_VERSION__ < __MSVCR80_DLL && _WIN32_WINNT < _WIN32_WINNT_VISTA + +#define EINVAL 22 /* Invalid argument */ + +__CRT_ALIAS __cdecl __MINGW_NOTHROW int _get_errno( int *__val ) +{ return (__val == NULL) ? (errno = EINVAL) : 0 & (*__val = errno); } + +__CRT_ALIAS __cdecl __MINGW_NOTHROW int _set_errno( int __val ) +{ errno = __val; return 0; } +#endif + _CRTIMP __cdecl __MINGW_NOTHROW int *__doserrno(void); #define _doserrno (*__doserrno()) #if !defined (__STRICT_ANSI__) /* Use environ from the DLL, not as a global. diff --git a/mingwrt/include/unistd.h b/mingwrt/include/unistd.h --- a/mingwrt/include/unistd.h +++ b/mingwrt/include/unistd.h @@ -130,10 +130,19 @@ int __cdecl ftruncate( int, off_t ); #ifndef __NO_INLINE__ __CRT_INLINE __JMPSTUB__(( FUNCTION = ftruncate, DLLENTRY = _chsize )) int ftruncate( int __fd, off_t __length ){ return _chsize( __fd, __length ); } #endif +/* Although non-standard, GCC's C++ library from GCC-9.x gratuitously + * assumes, and requires, this 64-bit off_t variant to be available; it + * could be emulated by Microsoft's _chsize_s() function, which is only + * supported from Vista onward; therefore, to ensure support on legacy + * platforms, we prefer our own libmingwex.a implementation, and so, + * we do not provide an inline implementation. + */ +int __cdecl ftruncate64( int, __off64_t ); + _END_C_DECLS #endif /* _POSIX_C_SOURCE */ #undef __UNISTD_H_SOURCED__ diff --git a/mingwrt/mingwex/ftruncate.c b/mingwrt/mingwex/ftruncate.c new file mode 100644 --- /dev/null +++ b/mingwrt/mingwex/ftruncate.c @@ -0,0 +1,167 @@ +/* + * ftruncate.c + * + * Implement a 64-bit file size capable ftruncate() function; GCC-9.x + * gratuitously assumes that this is available, via the ftruncate64() + * entry point. + * + * $Id$ + * + * Written by Keith Marshall + * Copyright (C) 2019, MinGW.org Project + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#include +#include +#include +#include +#include +#include +#include + +/* The following in-line function is provided to facilitate abnormal return + * from ftruncate64(), (in which case the return value is always -1), while + * setting the global errno indicator to an appropriate error code. + */ +static __inline__ __attribute__((__always_inline__)) +int errout( int error_code ){ errno = error_code; return -1L; } + +/* When running on Vista, or later, or for applications which have been + * linked against non-free MSVCR80.DLL, or later, we may be able to simply + * substitute a call to Microsoft's _chsize_s() function, (which behaves + * as a 64-bit variant of the universally available _chsize() function). + * On legacy Windows versions, which are unlikely to provide _chsize_s(), + * we need to provide our own fallback 64-bit chsize() implementation; + * this may be static, but cannot be inlined, because we need a physical + * entry point address to which execution may be redirected. + */ +static int mingw_chsize64_fallback( int fd, __off64_t offset ) +{ + /* POSIX.1 requires the file pointer to be unchanged, as a consequence + * of calling ftruncate(), (and Microsoft's _chsize() functions do seem + * to satisfy this requirement); however, to mark a new end of file, we + * need move the file pointer to the new end of file offset, so we need + * to save the original pointer now, to restore later. + */ + __off64_t cur_offset = _lseeki64( fd, 0LL, SEEK_CUR ); + + /* In the event that the new end of file offset requires the file to be + * extended beyond its current end of file offset, POSIX.1 also requires + * NUL byte padding to be written to the extended file space, (and again, + * Microsoft's _chsize() functions seem to do this); we may reposition + * the file pointer to its current end of file offset, in preparation + * for the possibility that we need to fulfil this requirement. + */ + __off64_t end_offset = _lseeki64( fd, 0LL, SEEK_END ); + + /* We will eventually need to restore the original file pointer, AFTER + * we have evaluated the return status code, so we will need to save + * this. + */ + int retval; + + /* There are two possible options for repositioning the end of file + * pointer: + */ + if( offset > end_offset ) + { + /* In this case, the file is to be extended beyond its current + * end of file offset; initialize a NUL filled buffer, which we + * may then copy to the extended region of the file, to satisfy + * the POSIX.1 requirement that this region shall be NUL filled. + */ + char padding[BUFSIZ]; + memset( padding, 0, sizeof( padding ) ); + + /* Recompute the desired offset, relative to the current end of + * file, then repeatedly write copies of the NUL filled buffer, + * until the file space represented by this relative offset has + * been completely filled; (this results in advancement of the + * file pointer to the desired new end of file offset). + */ + offset -= end_offset; + while( offset > (__off64_t)(sizeof( padding )) ) + offset -= write( fd, padding, sizeof( padding ) ); + write( fd, padding, offset ); + } + else + /* In the alternative case, the new end of file pointer will lie + * within the space already occupied by the file; we may simply + * seek directly to the desired offset. + */ + _lseeki64( fd, offset, SEEK_SET ); + + /* We have now adjusted the file pointer to be coincident with the + * desired new end of file offset; this is exactly what is required + * by the Windows API function, to mark the new end of file. + */ + retval = SetEndOfFile( (void *)(_get_osfhandle( fd )) ) + ? 0 : errout( EBADF ); + + /* Finally, we must restore the originally saved file pointer, before + * we return the status code from the ftruncate() operation. + */ + _lseeki64( fd, cur_offset, SEEK_SET ); + return retval; +} + +/* Regardless of the platform version, Microsoft do not provide an + * implementation of ftruncate64(); all link-time references to this + * function will be resolved by this libmingwex.a implementation. + */ +int ftruncate64( int fd, __off64_t offset ) +{ + /* The offset parameter MUST be positive valued; bail out if not. + */ + if( 0LL > offset ) return errout( EINVAL ); + + /* For offsets which may be represented by a 32-bit integer, we + * may ALWAYS delegate this call to Microsoft's _chsize(). + */ + if( INT32_MAX >= offset ) return _chsize( fd, (off_t)(offset) ); + + { /* For offsets which cannot be represented within 32-bits, we + * MAY be able to delegate this call, (and also any subsequent + * calls), to Microsoft's _chsize_s(); set up a redirector to + * handle such delegation... + */ + static int (*redirector_hook)( int, __off64_t ) = NULL; + + /* ...initially checking for _chsize_s() availability... + */ + if( (redirector_hook == NULL) + && ((redirector_hook = dlsym( RTLD_DEFAULT, "_chsize_s" )) == NULL) ) + + /* ...and setting up a suitable fallback if not... + */ + redirector_hook = mingw_chsize64_fallback; + + /* ...and ultimately, on initial selection, (and directly on + * all subsequent calls), hand off execution to the selected + * delegate function. + */ + return redirector_hook( fd, offset ); + } +} + +/* $RCSfile$: end of file */ diff --git a/mingwrt/msvcrt-xref/msvcrt.def.in b/mingwrt/msvcrt-xref/msvcrt.def.in --- a/mingwrt/msvcrt-xref/msvcrt.def.in +++ b/mingwrt/msvcrt-xref/msvcrt.def.in @@ -654,11 +654,11 @@ EXPORTS #endif _chmod _chsize #if __MSVCRT_VERSION__ >= 0x0600UL # if __MSVCRT_VERSION__ < 0x07000000UL || __MSVCRT_VERSION__ >= 0x08000000UL -_chsize_s +__MINGW_DLSYM(_chsize_s) # endif #endif #if __MSVCRT_VERSION__ >= 0x0600UL # if __MSVCRT_VERSION__ < 0x07000000UL _chvalidator