maint: update copyright
[gnulib.git] / lib / ftruncate.c
1 /* ftruncate emulations for native Windows.
2    Copyright (C) 1992-2014 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
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
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
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
182 ftruncate (int fd, off_t length)
183 {
184   return chsize (fd, length);
185 }
186
187 # endif
188 #endif