LCOV - code coverage report
Current view: top level - src/common - metadata.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 139 158 88.0 %
Date: 2024-04-30 13:21:35 Functions: 22 27 81.5 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.16