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