Blame sysdeps/posix/posix_fallocate64.c

Packit Service 82fcde
/* Copyright (C) 2000-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <fcntl.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <stdint.h>
Packit Service 82fcde
#include <sys/fcntl.h>
Packit Service 82fcde
#include <sys/stat.h>
Packit Service 82fcde
#include <sys/statfs.h>
Packit Service 82fcde
Packit Service 82fcde
/* Reserve storage for the data of the file associated with FD.  This
Packit Service 82fcde
   emulation is far from perfect, but the kernel cannot do not much
Packit Service 82fcde
   better for network file systems, either.  */
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
__posix_fallocate64_l64 (int fd, __off64_t offset, __off64_t len)
Packit Service 82fcde
{
Packit Service 82fcde
  struct stat64 st;
Packit Service 82fcde
Packit Service 82fcde
  if (offset < 0 || len < 0)
Packit Service 82fcde
    return EINVAL;
Packit Service 82fcde
Packit Service 82fcde
  /* Perform overflow check.  The outer cast relies on a GCC
Packit Service 82fcde
     extension.  */
Packit Service 82fcde
  if ((__off64_t) ((uint64_t) offset + (uint64_t) len) < 0)
Packit Service 82fcde
    return EFBIG;
Packit Service 82fcde
Packit Service 82fcde
  /* pwrite64 below will not do the right thing in O_APPEND mode.  */
Packit Service 82fcde
  {
Packit Service 82fcde
    int flags = __fcntl (fd, F_GETFL, 0);
Packit Service 82fcde
    if (flags < 0 || (flags & O_APPEND) != 0)
Packit Service 82fcde
      return EBADF;
Packit Service 82fcde
  }
Packit Service 82fcde
Packit Service 82fcde
  /* We have to make sure that this is really a regular file.  */
Packit Service 82fcde
  if (__fxstat64 (_STAT_VER, fd, &st) != 0)
Packit Service 82fcde
    return EBADF;
Packit Service 82fcde
  if (S_ISFIFO (st.st_mode))
Packit Service 82fcde
    return ESPIPE;
Packit Service 82fcde
  if (! S_ISREG (st.st_mode))
Packit Service 82fcde
    return ENODEV;
Packit Service 82fcde
Packit Service 82fcde
  if (len == 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      /* This is racy, but there is no good way to satisfy a
Packit Service 82fcde
	 zero-length allocation request.  */
Packit Service 82fcde
      if (st.st_size < offset)
Packit Service 82fcde
	{
Packit Service 82fcde
	  int ret = __ftruncate64 (fd, offset);
Packit Service 82fcde
Packit Service 82fcde
	  if (ret != 0)
Packit Service 82fcde
	    ret = errno;
Packit Service 82fcde
	  return ret;
Packit Service 82fcde
	}
Packit Service 82fcde
      return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* Minimize data transfer for network file systems, by issuing
Packit Service 82fcde
     single-byte write requests spaced by the file system block size.
Packit Service 82fcde
     (Most local file systems have fallocate support, so this fallback
Packit Service 82fcde
     code is not used there.)  */
Packit Service 82fcde
Packit Service 82fcde
  unsigned increment;
Packit Service 82fcde
  {
Packit Service 82fcde
    struct statfs64 f;
Packit Service 82fcde
Packit Service 82fcde
    if (__fstatfs64 (fd, &f) != 0)
Packit Service 82fcde
      return errno;
Packit Service 82fcde
    if (f.f_bsize == 0)
Packit Service 82fcde
      increment = 512;
Packit Service 82fcde
    else if (f.f_bsize < 4096)
Packit Service 82fcde
      increment = f.f_bsize;
Packit Service 82fcde
    else
Packit Service 82fcde
      /* NFS clients do not propagate the block size of the underlying
Packit Service 82fcde
	 storage and may report a much larger value which would still
Packit Service 82fcde
	 leave holes after the loop below, so we cap the increment at
Packit Service 82fcde
	 4096.  */
Packit Service 82fcde
      increment = 4096;
Packit Service 82fcde
  }
Packit Service 82fcde
Packit Service 82fcde
  /* Write a null byte to every block.  This is racy; we currently
Packit Service 82fcde
     lack a better option.  Compare-and-swap against a file mapping
Packit Service 82fcde
     might address local races, but requires interposition of a signal
Packit Service 82fcde
     handler to catch SIGBUS.  */
Packit Service 82fcde
  for (offset += (len - 1) % increment; len > 0; offset += increment)
Packit Service 82fcde
    {
Packit Service 82fcde
      len -= increment;
Packit Service 82fcde
Packit Service 82fcde
      if (offset < st.st_size)
Packit Service 82fcde
	{
Packit Service 82fcde
	  unsigned char c;
Packit Service 82fcde
	  ssize_t rsize = __libc_pread64 (fd, &c, 1, offset);
Packit Service 82fcde
Packit Service 82fcde
	  if (rsize < 0)
Packit Service 82fcde
	    return errno;
Packit Service 82fcde
	  /* If there is a non-zero byte, the block must have been
Packit Service 82fcde
	     allocated already.  */
Packit Service 82fcde
	  else if (rsize == 1 && c != 0)
Packit Service 82fcde
	    continue;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      if (__libc_pwrite64 (fd, "", 1, offset) != 1)
Packit Service 82fcde
	return errno;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#undef __posix_fallocate64_l64
Packit Service 82fcde
#include <shlib-compat.h>
Packit Service 82fcde
#include <bits/wordsize.h>
Packit Service 82fcde
Packit Service 82fcde
#if __WORDSIZE == 32 && SHLIB_COMPAT(libc, GLIBC_2_2, GLIBC_2_3_3)
Packit Service 82fcde
Packit Service 82fcde
int
Packit Service 82fcde
attribute_compat_text_section
Packit Service 82fcde
__posix_fallocate64_l32 (int fd, off64_t offset, size_t len)
Packit Service 82fcde
{
Packit Service 82fcde
  return __posix_fallocate64_l64 (fd, offset, len);
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
versioned_symbol (libc, __posix_fallocate64_l64, posix_fallocate64,
Packit Service 82fcde
		  GLIBC_2_3_3);
Packit Service 82fcde
compat_symbol (libc, __posix_fallocate64_l32, posix_fallocate64, GLIBC_2_2);
Packit Service 82fcde
#else
Packit Service 82fcde
strong_alias (__posix_fallocate64_l64, posix_fallocate64);
Packit Service 82fcde
#endif