Blame support/support_descriptor_supports_holes.c

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