| 
					
				 | 
			
			
				@@ -0,0 +1,328 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <set> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <kernel/async/lock.hpp> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <kernel/vfs.hpp> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include <kernel/vfs/filearr.hpp> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using namespace fs; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using kernel::async::mutex, kernel::async::lock_guard; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct fditem { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::shared_ptr<file> pfile; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct fditem_comparator { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    constexpr bool operator()(const fditem& lhs, const fditem& rhs) const 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return lhs.fd < rhs.fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    constexpr bool operator()(int fd, const fditem& rhs) const 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return fd < rhs.fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    constexpr bool operator()(const fditem& lhs, int fd) const 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return lhs.fd < fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// ALL METHODS SHOULD BE CALLED WITH LOCK HELD 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+struct filearray::impl { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mutex mtx; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::set<fditem, fditem_comparator> arr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int min_avail{}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int allocate_fd(int from); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    void release_fd(int fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int next_fd(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int do_dup(const fditem& oldfile, int new_fd, int flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int place_new_file(std::shared_ptr<file> pfile, int flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int filearray::impl::allocate_fd(int from) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (from < min_avail) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        from = min_avail; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (from == min_avail) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int nextfd = min_avail + 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        auto iter = arr.find(nextfd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        while (iter && nextfd == iter->fd) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ++nextfd, ++iter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int retval = min_avail; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        min_avail = nextfd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return retval; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int fd = from; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto iter = arr.find(fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    while (iter && fd == iter->fd) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ++fd, ++iter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void filearray::impl::release_fd(int fd) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (fd < min_avail) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        min_avail = fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int filearray::impl::next_fd() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return allocate_fd(min_avail); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int filearray::impl::do_dup(const fditem& oldfile, int new_fd, int flags) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    bool inserted; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::tie(std::ignore, inserted) = arr.emplace(new_fd, flags, oldfile.pfile); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert(inserted); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return new_fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int filearray::impl::place_new_file(std::shared_ptr<file> pfile, int flags) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int fd = next_fd(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    bool inserted; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    std::tie(std::ignore, inserted) = arr.emplace(fd, std::move(flags), pfile); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert(inserted); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int filearray::dup(int old_fd) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lock_guard lck{pimpl->mtx}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto iter = pimpl->arr.find(old_fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!iter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return -EBADF; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int fd = pimpl->next_fd(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return pimpl->do_dup(*iter, fd, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int filearray::dup(int old_fd, int new_fd, int flags) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lock_guard lck{pimpl->mtx}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto iter_old = pimpl->arr.find(old_fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!iter_old) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return -EBADF; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto iter_new = pimpl->arr.find(new_fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (iter_new) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        iter_new->pfile = iter_old->pfile; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        iter_new->flags = flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return new_fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int fd = pimpl->allocate_fd(new_fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert(fd == new_fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return pimpl->do_dup(*iter_old, fd, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int filearray::dupfd(int fd, int min_fd, int flags) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lock_guard lck{pimpl->mtx}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto iter = pimpl->arr.find(fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!iter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return -EBADF; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int new_fd = pimpl->allocate_fd(min_fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return pimpl->do_dup(*iter, new_fd, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int filearray::set_flags(int fd, int flags) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lock_guard lck{pimpl->mtx}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto iter = pimpl->arr.find(fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!iter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return -EBADF; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iter->flags |= flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int filearray::close(int fd) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lock_guard lck{pimpl->mtx}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto iter = pimpl->arr.find(fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!iter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return -EBADF; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pimpl->release_fd(fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pimpl->arr.erase(iter); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static inline int _open_file(dentry*& out_dent, dentry& root, const types::path& filepath, int flags, mode_t mode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto* dent = vfs_open(root, filepath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (dent) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if ((flags & O_CREAT) && (flags & O_EXCL)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return -EEXIST; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        out_dent = dent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!(flags & O_CREAT)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return -ENOENT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // create file 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto filename = filepath.last_name(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto parent_path = filepath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    parent_path.remove_last(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto* parent = vfs_open(root, parent_path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!parent) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return -EINVAL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int ret = vfs_mkfile(parent, filename.c_str(), mode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (ret != 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return ret; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dent = parent->find(filename); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    assert(dent); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    out_dent = dent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// TODO: file opening permissions check 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int filearray::open(dentry& root, const types::path& filepath, int flags, mode_t mode) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lock_guard lck{pimpl->mtx}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dentry* dent {}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int ret = _open_file(dent, root, filepath, flags, mode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (ret != 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return ret; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto filemode = dent->ind->mode; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int fdflag = (flags & O_CLOEXEC) ? FD_CLOEXEC : 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    file::file_flags fflags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fflags.read = !(flags & O_WRONLY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fflags.write = (flags & (O_WRONLY | O_RDWR)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fflags.append = S_ISREG(filemode) && (flags & O_APPEND); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // check whether dentry is a file if O_DIRECTORY is set 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (flags & O_DIRECTORY) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!S_ISDIR(filemode)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return -ENOTDIR; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (S_ISDIR(filemode) && fflags.write) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return -EISDIR; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // truncate file 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (flags & O_TRUNC) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (fflags.write && S_ISREG(filemode)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            auto ret = vfs_truncate(dent->ind, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (ret != 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return ret; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return pimpl->place_new_file( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        std::make_shared<regular_file>( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            dent->parent, fflags, 0, dent->ind), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fdflag); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int filearray::pipe(int (&pipefd)[2]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lock_guard lck{pimpl->mtx}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        std::shared_ptr<fs::pipe> ppipe { new fs::pipe }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pipefd[0] = pimpl->place_new_file( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            std::make_shared<fifo_file>( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                nullptr, file::file_flags { 1, 0, 0 }, ppipe), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pipefd[1] = pimpl->place_new_file( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            std::make_shared<fifo_file>( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                nullptr, file::file_flags { 0, 1, 0 }, ppipe), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+filearray::filearray(std::shared_ptr<impl> ptr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    : pimpl { ptr } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+filearray::filearray() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    : filearray { std::make_shared<impl>() } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+filearray filearray::copy() const 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lock_guard lck { pimpl->mtx }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    filearray ret {}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ret.pimpl->min_avail = pimpl->min_avail; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ret.pimpl->arr = pimpl->arr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return ret; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+filearray filearray::share() const 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return filearray { pimpl }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void filearray::clear() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pimpl.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void filearray::onexec() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lock_guard lck{pimpl->mtx}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (auto iter = pimpl->arr.begin(); iter;) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!(iter->flags & FD_CLOEXEC)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ++iter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        pimpl->release_fd(iter->fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        iter = pimpl->arr.erase(iter); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+file* filearray::operator[](int i) const 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    lock_guard lck{pimpl->mtx}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    auto iter = pimpl->arr.find(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!iter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return nullptr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return iter->pfile.get(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |