LCOV - code coverage report
Current view: top level - src/common - path_util.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 34 53 64.2 %
Date: 2024-04-30 13:21:35 Functions: 6 7 85.7 %
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/path_util.hpp>
      30             : 
      31             : #include <system_error>
      32             : #include <cstring>
      33             : #include <cassert>
      34             : 
      35             : using namespace std;
      36             : 
      37             : namespace gkfs::path {
      38             : 
      39             : bool
      40         284 : is_relative(const string& path) {
      41         284 :     return (!path.empty()) && (path.front() != separator);
      42             : }
      43             : 
      44             : bool
      45        9795 : is_absolute(const string& path) {
      46        9795 :     return (!path.empty()) && (path.front() == separator);
      47             : }
      48             : 
      49             : bool
      50        1347 : has_trailing_slash(const string& path) {
      51        1347 :     return (!path.empty()) && (path.back() == separator);
      52             : }
      53             : 
      54             : /** Add path prefix to a given C string.
      55             :  *
      56             :  * Returns a string composed by the `prefix_path`
      57             :  * followed by `raw_path`.
      58             :  *
      59             :  * This would return the same of:
      60             :  * ```
      61             :  * string(raw_path).append(prefix_path);
      62             :  * ```
      63             :  * But it is faster because it avoids to copy the `raw_path` twice.
      64             :  *
      65             :  *
      66             :  * Time cost approx: O(len(prefix_path)) + 2 O(len(raw_path))
      67             :  *
      68             :  * Example:
      69             :  * ```
      70             :  * prepend_path("/tmp/prefix", "./my/path") == "/tmp/prefix/./my/path"
      71             :  * ```
      72             :  */
      73             : string
      74           7 : prepend_path(const string& prefix_path, const char* raw_path) {
      75           7 :     assert(!has_trailing_slash(prefix_path));
      76           7 :     ::size_t raw_len = ::strlen(raw_path);
      77           7 :     string res;
      78           7 :     res.reserve(prefix_path.size() + 1 + raw_len);
      79           7 :     res.append(prefix_path);
      80           7 :     res.push_back(separator);
      81           7 :     res.append(raw_path, raw_len);
      82           7 :     return res;
      83             : }
      84             : 
      85             : /** Split a path into its components
      86             :  *
      87             :  * Returns a vector of the components of the given path.
      88             :  *
      89             :  * Example:
      90             :  *  split_path("/first/second/third") == ["first", "second", "third"]
      91             :  */
      92             : ::vector<string>
      93         248 : split_path(const string& path) {
      94         248 :     ::vector<string> tokens;
      95         248 :     size_t start = string::npos;
      96         248 :     size_t end = (path.front() != separator) ? 0 : 1;
      97        3224 :     while(end != string::npos && end < path.size()) {
      98        2976 :         start = end;
      99        2976 :         end = path.find(separator, start);
     100        5952 :         tokens.push_back(path.substr(start, end - start));
     101        2976 :         if(end != string::npos) {
     102        2728 :             ++end;
     103             :         }
     104             :     }
     105         248 :     return tokens;
     106             : }
     107             : 
     108             : 
     109             : /** Make an absolute path relative to a root path
     110             :  *
     111             :  * Convert @absolute_path into a relative one with respect to the given
     112             :  * @root_path. If @absolute_path do not start at the given @root_path an empty
     113             :  * string will be returned. NOTE: Trailing slash will be stripped from the new
     114             :  * constructed relative path.
     115             :  */
     116             : string
     117           0 : absolute_to_relative(const string& root_path, const string& absolute_path) {
     118           0 :     assert(is_absolute(root_path));
     119           0 :     assert(is_absolute(absolute_path));
     120           0 :     assert(!has_trailing_slash(root_path));
     121             : 
     122           0 :     auto diff_its = ::mismatch(absolute_path.cbegin(), absolute_path.cend(),
     123           0 :                                root_path.cbegin());
     124           0 :     if(diff_its.second != root_path.cend()) {
     125             :         // complete path doesn't start with root_path
     126           0 :         return {};
     127             :     }
     128             : 
     129             :     // iterator to the starting char of the relative portion of the
     130             :     // @absolute_path
     131           0 :     auto rel_it_begin = diff_its.first;
     132             :     // iterator to the end of the relative portion of the @absolute_path
     133           0 :     auto rel_it_end = absolute_path.cend();
     134             : 
     135             :     // relative path start exactly after the root_path prefix
     136           0 :     assert((size_t) (rel_it_begin - absolute_path.cbegin()) ==
     137             :            root_path.size());
     138             : 
     139           0 :     if(rel_it_begin == rel_it_end) {
     140             :         // relative path is empty, @absolute_path was equal to @root_path
     141           0 :         return {'/'};
     142             :     }
     143             : 
     144             :     // remove the trailing slash from relative path
     145           0 :     if(has_trailing_slash(absolute_path) &&
     146           0 :        rel_it_begin !=
     147           0 :                rel_it_end -
     148           0 :                        1) { // the relative path is longer then 1 char ('/')
     149           0 :         --rel_it_end;
     150             :     }
     151             : 
     152           0 :     return {rel_it_begin, rel_it_end};
     153             : }
     154             : 
     155             : /**
     156             :  * returns the directory name for given path
     157             :  * @param path
     158             :  * @return
     159             :  */
     160             : string
     161        1059 : dirname(const string& path) {
     162        1059 :     assert(path.size() > 1 || path.front() == separator);
     163        1059 :     assert(path.size() == 1 || !has_trailing_slash(path));
     164             : 
     165        1059 :     auto parent_path_size = path.find_last_of(separator);
     166        1059 :     assert(parent_path_size != string::npos);
     167        1059 :     if(parent_path_size == 0) {
     168             :         // parent is '/'
     169          43 :         parent_path_size = 1;
     170             :     }
     171        1059 :     return path.substr(0, parent_path_size);
     172             : }
     173             : 
     174             : } // namespace gkfs::path

Generated by: LCOV version 1.16