file-set-size.c revision 54fc3887b43fac7cb0a62babcff6234b9517e302
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef HAVE_CONFIG_H
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen# include "config.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef HAVE_POSIX_FALLOCATE
345212e8f61ebf14ff4f80df26df9e655eb5121eTimo Sirainen# define _XOPEN_SOURCE 600 /* Required by glibc, breaks Solaris 9 */
08b30498acefc69e223baf7eda6429be98cc3a10Timo Sirainen#endif
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define _GNU_SOURCE /* for fallocate() */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen#include "file-set-size.h"
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen#include <unistd.h>
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen#include <fcntl.h>
5363a534097c170ef9cccbdde5ca802f581f5eb7Timo Sirainen#include <sys/stat.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef HAVE_LINUX_FALLOC_H
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen# include <linux/falloc.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint file_set_size(int fd, off_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen#ifdef HAVE_POSIX_FALLOCATE
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen static bool posix_fallocate_supported = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char block[IO_BLOCK_SIZE];
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen off_t offset;
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen ssize_t ret;
d371507847d62ba311b4bcc23d18f45c3d0f1a38Timo Sirainen struct stat st;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen i_assert(size >= 0);
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (fstat(fd, &st) < 0) {
2d3aac5be07b96f72cf0551fac35ac74a4f07770Timo Sirainen i_error("fstat() failed: %m");
2d3aac5be07b96f72cf0551fac35ac74a4f07770Timo Sirainen return -1;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (size < st.st_size) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (ftruncate(fd, size) < 0) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen i_error("ftruncate() failed: %m");
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen return -1;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen }
a205d315b0978985ba77d871f44e4a98273612e6Timo Sirainen return 0;
a205d315b0978985ba77d871f44e4a98273612e6Timo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen if (size == st.st_size)
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen return 0;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen#ifdef HAVE_POSIX_FALLOCATE
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen if (posix_fallocate_supported) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen int err;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen err = posix_fallocate(fd, st.st_size, size - st.st_size);
a6a2b38d806f3ab3198160e39240a8200775e525Timo Sirainen if (err == 0)
a6a2b38d806f3ab3198160e39240a8200775e525Timo Sirainen return 0;
a6a2b38d806f3ab3198160e39240a8200775e525Timo Sirainen
fb2e0bbb7737f3223b16aa41e4b40fb0cd5f288fTimo Sirainen if (err != EINVAL /* Solaris */ &&
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen err != EOPNOTSUPP /* AOX */) {
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen if (!ENOSPACE(err))
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen i_error("posix_fallocate() failed: %m");
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen return -1;
12d34ab79772e0748a1daef30fa749dfe3036608Timo Sirainen }
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen /* Not supported by kernel, fallback to writing. */
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen posix_fallocate_supported = FALSE;
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen }
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen#endif
f0569d9fbb25c8437760be69f194595a841ad711Timo Sirainen /* start growing the file */
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen offset = st.st_size;
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen memset(block, 0, I_MIN((ssize_t)sizeof(block), size - offset));
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen while (offset < size) {
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen ret = pwrite(fd, block,
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen I_MIN((ssize_t)sizeof(block), size - offset),
abe8230dd1dd37d7ccf0163100e934bb5e658c20Timo Sirainen offset);
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (ret < 0) {
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (!ENOSPACE(errno))
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen i_error("pwrite() failed: %m");
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return -1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen }
821984ecb6c90696f35c32a8dc4c8a60f9e98f99Timo Sirainen offset += ret;
821984ecb6c90696f35c32a8dc4c8a60f9e98f99Timo Sirainen }
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen return 0;
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen}
9aa52288a4b53186d81b0ec9afa7d9e0a8ee8753Timo Sirainen
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainenint file_preallocate(int fd ATTR_UNUSED, off_t size ATTR_UNUSED)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen{
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_KEEP_SIZE)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen /* Linux */
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen if (fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, size) < 0)
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return errno == ENOSYS ? 0 : -1;
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return 1;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen#else
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen return 0;
e5759add4dc24b96606dccc4a989838e260f2a12Timo Sirainen#endif
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen}
313fe89df4d91cd0cd7f3558dc6d7fd21ad39eeeTimo Sirainen