openat: don’t close (-1)
[gnulib.git] / lib / ftruncate.c
blob29a5ae96c515746c3cbfab4cef9a0974f1bffe7b
1 /* ftruncate emulations for native Windows.
2 Copyright (C) 1992-2024 Free Software Foundation, Inc.
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.
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.
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/>. */
17 #include <config.h>
19 /* Specification. */
20 #include <unistd.h>
22 #if HAVE__CHSIZE
23 /* A native Windows platform. */
25 # include <errno.h>
27 /* We need to test _FILE_OFFSET_BITS for mingw-w64
28 and _GL_WINDOWS_64_BIT_OFF_T for MSVC. */
29 # if (_FILE_OFFSET_BITS == 64 || _GL_WINDOWS_64_BIT_OFF_T)
31 /* Large File Support: off_t is 64-bit, but _chsize() takes only a 32-bit
32 argument. Some newer versions of the Windows CRT have a _chsize_s function
33 that takes a 64-bit argument, but we cannot rely on that.
34 So, define a 64-bit safe SetFileSize function ourselves. */
36 /* Ensure that <windows.h> declares GetFileSizeEx. */
37 # if !defined _WIN32_WINNT || (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
38 # undef _WIN32_WINNT
39 # define _WIN32_WINNT _WIN32_WINNT_WIN2K
40 # endif
42 /* Get declarations of the native Windows API functions. */
43 # define WIN32_LEAN_AND_MEAN
44 # include <windows.h>
46 /* Get _get_osfhandle. */
47 # if GNULIB_MSVC_NOTHROW
48 # include "msvc-nothrow.h"
49 # else
50 # include <io.h>
51 # endif
53 static BOOL
54 SetFileSize (HANDLE h, LONGLONG size)
56 LARGE_INTEGER old_size;
58 if (!GetFileSizeEx (h, &old_size))
59 return FALSE;
61 if (size != old_size.QuadPart)
63 /* Duplicate the handle, so we are free to modify its file position. */
64 HANDLE curr_process = GetCurrentProcess ();
65 HANDLE tmph;
67 if (!DuplicateHandle (curr_process, /* SourceProcessHandle */
68 h, /* SourceHandle */
69 curr_process, /* TargetProcessHandle */
70 (PHANDLE) &tmph, /* TargetHandle */
71 (DWORD) 0, /* DesiredAccess */
72 FALSE, /* InheritHandle */
73 DUPLICATE_SAME_ACCESS)) /* Options */
74 return FALSE;
76 if (size < old_size.QuadPart)
78 /* Reduce the size. */
79 LONG size_hi = (LONG) (size >> 32);
80 if (SetFilePointer (tmph, (LONG) size, &size_hi, FILE_BEGIN)
81 == INVALID_SET_FILE_POINTER
82 && GetLastError() != NO_ERROR)
84 CloseHandle (tmph);
85 return FALSE;
87 if (!SetEndOfFile (tmph))
89 CloseHandle (tmph);
90 return FALSE;
93 else
95 /* Increase the size by adding zero bytes at the end. */
96 static char zero_bytes[1024];
97 LONG pos_hi = 0;
98 LONG pos_lo = SetFilePointer (tmph, (LONG) 0, &pos_hi, FILE_END);
99 LONGLONG pos;
100 if (pos_lo == INVALID_SET_FILE_POINTER
101 && GetLastError() != NO_ERROR)
103 CloseHandle (tmph);
104 return FALSE;
106 pos = ((LONGLONG) pos_hi << 32) | (ULONGLONG) (ULONG) pos_lo;
107 while (pos < size)
109 DWORD written;
110 LONGLONG count = size - pos;
111 if (count > sizeof (zero_bytes))
112 count = sizeof (zero_bytes);
113 if (!WriteFile (tmph, zero_bytes, (DWORD) count, &written, NULL)
114 || written == 0)
116 CloseHandle (tmph);
117 return FALSE;
119 pos += (ULONGLONG) (ULONG) written;
122 /* Close the handle. */
123 CloseHandle (tmph);
125 return TRUE;
129 ftruncate (int fd, off_t length)
131 HANDLE handle = (HANDLE) _get_osfhandle (fd);
133 if (handle == INVALID_HANDLE_VALUE)
135 errno = EBADF;
136 return -1;
138 if (length < 0)
140 errno = EINVAL;
141 return -1;
143 if (!SetFileSize (handle, length))
145 switch (GetLastError ())
147 case ERROR_ACCESS_DENIED:
148 errno = EACCES;
149 break;
150 case ERROR_HANDLE_DISK_FULL:
151 case ERROR_DISK_FULL:
152 case ERROR_DISK_TOO_FRAGMENTED:
153 errno = ENOSPC;
154 break;
155 default:
156 errno = EIO;
157 break;
159 return -1;
161 return 0;
164 # else
166 # include <io.h>
168 # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
169 # include "msvc-inval.h"
170 static int
171 chsize_nothrow (int fd, long length)
173 int result;
175 TRY_MSVC_INVAL
177 result = _chsize (fd, length);
179 CATCH_MSVC_INVAL
181 result = -1;
182 errno = EBADF;
184 DONE_MSVC_INVAL;
186 return result;
188 # else
189 # define chsize_nothrow _chsize
190 # endif
193 ftruncate (int fd, off_t length)
195 return chsize_nothrow (fd, length);
198 # endif
199 #endif