|
Packit |
33f14e |
/* ftruncate emulations for native Windows.
|
|
Packit |
33f14e |
Copyright (C) 1992-2017 Free Software Foundation, Inc.
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
33f14e |
it under the terms of the GNU General Public License as published by
|
|
Packit |
33f14e |
the Free Software Foundation; either version 3, or (at your option)
|
|
Packit |
33f14e |
any later version.
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
This program is distributed in the hope that it will be useful,
|
|
Packit |
33f14e |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
33f14e |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
33f14e |
GNU General Public License for more details.
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
You should have received a copy of the GNU General Public License along
|
|
Packit |
33f14e |
with this program; if not, see <http://www.gnu.org/licenses/>. */
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#include <config.h>
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Specification. */
|
|
Packit |
33f14e |
#include <unistd.h>
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
#if HAVE_CHSIZE
|
|
Packit |
33f14e |
/* A native Windows platform. */
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
# include <errno.h>
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
# if _GL_WINDOWS_64_BIT_OFF_T
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Large File Support: off_t is 64-bit, but chsize() takes only a 32-bit
|
|
Packit |
33f14e |
argument. So, define a 64-bit safe SetFileSize function ourselves. */
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Ensure that <windows.h> declares GetFileSizeEx. */
|
|
Packit |
33f14e |
# undef _WIN32_WINNT
|
|
Packit |
33f14e |
# define _WIN32_WINNT _WIN32_WINNT_WIN2K
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Get declarations of the native Windows API functions. */
|
|
Packit |
33f14e |
# define WIN32_LEAN_AND_MEAN
|
|
Packit |
33f14e |
# include <windows.h>
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
/* Get _get_osfhandle. */
|
|
Packit |
33f14e |
# if GNULIB_MSVC_NOTHROW
|
|
Packit |
33f14e |
# include "msvc-nothrow.h"
|
|
Packit |
33f14e |
# else
|
|
Packit |
33f14e |
# include <io.h>
|
|
Packit |
33f14e |
# endif
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
static BOOL
|
|
Packit |
33f14e |
SetFileSize (HANDLE h, LONGLONG size)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
LARGE_INTEGER old_size;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (!GetFileSizeEx (h, &old_size))
|
|
Packit |
33f14e |
return FALSE;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (size != old_size.QuadPart)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* Duplicate the handle, so we are free to modify its file position. */
|
|
Packit |
33f14e |
HANDLE curr_process = GetCurrentProcess ();
|
|
Packit |
33f14e |
HANDLE tmph;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (!DuplicateHandle (curr_process, /* SourceProcessHandle */
|
|
Packit |
33f14e |
h, /* SourceHandle */
|
|
Packit |
33f14e |
curr_process, /* TargetProcessHandle */
|
|
Packit |
33f14e |
(PHANDLE) &tmph, /* TargetHandle */
|
|
Packit |
33f14e |
(DWORD) 0, /* DesiredAccess */
|
|
Packit |
33f14e |
FALSE, /* InheritHandle */
|
|
Packit |
33f14e |
DUPLICATE_SAME_ACCESS)) /* Options */
|
|
Packit |
33f14e |
return FALSE;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (size < old_size.QuadPart)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* Reduce the size. */
|
|
Packit |
33f14e |
LONG size_hi = (LONG) (size >> 32);
|
|
Packit |
33f14e |
if (SetFilePointer (tmph, (LONG) size, &size_hi, FILE_BEGIN)
|
|
Packit |
33f14e |
== INVALID_SET_FILE_POINTER
|
|
Packit |
33f14e |
&& GetLastError() != NO_ERROR)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
CloseHandle (tmph);
|
|
Packit |
33f14e |
return FALSE;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
if (!SetEndOfFile (tmph))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
CloseHandle (tmph);
|
|
Packit |
33f14e |
return FALSE;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
else
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
/* Increase the size by adding zero bytes at the end. */
|
|
Packit |
33f14e |
static char zero_bytes[1024];
|
|
Packit |
33f14e |
LONG pos_hi = 0;
|
|
Packit |
33f14e |
LONG pos_lo = SetFilePointer (tmph, (LONG) 0, &pos_hi, FILE_END);
|
|
Packit |
33f14e |
LONGLONG pos;
|
|
Packit |
33f14e |
if (pos_lo == INVALID_SET_FILE_POINTER
|
|
Packit |
33f14e |
&& GetLastError() != NO_ERROR)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
CloseHandle (tmph);
|
|
Packit |
33f14e |
return FALSE;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
pos = ((LONGLONG) pos_hi << 32) | (ULONGLONG) (ULONG) pos_lo;
|
|
Packit |
33f14e |
while (pos < size)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
DWORD written;
|
|
Packit |
33f14e |
LONGLONG count = size - pos;
|
|
Packit |
33f14e |
if (count > sizeof (zero_bytes))
|
|
Packit |
33f14e |
count = sizeof (zero_bytes);
|
|
Packit |
33f14e |
if (!WriteFile (tmph, zero_bytes, (DWORD) count, &written, NULL)
|
|
Packit |
33f14e |
|| written == 0)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
CloseHandle (tmph);
|
|
Packit |
33f14e |
return FALSE;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
pos += (ULONGLONG) (ULONG) written;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
/* Close the handle. */
|
|
Packit |
33f14e |
CloseHandle (tmph);
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
return TRUE;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
int
|
|
Packit |
33f14e |
ftruncate (int fd, off_t length)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
HANDLE handle = (HANDLE) _get_osfhandle (fd);
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
if (handle == INVALID_HANDLE_VALUE)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
errno = EBADF;
|
|
Packit |
33f14e |
return -1;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
if (length < 0)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
errno = EINVAL;
|
|
Packit |
33f14e |
return -1;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
if (!SetFileSize (handle, length))
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
switch (GetLastError ())
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
case ERROR_ACCESS_DENIED:
|
|
Packit |
33f14e |
errno = EACCES;
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
case ERROR_HANDLE_DISK_FULL:
|
|
Packit |
33f14e |
case ERROR_DISK_FULL:
|
|
Packit |
33f14e |
case ERROR_DISK_TOO_FRAGMENTED:
|
|
Packit |
33f14e |
errno = ENOSPC;
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
default:
|
|
Packit |
33f14e |
errno = EIO;
|
|
Packit |
33f14e |
break;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
return -1;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
return 0;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
# else
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
# include <io.h>
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
# if HAVE_MSVC_INVALID_PARAMETER_HANDLER
|
|
Packit |
33f14e |
# include "msvc-inval.h"
|
|
Packit |
33f14e |
static int
|
|
Packit |
33f14e |
chsize_nothrow (int fd, long length)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
int result;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
TRY_MSVC_INVAL
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
result = chsize (fd, length);
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
CATCH_MSVC_INVAL
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
result = -1;
|
|
Packit |
33f14e |
errno = EBADF;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
DONE_MSVC_INVAL;
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
return result;
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
# else
|
|
Packit |
33f14e |
# define chsize_nothrow chsize
|
|
Packit |
33f14e |
# endif
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
int
|
|
Packit |
33f14e |
ftruncate (int fd, off_t length)
|
|
Packit |
33f14e |
{
|
|
Packit |
33f14e |
return chsize_nothrow (fd, length);
|
|
Packit |
33f14e |
}
|
|
Packit |
33f14e |
|
|
Packit |
33f14e |
# endif
|
|
Packit |
33f14e |
#endif
|