Blame gnulib-tests/ftruncate.c

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