From 1b269c2dbbc441a138efe5445563a92fac9c1ee2 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Thu, 28 Jun 2018 20:21:46 +0200 Subject: [PATCH] Fix raw_fallocate for Android and deal with unsupported filesystems. --- io/include/pcl/io/low_level_io.h | 92 ++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 21 deletions(-) diff --git a/io/include/pcl/io/low_level_io.h b/io/include/pcl/io/low_level_io.h index 958175b88b0..67f4df2485e 100644 --- a/io/include/pcl/io/low_level_io.h +++ b/io/include/pcl/io/low_level_io.h @@ -60,6 +60,7 @@ typedef SSIZE_T ssize_t; # include # include # include +# include #endif namespace pcl @@ -97,10 +98,16 @@ namespace pcl return ::_write(fd, buffer, count); } - inline int raw_fallocate(int fd, long len) + inline int raw_ftruncate(int fd, long length) { return ::_chsize(fd, len); } + + inline int raw_fallocate(int fd, long len) + { + // Doesn't actually allocate, but best we can do? + return raw_ftruncate(fd, len); + } #else inline int raw_open(const char * pathname, int flags, int mode) { @@ -132,32 +139,75 @@ namespace pcl return ::write(fd, buffer, count); } -# ifndef __APPLE__ - inline int raw_fallocate(int fd, off_t len) + inline int raw_ftruncate(int fd, off_t length) { - return ::posix_fallocate(fd, 0, len); + return ::ftruncate(fd, length); } -# else + +# ifdef __APPLE__ inline int raw_fallocate(int fd, off_t len) { + // OS X doesn't have posix_fallocate, but it has a fcntl that does the job. + // It may make the file too big though, so we truncate before returning. + // Try to allocate contiguous space first. ::fstore_t store = {F_ALLOCATEALL | F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, len}; - if (::fcntl(fd, F_PREALLOCATE, &store) < 0) - { - // Try fragmented if that failed. - store.fst_flags = F_ALLOCATEALL; - int ret = ::fcntl(fd, F_PREALLOCATE, &store); - - // Bail if it still failed. - if (ret < 0) { - return ret; - } - } - - // File could be larger than requested, so truncate. - return ::ftruncate(fd, len); - } -# endif // __APPLE__ + if (::fcntl(fd, F_PREALLOCATE, &store) != -1) + return raw_ftruncate(fd, len); + + // Try fragmented if it failed. + store.fst_flags = F_ALLOCATEALL; + if (::fcntl(fd, F_PREALLOCATE, &store) != -1) + return raw_ftruncate(fd, len); + + // Fragmented also failed. + return -1; + } + +# else // __APPLE__ + inline int raw_fallocate(int fd, off_t len) + { +# ifdef ANDROID + // Android's libc doesn't have posix_fallocate. + if (::fallocate(fd, 0, 0, len) == 0) + return 0; +# else + // Conforming POSIX systems have posix_fallocate. + if (::posix_fallocate(fd, 0, len) == 0) + return 0; +# endif + + // EINVAL should indicate an unsupported filesystem. + // All other errors are passed up. + if (errno != EINVAL) + return -1; + + // Try to deal with unsupported filesystems by simply seeking + writing. + // This may not really allocate space, but the file size will be set. + // Write to the mmapped file may still trigger SIGBUS errors later. + + // Remember the old position and seek to the desired length. + off_t old_pos = raw_lseek(fd, 0, SEEK_CUR); + if (old_pos == -1) + return -1; + if (raw_lseek(fd, len - 1, SEEK_SET) == -1) + return -1; + + // Write a single byte to resize the file. + char buffer = 0; + ssize_t written = raw_write(fd, &buffer, 1); + + // Seek back to the old position. + if (raw_lseek(fd, old_pos, SEEK_SET) == -1) + return -1; + + // Fail if we didn't write exactly one byte, + if (written != 1) + return -1; + + return 0; + } +# endif // __APPLE #endif // _WIN32 }