From 6232d13f5321b87ddf12a1aa36b4545da45f173d Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Wed, 17 Nov 2021 22:34:57 +0100 Subject: Travel3: Simple image and video display site Reads the images and videos from filesystem and builds a site in memroy. --- src/io.cc | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 src/io.cc (limited to 'src/io.cc') diff --git a/src/io.cc b/src/io.cc new file mode 100644 index 0000000..04e6dfa --- /dev/null +++ b/src/io.cc @@ -0,0 +1,234 @@ +#include "common.hh" + +#include "buffer.hh" +#include "io.hh" +#include "unique_fd.hh" + +#include +#include +#include +#include + +namespace { + +bool mkdirs_internal(int root, std::filesystem::path const& path, mode_t mode, + unique_fd* out) { + if (mkdirat(root, path.c_str(), mode) == 0) { + if (out) + *out = io::openat(root, path, io::open_flags::path | + io::open_flags::directory); + return true; + } + if (errno == EEXIST) { + struct stat buf; + if (fstatat(root, path.c_str(), &buf, 0)) + return false; + if (!S_ISDIR(buf.st_mode)) + return false; + if (out) + *out = io::openat(root, path, + io::open_flags::path | io::open_flags::directory); + return true; + } + if (errno != ENOENT) + return false; + + auto parent = path.parent_path(); + if (parent == path || !parent.has_relative_path()) + return false; + + unique_fd parent_fd; + if (!mkdirs_internal(root, parent, mode, &parent_fd)) + return false; + auto name = path.filename(); + if (mkdirat(parent_fd.get(), name.c_str(), mode)) + return false; + if (out) + *out = io::openat(parent_fd.get(), name, + io::open_flags::path | io::open_flags::directory); + return true; +} + +} // namespace + +namespace io { + +bool read_all(int fd, void* data, size_t size) { + auto* d = reinterpret_cast(data); + size_t offset = 0; + while (offset < size) { + auto got = read(fd, d + offset, size - offset); + if (got < 0) { + if (errno == EINTR) + continue; + return false; + } + if (got == 0) + return false; + offset += got; + } + return true; +} + +bool write_all(int fd, void const* data, size_t size) { + auto* d = reinterpret_cast(data); + size_t offset = 0; + while (offset < size) { + auto wrote = write(fd, d + offset, size - offset); + if (wrote < 0) { + if (errno == EINTR) + continue; + return false; + } + if (wrote == 0) + return false; + offset += wrote; + } + return true; +} + +Return fill(int fd, Buffer* out, size_t buf_request_size, + size_t* bytes) { + if (bytes) + *bytes = 0; + while (true) { + size_t avail; + auto* ptr = out->wbuf(buf_request_size, avail); + if (avail == 0) + return Return::OK; + auto got = read(fd, ptr, avail); + if (got < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) + return Return::OK; + return Return::ERR; + } + if (got == 0) + return Return::CLOSED; + if (bytes) + *bytes += got; + out->wcommit(got); + // No point in trying again, will most likely get EAGAIN or EWOULDBLOCK. + // Might also be because the connection got closed, but we are in no hurry + // to find out so worth the not extra syscall at every read. + if (static_cast(got) < avail) + return Return::OK; + } +} + +bool drain(RoBuffer* in, int fd, size_t* bytes) { + if (bytes) + *bytes = 0; + while (true) { + size_t avail; + auto* ptr = in->rbuf(0, avail); + if (avail == 0) + return true; + auto wrote = write(fd, ptr, avail); + if (wrote < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) + return true; + return false; + } + if (wrote == 0) + return false; + if (bytes) + *bytes += wrote; + in->rcommit(wrote); + // No point in trying again, will most likely get EAGAIN or EWOULDBLOCK + if (static_cast(wrote) < avail) + return true; + } +} + +bool mkdirs(std::filesystem::path const& path, mode_t mode) { + return mkdirs(AT_FDCWD, path, mode); +} + +bool mkdirs(int fd, std::filesystem::path const& path, mode_t mode) { + return mkdirs_internal(fd, path, mode, nullptr); +} + +bool make_nonblocking(int fd) { + int status = fcntl(fd, F_GETFL, 0); + if (status == -1) + return false; + if ((status & O_NONBLOCK) == 0) { + if (fcntl(fd, F_SETFL, status | O_NONBLOCK)) + return false; + } + return true; +} + +unique_fd open(std::filesystem::path const& path, open_flags flags, + std::filesystem::perms perms) { + return openat(AT_FDCWD, path, flags, perms); +} + +unique_fd openat(int fd, std::filesystem::path const& path, open_flags flags, + std::filesystem::perms perms) { + int posix_flags = O_RDONLY; + if ((flags & open_flags::wronly) == open_flags::wronly) + posix_flags |= O_WRONLY; + if ((flags & open_flags::rdwr) == open_flags::rdwr) + posix_flags |= O_RDWR; + if ((flags & open_flags::create) == open_flags::create) + posix_flags |= O_CREAT; + if ((flags & open_flags::excl) == open_flags::excl) + posix_flags |= O_EXCL; + if ((flags & open_flags::trunc) == open_flags::trunc) + posix_flags |= O_TRUNC; + if ((flags & open_flags::append) == open_flags::append) + posix_flags |= O_APPEND; + if ((flags & open_flags::directory) == open_flags::directory) + posix_flags |= O_DIRECTORY; + if ((flags & open_flags::path) == open_flags::path) + posix_flags |= O_PATH; + return unique_fd(::openat(fd, path.c_str(), posix_flags, + static_cast(perms))); +} + +bool close(int fd) { + return ::close(fd) == 0; +} + +ssize_t pread(int fd, void *buf, size_t count, off_t offset) { + return ::pread(fd, buf, count, offset); +} + +ssize_t read(int fd, void *buf, size_t count) { + return ::read(fd, buf, count); +} + +ssize_t write(int fd, const void *buf, size_t count) { + return ::write(fd, buf, count); +} + +bool access(std::filesystem::path const& path, access_mode mode) { + int posix_mode; + if (mode == access_mode::exists) { + posix_mode = F_OK; + } else { + posix_mode = 0; + if ((mode & access_mode::read) == access_mode::read) + posix_mode |= R_OK; + if ((mode & access_mode::write) == access_mode::write) + posix_mode |= W_OK; + if ((mode & access_mode::exec) == access_mode::exec) + posix_mode |= X_OK; + } + return ::access(path.c_str(), posix_mode) == 0; +} + +bool unlinkat(int fd, std::filesystem::path const& path) { + return ::unlinkat(fd, path.c_str(), 0) == 0; +} + +bool fallocate(int fd, off_t offset, off_t len) { + return posix_fallocate(fd, offset, len) == 0; +} + +} // namespace io -- cgit v1.2.3-70-g09d2