Implement Storage::save() using StorageSerializer and clean up
[platform/core/security/cynara.git] / src / service / 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        InMemoryStorageBackend.cpp
18  * @author      Aleksander Zdyb <a.zdyb@partner.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 <string>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unordered_map>
30 #include <vector>
31
32 #include <log/log.h>
33 #include <exceptions/BucketNotExistsException.h>
34 #include <exceptions/CannotCreateFileException.h>
35 #include <exceptions/FileNotFoundException.h>
36 #include <exceptions/UnexpectedErrorException.h>
37 #include <types/PolicyBucket.h>
38 #include <types/PolicyResult.h>
39 #include <types/PolicyType.h>
40
41 #include <storage/BucketDeserializer.h>
42 #include <storage/StorageDeserializer.h>
43 #include <storage/StorageSerializer.h>
44
45 #include "InMemoryStorageBackend.h"
46
47 namespace Cynara {
48
49 void InMemoryStorageBackend::load(void) {
50     std::string indexFilename = m_dbPath + m_indexFileName;
51
52     try {
53         std::ifstream indexStream;
54         openFileStream(indexStream, indexFilename);
55
56         StorageDeserializer storageDeserializer(indexStream,
57             std::bind(&InMemoryStorageBackend::bucketStreamOpener, this, std::placeholders::_1));
58
59         storageDeserializer.initBuckets(buckets());
60         storageDeserializer.loadBuckets(buckets());
61     } catch (const FileNotFoundException &) {
62         LOGE("Reading cynara database failed.");
63     }
64
65     if (!hasBucket(defaultPolicyBucketId)) {
66             LOGN("Creating defaultBucket.");
67             this->buckets().insert({ defaultPolicyBucketId, PolicyBucket() });
68     }
69 }
70
71 void InMemoryStorageBackend::save(void) {
72
73     //create directory
74     int ret = mkdir(m_dbPath.c_str(), S_IRWXU);
75     if (ret < 0) {
76         int err = errno;
77         if (err != EEXIST) {
78             LOGE("Cannot create directory <%s>. Error [%d] : <%s>.",
79                  m_dbPath.c_str(), err, strerror(err));
80             throw UnexpectedErrorException(err, strerror(err));
81         }
82     }
83
84     std::ofstream indexStream;
85     openDumpFileStream(indexStream, m_dbPath + m_indexFileName);
86
87     StorageSerializer storageSerializer(indexStream);
88     storageSerializer.dump(buckets(), std::bind(&InMemoryStorageBackend::bucketDumpStreamOpener,
89                            this, std::placeholders::_1));
90 }
91
92 PolicyBucket InMemoryStorageBackend::searchDefaultBucket(const PolicyKey &key) {
93     return searchBucket(defaultPolicyBucketId, key);
94 }
95
96 PolicyBucket InMemoryStorageBackend::searchBucket(const PolicyBucketId &bucketId,
97                                                   const PolicyKey &key) {
98     try {
99         const auto &bucket = this->buckets().at(bucketId);
100         return bucket.filtered(key);
101     } catch (const std::out_of_range &) {
102         throw BucketNotExistsException(bucketId);
103     }
104 }
105
106 void InMemoryStorageBackend::insertPolicy(const PolicyBucketId &bucketId, PolicyPtr policy) {
107     try {
108         auto &bucket = buckets().at(bucketId);
109         auto &policies = bucket.policyCollection();
110         policies.push_back(policy);
111     } catch (const std::out_of_range &) {
112         throw BucketNotExistsException(bucketId);
113     }
114 }
115
116 void InMemoryStorageBackend::createBucket(const PolicyBucketId &bucketId,
117                                           const PolicyResult &defaultPolicy) {
118     PolicyBucket newBucket;
119     newBucket.setDefaultPolicy(defaultPolicy);
120     buckets().insert({ bucketId, newBucket });
121 }
122
123 void InMemoryStorageBackend::updateBucket(const PolicyBucketId &bucketId,
124                                           const PolicyResult &defaultPolicy) {
125     try {
126         auto &bucket = buckets().at(bucketId);
127         bucket.setDefaultPolicy(defaultPolicy);
128     } catch (const std::out_of_range &) {
129         throw BucketNotExistsException(bucketId);
130     }
131 }
132
133 void InMemoryStorageBackend::deleteBucket(const PolicyBucketId &bucketId) {
134     auto bucketErased = buckets().erase(bucketId);
135     if (bucketErased == 0) {
136         throw BucketNotExistsException(bucketId);
137     }
138 }
139
140 bool InMemoryStorageBackend::hasBucket(const PolicyBucketId &bucketId) {
141     return buckets().find(bucketId) != buckets().end();
142 }
143
144 void InMemoryStorageBackend::deletePolicy(const PolicyBucketId &bucketId, const PolicyKey &key) {
145     try {
146         // TODO: Move the erase code to PolicyCollection maybe?
147         auto &bucket = buckets().at(bucketId);
148         auto &policies = bucket.policyCollection();
149         policies.erase(remove_if(policies.begin(), policies.end(),
150                 [key](PolicyPtr policy) -> bool {
151                     return policy->key() == key;
152             }), policies.end());
153     } catch (const std::out_of_range &) {
154         throw BucketNotExistsException(bucketId);
155     }
156 }
157
158 void InMemoryStorageBackend::deleteLinking(const PolicyBucketId &bucketId) {
159     auto bucketIdMatches = [&bucketId] (PolicyPtr policy) -> bool {
160         auto policyResult = policy->result();
161
162         // Check bucket id only if policy is a bucket policy
163         // TODO: Maybe move the test to PolicyResult
164         if (policyResult.policyType() == PredefinedPolicyType::BUCKET) {
165             return policyResult.metadata() == bucketId;
166         }
167         return false;
168     };
169
170     for (auto &bucketIter : buckets()) {
171         // TODO: Move the erase code to PolicyCollection maybe?
172         auto &bucket = bucketIter.second;
173         auto &policies = bucket.policyCollection();
174         policies.erase(remove_if(policies.begin(), policies.end(), bucketIdMatches),
175                 policies.end());
176     }
177 }
178
179 void InMemoryStorageBackend::openFileStream(std::ifstream &stream, 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::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         return;
195     }
196 }
197
198 std::shared_ptr<BucketDeserializer> InMemoryStorageBackend::bucketStreamOpener(
199         const PolicyBucketId &bucketId) {
200     std::string bucketFilename = m_dbPath + "_" + bucketId;
201     std::ifstream bucketStream;
202     try {
203         openFileStream(bucketStream, bucketFilename);
204         return std::make_shared<BucketDeserializer>(bucketStream);
205     } catch (const FileNotFoundException &) {
206         return nullptr;
207     }
208 }
209
210 std::shared_ptr<StorageSerializer> InMemoryStorageBackend::bucketDumpStreamOpener(
211         const PolicyBucketId &bucketId) {
212     std::string bucketFilename = m_dbPath + "_" + bucketId;
213     std::ofstream bucketStream;
214
215     openDumpFileStream(bucketStream, bucketFilename);
216     return std::make_shared<StorageSerializer>(bucketStream);
217 }
218
219 } /* namespace Cynara */