Line data Source code
1 : /* 2 : Copyright 2018-2024, Barcelona Supercomputing Center (BSC), Spain 3 : Copyright 2015-2024, Johannes Gutenberg Universitaet Mainz, Germany 4 : 5 : This software was partially supported by the 6 : EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). 7 : 8 : This software was partially supported by the 9 : ADA-FS project under the SPPEXA project funded by the DFG. 10 : 11 : This file is part of GekkoFS. 12 : 13 : GekkoFS is free software: you can redistribute it and/or modify 14 : it under the terms of the GNU General Public License as published by 15 : the Free Software Foundation, either version 3 of the License, or 16 : (at your option) any later version. 17 : 18 : GekkoFS is distributed in the hope that it will be useful, 19 : but WITHOUT ANY WARRANTY; without even the implied warranty of 20 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 : GNU General Public License for more details. 22 : 23 : You should have received a copy of the GNU General Public License 24 : along with GekkoFS. If not, see <https://www.gnu.org/licenses/>. 25 : 26 : SPDX-License-Identifier: GPL-3.0-or-later 27 : */ 28 : 29 : #include <common/metadata.hpp> 30 : #include <config.hpp> 31 : 32 : #include <fmt/format.h> 33 : 34 : extern "C" { 35 : #include <sys/stat.h> 36 : #include <unistd.h> 37 : } 38 : 39 : #include <ctime> 40 : #include <cassert> 41 : #include <random> 42 : 43 : namespace gkfs::metadata { 44 : 45 : static const char MSP = '|'; // metadata separator 46 : 47 : /** 48 : * Generate a unique ID for a given path 49 : * @param path 50 : * @return unique ID 51 : */ 52 : uint16_t 53 3 : gen_unique_id(const std::string& path) { 54 : // Generate a random salt value using a pseudo-random number generator 55 3 : std::random_device rd; 56 3 : std::mt19937 gen(rd()); 57 3 : std::uniform_int_distribution<> dis(0, 58 3 : std::numeric_limits<uint16_t>::max()); 59 3 : auto salt = static_cast<uint16_t>(dis(gen)); 60 : 61 : // Concatenate the identifier and salt values into a single string 62 6 : auto input_str = fmt::format("{}{}", path, salt); 63 : 64 : // Use std::hash function to generate a hash value from the input string 65 3 : std::hash<std::string> const hasher; 66 3 : auto hash_value = hasher(input_str); 67 : 68 : // Use the lower 16 bits of the hash value as the unique ID 69 6 : return static_cast<uint16_t>(hash_value & 0xFFFF); 70 : } 71 : 72 : inline void 73 1100 : Metadata::init_time() { 74 1100 : if constexpr(gkfs::config::metadata::use_ctime) { 75 1100 : ctime_ = std::time(nullptr); 76 : } 77 1100 : if constexpr(gkfs::config::metadata::use_mtime) { 78 1100 : mtime_ = std::time(nullptr); 79 : } 80 1100 : if constexpr(gkfs::config::metadata::use_atime) { 81 1100 : atime_ = std::time(nullptr); 82 : } 83 1100 : } 84 : 85 1100 : Metadata::Metadata(const mode_t mode) 86 1100 : : mode_(mode), link_count_(0), size_(0), blocks_(0) { 87 1100 : assert(S_ISDIR(mode_) || S_ISREG(mode_)); 88 1100 : init_time(); 89 1100 : } 90 : 91 : #ifdef HAS_SYMLINKS 92 : 93 0 : Metadata::Metadata(const mode_t mode, const std::string& target_path) 94 : : mode_(mode), link_count_(0), size_(0), blocks_(0), 95 0 : target_path_(target_path) { 96 0 : assert(S_ISLNK(mode_) || S_ISDIR(mode_) || S_ISREG(mode_)); 97 : // target_path should be there only if this is a link 98 0 : assert(target_path_.empty() || S_ISLNK(mode_)); 99 : // target_path should be absolute 100 0 : assert(target_path_.empty() || target_path_[0] == '/'); 101 0 : init_time(); 102 0 : } 103 : 104 : #endif 105 : 106 4838 : Metadata::Metadata(const std::string& binary_str) { 107 4838 : size_t read = 0; 108 : 109 4838 : auto ptr = binary_str.data(); 110 9676 : mode_ = static_cast<unsigned int>(std::stoul(ptr, &read)); 111 : // we read something 112 4838 : assert(read > 0); 113 4838 : ptr += read; 114 : 115 : // last parsed char is the separator char 116 4838 : assert(*ptr == MSP); 117 : // yet we have some character to parse 118 : 119 9676 : size_ = std::stol(++ptr, &read); 120 4838 : assert(read > 0); 121 4838 : ptr += read; 122 : 123 : // The order is important. don't change. 124 4838 : if constexpr(gkfs::config::metadata::use_atime) { 125 4838 : assert(*ptr == MSP); 126 9676 : atime_ = static_cast<time_t>(std::stol(++ptr, &read)); 127 4838 : assert(read > 0); 128 4838 : ptr += read; 129 : } 130 4838 : if constexpr(gkfs::config::metadata::use_mtime) { 131 4838 : assert(*ptr == MSP); 132 9676 : mtime_ = static_cast<time_t>(std::stol(++ptr, &read)); 133 4838 : assert(read > 0); 134 4838 : ptr += read; 135 : } 136 4838 : if constexpr(gkfs::config::metadata::use_ctime) { 137 4838 : assert(*ptr == MSP); 138 9676 : ctime_ = static_cast<time_t>(std::stol(++ptr, &read)); 139 4838 : assert(read > 0); 140 4838 : ptr += read; 141 : } 142 4838 : if constexpr(gkfs::config::metadata::use_link_cnt) { 143 4838 : assert(*ptr == MSP); 144 14514 : link_count_ = static_cast<nlink_t>(std::stoul(++ptr, &read)); 145 4838 : assert(read > 0); 146 4838 : ptr += read; 147 : } 148 4838 : if constexpr(gkfs::config::metadata::use_blocks) { // last one will not 149 : // encounter a 150 : // delimiter anymore 151 4838 : assert(*ptr == MSP); 152 9676 : blocks_ = static_cast<blkcnt_t>(std::stol(++ptr, &read)); 153 4838 : assert(read > 0); 154 4838 : ptr += read; 155 : } 156 : 157 : #ifdef HAS_SYMLINKS 158 : // Read target_path 159 4838 : assert(*ptr == MSP); 160 4838 : target_path_ = ++ptr; 161 : // target_path should be there only if this is a link 162 4838 : ptr += target_path_.size(); 163 : #ifdef HAS_RENAME 164 : // Read rename target, we had captured '|' so we need to recover it 165 4838 : if(!target_path_.empty()) { 166 4838 : auto index = target_path_.find_last_of(MSP); 167 4838 : auto size = target_path_.size(); 168 4838 : target_path_ = target_path_.substr(0, index); 169 4838 : ptr -= (size - index); 170 : } 171 4838 : assert(*ptr == MSP); 172 4838 : rename_path_ = ++ptr; 173 4838 : ptr += rename_path_.size(); 174 : #endif // HAS_RENAME 175 : #endif // HAS_SYMLINKS 176 : 177 : // we consumed all the binary string 178 4838 : assert(*ptr == '\0'); 179 4838 : } 180 : 181 : std::string 182 3504 : Metadata::serialize() const { 183 3504 : std::string s; 184 : // The order is important. don't change. 185 3504 : s += fmt::format_int(mode_).c_str(); // add mandatory mode 186 3504 : s += MSP; 187 3504 : s += fmt::format_int(size_).c_str(); // add mandatory size 188 3504 : if constexpr(gkfs::config::metadata::use_atime) { 189 3504 : s += MSP; 190 3504 : s += fmt::format_int(atime_).c_str(); 191 : } 192 3504 : if constexpr(gkfs::config::metadata::use_mtime) { 193 3504 : s += MSP; 194 3504 : s += fmt::format_int(mtime_).c_str(); 195 : } 196 3504 : if constexpr(gkfs::config::metadata::use_ctime) { 197 3504 : s += MSP; 198 3504 : s += fmt::format_int(ctime_).c_str(); 199 : } 200 3504 : if constexpr(gkfs::config::metadata::use_link_cnt) { 201 3504 : s += MSP; 202 3504 : s += fmt::format_int(link_count_).c_str(); 203 : } 204 3504 : if constexpr(gkfs::config::metadata::use_blocks) { 205 3504 : s += MSP; 206 3504 : s += fmt::format_int(blocks_).c_str(); 207 : } 208 : 209 : #ifdef HAS_SYMLINKS 210 3504 : s += MSP; 211 3504 : s += target_path_; 212 : #ifdef HAS_RENAME 213 3504 : s += MSP; 214 3504 : s += rename_path_; 215 : #endif // HAS_RENAME 216 : #endif // HAS_SYMLINKS 217 : 218 3504 : return s; 219 : } 220 : 221 : void 222 0 : Metadata::update_atime_now() { 223 0 : auto time = std::time(nullptr); 224 0 : atime_ = time; 225 0 : } 226 : 227 : void 228 126 : Metadata::update_mtime_now() { 229 126 : auto time = std::time(nullptr); 230 126 : mtime_ = time; 231 126 : } 232 : 233 : //-------------------------------------------- GETTER/SETTER 234 : 235 : time_t 236 73 : Metadata::atime() const { 237 73 : return atime_; 238 : } 239 : 240 : void 241 1110 : Metadata::atime(time_t atime) { 242 1110 : Metadata::atime_ = atime; 243 1110 : } 244 : 245 : time_t 246 73 : Metadata::mtime() const { 247 73 : return mtime_; 248 : } 249 : 250 : void 251 1110 : Metadata::mtime(time_t mtime) { 252 1110 : Metadata::mtime_ = mtime; 253 1110 : } 254 : 255 : time_t 256 77 : Metadata::ctime() const { 257 77 : return ctime_; 258 : } 259 : 260 : void 261 1110 : Metadata::ctime(time_t ctime) { 262 1110 : Metadata::ctime_ = ctime; 263 1110 : } 264 : 265 : mode_t 266 2391 : Metadata::mode() const { 267 2391 : return mode_; 268 : } 269 : 270 : void 271 0 : Metadata::mode(mode_t mode) { 272 0 : Metadata::mode_ = mode; 273 0 : } 274 : 275 : nlink_t 276 73 : Metadata::link_count() const { 277 73 : return link_count_; 278 : } 279 : 280 : void 281 0 : Metadata::link_count(nlink_t link_count) { 282 0 : Metadata::link_count_ = link_count; 283 0 : } 284 : 285 : size_t 286 2457 : Metadata::size() const { 287 2457 : return size_; 288 : } 289 : 290 : void 291 2359 : Metadata::size(size_t size) { 292 2359 : Metadata::size_ = size; 293 2359 : } 294 : 295 : blkcnt_t 296 1322 : Metadata::blocks() const { 297 1322 : return blocks_; 298 : } 299 : 300 : void 301 12 : Metadata::blocks(blkcnt_t blocks) { 302 12 : Metadata::blocks_ = blocks; 303 12 : } 304 : 305 : #ifdef HAS_SYMLINKS 306 : 307 : std::string 308 263 : Metadata::target_path() const { 309 263 : return target_path_; 310 : } 311 : 312 : void 313 21 : Metadata::target_path(const std::string& target_path) { 314 21 : target_path_ = target_path; 315 21 : } 316 : 317 : bool 318 228 : Metadata::is_link() const { 319 228 : return S_ISLNK(mode_); 320 : } 321 : 322 : #ifdef HAS_RENAME 323 : std::string 324 0 : Metadata::rename_path() const { 325 0 : return rename_path_; 326 : } 327 : 328 : void 329 10 : Metadata::rename_path(const std::string& rename_path) { 330 10 : rename_path_ = rename_path; 331 10 : } 332 : 333 : #endif // HAS_RENAME 334 : #endif // HAS_SYMLINKS 335 : 336 : } // namespace gkfs::metadata