]>
Commit | Line | Data |
---|---|---|
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 | ||
31 | namespace seastar { | |
32 | ||
33 | namespace fs = std::filesystem; | |
34 | ||
35 | future<> make_directory(std::string_view name, file_permissions permissions) noexcept { | |
36 | return engine().make_directory(name, permissions); | |
37 | } | |
38 | ||
39 | future<> touch_directory(std::string_view name, file_permissions permissions) noexcept { | |
40 | return engine().touch_directory(name, permissions); | |
41 | } | |
42 | ||
43 | future<> 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 | ||
53 | static 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 | ||
85 | future<> 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 | ||
95 | future<> remove_file(std::string_view pathname) noexcept { | |
96 | return engine().remove_file(pathname); | |
97 | } | |
98 | ||
99 | future<> rename_file(std::string_view old_pathname, std::string_view new_pathname) noexcept { | |
100 | return engine().rename_file(old_pathname, new_pathname); | |
101 | } | |
102 | ||
103 | future<fs_type> file_system_at(std::string_view name) noexcept { | |
104 | return engine().file_system_at(name); | |
105 | } | |
106 | ||
107 | future<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 | ||
113 | future<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 | ||
119 | future<stat_data> file_stat(std::string_view name, follow_symlink follow) noexcept { | |
120 | return engine().file_stat(name, follow); | |
121 | } | |
122 | ||
123 | future<uint64_t> file_size(std::string_view name) noexcept { | |
124 | return engine().file_size(name); | |
125 | } | |
126 | ||
127 | future<bool> file_accessible(std::string_view name, access_flags flags) noexcept { | |
128 | return engine().file_accessible(name, flags); | |
129 | } | |
130 | ||
131 | future<bool> file_exists(std::string_view name) noexcept { | |
132 | return engine().file_exists(name); | |
133 | } | |
134 | ||
135 | future<> link_file(std::string_view oldpath, std::string_view newpath) noexcept { | |
136 | return engine().link_file(oldpath, newpath); | |
137 | } | |
138 | ||
139 | future<> chmod(std::string_view name, file_permissions permissions) noexcept { | |
140 | return engine().chmod(name, permissions); | |
141 | } | |
142 | ||
143 | static 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 | ||
186 | future<> 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 |