ae9c624f4f3e273f8f79f5caf6fd3b87daa4adcb
[platform/core/security/cynara.git] / src / storage / InMemoryStorageBackend.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /**
17  * @file        src/storage/InMemoryStorageBackend.cpp
18  * @author      Aleksander Zdyb <a.zdyb@samsung.com>
19  * @version     1.0
20  * @brief       Implementation of InMemoryStorageBackend
21  */
22
23 #include <errno.h>
24 #include <fstream>
25 #include <functional>
26 #include <memory>
27 #include <stdexcept>
28 #include <string>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <unordered_map>
33 #include <vector>
34
35 #include <log/log.h>
36 #include <exceptions/BucketNotExistsException.h>
37 #include <exceptions/CannotCreateFileException.h>
38 #include <exceptions/DatabaseException.h>
39 #include <exceptions/FileNotFoundException.h>
40 #include <exceptions/UnexpectedErrorException.h>
41 #include <types/PolicyBucket.h>
42 #include <types/PolicyResult.h>
43 #include <types/PolicyType.h>
44
45 #include <storage/BucketDeserializer.h>
46 #include <storage/StorageDeserializer.h>
47 #include <storage/StorageSerializer.h>
48
49 #include "InMemoryStorageBackend.h"
50
51 namespace Cynara {
52
53 const std::string InMemoryStorageBackend::m_indexFileName = "buckets";
54
55 void InMemoryStorageBackend::load(void) {
56     std::string indexFilename = m_dbPath + m_indexFileName;
57
58     try {
59         auto indexStream = std::make_shared<std::ifstream>();
60         openFileStream(indexStream, indexFilename);
61
62         StorageDeserializer storageDeserializer(indexStream,
63             std::bind(&InMemoryStorageBackend::bucketStreamOpener, this, std::placeholders::_1));
64
65         storageDeserializer.initBuckets(buckets());
66         storageDeserializer.loadBuckets(buckets());
67     } catch (const DatabaseException &) {
68         LOGC("Reading cynara database failed.");
69         buckets().clear();
70         // TODO: Implement emergency mode toggle
71     }
72
73     if (!hasBucket(defaultPolicyBucketId)) {
74         LOGN("Creating defaultBucket.");
75         this->buckets().insert({ defaultPolicyBucketId, PolicyBucket() });
76     }
77 }
78
79 void InMemoryStorageBackend::save(void) {
80
81     //create directory
82     int ret = mkdir(m_dbPath.c_str(), S_IRWXU);
83     if (ret < 0) {
84         int err = errno;
85         if (err != EEXIST) {
86             LOGE("Cannot create directory <%s>. Error [%d] : <%s>.",
87                  m_dbPath.c_str(), err, strerror(err));
88             throw UnexpectedErrorException(err, strerror(err));
89         }
90     }
91
92     auto indexStream = std::make_shared<std::ofstream>();
93     openDumpFileStream(indexStream, m_dbPath + m_indexFileName);
94
95     StorageSerializer storageSerializer(indexStream);
96     storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener,
97                            this, std::placeholders::_1));
98 }
99
100 PolicyBucket InMemoryStorageBackend::searchDefaultBucket(const PolicyKey &key) {
101     return searchBucket(defaultPolicyBucketId, key);
102 }
103
104 PolicyBucket InMemoryStorageBackend::searchBucket(const PolicyBucketId &bucketId,
105                                                   const PolicyKey &key) {
106     try {
107         const auto &bucket = this->buckets().at(bucketId);
108         return bucket.filtered(key);
109     } catch (const std::out_of_range &) {
110         throw BucketNotExistsException(bucketId);
111     }
112 }
113
114 void InMemoryStorageBackend::insertPolicy(const PolicyBucketId &bucketId, PolicyPtr policy) {
115     try {
116         auto &bucket = buckets().at(bucketId);
117         bucket.insertPolicy(policy);
118     } catch (const std::out_of_range &) {
119         throw BucketNotExistsException(bucketId);
120     }
121 }
122
123 void InMemoryStorageBackend::createBucket(const PolicyBucketId &bucketId,
124                                           const PolicyResult &defaultPolicy) {
125     PolicyBucket newBucket(bucketId, defaultPolicy);
126     buckets().insert({ bucketId, newBucket });
127 }
128
129 void InMemoryStorageBackend::updateBucket(const PolicyBucketId &bucketId,
130                                           const PolicyResult &defaultPolicy) {
131     try {
132         auto &bucket = buckets().at(bucketId);
133         bucket.setDefaultPolicy(defaultPolicy);
134     } catch (const std::out_of_range &) {
135         throw BucketNotExistsException(bucketId);
136     }
137 }
138
139 void InMemoryStorageBackend::deleteBucket(const PolicyBucketId &bucketId) {
140     auto bucketErased = buckets().erase(bucketId);
141     if (bucketErased == 0) {
142         throw BucketNotExistsException(bucketId);
143     }
144 }
145
146 bool InMemoryStorageBackend::hasBucket(const PolicyBucketId &bucketId) {
147     return buckets().find(bucketId) != buckets().end();
148 }
149
150 void InMemoryStorageBackend::deletePolicy(const PolicyBucketId &bucketId, const PolicyKey &key) {
151     try {
152         // TODO: Move the erase code to PolicyCollection maybe?
153         auto &bucket = buckets().at(bucketId);
154         bucket.deletePolicy(key);
155     } catch (const std::out_of_range &) {
156         throw BucketNotExistsException(bucketId);
157     }
158 }
159
160 void InMemoryStorageBackend::deleteLinking(const PolicyBucketId &bucketId) {
161     auto bucketIdMatches = [&bucketId] (PolicyPtr policy) -> bool {
162         auto policyResult = policy->result();
163
164         // Check bucket id only if policy is a bucket policy
165         // TODO: Maybe move the test to PolicyResult
166         if (policyResult.policyType() == PredefinedPolicyType::BUCKET) {
167             return policyResult.metadata() == bucketId;
168         }
169         return false;
170     };
171
172     for (auto &bucketIter : buckets()) {
173         auto &bucket = bucketIter.second;
174         bucket.deletePolicy(bucketIdMatches);
175     }
176 }
177
178 void InMemoryStorageBackend::openFileStream(std::shared_ptr<std::ifstream> stream,
179                                             const std::string &filename) {
180     // TODO: Consider adding exceptions to streams and handling them:
181     // stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
182     stream->open(filename);
183
184     if (!stream->is_open())
185         throw FileNotFoundException(filename);
186 }
187
188 void InMemoryStorageBackend::openDumpFileStream(std::shared_ptr<std::ofstream> stream,
189                                                 const std::string &filename) {
190     stream->open(filename, std::ofstream::out | std::ofstream::trunc);
191
192     if (!stream->is_open()) {
193         throw CannotCreateFileException(filename);
194     }
195 }
196
197 std::shared_ptr<BucketDeserializer> InMemoryStorageBackend::bucketStreamOpener(
198         const PolicyBucketId &bucketId) {
199     std::string bucketFilename = m_dbPath + "_" + bucketId;
200     auto bucketStream = std::make_shared<std::ifstream>();
201     try {
202         openFileStream(bucketStream, bucketFilename);
203         return std::make_shared<BucketDeserializer>(bucketStream);
204     } catch (const FileNotFoundException &) {
205         return nullptr;
206     }
207 }
208
209 std::shared_ptr<StorageSerializer> InMemoryStorageBackend::bucketDumpStreamOpener(
210         const PolicyBucketId &bucketId) {
211     std::string bucketFilename = m_dbPath + "_" + bucketId;
212     auto bucketStream = std::make_shared<std::ofstream>();
213
214     openDumpFileStream(bucketStream, bucketFilename);
215     return std::make_shared<StorageSerializer>(bucketStream);
216 }
217
218 } /* namespace Cynara */