1 /* ftruncate emulations for native Windows.
2 Copyright (C) 1992-2013 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 <http://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 0x500
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 # include "msvc-nothrow.h"
42
43 static BOOL
SetFileSize(HANDLE h,LONGLONG size)44 SetFileSize (HANDLE h, LONGLONG size)
45 {
46 LARGE_INTEGER old_size;
47
48 if (!GetFileSizeEx (h, &old_size))
49 return FALSE;
50
51 if (size != old_size.QuadPart)
52 {
53 /* Duplicate the handle, so we are free to modify its file position. */
54 HANDLE curr_process = GetCurrentProcess ();
55 HANDLE tmph;
56
57 if (!DuplicateHandle (curr_process, /* SourceProcessHandle */
58 h, /* SourceHandle */
59 curr_process, /* TargetProcessHandle */
60 (PHANDLE) &tmph, /* TargetHandle */
61 (DWORD) 0, /* DesiredAccess */
62 FALSE, /* InheritHandle */
63 DUPLICATE_SAME_ACCESS)) /* Options */
64 return FALSE;
65
66 if (size < old_size.QuadPart)
67 {
68 /* Reduce the size. */
69 LONG size_hi = (LONG) (size >> 32);
70 if (SetFilePointer (tmph, (LONG) size, &size_hi, FILE_BEGIN)
71 == INVALID_SET_FILE_POINTER
72 && GetLastError() != NO_ERROR)
73 {
74 CloseHandle (tmph);
75 return FALSE;
76 }
77 if (!SetEndOfFile (tmph))
78 {
79 CloseHandle (tmph);
80 return FALSE;
81 }
82 }
83 else
84 {
85 /* Increase the size by adding zero bytes at the end. */
86 static char zero_bytes[1024];
87 LONG pos_hi = 0;
88 LONG pos_lo = SetFilePointer (tmph, (LONG) 0, &pos_hi, FILE_END);
89 LONGLONG pos;
90 if (pos_lo == INVALID_SET_FILE_POINTER
91 && GetLastError() != NO_ERROR)
92 {
93 CloseHandle (tmph);
94 return FALSE;
95 }
96 pos = ((LONGLONG) pos_hi << 32) | (ULONGLONG) (ULONG) pos_lo;
97 while (pos < size)
98 {
99 DWORD written;
100 LONGLONG count = size - pos;
101 if (count > sizeof (zero_bytes))
102 count = sizeof (zero_bytes);
103 if (!WriteFile (tmph, zero_bytes, (DWORD) count, &written, NULL)
104 || written == 0)
105 {
106 CloseHandle (tmph);
107 return FALSE;
108 }
109 pos += (ULONGLONG) (ULONG) written;
110 }
111 }
112 /* Close the handle. */
113 CloseHandle (tmph);
114 }
115 return TRUE;
116 }
117
118 int
ftruncate(int fd,off_t length)119 ftruncate (int fd, off_t length)
120 {
121 HANDLE handle = (HANDLE) _get_osfhandle (fd);
122
123 if (handle == INVALID_HANDLE_VALUE)
124 {
125 errno = EBADF;
126 return -1;
127 }
128 if (length < 0)
129 {
130 errno = EINVAL;
131 return -1;
132 }
133 if (!SetFileSize (handle, length))
134 {
135 switch (GetLastError ())
136 {
137 case ERROR_ACCESS_DENIED:
138 errno = EACCES;
139 break;
140 case ERROR_HANDLE_DISK_FULL:
141 case ERROR_DISK_FULL:
142 case ERROR_DISK_TOO_FRAGMENTED:
143 errno = ENOSPC;
144 break;
145 default:
146 errno = EIO;
147 break;
148 }
149 return -1;
150 }
151 return 0;
152 }
153
154 # else
155
156 # include <io.h>
157
158 # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
159 # include "msvc-inval.h"
160 static int
chsize_nothrow(int fd,long length)161 chsize_nothrow (int fd, long length)
162 {
163 int result;
164
165 TRY_MSVC_INVAL
166 {
167 result = chsize (fd, length);
168 }
169 CATCH_MSVC_INVAL
170 {
171 result = -1;
172 errno = EBADF;
173 }
174 DONE_MSVC_INVAL;
175
176 return result;
177 }
178 # define chsize chsize_nothrow
179 # endif
180
181 int
ftruncate(int fd,off_t length)182 ftruncate (int fd, off_t length)
183 {
184 return chsize (fd, length);
185 }
186
187 # endif
188 #endif
189