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

wirenboard / wb-mqtt-serial / 973

13 Oct 2026 12:17PM UTC coverage: 86.78% (+1.1%) from 85.703%
973

push

github

web-flow
Apply uploaded and deleted templates to polling (#1277)

templates/Upload and templates/Delete update the configuration of the devices using the template, if possible.
device/LoadConfig reads only devices with "hw" in the template.

31091 of 80727 branches covered (38.51%)

1849 of 1928 new or added lines in 21 files covered. (95.9%)

8 existing lines in 5 files now uncovered.

22403 of 25816 relevant lines covered (86.78%)

2617.69 hits per line

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

72.22
/src/file_utils.cpp
1
#include "file_utils.h"
2
#include "log.h"
3
#include <algorithm>
4
#include <fcntl.h>
5
#include <filesystem>
6
#include <unistd.h>
7

8
#define LOG(logger) ::logger.Log() << "[file utils] "
9

10
TNoDirError::TNoDirError(const std::string& msg): std::runtime_error(msg)
3 ✔
11
{}
3 ✔
12

13
bool TryOpen(const std::vector<std::string>& fnames, std::ifstream& file)
×
14
{
15
    for (auto& fname: fnames) {
×
16
        file.open(fname);
×
17
        if (file.is_open()) {
×
18
            return true;
×
19
        }
20
        file.clear();
×
21
    }
22
    return false;
×
23
}
24

25
void WriteToFile(const std::string& fileName, const std::string& value)
84 ✔
26
{
27
    std::ofstream f;
84 !
28
    OpenWithException(f, fileName);
84 !
29
    f << value;
84 !
30
}
84 ✔
31

32
namespace
33
{
34
    bool SyncFile(const std::string& fileName)
204 ✔
35
    {
36
        int fd = open(fileName.c_str(), O_RDONLY);
204 ✔
37
        if (fd < 0) {
204 !
38
            return false;
×
39
        }
40
        int res = fsync(fd);
204 ✔
41
        close(fd);
204 ✔
42
        return res == 0;
204 ✔
43
    }
44
}
45

46
TAtomicFileWrite::TAtomicFileWrite(const std::string& fileName, const std::string& content): Path(fileName)
110 ✔
47
{
48
    if (std::filesystem::is_symlink(Path)) {
110 !
49
        Path = std::filesystem::canonical(Path);
1 !
50
    }
51
    TmpFileName = Path.string() + ".tmp";
110 !
52
    try {
53
        {
54
            std::ofstream file;
110 !
55
            OpenWithException(file, TmpFileName);
110 ✔
56
            file << content;
103 !
57
            file.flush();
103 !
58
            if (!file.good()) {
103 !
NEW
59
                throw std::runtime_error("Failed to write file: " + TmpFileName);
×
60
            }
61
        }
110 ✔
62
        // Closing the file leaves the data in the kernel cache, without the sync the renamed file
63
        // may be empty after a power loss
64
        if (!SyncFile(TmpFileName)) {
103 !
NEW
65
            throw std::runtime_error("Failed to sync file: " + TmpFileName);
×
66
        }
67
    } catch (...) {
7 ✔
68
        std::error_code ec;
7 ✔
69
        std::filesystem::remove(TmpFileName, ec);
7 !
70
        throw;
7 ✔
71
    }
7 ✔
72
}
117 ✔
73

74
TAtomicFileWrite::~TAtomicFileWrite()
103 ✔
75
{
76
    if (!Committed) {
103 ✔
77
        std::error_code ec;
2 ✔
78
        std::filesystem::remove(TmpFileName, ec);
2 ✔
79
    }
80
}
103 ✔
81

82
void TAtomicFileWrite::Commit()
101 ✔
83
{
84
    std::filesystem::rename(TmpFileName, Path);
101 !
85
    Committed = true;
101 ✔
86
    // The rename is in the kernel cache too, without the sync the old file may come back after a power loss.
87
    // Nothing is known about the disk after a failed sync, the file is replaced for the readers anyway
88
    auto dirName = Path.parent_path().empty() ? std::string(".") : Path.parent_path().string();
101 !
89
    if (!SyncFile(dirName)) {
101 !
NEW
90
        LOG(Warn) << "Failed to sync directory " << dirName << ", " << Path.string()
×
91
                  << " may be old after a power loss";
×
92
    }
93
}
101 ✔
94

95
void WriteFileAtomically(const std::string& fileName, const std::string& content)
67 ✔
96
{
97
    TAtomicFileWrite(fileName, content).Commit();
67 !
98
}
64 ✔
99

100
void IterateDir(const std::string& dirName, std::function<bool(const std::string&)> fn)
491 ✔
101
{
102
    try {
103
        const std::filesystem::path dirPath{dirName};
491 !
104

105
        for (const auto& entry: std::filesystem::directory_iterator(dirPath)) {
10,395 !
106
            const auto filenameStr = entry.path().filename().string();
9,904 !
107
            if (fn(filenameStr)) {
9,904 !
108
                return;
×
109
            }
110
        }
10,392 !
111
    } catch (std::filesystem::filesystem_error const& ex) {
494 !
112
        throw TNoDirError(ex.what());
9 !
113
    }
3 ✔
114
}
115

116
std::string IterateDirByPattern(const std::string& dirName,
280 ✔
117
                                const std::string& pattern,
118
                                std::function<bool(const std::string&)> fn,
119
                                bool sort)
120
{
121
    if (sort) {
280 !
122
        std::vector<std::string> files;
280 ✔
123
        IterateDir(dirName, [&](const auto& name) {
283 !
124
            if (name.find(pattern) != std::string::npos) {
7,005 !
125
                files.push_back(dirName + "/" + name);
7,005 !
126
            }
127
            return false;
7,005 ✔
128
        });
129
        std::sort(files.begin(), files.end());
277 !
130
        for (const auto& fileName: files) {
7,282 ✔
131
            if (fn(fileName)) {
7,005 !
132
                return fileName;
×
133
            }
134
        }
135
        return std::string();
277 ✔
136
    }
280 ✔
137
    std::string res;
×
138
    IterateDir(dirName, [&](const auto& name) {
×
139
        if (name.find(pattern) != std::string::npos) {
×
140
            std::string d(dirName + "/" + name);
×
141
            if (fn(d)) {
×
142
                res = d;
×
143
                return true;
×
144
            }
145
        }
×
146
        return false;
×
147
    });
148
    return res;
×
149
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc