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

mendersoftware / mender / 1273058123

30 Apr 2024 09:04AM UTC coverage: 75.594% (+0.04%) from 75.555%
1273058123

push

gitlab-ci

danielskinstad
test: Add test for AreFilesIdentical

Signed-off-by: Daniel Skinstad Drabitzius <daniel.drabitzius@northern.tech>

7062 of 9342 relevant lines covered (75.59%)

11668.19 hits per line

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

58.12
/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/io.hpp>
16
#include <common/path.hpp>
17

18
#include <filesystem>
19
#include <functional>
20
#include <iterator>
21
#include <string>
22
#include <unordered_set>
23

24
#include <common/error.hpp>
25

26
namespace mender {
27
namespace common {
28
namespace path {
29

30
using namespace std;
31
namespace fs = std::filesystem;
32
namespace io = mender::common::io;
33

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

46
string JoinOne(const string &prefix, const string &suffix) {
44,720✔
47
        return (fs::path(prefix) / suffix).string();
44,720✔
48
}
49

50
string BaseName(const string &path) {
11,945✔
51
        return fs::path(path).filename().string();
11,945✔
52
}
53

54
string DirName(const string &path) {
91✔
55
        return fs::path(path).parent_path().string();
91✔
56
}
57

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

68
bool IsAbsolute(const string &path) {
2,461✔
69
        return fs::path(path).is_absolute();
4,922✔
70
}
71

72
bool FileExists(const string &path) {
1,619✔
73
        try {
74
                return fs::exists(path);
1,619✔
75
        } catch (const fs::filesystem_error &e) {
×
76
                log::Error("Could not check file existence of '" + path + "': " + e.what());
×
77
                return false;
78
        }
79
}
80

81
error::Error FileDelete(const string &path) {
4✔
82
        error_code ec;
4✔
83
        bool deleted = fs::remove(fs::path(path), ec);
4✔
84
        if (not deleted) {
4✔
85
                return error::Error(
86
                        ec.default_error_condition(),
×
87
                        "Failed to remove the file: '" + path + "'. error: " + ec.message());
×
88
        }
89
        return error::NoError;
4✔
90
}
91

92
error::Error DeleteRecursively(const string &path) {
104✔
93
        error_code ec;
104✔
94
        fs::remove_all(path, ec);
104✔
95
        if (ec) {
104✔
96
                return error::Error(ec.default_error_condition(), "Could not remove path");
×
97
        }
98
        return error::NoError;
104✔
99
}
100

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

119
expected::ExpectedBool AreFilesIdentical(const string &file_one, const string &file_two) {
3✔
120
        auto file_one_expected_stream = io::OpenIfstream(file_one);
3✔
121
        if (!file_one_expected_stream) {
3✔
122
                return expected::unexpected(file_one_expected_stream.error());
×
123
        }
124
        auto file_two_expected_stream = io::OpenIfstream(file_two);
3✔
125
        if (!file_two_expected_stream) {
3✔
126
                return expected::unexpected(file_two_expected_stream.error());
×
127
        }
128

129
        auto &file_one_stream = file_one_expected_stream.value();
3✔
130
        auto &file_two_stream = file_two_expected_stream.value();
3✔
131

132
        // Compare file sizes
133
        file_one_stream.seekg(0, ios::end);
3✔
134
        file_two_stream.seekg(0, ios::end);
3✔
135
        if (file_one_stream.tellg() != file_two_stream.tellg()) {
3✔
136
                return false;
137
        }
138
        file_one_stream.seekg(0, ios::beg);
3✔
139
        file_two_stream.seekg(0, ios::beg);
3✔
140

141
        string file_one_contents {
142
                istreambuf_iterator<char>(file_one_stream), istreambuf_iterator<char>()};
3✔
143
        string file_two_contents {
144
                istreambuf_iterator<char>(file_two_stream), istreambuf_iterator<char>()};
3✔
145

146
        size_t file_one_hash = std::hash<string> {}(file_one_contents);
3✔
147
        size_t file_two_hash = std::hash<string> {}(file_two_contents);
3✔
148

149

150
        return file_one_hash == file_two_hash;
3✔
151
}
152

153
error::Error Permissions(const string &file_path, const vector<Perms> perms) {
1,000✔
154
        if (perms.size() == 0) {
1,000✔
155
                return error::NoError;
×
156
        }
157
        fs::perms p {};
1,000✔
158
        std::for_each(perms.cbegin(), perms.cend(), [&p](const Perms perm) { p |= perm_map.at(perm); });
4,000✔
159
        try {
160
                fs::permissions(file_path, p);
1,000✔
161
        } catch (const fs::filesystem_error &e) {
×
162
                return error::Error(
163
                        e.code().default_error_condition(), "Could not set permissions on '" + file_path + "'");
×
164
        }
165
        return error::NoError;
1,000✔
166
}
167

168
expected::ExpectedUnorderedSet<string> ListFiles(
1,344✔
169
        const string &in_directory, function<bool(string)> matcher) {
170
        try {
171
                unordered_set<string> matching_files {};
1,344✔
172
                fs::path dir_path(in_directory);
2,688✔
173
                if (!fs::exists(dir_path)) {
1,344✔
174
                        auto err {errno};
161✔
175
                        return expected::unexpected(error::Error(
161✔
176
                                generic_category().default_error_condition(err),
322✔
177
                                "No such file or directory: " + in_directory));
483✔
178
                }
179

180
                for (const auto &entry : fs::directory_iterator {dir_path}) {
15,514✔
181
                        fs::path file_path = entry.path();
23,930✔
182
                        if (!fs::is_regular_file(file_path)) {
11,965✔
183
                                log::Warning("'" + file_path.string() + "'" + " is not a regular file. Ignoring.");
×
184
                                continue;
×
185
                        }
186

187
                        if (matcher(file_path)) {
23,930✔
188
                                matching_files.insert(file_path);
848✔
189
                        }
190
                }
191

192
                return matching_files;
1,183✔
193
        } catch (const fs::filesystem_error &e) {
×
194
                return expected::unexpected(error::Error(
×
195
                        e.code().default_error_condition(), "Could not list files in '" + in_directory + "'"));
×
196
        }
197
}
198

199
error::Error CreateDirectory(const string &path) {
1✔
200
        try {
201
                fs::path fs_path {path};
2✔
202
                if (not fs::create_directory(fs_path)) {
1✔
203
                        auto err {errno};
×
204
                        return error::Error(
205
                                generic_category().default_error_condition(err),
×
206
                                "Failed to create the directory: " + path);
×
207
                }
208
        } catch (const fs::filesystem_error &e) {
×
209
                return error::Error(
210
                        e.code().default_error_condition(), "Failed to create directory: '" + path + "'");
×
211
        }
212
        return error::NoError;
1✔
213
}
214

215
error::Error CreateDirectories(const string &dir) {
462✔
216
        try {
217
                const fs::path p {dir};
924✔
218
                fs::create_directories(p);
462✔
219
        } catch (const fs::filesystem_error &e) {
×
220
                return error::Error(
221
                        e.code().default_error_condition(), "Failed to create directory: '" + dir + "'");
×
222
        }
223
        return error::NoError;
462✔
224
}
225

226
error::Error Rename(const string &oldname, const string &newname) {
×
227
        error_code ec;
×
228
        fs::rename(fs::path(oldname), fs::path(newname), ec);
×
229
        if (ec) {
×
230
                return error::Error(
231
                        ec.default_error_condition(),
×
232
                        "Failed to rename '" + oldname + "' to '" + newname + "'. error: " + ec.message());
×
233
        }
234
        return error::NoError;
×
235
}
236

237
error::Error FileCopy(const string &what, const string &where) {
×
238
        error_code ec;
×
239
        fs::copy_file(fs::path(what), fs::path(where), fs::copy_options::overwrite_existing, ec);
×
240
        if (ec) {
×
241
                return error::Error(
242
                        ec.default_error_condition(),
×
243
                        "Failed to copy '" + what + "' to '" + where + "'. error: " + ec.message());
×
244
        }
245
        return error::NoError;
×
246
}
247

248
} // namespace path
249
} // namespace common
250
} // 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