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)
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/>. */
23 /* A native Windows platform. */
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)
39 # define _WIN32_WINNT _WIN32_WINNT_WIN2K
42 /* Get declarations of the native Windows API functions. */
43 # define WIN32_LEAN_AND_MEAN
46 /* Get _get_osfhandle. */
47 # if GNULIB_MSVC_NOTHROW
48 # include "msvc-nothrow.h"
54 SetFileSize (HANDLE h
, LONGLONG size
)
56 LARGE_INTEGER old_size
;
58 if (!GetFileSizeEx (h
, &old_size
))
61 if (size
!= old_size
.QuadPart
)
63 /* Duplicate the handle, so we are free to modify its file position. */
64 HANDLE curr_process
= GetCurrentProcess ();
67 if (!DuplicateHandle (curr_process
, /* SourceProcessHandle */
69 curr_process
, /* TargetProcessHandle */
70 (PHANDLE
) &tmph
, /* TargetHandle */
71 (DWORD
) 0, /* DesiredAccess */
72 FALSE
, /* InheritHandle */
73 DUPLICATE_SAME_ACCESS
)) /* Options */
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
)
87 if (!SetEndOfFile (tmph
))
95 /* Increase the size by adding zero bytes at the end. */
96 static char zero_bytes
[1024];
98 LONG pos_lo
= SetFilePointer (tmph
, (LONG
) 0, &pos_hi
, FILE_END
);
100 if (pos_lo
== INVALID_SET_FILE_POINTER
101 && GetLastError() != NO_ERROR
)
106 pos
= ((LONGLONG
) pos_hi
<< 32) | (ULONGLONG
) (ULONG
) pos_lo
;
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
)
119 pos
+= (ULONGLONG
) (ULONG
) written
;
122 /* Close the handle. */
129 ftruncate (int fd
, off_t length
)
131 HANDLE handle
= (HANDLE
) _get_osfhandle (fd
);
133 if (handle
== INVALID_HANDLE_VALUE
)
143 if (!SetFileSize (handle
, length
))
145 switch (GetLastError ())
147 case ERROR_ACCESS_DENIED
:
150 case ERROR_HANDLE_DISK_FULL
:
151 case ERROR_DISK_FULL
:
152 case ERROR_DISK_TOO_FRAGMENTED
:
168 # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
169 # include "msvc-inval.h"
171 chsize_nothrow (int fd
, long length
)
177 result
= _chsize (fd
, length
);
189 # define chsize_nothrow _chsize
193 ftruncate (int fd
, off_t length
)
195 return chsize_nothrow (fd
, length
);