Skip to content

Commit

Permalink
Merge pull request #2363 from fizyr-forks/fallocate-fallbacks
Browse files Browse the repository at this point in the history
Fix raw_fallocate for Android and deal with unsupported filesystems.
  • Loading branch information
SergioRAgostinho authored Aug 26, 2018
2 parents 540cae5 + 713cd70 commit 5b89b76
Showing 1 changed file with 74 additions and 24 deletions.
98 changes: 74 additions & 24 deletions io/include/pcl/io/low_level_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ typedef SSIZE_T ssize_t;
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/fcntl.h>
# include <cerrno>
#endif

namespace pcl
Expand Down Expand Up @@ -97,9 +98,15 @@ 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);
return ::_chsize(fd, length);
}

inline int raw_fallocate(int fd, long length)
{
// Doesn't actually allocate, but best we can do?
return raw_ftruncate(fd, length);
}
#else
inline int raw_open(const char * pathname, int flags, int mode)
Expand Down Expand Up @@ -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
inline int raw_fallocate(int fd, off_t len)

# ifdef __APPLE__
inline int raw_fallocate(int fd, off_t length)
{
// 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__
::fstore_t store = {F_ALLOCATEALL | F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, length};
if (::fcntl(fd, F_PREALLOCATE, &store) != -1)
return raw_ftruncate(fd, length);

// Try fragmented if it failed.
store.fst_flags = F_ALLOCATEALL;
if (::fcntl(fd, F_PREALLOCATE, &store) != -1)
return raw_ftruncate(fd, length);

// Fragmented also failed.
return -1;
}

# else // __APPLE__
inline int raw_fallocate(int fd, off_t length)
{
# ifdef ANDROID
// Android's libc doesn't have posix_fallocate.
if (::fallocate(fd, 0, 0, length) == 0)
return 0;
# else
// Conforming POSIX systems have posix_fallocate.
if (::posix_fallocate(fd, 0, length) == 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.
// Writes 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, length - 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

}
Expand Down

0 comments on commit 5b89b76

Please sign in to comment.