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

mendersoftware / mender / 1033353997

11 Oct 2023 01:43PM UTC coverage: 79.99% (-0.2%) from 80.166%
1033353997

push

gitlab-ci

oleorhagen
style: Run clang-format on the whole repository

Signed-off-by: Ole Petter <ole.orhagen@northern.tech>

1 of 1 new or added line in 1 file covered. (100.0%)

6492 of 8116 relevant lines covered (79.99%)

9901.24 hits per line

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

69.61
/artifact/v3/header/header.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 <artifact/v3/header/header.hpp>
16

17
#include <sys/stat.h>
18

19
#include <iomanip>
20
#include <memory>
21
#include <string>
22
#include <system_error>
23
#include <vector>
24
#include <iostream>
25
#include <fstream>
26

27
#include <common/expected.hpp>
28
#include <common/error.hpp>
29
#include <common/io.hpp>
30
#include <common/log.hpp>
31
#include <common/json.hpp>
32
#include <common/common.hpp>
33
#include <common/path.hpp>
34

35
#include <artifact/error.hpp>
36
#include <artifact/lexer.hpp>
37
#include <artifact/tar/tar.hpp>
38

39
#include <artifact/v3/header/token.hpp>
40

41
namespace mender {
42
namespace artifact {
43
namespace v3 {
44
namespace header {
45

46
using namespace std;
47

48
namespace expected = mender::common::expected;
49
namespace io = mender::common::io;
50
namespace error = mender::common::error;
51
namespace log = mender::common::log;
52
namespace json = mender::common::json;
53
namespace path = mender::common::path;
54

55

56
namespace {
57
string IndexString(int index) {
1✔
58
        stringstream index_string {};
2✔
59
        index_string << setw(4) << setfill('0') << index;
1✔
60
        return index_string.str();
1✔
61
}
62
} // namespace
63

64
ExpectedHeader Parse(io::Reader &reader, ParserConfig conf) {
139✔
65
        Header header {};
278✔
66

67
        shared_ptr<tar::Reader> tar_reader {make_shared<tar::Reader>(reader)};
139✔
68

69
        auto lexer = lexer::Lexer<header::token::Token, header::token::Type> {tar_reader};
278✔
70

71
        token::Token tok = lexer.Next();
278✔
72

73
        if (tok.type != token::Type::HeaderInfo) {
139✔
74
                return expected::unexpected(parser_error::MakeError(
1✔
75
                        parser_error::Code::ParseError,
76
                        "Got unexpected token: '" + tok.TypeToString() + "' expected 'header-info'"));
3✔
77
        }
78

79
        auto expected_info = header::info::Parse(*tok.value);
138✔
80

81
        if (!expected_info) {
138✔
82
                return expected::unexpected(parser_error::MakeError(
×
83
                        parser_error::Code::ParseError,
84
                        "Failed to parse the header-info: " + expected_info.error().message));
×
85
        }
86
        header.info = expected_info.value();
138✔
87

88
        tok = lexer.Next();
138✔
89
        vector<ArtifactScript> state_scripts {};
138✔
90
        if (tok.type == token::Type::ArtifactScripts) {
138✔
91
                // Make sure the `scripts` dir exists
92
                if (not path::FileExists(conf.artifact_scripts_filesystem_path)) {
4✔
93
                        log::Trace(
×
94
                                "Creating the Artifact script directory: " + conf.artifact_scripts_filesystem_path);
×
95
                        error::Error err = path::CreateDirectory(conf.artifact_scripts_filesystem_path);
×
96
                        if (err != error::NoError) {
×
97
                                return expected::unexpected(err.WithContext(
×
98
                                        "Failed to create the scripts directory for installing Artifact scripts"));
×
99
                        }
100
                }
101
        }
102
        while (tok.type == token::Type::ArtifactScripts) {
145✔
103
                log::Trace("Parsing state script...");
14✔
104
                const string artifact_script_path =
105
                        path::Join(conf.artifact_scripts_filesystem_path, tok.name);
7✔
106
                errno = 0;
7✔
107
                ofstream myfile(artifact_script_path);
14✔
108
                log::Trace("state script name: " + tok.name);
14✔
109
                if (!myfile.good()) {
7✔
110
                        auto io_errno = errno;
×
111
                        return expected::unexpected(error::Error(
×
112
                                std::generic_category().default_error_condition(io_errno),
×
113
                                "Failed to create a file for writing the Artifact script: " + artifact_script_path
×
114
                                        + " to the filesystem"));
×
115
                }
116
                io::StreamWriter sw {myfile};
14✔
117

118
                auto err = io::Copy(sw, *tok.value);
7✔
119
                if (err != error::NoError) {
7✔
120
                        return expected::unexpected(err);
×
121
                }
122

123
                state_scripts.push_back(artifact_script_path);
7✔
124

125
                // Set the permissions on the installed Artifact scripts
126
                path::Permissions(
7✔
127
                        artifact_script_path,
128
                        {path::Perms::Owner_read, path::Perms::Owner_write, path::Perms::Owner_exec});
14✔
129

130
                tok = lexer.Next();
7✔
131
        }
132

133
        // Write the Artifact script version file
134
        if (state_scripts.size() > 0) {
138✔
135
                const string artifact_script_version_file =
136
                        path::Join(conf.artifact_scripts_filesystem_path, "version");
4✔
137
                errno = 0;
4✔
138
                ofstream myfile(artifact_script_version_file);
8✔
139
                log::Trace("Creating the Artifact script version file: " + artifact_script_version_file);
8✔
140
                if (!myfile.good()) {
4✔
141
                        auto io_errno = errno;
×
142
                        return expected::unexpected(error::Error(
×
143
                                std::generic_category().default_error_condition(io_errno),
×
144
                                "Failed to create the Artifact script version file: "
145
                                        + artifact_script_version_file));
×
146
                }
147
                myfile << to_string(conf.artifact_scripts_version);
8✔
148
                if (!myfile.good()) {
4✔
149
                        auto io_errno = errno;
×
150
                        return expected::unexpected(error::Error(
×
151
                                std::generic_category().default_error_condition(io_errno),
×
152
                                "I/O error writing the Artifact scripts version file"));
×
153
                }
154
        }
155

156

157
        header.artifactScripts = std::move(state_scripts);
138✔
158

159
        vector<SubHeader> subheaders {};
138✔
160

161
        int current_index {0};
162
        while (tok.type != token::Type::EOFToken) {
275✔
163
                log::Trace("Parsing the sub-header ...");
276✔
164

165
                // NOTE: We currently do not support multiple payloads
166
                if (current_index != 0) {
138✔
167
                        return expected::unexpected(parser_error::MakeError(
×
168
                                parser_error::Code::ParseError,
169
                                "Multiple header entries found. Currently only one is supported"));
×
170
                }
171

172
                SubHeader sub_header {};
275✔
173
                if (tok.type != token::Type::ArtifactHeaderTypeInfo) {
138✔
174
                        return expected::unexpected(parser_error::MakeError(
×
175
                                parser_error::Code::ParseError,
176
                                "Unexpected entry: " + tok.TypeToString() + " expected: type-info"));
×
177
                }
178

179
                if (current_index != tok.Index()) {
138✔
180
                        return expected::unexpected(parser_error::MakeError(
1✔
181
                                parser_error::Code::ParseError,
182
                                "Unexpected index order for the type-info: " + tok.name + " expected: headers/"
2✔
183
                                        + IndexString(current_index) + "/type-info"));
5✔
184
                }
185
                auto expected_type_info = type_info::Parse(*tok.value);
137✔
186
                if (!expected_type_info) {
137✔
187
                        return expected::unexpected(expected_type_info.error());
×
188
                }
189
                sub_header.type_info = expected_type_info.value();
137✔
190

191
                // NOTE (workaround): Bug in the Artifact format writer:
192
                // If the type is a RootfsImage, then the payload-type will be empty. This
193
                // is a bug in the mender-artifact tool, which writes the payload. For now,
194
                // just work around it.
195
                if (header.info.payloads[current_index].type == Payload::RootfsImage) {
137✔
196
                        log::Debug(
53✔
197
                                "Setting the type-info in payload nr " + to_string(current_index)
106✔
198
                                + " to rootfs-image");
106✔
199
                        sub_header.type_info.type = "rootfs-image";
53✔
200
                }
201

202
                tok = lexer.Next();
137✔
203

204
                log::Trace("sub-header: looking for meta-data");
274✔
205

206
                // meta-data (optional)
207
                if (tok.type == token::Type::ArtifactHeaderMetaData) {
137✔
208
                        if (current_index != tok.Index()) {
54✔
209
                                return expected::unexpected(parser_error::MakeError(
×
210
                                        parser_error::Code::ParseError,
211
                                        "Unexpected index order for the meta-data: " + tok.name + " expected: headers/"
×
212
                                                + IndexString(current_index) + "/meta-data"));
×
213
                        }
214
                        auto expected_meta_data = meta_data::Parse(*tok.value);
54✔
215
                        if (!expected_meta_data) {
54✔
216
                                return expected::unexpected(expected_meta_data.error());
×
217
                        }
218
                        sub_header.metadata = expected_meta_data.value();
54✔
219
                        tok = lexer.Next();
54✔
220
                }
221
                log::Trace("sub-header: parsed the meta-data");
274✔
222

223
                header.subHeaders.push_back(sub_header);
137✔
224

225
                current_index++;
226
        }
227

228
        return header;
137✔
229
}
230

231
} // namespace header
232
} // namespace v3
233
} // namespace artifact
234
} // 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

© 2025 Coveralls, Inc