Commit 64257713 authored by Kenton Varda's avatar Kenton Varda

Fix Mac: Work around missing syscalls.

parent 8b3feab2
...@@ -192,6 +192,10 @@ private: ...@@ -192,6 +192,10 @@ private:
bool isWine() { return false; } bool isWine() { return false; }
#if __APPLE__
#define HOLES_NOT_SUPPORTED 1
#endif
static Own<File> newTempFile() { static Own<File> newTempFile() {
char filename[] = "/var/tmp/kj-filesystem-test.XXXXXX"; char filename[] = "/var/tmp/kj-filesystem-test.XXXXXX";
int fd; int fd;
......
...@@ -63,6 +63,11 @@ namespace { ...@@ -63,6 +63,11 @@ namespace {
#define MAYBE_O_DIRECTORY 0 #define MAYBE_O_DIRECTORY 0
#endif #endif
#if __APPLE__
// Mac OSX defines SEEK_HOLE, but it doesn't work. ("Inappropriate ioctl for device", it says.)
#undef SEEK_HOLE
#endif
static void setCloexec(int fd) KJ_UNUSED; static void setCloexec(int fd) KJ_UNUSED;
static void setCloexec(int fd) { static void setCloexec(int fd) {
// Set the O_CLOEXEC flag on the given fd. // Set the O_CLOEXEC flag on the given fd.
...@@ -119,7 +124,11 @@ static FsNode::Metadata statToMetadata(struct stat& stats) { ...@@ -119,7 +124,11 @@ static FsNode::Metadata statToMetadata(struct stat& stats) {
modeToType(stats.st_mode), modeToType(stats.st_mode),
implicitCast<uint64_t>(stats.st_size), implicitCast<uint64_t>(stats.st_size),
implicitCast<uint64_t>(stats.st_blocks * 512u), implicitCast<uint64_t>(stats.st_blocks * 512u),
#if __APPLE__
toKjDate(stats.st_mtimespec),
#else
toKjDate(stats.st_mtim), toKjDate(stats.st_mtim),
#endif
implicitCast<uint>(stats.st_nlink) implicitCast<uint>(stats.st_nlink)
}; };
} }
...@@ -280,8 +289,26 @@ public: ...@@ -280,8 +289,26 @@ public:
return statToMetadata(stats); return statToMetadata(stats);
} }
void sync() { KJ_SYSCALL(fsync(fd)); } void sync() {
void datasync() { KJ_SYSCALL(fdatasync(fd)); } #if __APPLE__
// For whatever reason, fsync() on OSX only flushes kernel buffers. It does not flush hardware
// disk buffers. This makes it not very useful. But OSX documents fcntl F_FULLFSYNC which does
// the right thing. Why they don't just make fsync() do the right thing, I do not know.
KJ_SYSCALL(fcntl(fd, F_FULLFSYNC));
#else
KJ_SYSCALL(fsync(fd));
#endif
}
void datasync() {
// The presence of the _POSIX_SYNCHRONIZED_IO define is supposed to tell us that fdatasync()
// exists. But Apple defines this yet doesn't offer fdatasync(). Thanks, Apple.
#if _POSIX_SYNCHRONIZED_IO && !__APPLE__
KJ_SYSCALL(fdatasync(fd));
#else
this->sync();
#endif
}
// ReadableFile -------------------------------------------------------------- // ReadableFile --------------------------------------------------------------
...@@ -350,9 +377,18 @@ public: ...@@ -350,9 +377,18 @@ public:
} }
#endif #endif
// Use a 4k buffer of zeros amplified by iov to write zeros with as few syscalls as possible.
static const byte ZEROS[4096] = { 0 }; static const byte ZEROS[4096] = { 0 };
#if __APPLE__
// Mac doesn't have pwritev().
while (size > sizeof(ZEROS)) {
write(offset, ZEROS);
size -= sizeof(ZEROS);
offset += sizeof(ZEROS);
}
write(offset, kj::arrayPtr(ZEROS, size));
#else
// Use a 4k buffer of zeros amplified by iov to write zeros with as few syscalls as possible.
size_t count = (size + sizeof(ZEROS) - 1) / sizeof(ZEROS); size_t count = (size + sizeof(ZEROS) - 1) / sizeof(ZEROS);
const size_t iovmax = miniposix::iovMax(count); const size_t iovmax = miniposix::iovMax(count);
KJ_STACK_ARRAY(struct iovec, iov, kj::min(iovmax, count), 16, 256); KJ_STACK_ARRAY(struct iovec, iov, kj::min(iovmax, count), 16, 256);
...@@ -381,6 +417,7 @@ public: ...@@ -381,6 +417,7 @@ public:
offset += n; offset += n;
size -= n; size -= n;
} }
#endif
} }
void truncate(uint64_t size) { void truncate(uint64_t size) {
...@@ -1092,7 +1129,15 @@ public: ...@@ -1092,7 +1129,15 @@ public:
if (S_ISDIR(stats.st_mode)) { if (S_ISDIR(stats.st_mode)) {
return mkdirat(fd, candidatePath.cStr(), 0700); return mkdirat(fd, candidatePath.cStr(), 0700);
} else { } else {
#if __APPLE__
// No mknodat() on OSX, gotta open() a file, ugh.
int newFd = openat(fd, candidatePath.cStr(),
O_RDWR | O_CREAT | O_EXCL | MAYBE_O_CLOEXEC, 0700);
if (newFd >= 0) close(newFd);
return newFd;
#else
return mknodat(fd, candidatePath.cStr(), S_IFREG | 0600, dev_t()); return mknodat(fd, candidatePath.cStr(), S_IFREG | 0600, dev_t());
#endif
} }
})) { })) {
away = kj::mv(*awayPath); away = kj::mv(*awayPath);
......
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