summaryrefslogtreecommitdiff
path: root/ept/utils/sys.h
diff options
context:
space:
mode:
Diffstat (limited to 'ept/utils/sys.h')
-rw-r--r--ept/utils/sys.h468
1 files changed, 468 insertions, 0 deletions
diff --git a/ept/utils/sys.h b/ept/utils/sys.h
new file mode 100644
index 0000000..334c983
--- /dev/null
+++ b/ept/utils/sys.h
@@ -0,0 +1,468 @@
+#ifndef EPT_SYS_H
+#define EPT_SYS_H
+
+/**
+ * @author Enrico Zini <enrico@enricozini.org>
+ * @brief Operating system functions
+ *
+ * Copyright (C) 2007--2015 Enrico Zini <enrico@debian.org>
+ */
+
+#include <string>
+//#include <iosfwd>
+#include <memory>
+#include <iterator>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+namespace ept {
+namespace sys {
+
+/**
+ * stat() the given file and return the struct stat with the results.
+ * If the file does not exist, return NULL.
+ * Raises exceptions in case of errors.
+ */
+std::unique_ptr<struct stat> stat(const std::string& pathname);
+
+/**
+ * stat() the given file filling in the given structure.
+ * Raises exceptions in case of errors, including if the file does not exist.
+ */
+void stat(const std::string& pathname, struct stat& st);
+
+/**
+ * Returns true if the given pathname is a directory, else false.
+ *
+ * It also returns false if the pathname does not exist.
+ */
+bool isdir(const std::string& pathname);
+
+/// Same as isdir but checks for block devices
+bool isblk(const std::string& pathname);
+
+/// Same as isdir but checks for character devices
+bool ischr(const std::string& pathname);
+
+/// Same as isdir but checks for FIFOs
+bool isfifo(const std::string& pathname);
+
+/// Same as isdir but checks for symbolic links
+bool islnk(const std::string& pathname);
+
+/// Same as isdir but checks for regular files
+bool isreg(const std::string& pathname);
+
+/// Same as isdir but checks for sockets
+bool issock(const std::string& pathname);
+
+/// File mtime
+time_t timestamp(const std::string& file);
+
+/// File mtime (or def if the file does not exist)
+time_t timestamp(const std::string& file, time_t def);
+
+/// File size
+size_t size(const std::string& file);
+
+/// File size (or def if the file does not exist)
+size_t size(const std::string& file, size_t def);
+
+/// File inode number
+ino_t inode(const std::string& file);
+
+/// File inode number (or 0 if the file does not exist)
+ino_t inode(const std::string& file, ino_t def);
+
+/// access() a filename
+bool access(const std::string& s, int m);
+
+/// Same as access(s, F_OK);
+bool exists(const std::string& s);
+
+/// Get the absolute path of the current working directory
+std::string getcwd();
+
+/// Get the absolute path of a file
+std::string abspath(const std::string& pathname);
+
+/**
+ * Wraps a mmapped memory area, unmapping it on destruction.
+ *
+ * MMap objects can be used as normal pointers
+ */
+class MMap
+{
+ void* addr;
+ size_t length;
+
+public:
+ MMap(const MMap&) = delete;
+ MMap(MMap&&);
+ MMap(void* addr, size_t length);
+ ~MMap();
+
+ MMap& operator=(const MMap&) = delete;
+ MMap& operator=(MMap&&);
+
+ size_t size() const { return length; }
+
+ void munmap();
+
+ template<typename T>
+ operator const T*() const { return reinterpret_cast<const T*>(addr); }
+
+ template<typename T>
+ operator T*() const { return reinterpret_cast<T*>(addr); };
+};
+
+/**
+ * Common operations on file descriptors.
+ *
+ * Except when documented otherwise, methods of this class are just thin
+ * wrappers around the libc functions with the same name, that check error
+ * results and throw exceptions if the functions failed.
+ *
+ * Implementing what to do on construction and destruction is left to the
+ * subclassers: at the FileDescriptor level, the destructor does nothing and
+ * leaves the file descriptor open.
+ */
+class FileDescriptor
+{
+protected:
+ int fd = -1;
+
+public:
+ FileDescriptor();
+ FileDescriptor(FileDescriptor&& o);
+ FileDescriptor(int fd);
+ virtual ~FileDescriptor();
+
+ /**
+ * Throw an exception based on errno and the given message.
+ *
+ * This can be overridden by subclasses that may have more information
+ * about the file descriptor, so that they can generate more descriptive
+ * messages.
+ */
+ [[noreturn]] virtual void throw_error(const char* desc);
+
+ void close();
+
+ void fstat(struct stat& st);
+ void fchmod(mode_t mode);
+
+ size_t write(const void* buf, size_t count);
+
+ /**
+ * Write all the data in buf, retrying partial writes
+ */
+ void write_all(const void* buf, size_t count);
+
+ MMap mmap(size_t length, int prot, int flags, off_t offset=0);
+
+ operator int() const { return fd; }
+};
+
+
+/**
+ * File descriptor with a name
+ */
+
+class NamedFileDescriptor : public FileDescriptor
+{
+protected:
+ std::string pathname;
+
+public:
+ NamedFileDescriptor(int fd, const std::string& pathname);
+ NamedFileDescriptor(NamedFileDescriptor&&);
+
+ NamedFileDescriptor& operator=(NamedFileDescriptor&&);
+
+ [[noreturn]] virtual void throw_error(const char* desc);
+
+ /// Return the file pathname
+ const std::string& name() const { return pathname; }
+};
+
+/**
+ * Wrap a path on the file system opened with O_PATH
+ */
+struct Path : public NamedFileDescriptor
+{
+ /**
+ * Iterator for directory entries
+ */
+ struct iterator : public std::iterator<std::input_iterator_tag, struct dirent>
+ {
+ Path* path = nullptr;
+ DIR* dir = nullptr;
+ struct dirent* cur_entry = nullptr;
+
+ // End iterator
+ iterator();
+ // Start iteration on dir
+ iterator(Path& dir);
+ iterator(iterator&) = delete;
+ iterator(iterator&& o)
+ : dir(o.dir), cur_entry(o.cur_entry)
+ {
+ o.dir = nullptr;
+ o.cur_entry = nullptr;
+ }
+ ~iterator();
+ iterator& operator=(iterator&) = delete;
+ iterator& operator=(iterator&&) = delete;
+
+ bool operator==(const iterator& i) const;
+ bool operator!=(const iterator& i) const;
+ struct dirent& operator*() const { return *cur_entry; }
+ struct dirent* operator->() const { return cur_entry; }
+ void operator++();
+
+ /// @return true if we refer to a directory, else false
+ bool isdir() const;
+
+ /// @return true if we refer to a block device, else false
+ bool isblk() const;
+
+ /// @return true if we refer to a character device, else false
+ bool ischr() const;
+
+ /// @return true if we refer to a named pipe (FIFO).
+ bool isfifo() const;
+
+ /// @return true if we refer to a symbolic link.
+ bool islnk() const;
+
+ /// @return true if we refer to a regular file.
+ bool isreg() const;
+
+ /// @return true if we refer to a Unix domain socket.
+ bool issock() const;
+ };
+
+ using NamedFileDescriptor::NamedFileDescriptor;
+
+ /**
+ * Open the given pathname with flags | O_PATH.
+ */
+ Path(const char* pathname, int flags=0);
+ /**
+ * Open the given pathname with flags | O_PATH.
+ */
+ Path(const std::string& pathname, int flags=0);
+ /**
+ * Open the given pathname calling parent.openat, with flags | O_PATH
+ */
+ Path(Path& parent, const char* pathname, int flags=0);
+ Path(const Path&) = delete;
+ Path(Path&&) = default;
+ Path& operator=(const Path&) = delete;
+ Path& operator=(Path&&) = default;
+
+ /**
+ * The destructor closes the file descriptor, but does not check errors on
+ * ::close().
+ *
+ * In normal program flow, it is a good idea to explicitly call
+ * Path::close() in places where it can throw safely.
+ */
+ ~Path();
+
+ DIR* fdopendir();
+
+ /// Begin iterator on all directory entries
+ iterator begin();
+
+ /// End iterator on all directory entries
+ iterator end();
+
+ int openat(const char* pathname, int flags, mode_t mode=0777);
+
+ void fstatat(const char* pathname, struct stat& st);
+
+ /// fstatat with the AT_SYMLINK_NOFOLLOW flag set
+ void lstatat(const char* pathname, struct stat& st);
+
+ void unlinkat(const char* pathname);
+
+ /// unlinkat with the AT_REMOVEDIR flag set
+ void rmdirat(const char* pathname);
+
+ /**
+ * Delete the directory pointed to by this Path, with all its contents.
+ *
+ * The path must point to a directory.
+ */
+ void rmtree();
+};
+
+
+/**
+ * open(2) file descriptors
+ */
+class File : public NamedFileDescriptor
+{
+public:
+ using NamedFileDescriptor::NamedFileDescriptor;
+
+ File(File&&) = default;
+ File(const File&) = delete;
+
+ /// Wrapper around open(2)
+ File(const std::string& pathname, int flags, mode_t mode=0777);
+
+ /**
+ * The destructor closes the file descriptor, but does not check errors on
+ * ::close().
+ *
+ * In normal program flow, it is a good idea to explicitly call
+ * File::close() in places where it can throw safely.
+ */
+ ~File();
+
+ File& operator=(const File&) = delete;
+ File& operator=(File&&) = default;
+
+ static File mkstemp(const std::string& prefix);
+};
+
+/// Read whole file into memory. Throws exceptions on failure.
+std::string read_file(const std::string &file);
+
+/**
+ * Write \a data to \a file, replacing existing contents if it already exists.
+ *
+ * New files are created with the given permission mode, honoring umask.
+ * Permissions of existing files do not change.
+ */
+void write_file(const std::string& file, const std::string& data, mode_t mode=0777);
+
+/**
+ * Write \a data to \a file, replacing existing contents if it already exists.
+ *
+ * Files are created with the given permission mode, honoring umask. If the
+ * file already exists, its mode is ignored.
+ *
+ * Data is written to a temporary file, then moved to its final destination, to
+ * ensure an atomic operation.
+ */
+void write_file_atomically(const std::string& file, const std::string& data, mode_t mode=0777);
+
+#if 0
+// Create a temporary directory based on a template.
+std::string mkdtemp(std::string templ);
+
+/// Ensure that the path to the given file exists, creating it if it does not.
+/// The file itself will not get created.
+void mkFilePath(const std::string& file);
+#endif
+
+/**
+ * Delete a file if it exists. If it does not exist, do nothing.
+ *
+ * @return true if the file was deleted, false if it did not exist
+ */
+bool unlink_ifexists(const std::string& file);
+
+/**
+ * Move \a src to \a dst, without raising exception if \a src does not exist
+ *
+ * @return true if the file was renamed, false if it did not exist
+ */
+bool rename_ifexists(const std::string& src, const std::string& dst);
+
+/// Create the given directory, if it does not already exists.
+/// It will complain if the given pathname already exists but is not a
+/// directory.
+void mkdir_ifmissing(const char* pathname, mode_t mode=0777);
+
+void mkdir_ifmissing(const std::string& pathname, mode_t mode=0777);
+
+/// Create all the component of the given directory, including the directory
+/// itself.
+void makedirs(const std::string& pathname, mode_t=0777);
+
+/**
+ * Compute the absolute path of an executable.
+ *
+ * If \a name is specified as a partial path, it ensures it is made absolute.
+ * If \a name is not specified as a path, it looks for the executable in $PATH
+ * and return its absolute pathname.
+ */
+std::string which(const std::string& name);
+
+/// Delete the file using unlink()
+void unlink(const std::string& pathname);
+
+/// Remove the directory using rmdir(2)
+void rmdir(const std::string& pathname);
+
+/// Delete the directory \a pathname and all its contents.
+void rmtree(const std::string& pathname);
+
+#if 0
+/// Nicely wrap access to directories
+class Directory
+{
+protected:
+ /// Directory pathname
+ std::string m_path;
+
+public:
+ class const_iterator
+ {
+ /// Directory we are iterating
+ const Directory* dir;
+ /// DIR* pointer
+ void* dirp;
+ /// dirent structure used for iterating entries
+ struct dirent* direntbuf;
+
+ public:
+ // Create an end iterator
+ const_iterator();
+ // Create a begin iterator
+ const_iterator(const Directory& dir);
+ // Cleanup properly
+ ~const_iterator();
+
+ /// auto_ptr style copy semantics
+ const_iterator(const const_iterator& i);
+ const_iterator& operator=(const const_iterator& i);
+
+ /// Move to the next directory entry
+ const_iterator& operator++();
+
+ /// @return the current file name
+ std::string operator*() const;
+
+ bool operator==(const const_iterator& iter) const;
+ bool operator!=(const const_iterator& iter) const;
+ };
+
+ Directory(const std::string& path);
+ ~Directory();
+
+ /// Pathname of the directory
+ const std::string& path() const { return m_path; }
+
+ /// Check if the directory exists
+ bool exists() const;
+
+ /// Begin iterator
+ const_iterator begin() const;
+
+ /// End iterator
+ const_iterator end() const;
+};
+
+#endif
+}
+}
+
+#endif