Blame gl/tests/ftruncate.c

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