diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-01-20 10:55:18 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-01-20 10:55:18 +0000 |
commit | 70e9163c9c18e995515598085cb824e554eb7ae7 (patch) | |
tree | a42dc8b2a6c031354bf31472de888bfc8a060132 /lib/ftruncate.c | |
parent | cbf5993c43f49281173f185863577d86bfac6eae (diff) | |
download | coreutils-tarball-70e9163c9c18e995515598085cb824e554eb7ae7.tar.gz |
coreutils-8.25HEADcoreutils-8.25master
Diffstat (limited to 'lib/ftruncate.c')
-rw-r--r-- | lib/ftruncate.c | 212 |
1 files changed, 155 insertions, 57 deletions
diff --git a/lib/ftruncate.c b/lib/ftruncate.c index ff7d11b..1b39c87 100644 --- a/lib/ftruncate.c +++ b/lib/ftruncate.c @@ -1,90 +1,188 @@ -/* ftruncate emulations that work on some System V's. - This file is in the public domain. */ +/* ftruncate emulations for native Windows. + Copyright (C) 1992-2016 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 <http://www.gnu.org/licenses/>. */ #include <config.h> /* Specification. */ #include <unistd.h> -#include <sys/types.h> -#include <fcntl.h> +#if HAVE_CHSIZE +/* A native Windows platform. */ -#ifdef F_CHSIZE +# include <errno.h> -int -ftruncate (int fd, off_t length) -{ - return fcntl (fd, F_CHSIZE, length); -} +# if _GL_WINDOWS_64_BIT_OFF_T -#else /* not F_CHSIZE */ -# ifdef F_FREESP +/* 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. */ -/* By William Kucharski <kucharsk@netcom.com>. */ +/* Ensure that <windows.h> declares GetFileSizeEx. */ +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x500 -# include <sys/stat.h> -# include <errno.h> +/* Get declarations of the native Windows API functions. */ +# define WIN32_LEAN_AND_MEAN +# include <windows.h> -int -ftruncate (int fd, off_t length) +/* Get _get_osfhandle. */ +# include "msvc-nothrow.h" + +static BOOL +SetFileSize (HANDLE h, LONGLONG size) { - struct flock fl; - struct stat filebuf; + LARGE_INTEGER old_size; - if (fstat (fd, &filebuf) < 0) - return -1; + if (!GetFileSizeEx (h, &old_size)) + return FALSE; - if (filebuf.st_size < length) + if (size != old_size.QuadPart) { - /* Extend file length. */ - if (lseek (fd, (length - 1), SEEK_SET) < 0) - return -1; - - /* Write a "0" byte. */ - if (write (fd, "", 1) != 1) - return -1; + /* 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); } - else - { - - /* Truncate length. */ - - fl.l_whence = 0; - fl.l_len = 0; - fl.l_start = length; - fl.l_type = F_WRLCK; /* write lock on file space */ + return TRUE; +} - /* This relies on the *undocumented* F_FREESP argument to fcntl, - which truncates the file so that it ends at the position - indicated by fl.l_start. Will minor miracles never cease? */ +int +ftruncate (int fd, off_t length) +{ + HANDLE handle = (HANDLE) _get_osfhandle (fd); - if (fcntl (fd, F_FREESP, &fl) < 0) - return -1; + 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 /* not F_CHSIZE nor F_FREESP */ -# if HAVE_CHSIZE /* native Windows, e.g. mingw */ +# else -int -ftruncate (int fd, off_t length) +# include <io.h> + +# if HAVE_MSVC_INVALID_PARAMETER_HANDLER +# include "msvc-inval.h" +static int +chsize_nothrow (int fd, long length) { - return chsize (fd, length); -} + int result; -# else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */ + TRY_MSVC_INVAL + { + result = chsize (fd, length); + } + CATCH_MSVC_INVAL + { + result = -1; + errno = EBADF; + } + DONE_MSVC_INVAL; -# include <errno.h> + return result; +} +# define chsize chsize_nothrow +# endif int ftruncate (int fd, off_t length) { - errno = EIO; - return -1; + return chsize (fd, length); } -# endif /* not HAVE_CHSIZE */ -# endif /* not F_FREESP */ -#endif /* not F_CHSIZE */ +# endif +#endif |