Blame gl/tests/ftruncate.c

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