(root)/
sed-4.9/
gnulib-tests/
ftruncate.c
       1  /* ftruncate emulations for native Windows.
       2     Copyright (C) 1992-2022 Free Software Foundation, Inc.
       3  
       4     This program is free software; you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation, either version 3, or (at your option)
       7     any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License along
      15     with this program; if not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  /* Specification.  */
      20  #include <unistd.h>
      21  
      22  #if HAVE__CHSIZE
      23  /* A native Windows platform.  */
      24  
      25  # include <errno.h>
      26  
      27  # if _GL_WINDOWS_64_BIT_OFF_T
      28  
      29  /* Large File Support: off_t is 64-bit, but _chsize() takes only a 32-bit
      30     argument.  So, define a 64-bit safe SetFileSize function ourselves.  */
      31  
      32  /* Ensure that <windows.h> declares GetFileSizeEx.  */
      33  #  if !defined _WIN32_WINNT || (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
      34  #   undef _WIN32_WINNT
      35  #   define _WIN32_WINNT _WIN32_WINNT_WIN2K
      36  #  endif
      37  
      38  /* Get declarations of the native Windows API functions.  */
      39  #  define WIN32_LEAN_AND_MEAN
      40  #  include <windows.h>
      41  
      42  /* Get _get_osfhandle.  */
      43  #  if GNULIB_MSVC_NOTHROW
      44  #   include "msvc-nothrow.h"
      45  #  else
      46  #   include <io.h>
      47  #  endif
      48  
      49  static BOOL
      50  SetFileSize (HANDLE h, LONGLONG size)
      51  {
      52    LARGE_INTEGER old_size;
      53  
      54    if (!GetFileSizeEx (h, &old_size))
      55      return FALSE;
      56  
      57    if (size != old_size.QuadPart)
      58      {
      59        /* Duplicate the handle, so we are free to modify its file position.  */
      60        HANDLE curr_process = GetCurrentProcess ();
      61        HANDLE tmph;
      62  
      63        if (!DuplicateHandle (curr_process,           /* SourceProcessHandle */
      64                              h,                      /* SourceHandle */
      65                              curr_process,           /* TargetProcessHandle */
      66                              (PHANDLE) &tmph,        /* TargetHandle */
      67                              (DWORD) 0,              /* DesiredAccess */
      68                              FALSE,                  /* InheritHandle */
      69                              DUPLICATE_SAME_ACCESS)) /* Options */
      70          return FALSE;
      71  
      72        if (size < old_size.QuadPart)
      73          {
      74            /* Reduce the size.  */
      75            LONG size_hi = (LONG) (size >> 32);
      76            if (SetFilePointer (tmph, (LONG) size, &size_hi, FILE_BEGIN)
      77                == INVALID_SET_FILE_POINTER
      78                && GetLastError() != NO_ERROR)
      79              {
      80                CloseHandle (tmph);
      81                return FALSE;
      82              }
      83            if (!SetEndOfFile (tmph))
      84              {
      85                CloseHandle (tmph);
      86                return FALSE;
      87              }
      88          }
      89        else
      90          {
      91            /* Increase the size by adding zero bytes at the end.  */
      92            static char zero_bytes[1024];
      93            LONG pos_hi = 0;
      94            LONG pos_lo = SetFilePointer (tmph, (LONG) 0, &pos_hi, FILE_END);
      95            LONGLONG pos;
      96            if (pos_lo == INVALID_SET_FILE_POINTER
      97                && GetLastError() != NO_ERROR)
      98              {
      99                CloseHandle (tmph);
     100                return FALSE;
     101              }
     102            pos = ((LONGLONG) pos_hi << 32) | (ULONGLONG) (ULONG) pos_lo;
     103            while (pos < size)
     104              {
     105                DWORD written;
     106                LONGLONG count = size - pos;
     107                if (count > sizeof (zero_bytes))
     108                  count = sizeof (zero_bytes);
     109                if (!WriteFile (tmph, zero_bytes, (DWORD) count, &written, NULL)
     110                    || written == 0)
     111                  {
     112                    CloseHandle (tmph);
     113                    return FALSE;
     114                  }
     115                pos += (ULONGLONG) (ULONG) written;
     116              }
     117          }
     118        /* Close the handle.  */
     119        CloseHandle (tmph);
     120      }
     121    return TRUE;
     122  }
     123  
     124  int
     125  ftruncate (int fd, off_t length)
     126  {
     127    HANDLE handle = (HANDLE) _get_osfhandle (fd);
     128  
     129    if (handle == INVALID_HANDLE_VALUE)
     130      {
     131        errno = EBADF;
     132        return -1;
     133      }
     134    if (length < 0)
     135      {
     136        errno = EINVAL;
     137        return -1;
     138      }
     139    if (!SetFileSize (handle, length))
     140      {
     141        switch (GetLastError ())
     142          {
     143          case ERROR_ACCESS_DENIED:
     144            errno = EACCES;
     145            break;
     146          case ERROR_HANDLE_DISK_FULL:
     147          case ERROR_DISK_FULL:
     148          case ERROR_DISK_TOO_FRAGMENTED:
     149            errno = ENOSPC;
     150            break;
     151          default:
     152            errno = EIO;
     153            break;
     154          }
     155        return -1;
     156      }
     157    return 0;
     158  }
     159  
     160  # else
     161  
     162  #  include <io.h>
     163  
     164  #  if HAVE_MSVC_INVALID_PARAMETER_HANDLER
     165  #   include "msvc-inval.h"
     166  static int
     167  chsize_nothrow (int fd, long length)
     168  {
     169    int result;
     170  
     171    TRY_MSVC_INVAL
     172      {
     173        result = _chsize (fd, length);
     174      }
     175    CATCH_MSVC_INVAL
     176      {
     177        result = -1;
     178        errno = EBADF;
     179      }
     180    DONE_MSVC_INVAL;
     181  
     182    return result;
     183  }
     184  #  else
     185  #   define chsize_nothrow _chsize
     186  #  endif
     187  
     188  int
     189  ftruncate (int fd, off_t length)
     190  {
     191    return chsize_nothrow (fd, length);
     192  }
     193  
     194  # endif
     195  #endif