2 * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file src/storage/Integrity.cpp
18 * @author Pawel Wieczorek <p.wieczorek2@samsung.com>
20 * @brief Implementation of Cynara::Integrity
29 #include <sys/types.h>
32 #include <config/PathConfig.h>
33 #include <exceptions/CannotCreateFileException.h>
34 #include <exceptions/UnexpectedErrorException.h>
37 #include "Integrity.h"
41 namespace StorageConfig = PathConfig::StoragePath;
43 const std::string Integrity::m_guardFilename(StorageConfig::guardFilename);
44 const std::string Integrity::m_indexFilename(StorageConfig::indexFilename);
45 const std::string Integrity::m_backupFilenameSuffix(StorageConfig::backupFilenameSuffix);
46 const std::string Integrity::m_bucketFilenamePrefix(StorageConfig::bucketFilenamePrefix);
48 bool Integrity::backupGuardExists(void) const {
50 std::string guardFilename = m_dbPath + m_guardFilename;
52 int ret = stat(guardFilename.c_str(), &buffer);
59 LOGE("'stat' function error [%d] : <%s>", err, strerror(err));
60 throw UnexpectedErrorException(err, strerror(err));
66 void Integrity::createBackupGuard(void) const {
67 syncElement(m_dbPath + m_guardFilename, O_CREAT | O_EXCL | O_WRONLY | O_TRUNC);
68 syncDirectory(m_dbPath);
71 void Integrity::syncDatabase(const Buckets &buckets, bool syncBackup) {
72 std::string suffix = "";
75 suffix += m_backupFilenameSuffix;
78 for (const auto &bucketIter : buckets) {
79 const auto &bucketId = bucketIter.first;
80 const auto &bucketFilename = m_dbPath + m_bucketFilenamePrefix + bucketId + suffix;
82 syncElement(bucketFilename);
85 syncElement(m_dbPath + m_indexFilename + suffix);
86 syncElement(m_dbPath + PathConfig::StoragePath::checksumFilename + suffix);
87 syncDirectory(m_dbPath);
90 void Integrity::revalidatePrimaryDatabase(const Buckets &buckets) {
91 createPrimaryHardLinks(buckets);
92 syncDatabase(buckets, false);
94 deleteHardLink(m_dbPath + m_guardFilename);
95 syncDirectory(m_dbPath);
97 deleteBackupHardLinks(buckets);
100 void Integrity::deleteNonIndexedFiles(BucketPresenceTester tester) {
101 DIR *dirPtr = nullptr;
102 struct dirent *direntPtr;
104 if ((dirPtr = opendir(m_dbPath.c_str())) == nullptr) {
106 LOGE("'opendir' function error [%d] : <%s>", err, strerror(err));
107 throw UnexpectedErrorException(err, strerror(err));
111 while (errno = 0, (direntPtr = readdir(dirPtr)) != nullptr) {
112 std::string filename = direntPtr->d_name;
113 //ignore all special files (working dir, parent dir, index, checksums)
114 if (isSpecialDirectory(filename) || isSpecialDatabaseEntry(filename)) {
118 std::string bucketId;
119 auto nameLength = filename.length();
120 auto prefixLength = m_bucketFilenamePrefix.length();
122 //remove if it is impossible that it is a bucket file
123 if (nameLength < prefixLength) {
124 deleteHardLink(m_dbPath + filename);
128 //remove if there is no bucket filename prefix
129 //0 is returned from string::compare() if strings are equal
130 if (0 != filename.compare(0, prefixLength, m_bucketFilenamePrefix)) {
131 deleteHardLink(m_dbPath + filename);
135 //remove if bucket is not in index
136 bucketId = filename.substr(prefixLength);
137 if (!tester(bucketId)) {
138 deleteHardLink(m_dbPath + filename);
144 LOGE("'readdir' function error [%d] : <%s>", err, strerror(err));
145 throw UnexpectedErrorException(err, strerror(err));
150 void Integrity::syncElement(const std::string &filename, int flags, mode_t mode) {
151 int fileFd = TEMP_FAILURE_RETRY(open(filename.c_str(), flags, mode));
156 LOGE("File <%s> : 'open' function error [%d] : <%s>", filename.c_str(), err,
158 throw UnexpectedErrorException(err, strerror(err));
160 throw CannotCreateFileException(filename);
164 int ret = fsync(fileFd);
168 LOGE("'fsync' function error [%d] : <%s>", err, strerror(err));
169 throw UnexpectedErrorException(err, strerror(err));
176 LOGE("'close' function error [%d] : <%s>", err, strerror(err));
177 throw UnexpectedErrorException(err, strerror(err));
182 // Calling fsync() does not necessarily ensure that the entry in the directory containing
183 // the file has also reached disk. For that an explicit fsync() on a file descriptor for
184 // the directory is also needed.
185 void Integrity::syncDirectory(const std::string &dirname, mode_t mode) {
186 syncElement(dirname, O_DIRECTORY, mode);
189 void Integrity::createPrimaryHardLinks(const Buckets &buckets) {
190 for (const auto &bucketIter : buckets) {
191 const auto &bucketId = bucketIter.first;
192 const auto &bucketFilename = m_dbPath + m_bucketFilenamePrefix + bucketId;
194 deleteHardLink(bucketFilename);
195 createHardLink(bucketFilename + m_backupFilenameSuffix, bucketFilename);
198 const auto &indexFilename = m_dbPath + m_indexFilename;
199 const auto &checksumFilename = m_dbPath + PathConfig::StoragePath::checksumFilename;
201 deleteHardLink(indexFilename);
202 createHardLink(indexFilename + m_backupFilenameSuffix, indexFilename);
203 deleteHardLink(checksumFilename);
204 createHardLink(checksumFilename + m_backupFilenameSuffix, checksumFilename);
207 void Integrity::deleteBackupHardLinks(const Buckets &buckets) {
208 for (const auto &bucketIter : buckets) {
209 const auto &bucketId = bucketIter.first;
210 const auto &bucketFilename = m_dbPath + m_bucketFilenamePrefix +
211 bucketId + m_backupFilenameSuffix;
213 deleteHardLink(bucketFilename);
216 deleteHardLink(m_dbPath + m_indexFilename + m_backupFilenameSuffix);
217 deleteHardLink(m_dbPath + PathConfig::StoragePath::checksumFilename + m_backupFilenameSuffix);
220 void Integrity::createHardLink(const std::string &oldName, const std::string &newName) {
221 int ret = link(oldName.c_str(), newName.c_str());
225 throw UnexpectedErrorException(err, strerror(err));
226 LOGN("Trying to link to non-existent file: <%s>", oldName.c_str());
230 void Integrity::deleteHardLink(const std::string &filename) {
231 int ret = unlink(filename.c_str());
236 LOGE("'unlink' function error [%d] : <%s>", err, strerror(err));
237 throw UnexpectedErrorException(err, strerror(err));
239 LOGN("Trying to unlink non-existent file: <%s>", filename.c_str());
244 bool Integrity::isSpecialDirectory(const std::string &filename) {
245 return "." == filename || ".." == filename;
248 bool Integrity::isSpecialDatabaseEntry(const std::string &filename) {
249 return PathConfig::StoragePath::indexFilename == filename ||
250 PathConfig::StoragePath::checksumFilename == filename;
253 } /* namespace Cynara */