Blame support/support_descriptor_supports_holes.c

Packit Service d34d2f
/* Test for file system hole support.
Packit Service d34d2f
   Copyright (C) 2018 Free Software Foundation, Inc.
Packit Service d34d2f
   This file is part of the GNU C Library.
Packit Service d34d2f
Packit Service d34d2f
   The GNU C Library is free software; you can redistribute it and/or
Packit Service d34d2f
   modify it under the terms of the GNU Lesser General Public
Packit Service d34d2f
   License as published by the Free Software Foundation; either
Packit Service d34d2f
   version 2.1 of the License, or (at your option) any later version.
Packit Service d34d2f
Packit Service d34d2f
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service d34d2f
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service d34d2f
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service d34d2f
   Lesser General Public License for more details.
Packit Service d34d2f
Packit Service d34d2f
   You should have received a copy of the GNU Lesser General Public
Packit Service d34d2f
   License along with the GNU C Library; if not, see
Packit Service d34d2f
   <http://www.gnu.org/licenses/>.  */
Packit Service d34d2f
Packit Service d34d2f
#include <stdbool.h>
Packit Service d34d2f
#include <support.h>
Packit Service d34d2f
#include <support/check.h>
Packit Service d34d2f
#include <sys/stat.h>
Packit Service d34d2f
#include <xunistd.h>
Packit Service d34d2f
Packit Service d34d2f
int
Packit Service d34d2f
support_descriptor_supports_holes (int fd)
Packit Service d34d2f
{
Packit Service d34d2f
  enum
Packit Service d34d2f
    {
Packit Service d34d2f
      /* Write offset for the enlarged file.  This value is arbitrary
Packit Service d34d2f
         and hopefully large enough to trigger the creation of holes.
Packit Service d34d2f
         We cannot use the file system block size as a reference here
Packit Service d34d2f
         because it is incorrect for network file systems.  */
Packit Service d34d2f
      write_offset = 16 * 1024 * 1024,
Packit Service d34d2f
Packit Service d34d2f
      /* Our write may add this number of additional blocks (see
Packit Service d34d2f
         block_limit below).  */
Packit Service d34d2f
      block_headroom = 8,
Packit Service d34d2f
    };
Packit Service d34d2f
Packit Service d34d2f
  struct stat64 st;
Packit Service d34d2f
  xfstat (fd, &st);
Packit Service d34d2f
  if (!S_ISREG (st.st_mode))
Packit Service d34d2f
    FAIL_EXIT1 ("descriptor %d does not refer to a regular file", fd);
Packit Service d34d2f
  if (st.st_size != 0)
Packit Service d34d2f
    FAIL_EXIT1 ("descriptor %d does not refer to an empty file", fd);
Packit Service d34d2f
  if (st.st_blocks > block_headroom)
Packit Service d34d2f
    FAIL_EXIT1 ("descriptor %d refers to a pre-allocated file (%lld blocks)",
Packit Service d34d2f
                fd, (long long int) st.st_blocks);
Packit Service d34d2f
Packit Service d34d2f
  /* Write a single byte at the start of the file to compute the block
Packit Service d34d2f
     usage for a single byte.  */
Packit Service d34d2f
  xlseek (fd, 0, SEEK_SET);
Packit Service d34d2f
  char b = '@';
Packit Service d34d2f
  xwrite (fd, &b, 1);
Packit Service d34d2f
  /* Attempt to bypass delayed allocation.  */
Packit Service d34d2f
  TEST_COMPARE (fsync (fd), 0);
Packit Service d34d2f
  xfstat (fd, &st);
Packit Service d34d2f
Packit Service d34d2f
  /* This limit is arbitrary.  The file system needs to store
Packit Service d34d2f
     somewhere that data exists at the write offset, and this may
Packit Service d34d2f
     moderately increase the number of blocks used by the file, in
Packit Service d34d2f
     proportion to the initial block count, but not in proportion to
Packit Service d34d2f
     the write offset.  */
Packit Service d34d2f
  unsigned long long int block_limit = 2 * st.st_blocks + block_headroom;
Packit Service d34d2f
Packit Service d34d2f
  /* Write a single byte at 16 megabytes.  */
Packit Service d34d2f
  xlseek (fd, write_offset, SEEK_SET);
Packit Service d34d2f
  xwrite (fd, &b, 1);
Packit Service d34d2f
  /* Attempt to bypass delayed allocation.  */
Packit Service d34d2f
  TEST_COMPARE (fsync (fd), 0);
Packit Service d34d2f
  xfstat (fd, &st);
Packit Service d34d2f
  bool supports_holes = st.st_blocks <= block_limit;
Packit Service d34d2f
Packit Service d34d2f
  /* Also check that extending the file does not fill up holes.  */
Packit Service d34d2f
  xftruncate (fd, 2 * write_offset);
Packit Service d34d2f
  /* Attempt to bypass delayed allocation.  */
Packit Service d34d2f
  TEST_COMPARE (fsync (fd), 0);
Packit Service d34d2f
  xfstat (fd, &st);
Packit Service d34d2f
  supports_holes = supports_holes && st.st_blocks <= block_limit;
Packit Service d34d2f
Packit Service d34d2f
  /* Return to a zero-length file.  */
Packit Service d34d2f
  xftruncate (fd, 0);
Packit Service d34d2f
  xlseek (fd, 0, SEEK_SET);
Packit Service d34d2f
Packit Service d34d2f
  return supports_holes;
Packit Service d34d2f
}