Blame gnulib-tests/ftruncate.c

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