OSDN Git Service

Support GCC-9.x gratuitous dependency on ftruncate64() function.
[mingw/mingw-org-wsl.git] / mingwrt / mingwex / ftruncate.c
1 /*
2  * ftruncate.c
3  *
4  * Implement a 64-bit file size capable ftruncate() function; GCC-9.x
5  * gratuitously assumes that this is available, via the ftruncate64()
6  * entry point.
7  *
8  * $Id$
9  *
10  * Written by Keith Marshall <keith@users.osdn.me>
11  * Copyright (C) 2020, 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 OR
26  * 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 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 #include <dlfcn.h>
35 #include <unistd.h>
36 #include <winbase.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <errno.h>
41
42 /* The following in-line function is provided to facilitate abnormal return
43  * from ftruncate64(), (in which case the return value is always -1), while
44  * setting the global errno indicator to an appropriate error code.
45  */
46 static __inline__ __attribute__((__always_inline__))
47 int errout( int error_code ){ errno = error_code; return -1L; }
48
49 /* When running on Vista, or later, or for applications which have been
50  * linked against non-free MSVCR80.DLL, or later, we may be able to simply
51  * substitute a call to Microsoft's _chsize_s() function, (which behaves
52  * as a 64-bit variant of the universally available _chsize() function).
53  * On legacy Windows versions, which are unlikely to provide _chsize_s(),
54  * we need to provide our own fallback 64-bit chsize() implementation;
55  * this may be static, but cannot be inlined, because we need a physical
56  * entry point address to which execution may be redirected.
57  */
58 static int mingw_chsize64_fallback( int fd, __off64_t offset )
59 {
60   /* POSIX.1 requires the file pointer to be unchanged, as a consequence
61    * of calling ftruncate(), (and Microsoft's _chsize() functions do seem
62    * to satisfy this requirement); however, to mark a new end of file, we
63    * need move the file pointer to the new end of file offset, so we need
64    * to save the original pointer now, to restore later.
65    */
66   __off64_t cur_offset = _lseeki64( fd, 0LL, SEEK_CUR );
67
68   /* In the event that the new end of file offset requires the file to be
69    * extended beyond its current end of file offset, POSIX.1 also requires
70    * NUL byte padding to be written to the extended file space, (and again,
71    * Microsoft's _chsize() functions seem to do this); we may reposition
72    * the file pointer to its current end of file offset, in preparation
73    * for the possibility that we need to fulfil this requirement.
74    */
75   __off64_t end_offset = _lseeki64( fd, 0LL, SEEK_END );
76
77   /* We will eventually need to restore the original file pointer, AFTER
78    * we have evaluated the return status code, so we will need to save
79    * this.
80    */
81   int retval;
82
83   /* There are two possible options for repositioning the end of file
84    * pointer:
85    */
86   if( offset > end_offset )
87   {
88     /* In this case, the file is to be extended beyond its current
89      * end of file offset; initialize a NUL filled buffer, which we
90      * may then copy to the extended region of the file, to satisfy
91      * the POSIX.1 requirement that this region shall be NUL filled.
92      */
93     char padding[BUFSIZ];
94     memset( padding, 0, sizeof( padding ) );
95
96     /* Recompute the desired offset, relative to the current end of
97      * file, then repeatedly write copies of the NUL filled buffer,
98      * until the file space represented by this relative offset has
99      * been completely filled; (this results in advancement of the
100      * file pointer to the desired new end of file offset).
101      */
102     offset -= end_offset;
103     while( offset > (__off64_t)(sizeof( padding )) )
104       offset -= write( fd, padding, sizeof( padding ) );
105     write( fd, padding, offset );
106   }
107   else
108     /* In the alternative case, the new end of file pointer will lie
109      * within the space already occupied by the file; we may simply
110      * seek directly to the desired offset.
111      */
112     _lseeki64( fd, offset, SEEK_SET );
113
114   /* We have now adjusted the file pointer to be coincident with the
115    * desired new end of file offset; this is exactly what is required
116    * by the Windows API function, to mark the new end of file.
117    */
118   retval = SetEndOfFile( (void *)(_get_osfhandle( fd )) )
119     ? 0 : errout( EBADF );
120
121   /* Finally, we must restore the originally saved file pointer, before
122    * we return the status code from the ftruncate() operation.
123    */
124   _lseeki64( fd, cur_offset, SEEK_SET );
125   return retval;
126 }
127
128 /* Regardless of the platform version, Microsoft do not provide an
129  * implementation of ftruncate64(); all link-time references to this
130  * function will be resolved by this libmingwex.a implementation.
131  */
132 int ftruncate64( int fd, __off64_t offset )
133 {
134   /* The offset parameter MUST be positive valued; bail out if not.
135    */
136   if( 0LL > offset ) return errout( EINVAL );
137
138   /* For offsets which may be represented by a 32-bit integer, we
139    * may ALWAYS delegate this call to Microsoft's _chsize().
140    */
141   if( INT32_MAX >= offset ) return _chsize( fd, (off_t)(offset) );
142
143   { /* For offsets which cannot be represented within 32-bits, we
144      * MAY be able to delegate this call, (and also any subsequent
145      * calls), to Microsoft's _chsize_s(); set up a redirector to
146      * handle such delegation...
147      */
148     static int (*redirector_hook)( int, __off64_t ) = NULL;
149
150     /* ...initially checking for _chsize_s() availability...
151      */
152     if(  (redirector_hook == NULL)
153     &&  ((redirector_hook = dlsym( RTLD_DEFAULT, "_chsize_s" )) == NULL)  )
154
155       /* ...and setting up a suitable fallback if not...
156        */
157       redirector_hook = mingw_chsize64_fallback;
158
159     /* ...and ultimately, on initial selection, (and directly on
160      * all subsequent calls), hand off execution to the selected
161      * delegate function.
162      */
163     return redirector_hook( fd, offset );
164   }
165 }
166
167 /* $RCSfile$: end of file */