1 /* ftruncate emulations for native Windows.
2 Copyright (C) 1992-2018 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, see <https://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 /* Specification. */
20 #include <unistd.h>
21
22 #if HAVE_CHSIZE
23 /* A native Windows platform. */
24
25 # include <errno.h>
26
27 # if _GL_WINDOWS_64_BIT_OFF_T
28
29 /* Large File Support: off_t is 64-bit, but chsize() takes only a 32-bit
30 argument. So, define a 64-bit safe SetFileSize function ourselves. */
31
32 /* Ensure that <windows.h> declares GetFileSizeEx. */
33 # undef _WIN32_WINNT
34 # define _WIN32_WINNT _WIN32_WINNT_WIN2K
35
36 /* Get declarations of the native Windows API functions. */
37 # define WIN32_LEAN_AND_MEAN
38 # include <windows.h>
39
40 /* Get _get_osfhandle. */
41 # if GNULIB_MSVC_NOTHROW
42 # include "msvc-nothrow.h"
43 # else
44 # include <io.h>
45 # endif
46
47 static BOOL
SetFileSize(HANDLE h,LONGLONG size)48 SetFileSize (HANDLE h, LONGLONG size)
49 {
50 LARGE_INTEGER old_size;
51
52 if (!GetFileSizeEx (h, &old_size))
53 return FALSE;
54
55 if (size != old_size.QuadPart)
56 {
57 /* Duplicate the handle, so we are free to modify its file position. */
58 HANDLE curr_process = GetCurrentProcess ();
59 HANDLE tmph;
60
61 if (!DuplicateHandle (curr_process, /* SourceProcessHandle */
62 h, /* SourceHandle */
63 curr_process, /* TargetProcessHandle */
64 (PHANDLE) &tmph, /* TargetHandle */
65 (DWORD) 0, /* DesiredAccess */
66 FALSE, /* InheritHandle */
67 DUPLICATE_SAME_ACCESS)) /* Options */
68 return FALSE;
69
70 if (size < old_size.QuadPart)
71 {
72 /* Reduce the size. */
73 LONG size_hi = (LONG) (size >> 32);
74 if (SetFilePointer (tmph, (LONG) size, &size_hi, FILE_BEGIN)
75 == INVALID_SET_FILE_POINTER
76 && GetLastError() != NO_ERROR)
77 {
78 CloseHandle (tmph);
79 return FALSE;
80 }
81 if (!SetEndOfFile (tmph))
82 {
83 CloseHandle (tmph);
84 return FALSE;
85 }
86 }
87 else
88 {
89 /* Increase the size by adding zero bytes at the end. */
90 static char zero_bytes[1024];
91 LONG pos_hi = 0;
92 LONG pos_lo = SetFilePointer (tmph, (LONG) 0, &pos_hi, FILE_END);
93 LONGLONG pos;
94 if (pos_lo == INVALID_SET_FILE_POINTER
95 && GetLastError() != NO_ERROR)
96 {
97 CloseHandle (tmph);
98 return FALSE;
99 }
100 pos = ((LONGLONG) pos_hi << 32) | (ULONGLONG) (ULONG) pos_lo;
101 while (pos < size)
102 {
103 DWORD written;
104 LONGLONG count = size - pos;
105 if (count > sizeof (zero_bytes))
106 count = sizeof (zero_bytes);
107 if (!WriteFile (tmph, zero_bytes, (DWORD) count, &written, NULL)
108 || written == 0)
109 {
110 CloseHandle (tmph);
111 return FALSE;
112 }
113 pos += (ULONGLONG) (ULONG) written;
114 }
115 }
116 /* Close the handle. */
117 CloseHandle (tmph);
118 }
119 return TRUE;
120 }
121
122 int
ftruncate(int fd,off_t length)123 ftruncate (int fd, off_t length)
124 {
125 HANDLE handle = (HANDLE) _get_osfhandle (fd);
126
127 if (handle == INVALID_HANDLE_VALUE)
128 {
129 errno = EBADF;
130 return -1;
131 }
132 if (length < 0)
133 {
134 errno = EINVAL;
135 return -1;
136 }
137 if (!SetFileSize (handle, length))
138 {
139 switch (GetLastError ())
140 {
141 case ERROR_ACCESS_DENIED:
142 errno = EACCES;
143 break;
144 case ERROR_HANDLE_DISK_FULL:
145 case ERROR_DISK_FULL:
146 case ERROR_DISK_TOO_FRAGMENTED:
147 errno = ENOSPC;
148 break;
149 default:
150 errno = EIO;
151 break;
152 }
153 return -1;
154 }
155 return 0;
156 }
157
158 # else
159
160 # include <io.h>
161
162 # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
163 # include "msvc-inval.h"
164 static int
chsize_nothrow(int fd,long length)165 chsize_nothrow (int fd, long length)
166 {
167 int result;
168
169 TRY_MSVC_INVAL
170 {
171 result = chsize (fd, length);
172 }
173 CATCH_MSVC_INVAL
174 {
175 result = -1;
176 errno = EBADF;
177 }
178 DONE_MSVC_INVAL;
179
180 return result;
181 }
182 # else
183 # define chsize_nothrow chsize
184 # endif
185
186 int
ftruncate(int fd,off_t length)187 ftruncate (int fd, off_t length)
188 {
189 return chsize_nothrow (fd, length);
190 }
191
192 # endif
193 #endif
194