Skip to content

Commit

Permalink
Fix raw_fallocate for Android and deal with unsupported filesystems.
Browse files Browse the repository at this point in the history
  • Loading branch information
de-vri-es committed Jun 28, 2018
1 parent cc7fe36 commit 7d713fa
Showing 1 changed file with 71 additions and 21 deletions.
92 changes: 71 additions & 21 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,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)
{
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

# 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.
// 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, 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

}
Expand Down

0 comments on commit 7d713fa

Please sign in to comment.