]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/seastar/src/util/file.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / seastar / src / util / file.cc
diff --git a/ceph/src/seastar/src/util/file.cc b/ceph/src/seastar/src/util/file.cc
new file mode 100644 (file)
index 0000000..79cb26a
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * This file is open source software, licensed to you under the terms
+ * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
+ * distributed with this work for additional information regarding copyright
+ * ownership.  You may not use this file except in compliance with the License.
+ *
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Copyright 2020 ScyllaDB
+ */
+
+#include <iostream>
+#include <list>
+#include <deque>
+
+#include <seastar/core/reactor.hh>
+#include <seastar/core/seastar.hh>
+#include <seastar/util/file.hh>
+
+namespace seastar {
+
+namespace fs = std::filesystem;
+
+future<> make_directory(std::string_view name, file_permissions permissions) noexcept {
+    return engine().make_directory(name, permissions);
+}
+
+future<> touch_directory(std::string_view name, file_permissions permissions) noexcept {
+    return engine().touch_directory(name, permissions);
+}
+
+future<> sync_directory(std::string_view name) noexcept {
+    return open_directory(name).then([] (file f) {
+        return do_with(std::move(f), [] (file& f) {
+            return f.flush().then([&f] () mutable {
+                return f.close();
+            });
+        });
+    });
+}
+
+static future<> do_recursive_touch_directory(std::string_view base_view, std::string_view name, file_permissions permissions) {
+    sstring base(base_view);
+    static const sstring::value_type separator = '/';
+
+    if (name.empty()) {
+        return make_ready_future<>();
+    }
+
+    size_t pos = std::min(name.find(separator), name.size() - 1);
+    base += sstring(name.substr(0 , pos + 1));
+    name = name.substr(pos + 1);
+    if (name.length() == 1 && name[0] == separator) {
+        name = {};
+    }
+    // use the optional permissions only for last component,
+    // other directories in the patch will always be created using the default_dir_permissions
+    auto f = name.empty() ? touch_directory(base, permissions) : touch_directory(base);
+    return f.then([base, name = sstring(name), permissions] {
+        return do_recursive_touch_directory(base, std::move(name), permissions);
+    }).then([base] {
+        // We will now flush the directory that holds the entry we potentially
+        // created. Technically speaking, we only need to touch when we did
+        // create. But flushing the unchanged ones should be cheap enough - and
+        // it simplifies the code considerably.
+        if (base.empty()) {
+            return make_ready_future<>();
+        }
+
+        return sync_directory(base);
+    });
+}
+
+future<> recursive_touch_directory(std::string_view name, file_permissions permissions) noexcept {
+    // If the name is empty,  it will be of the type a/b/c, which should be interpreted as
+    // a relative path. This means we have to flush our current directory
+    std::string_view base = "";
+    if (name[0] != '/' || name[0] == '.') {
+        base = "./";
+    }
+    return futurize_invoke(do_recursive_touch_directory, base, name, permissions);
+}
+
+future<> remove_file(std::string_view pathname) noexcept {
+    return engine().remove_file(pathname);
+}
+
+future<> rename_file(std::string_view old_pathname, std::string_view new_pathname) noexcept {
+    return engine().rename_file(old_pathname, new_pathname);
+}
+
+future<fs_type> file_system_at(std::string_view name) noexcept {
+    return engine().file_system_at(name);
+}
+
+future<uint64_t> fs_avail(std::string_view name) noexcept {
+    return engine().statvfs(name).then([] (struct statvfs st) {
+        return make_ready_future<uint64_t>(st.f_bavail * st.f_frsize);
+    });
+}
+
+future<uint64_t> fs_free(std::string_view name) noexcept {
+    return engine().statvfs(name).then([] (struct statvfs st) {
+        return make_ready_future<uint64_t>(st.f_bfree * st.f_frsize);
+    });
+}
+
+future<stat_data> file_stat(std::string_view name, follow_symlink follow) noexcept {
+    return engine().file_stat(name, follow);
+}
+
+future<uint64_t> file_size(std::string_view name) noexcept {
+    return engine().file_size(name);
+}
+
+future<bool> file_accessible(std::string_view name, access_flags flags) noexcept {
+    return engine().file_accessible(name, flags);
+}
+
+future<bool> file_exists(std::string_view name) noexcept {
+    return engine().file_exists(name);
+}
+
+future<> link_file(std::string_view oldpath, std::string_view newpath) noexcept {
+    return engine().link_file(oldpath, newpath);
+}
+
+future<> chmod(std::string_view name, file_permissions permissions) noexcept {
+    return engine().chmod(name, permissions);
+}
+
+static future<> do_recursive_remove_directory(const fs::path path) noexcept {
+    struct work_entry {
+        const fs::path path;
+        bool listed;
+
+        work_entry(const fs::path path, bool listed)
+                : path(std::move(path))
+                , listed(listed)
+        {
+        }
+    };
+
+    return do_with(std::deque<work_entry>(), [path = std::move(path)] (auto& work_queue) mutable {
+        work_queue.emplace_back(std::move(path), false);
+        return do_until([&work_queue] { return work_queue.empty(); }, [&work_queue] () mutable {
+            auto ent = work_queue.back();
+            work_queue.pop_back();
+            if (ent.listed) {
+                return remove_file(ent.path.native());
+            } else {
+                work_queue.emplace_back(ent.path, true);
+                return do_with(std::move(ent.path), [&work_queue] (const fs::path& path) {
+                    return open_directory(path.native()).then([&path, &work_queue] (file dir) mutable {
+                        return do_with(std::move(dir), [&path, &work_queue] (file& dir) mutable {
+                            return dir.list_directory([&path, &work_queue] (directory_entry de) mutable {
+                                const fs::path sub_path = path / de.name.c_str();
+                                if (de.type && *de.type == directory_entry_type::directory) {
+                                    work_queue.emplace_back(std::move(sub_path), false);
+                                } else {
+                                    work_queue.emplace_back(std::move(sub_path), true);
+                                }
+                                return make_ready_future<>();
+                            }).done().then([&dir] () mutable {
+                                return dir.close();
+                            });
+                        });
+                    });
+                });
+            }
+        });
+    });
+}
+
+future<> recursive_remove_directory(fs::path path) noexcept {
+    sstring parent;
+    try {
+        parent = (path / "..").native();
+    } catch (...) {
+        return current_exception_as_future();
+    }
+    return open_directory(std::move(parent)).then([path = std::move(path)] (file parent) mutable {
+        return do_with(std::move(parent), [path = std::move(path)] (file& parent) mutable {
+            return do_recursive_remove_directory(std::move(path)).then([&parent] {
+                return parent.flush().then([&parent] () mutable {
+                    return parent.close();
+                });
+            });
+        });
+    });
+}
+
+} //namespace seastar