]> git.proxmox.com Git - ceph.git/blame - ceph/src/seastar/src/util/file.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / seastar / src / util / file.cc
CommitLineData
f67539c2
TL
1/*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18
19/*
20 * Copyright 2020 ScyllaDB
21 */
22
23#include <iostream>
24#include <list>
25#include <deque>
26
27#include <seastar/core/reactor.hh>
28#include <seastar/core/seastar.hh>
29#include <seastar/util/file.hh>
30
31namespace seastar {
32
33namespace fs = std::filesystem;
34
35future<> make_directory(std::string_view name, file_permissions permissions) noexcept {
36 return engine().make_directory(name, permissions);
37}
38
39future<> touch_directory(std::string_view name, file_permissions permissions) noexcept {
40 return engine().touch_directory(name, permissions);
41}
42
43future<> sync_directory(std::string_view name) noexcept {
44 return open_directory(name).then([] (file f) {
45 return do_with(std::move(f), [] (file& f) {
46 return f.flush().then([&f] () mutable {
47 return f.close();
48 });
49 });
50 });
51}
52
53static future<> do_recursive_touch_directory(std::string_view base_view, std::string_view name, file_permissions permissions) {
54 sstring base(base_view);
55 static const sstring::value_type separator = '/';
56
57 if (name.empty()) {
58 return make_ready_future<>();
59 }
60
61 size_t pos = std::min(name.find(separator), name.size() - 1);
62 base += sstring(name.substr(0 , pos + 1));
63 name = name.substr(pos + 1);
64 if (name.length() == 1 && name[0] == separator) {
65 name = {};
66 }
67 // use the optional permissions only for last component,
68 // other directories in the patch will always be created using the default_dir_permissions
69 auto f = name.empty() ? touch_directory(base, permissions) : touch_directory(base);
70 return f.then([base, name = sstring(name), permissions] {
71 return do_recursive_touch_directory(base, std::move(name), permissions);
72 }).then([base] {
73 // We will now flush the directory that holds the entry we potentially
74 // created. Technically speaking, we only need to touch when we did
75 // create. But flushing the unchanged ones should be cheap enough - and
76 // it simplifies the code considerably.
77 if (base.empty()) {
78 return make_ready_future<>();
79 }
80
81 return sync_directory(base);
82 });
83}
84
85future<> recursive_touch_directory(std::string_view name, file_permissions permissions) noexcept {
86 // If the name is empty, it will be of the type a/b/c, which should be interpreted as
87 // a relative path. This means we have to flush our current directory
88 std::string_view base = "";
89 if (name[0] != '/' || name[0] == '.') {
90 base = "./";
91 }
92 return futurize_invoke(do_recursive_touch_directory, base, name, permissions);
93}
94
95future<> remove_file(std::string_view pathname) noexcept {
96 return engine().remove_file(pathname);
97}
98
99future<> rename_file(std::string_view old_pathname, std::string_view new_pathname) noexcept {
100 return engine().rename_file(old_pathname, new_pathname);
101}
102
103future<fs_type> file_system_at(std::string_view name) noexcept {
104 return engine().file_system_at(name);
105}
106
107future<uint64_t> fs_avail(std::string_view name) noexcept {
108 return engine().statvfs(name).then([] (struct statvfs st) {
109 return make_ready_future<uint64_t>(st.f_bavail * st.f_frsize);
110 });
111}
112
113future<uint64_t> fs_free(std::string_view name) noexcept {
114 return engine().statvfs(name).then([] (struct statvfs st) {
115 return make_ready_future<uint64_t>(st.f_bfree * st.f_frsize);
116 });
117}
118
119future<stat_data> file_stat(std::string_view name, follow_symlink follow) noexcept {
120 return engine().file_stat(name, follow);
121}
122
123future<uint64_t> file_size(std::string_view name) noexcept {
124 return engine().file_size(name);
125}
126
127future<bool> file_accessible(std::string_view name, access_flags flags) noexcept {
128 return engine().file_accessible(name, flags);
129}
130
131future<bool> file_exists(std::string_view name) noexcept {
132 return engine().file_exists(name);
133}
134
135future<> link_file(std::string_view oldpath, std::string_view newpath) noexcept {
136 return engine().link_file(oldpath, newpath);
137}
138
139future<> chmod(std::string_view name, file_permissions permissions) noexcept {
140 return engine().chmod(name, permissions);
141}
142
143static future<> do_recursive_remove_directory(const fs::path path) noexcept {
144 struct work_entry {
145 const fs::path path;
146 bool listed;
147
148 work_entry(const fs::path path, bool listed)
149 : path(std::move(path))
150 , listed(listed)
151 {
152 }
153 };
154
155 return do_with(std::deque<work_entry>(), [path = std::move(path)] (auto& work_queue) mutable {
156 work_queue.emplace_back(std::move(path), false);
157 return do_until([&work_queue] { return work_queue.empty(); }, [&work_queue] () mutable {
158 auto ent = work_queue.back();
159 work_queue.pop_back();
160 if (ent.listed) {
161 return remove_file(ent.path.native());
162 } else {
163 work_queue.emplace_back(ent.path, true);
164 return do_with(std::move(ent.path), [&work_queue] (const fs::path& path) {
165 return open_directory(path.native()).then([&path, &work_queue] (file dir) mutable {
166 return do_with(std::move(dir), [&path, &work_queue] (file& dir) mutable {
167 return dir.list_directory([&path, &work_queue] (directory_entry de) mutable {
168 const fs::path sub_path = path / de.name.c_str();
169 if (de.type && *de.type == directory_entry_type::directory) {
170 work_queue.emplace_back(std::move(sub_path), false);
171 } else {
172 work_queue.emplace_back(std::move(sub_path), true);
173 }
174 return make_ready_future<>();
175 }).done().then([&dir] () mutable {
176 return dir.close();
177 });
178 });
179 });
180 });
181 }
182 });
183 });
184}
185
186future<> recursive_remove_directory(fs::path path) noexcept {
187 sstring parent;
188 try {
189 parent = (path / "..").native();
190 } catch (...) {
191 return current_exception_as_future();
192 }
193 return open_directory(std::move(parent)).then([path = std::move(path)] (file parent) mutable {
194 return do_with(std::move(parent), [path = std::move(path)] (file& parent) mutable {
195 return do_recursive_remove_directory(std::move(path)).then([&parent] {
196 return parent.flush().then([&parent] () mutable {
197 return parent.close();
198 });
199 });
200 });
201 });
202}
203
204} //namespace seastar