• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender / 2271300743

19 Jan 2026 11:42AM UTC coverage: 81.376% (+1.7%) from 79.701%
2271300743

push

gitlab-ci

web-flow
Merge pull request #1879 from lluiscampos/MEN-8687-ci-debian-updates

MEN-8687: Update Debian base images for CI jobs

8791 of 10803 relevant lines covered (81.38%)

20310.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.26
/src/common/path/platform/c++17/path.cpp
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
#include <common/path.hpp>
16

17
#include <filesystem>
18
#include <string>
19
#include <unordered_set>
20

21
#include <common/error.hpp>
22

23
namespace mender {
24
namespace common {
25
namespace path {
26

27
using namespace std;
28
namespace fs = std::filesystem;
29

30
unordered_map<Perms, fs::perms> perm_map = {
31
        {Perms::Owner_exec, fs::perms::owner_exec},
32
        {Perms::Owner_read, fs::perms::owner_read},
33
        {Perms::Owner_write, fs::perms::owner_write},
34
        {Perms::Group_read, fs::perms::group_read},
35
        {Perms::Group_write, fs::perms::group_write},
36
        {Perms::Group_exec, fs::perms::group_exec},
37
        {Perms::Others_read, fs::perms::others_read},
38
        {Perms::Others_write, fs::perms::others_write},
39
        {Perms::Others_exec, fs::perms::others_exec},
40
};
41

42
string JoinOne(const string &prefix, const string &suffix) {
27,080✔
43
        return (fs::path(prefix) / suffix).string();
27,080✔
44
}
45

46
string BaseName(const string &path) {
12,004✔
47
        return fs::path(path).filename().string();
12,004✔
48
}
49

50
string DirName(const string &path) {
93✔
51
        return fs::path(path).parent_path().string();
93✔
52
}
53

54
expected::ExpectedString Canonical(const string &path) {
×
55
        error_code ec;
×
56
        auto canonical = fs::canonical(path, ec);
×
57
        if (ec) {
×
58
                return expected::unexpected(
×
59
                        error::Error(ec.default_error_condition(), "Could not get canonical path"));
×
60
        }
61
        return canonical.string();
×
62
}
×
63

64
expected::ExpectedString WeaklyCanonical(const string &path) {
2,838✔
65
        error_code ec;
2,838✔
66
        auto canonical = fs::weakly_canonical(path, ec);
2,838✔
67
        if (ec) {
2,838✔
68
                return expected::unexpected(
×
69
                        error::Error(ec.default_error_condition(), "Could not get weakly canonical path"));
×
70
        }
71
        return canonical.string();
5,676✔
72
}
2,838✔
73

74
bool IsAbsolute(const string &path) {
2,646✔
75
        return fs::path(path).is_absolute();
5,292✔
76
}
77

78
bool FileExists(const string &path) {
1,747✔
79
        try {
80
                return fs::exists(path);
1,747✔
81
        } catch (const fs::filesystem_error &e) {
×
82
                log::Error("Could not check file existence of '" + path + "': " + e.what());
×
83
                return false;
84
        }
×
85
}
86

87
error::Error FileDelete(const string &path) {
7✔
88
        error_code ec;
7✔
89
        bool deleted = fs::remove(fs::path(path), ec);
7✔
90
        if (not deleted) {
7✔
91
                return error::Error(
92
                        ec.default_error_condition(),
×
93
                        "Failed to remove the file: '" + path + "'. error: " + ec.message());
×
94
        }
95
        return error::NoError;
7✔
96
}
97

98
error::Error DeleteRecursively(const string &path) {
115✔
99
        error_code ec;
115✔
100
        fs::remove_all(path, ec);
115✔
101
        if (ec) {
115✔
102
                return error::Error(ec.default_error_condition(), "Could not remove path");
×
103
        }
104
        return error::NoError;
115✔
105
}
106

107
expected::ExpectedBool IsExecutable(const string &file_path, const bool warn) {
738✔
108
        try {
109
                fs::perms perms = fs::status(file_path).permissions();
738✔
110
                if ((perms & (fs::perms::owner_exec | fs::perms::group_exec | fs::perms::others_exec))
738✔
111
                        == fs::perms::none) {
112
                        if (warn) {
×
113
                                log::Warning("'" + file_path + "' is not executable");
×
114
                        }
115
                        return false;
116
                }
117
                return true;
118
        } catch (const fs::filesystem_error &e) {
×
119
                return expected::unexpected(error::Error(
×
120
                        e.code().default_error_condition(),
×
121
                        "Could not check executable status of '" + file_path + "'"));
×
122
        }
×
123
}
124

125
error::Error Permissions(
1,029✔
126
        const string &file_path, const vector<Perms> perms, WarnMode warn_on_change) {
127
        if (perms.size() == 0) {
1,029✔
128
                return error::NoError;
×
129
        }
130
        fs::perms old_perms {};
131
        try {
132
                old_perms = fs::status(file_path).permissions();
1,029✔
133
        } catch (const fs::filesystem_error &e) {
×
134
                return error::Error(
135
                        e.code().default_error_condition(),
×
136
                        "Could not check permissions on '" + file_path + "'");
×
137
        }
×
138

139
        fs::perms new_perms {};
1,029✔
140
        std::for_each(perms.cbegin(), perms.cend(), [&new_perms](const Perms perm) {
4,111✔
141
                new_perms |= perm_map.at(perm);
3,082✔
142
        });
3,082✔
143
        if (old_perms == new_perms) {
1,029✔
144
                return error::NoError;
3✔
145
        }
146
        if (warn_on_change == WarnMode::WarnOnChange) {
1,026✔
147
                log::Warning("Changing permissions on the '" + file_path + "' file");
10✔
148
        }
149
        try {
150
                fs::permissions(file_path, new_perms);
1,026✔
151
        } catch (const fs::filesystem_error &e) {
3✔
152
                return error::Error(
153
                        e.code().default_error_condition(), "Could not set permissions on '" + file_path + "'");
6✔
154
        }
3✔
155
        return error::NoError;
1,023✔
156
}
157

158
expected::ExpectedUnorderedSet<string> ListFiles(
1,435✔
159
        const string &in_directory, function<bool(string)> matcher) {
160
        try {
161
                unordered_set<string> matching_files {};
1,435✔
162
                fs::path dir_path(in_directory);
1,435✔
163
                if (!fs::exists(dir_path)) {
1,435✔
164
                        auto err {errno};
189✔
165
                        return expected::unexpected(error::Error(
189✔
166
                                generic_category().default_error_condition(err),
378✔
167
                                "No such file or directory: " + in_directory));
567✔
168
                }
169

170
                for (const auto &entry : fs::directory_iterator {dir_path}) {
15,762✔
171
                        fs::path file_path = entry.path();
12,024✔
172
                        if (!fs::is_regular_file(file_path)) {
12,024✔
173
                                log::Warning("'" + file_path.string() + "'" + " is not a regular file. Ignoring.");
×
174
                                continue;
175
                        }
176

177
                        if (matcher(file_path)) {
24,048✔
178
                                matching_files.insert(file_path);
850✔
179
                        }
180
                }
12,024✔
181

182
                return matching_files;
1,246✔
183
        } catch (const fs::filesystem_error &e) {
1,435✔
184
                return expected::unexpected(error::Error(
×
185
                        e.code().default_error_condition(), "Could not list files in '" + in_directory + "'"));
×
186
        }
×
187
}
188

189
error::Error CreateDirectory(const string &path) {
3✔
190
        try {
191
                fs::path fs_path {path};
3✔
192
                if (not fs::create_directory(fs_path)) {
3✔
193
                        auto err {errno};
×
194
                        return error::Error(
195
                                generic_category().default_error_condition(err),
×
196
                                "Failed to create the directory: " + path);
×
197
                }
198
        } catch (const fs::filesystem_error &e) {
3✔
199
                return error::Error(
200
                        e.code().default_error_condition(), "Failed to create directory: '" + path + "'");
×
201
        }
×
202
        return error::NoError;
3✔
203
}
204

205
error::Error CreateDirectories(const string &dir) {
569✔
206
        try {
207
                const fs::path p {dir};
569✔
208
                fs::create_directories(p);
569✔
209
        } catch (const fs::filesystem_error &e) {
569✔
210
                return error::Error(
211
                        e.code().default_error_condition(), "Failed to create directory: '" + dir + "'");
×
212
        }
×
213
        return error::NoError;
569✔
214
}
215

216
error::Error Rename(const string &oldname, const string &newname) {
×
217
        error_code ec;
×
218
        fs::rename(fs::path(oldname), fs::path(newname), ec);
×
219
        if (ec) {
×
220
                return error::Error(
221
                        ec.default_error_condition(),
×
222
                        "Failed to rename '" + oldname + "' to '" + newname + "'. error: " + ec.message());
×
223
        }
224
        return error::NoError;
×
225
}
226

227
error::Error FileCopy(const string &what, const string &where) {
×
228
        error_code ec;
×
229
        fs::copy_file(fs::path(what), fs::path(where), fs::copy_options::overwrite_existing, ec);
×
230
        if (ec) {
×
231
                return error::Error(
232
                        ec.default_error_condition(),
×
233
                        "Failed to copy '" + what + "' to '" + where + "'. error: " + ec.message());
×
234
        }
235
        return error::NoError;
×
236
}
237

238
} // namespace path
239
} // namespace common
240
} // namespace mender
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc