file_create (const char *name, int fd,
             off_t st_size, bool is_block, direction d)
{
  struct rw_file *rwf = calloc (1, sizeof *rwf);
  if (rwf == NULL) { perror ("calloc"); exit (EXIT_FAILURE); }

  rwf->rw.ops = &file_ops;
  rwf->rw.name = name;
  rwf->fd = fd;
  rwf->is_block = is_block;

  if (is_block) {
    /* Block device - ignore size passed in. */
    rwf->rw.size = lseek (fd, 0, SEEK_END);
    if (rwf->rw.size == -1) {
      perror ("lseek");
      exit (EXIT_FAILURE);
    }
    if (lseek (fd, 0, SEEK_SET) == -1) {
      perror ("lseek");
      exit (EXIT_FAILURE);
    }
    rwf->seek_hole_supported = seek_hole_supported (fd);
    rwf->sector_size = 4096;
#ifdef BLKSSZGET
    if (ioctl (fd, BLKSSZGET, &rwf->sector_size))
      fprintf (stderr, "warning: cannot get sector size: %s: %m", name);
#endif
    /* Possible efficient zero methods for block device. */
#ifdef FALLOC_FL_PUNCH_HOLE
    rwf->can_punch_hole = true;
#endif
#ifdef FALLOC_FL_ZERO_RANGE
    rwf->can_zero_range = true;
#endif
#ifdef BLKZEROOUT
    rwf->can_zeroout = true;
#endif
  }
  else {
    /* Regular file. */
    rwf->rw.size = st_size;
    rwf->seek_hole_supported = seek_hole_supported (fd);
    /* Possible efficient zero methods for regular file. */
#ifdef FALLOC_FL_PUNCH_HOLE
    rwf->can_punch_hole = true;
#endif
#ifdef FALLOC_FL_ZERO_RANGE
    rwf->can_zero_range = true;
#endif
    rwf->can_fallocate = true;
  }

  /* Set the POSIX_FADV_SEQUENTIAL flag on the file descriptor, but
   * don't fail.
   */
#if defined (HAVE_POSIX_FADVISE) && defined (POSIX_FADV_SEQUENTIAL)
  posix_fadvise (fd, 0, 0, POSIX_FADV_SEQUENTIAL);
#endif

#if PAGE_CACHE_MAPPING
  if (d == READING)
    page_cache_map (rwf);
#endif

  return &rwf->rw;
}
file_create (const char *name, int fd,
             off_t st_size, bool is_block, direction d)
{
  struct rw_file *rwf = calloc (1, sizeof *rwf);
  if (rwf == NULL) { perror ("calloc"); exit (EXIT_FAILURE); }

  rwf->rw.ops = &file_ops;
  rwf->rw.name = name;
  rwf->fd = fd;
  rwf->is_block = is_block;

  if (is_block) {
     
    rwf->rw.size = lseek (fd, 0, SEEK_END);
    if (rwf->rw.size == -1) {
      perror ("lseek");
      exit (EXIT_FAILURE);
    }
    if (lseek (fd, 0, SEEK_SET) == -1) {
      perror ("lseek");
      exit (EXIT_FAILURE);
    }
    rwf->seek_hole_supported = seek_hole_supported (fd);
    rwf->sector_size = 4096;
#ifdef BLKSSZGET
    if (ioctl (fd, BLKSSZGET, &rwf->sector_size))
      fprintf (stderr, "warning: cannot get sector size: %s: %m", name);
#endif
     
#ifdef FALLOC_FL_PUNCH_HOLE
    rwf->can_punch_hole = true;
#endif
#ifdef FALLOC_FL_ZERO_RANGE
    rwf->can_zero_range = true;
#endif
#ifdef BLKZEROOUT
    rwf->can_zeroout = true;
#endif
  }
  else {
     
    rwf->rw.size = st_size;
    rwf->seek_hole_supported = seek_hole_supported (fd);
     
#ifdef FALLOC_FL_PUNCH_HOLE
    rwf->can_punch_hole = true;
#endif
#ifdef FALLOC_FL_ZERO_RANGE
    rwf->can_zero_range = true;
#endif
    rwf->can_fallocate = true;
  }

   
#if defined (HAVE_POSIX_FADVISE) && defined (POSIX_FADV_SEQUENTIAL)
  posix_fadvise (fd, 0, 0, POSIX_FADV_SEQUENTIAL);
#endif

#if PAGE_CACHE_MAPPING
  if (d == READING)
    page_cache_map (rwf);
#endif

  return &rwf->rw;
}