Commit e55924ad authored by Martin Blix Grydeland's avatar Martin Blix Grydeland

Add a VFIL_allocate function

This function makes sure that the filesystem can accomodate the file
of the given size.

Checks the filesystem free space up against the allocated blocks as a
sanity check.

Uses fallocate if available to preallocate the needed blocks.

If fallocate isn't available, it will write zero bytes if insist is true.
parent f769dd1c
......@@ -216,6 +216,7 @@ AC_CHECK_FUNCS([getdtablesize])
AC_CHECK_FUNCS([timegm])
AC_CHECK_FUNCS([nanosleep])
AC_CHECK_FUNCS([setppriv])
AC_CHECK_FUNCS([fallocate])
save_LIBS="${LIBS}"
LIBS="${PTHREAD_LIBS}"
......
......@@ -35,3 +35,4 @@ char *VFIL_readfile(const char *pfx, const char *fn, ssize_t *sz);
char *VFIL_readfd(int fd, ssize_t *sz);
int VFIL_nonblocking(int fd);
int VFIL_fsinfo(int fd, unsigned *pbs, uintmax_t *size, uintmax_t *space);
int VFIL_allocate(int fd, off_t size, int insist);
......@@ -39,6 +39,7 @@
#include <time.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#ifdef HAVE_SYS_MOUNT_H
# include <sys/param.h>
......@@ -187,3 +188,55 @@ VFIL_fsinfo(int fd, unsigned *pbs, uintmax_t *psize, uintmax_t *pspace)
*pspace = space;
return (0);
}
/* Make sure that the file system can accomodate the file of the given
* size. Will use fallocate if available. If fallocate is not available
* and insist is true, it will write size zero bytes.
*
* Returns 0 on success, -1 on failure with errno set.
*/
int
VFIL_allocate(int fd, off_t size, int insist)
{
struct stat st;
uintmax_t fsspace;
size_t l;
ssize_t l2;
char buf[64 * 1024];
if (ftruncate(fd, size))
return (-1);
if (fstat(fd, &st))
return (-1);
if (VFIL_fsinfo(fd, NULL, NULL, &fsspace))
return (-1);
if ((st.st_blocks * 512) + fsspace < size) {
/* Sum of currently allocated blocks and available space
is less than requested size */
errno = ENOSPC;
return (-1);
}
#ifdef HAVE_FALLOCATE
if (!fallocate(fd, 0, 0, size))
return (0);
if (errno == ENOSPC)
return (-1);
#endif
if (!insist)
return (0);
/* Write size zero bytes to make sure the entire file is allocated
in the file system */
memset(buf, 0, sizeof buf);
assert(lseek(fd, 0, SEEK_SET) == 0);
for (l = 0; l < size; l += l2) {
l2 = sizeof buf;
if (l + l2 > size)
l2 = size - l;
l2 = write(fd, buf, l2);
if (l2 < 0)
return (-1);
}
assert(lseek(fd, 0, SEEK_SET) == 0);
return (0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment