Blame support/support_descriptor_supports_holes.c

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