]> git.saurik.com Git - cydia.git/blame - Cytore.hpp
firmware.sh has no assumed "current" directory :/.
[cydia.git] / Cytore.hpp
CommitLineData
94b0b3e5
JF
1// Copyright Notice (GNU Affero GPL) {{{
2/* Cyndir - (Awesome) Memory Mapped Dictionary
3 * Copyright (C) 2010 Jay Freeman (saurik)
4*/
5
6/*
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19*/
20// }}}
21
22#ifndef CYTORE_HPP
23#define CYTORE_HPP
24
25#include <fcntl.h>
26
27#include <sys/mman.h>
28#include <sys/stat.h>
29
30#include <cstdio>
31#include <cstdlib>
32
33#include <errno.h>
34#include <stdint.h>
35#include <unistd.h>
36
37#define _assert(test) do \
38 if (!(test)) { \
39 fprintf(stderr, "_assert(%d:%s)@%s:%u[%s]\n", errno, #test, __FILE__, __LINE__, __FUNCTION__); \
40 exit(-1); \
41 } \
42while (false)
43
44namespace Cytore {
45
46static const uint32_t Magic = 'cynd';
47
48struct Header {
49 uint32_t magic_;
50 uint32_t version_;
51 uint32_t size_;
52 uint32_t reserved_;
1fe922cd 53} _packed;
94b0b3e5 54
94b0b3e5
JF
55template <typename Target_>
56class Offset {
57 private:
58 uint32_t offset_;
59
60 public:
61 Offset() :
62 offset_(0)
63 {
64 }
65
66 Offset(uint32_t offset) :
67 offset_(offset)
68 {
69 }
70
71 Offset &operator =(uint32_t offset) {
72 offset_ = offset;
73 return *this;
74 }
75
76 uint32_t GetOffset() const {
77 return offset_;
78 }
79
80 bool IsNull() const {
81 return offset_ == 0;
82 }
1fe922cd 83} _packed;
94b0b3e5 84
05c98961
JF
85struct Block {
86 Cytore::Offset<void> reserved_;
1fe922cd 87} _packed;
05c98961 88
94b0b3e5
JF
89template <typename Type_>
90static _finline Type_ Round(Type_ value, Type_ size) {
91 Type_ mask(size - 1);
92 return value + mask & ~mask;
93}
94
95template <typename Base_>
96class File {
97 private:
98 static const unsigned Shift_ = 17;
99 static const size_t Block_ = 1 << Shift_;
100 static const size_t Mask_ = Block_ - 1;
101
102 private:
103 int file_;
ffbb3bd5
JF
104
105 typedef std::vector<uint8_t *> BlockVector_;
106 BlockVector_ blocks_;
107
108 struct Mapping_ {
109 uint8_t *data_;
110 size_t size_;
111
112 Mapping_(uint8_t *data, size_t size) :
113 data_(data),
114 size_(size)
115 {
116 }
117 };
118
119 typedef std::vector<Mapping_> MappingVector_;
120 MappingVector_ maps_;
94b0b3e5
JF
121
122 Header &Header_() {
123 return *reinterpret_cast<Header *>(blocks_[0]);
124 }
125
126 uint32_t &Size_() {
127 return Header_().size_;
128 }
129
130 void Map_(size_t size) {
131 size_t before(blocks_.size() * Block_);
132 size_t extend(size - before);
133
134 void *data(mmap(NULL, extend, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, file_, before));
2530ab22 135 _assert(data != MAP_FAILED);
ffbb3bd5
JF
136 uint8_t *bytes(reinterpret_cast<uint8_t *>(data));
137
2530ab22 138 maps_.push_back(Mapping_(bytes, extend));
94b0b3e5 139 for (size_t i(0); i != extend >> Shift_; ++i)
ffbb3bd5 140 blocks_.push_back(bytes + Block_ * i);
94b0b3e5
JF
141 }
142
2530ab22 143 bool Truncate_(size_t capacity) {
94b0b3e5 144 capacity = Round(capacity, Block_);
625aabed 145
2530ab22 146 int error(ftruncate(file_, capacity));
625aabed
JF
147 if (error != 0)
148 return false;
149
94b0b3e5 150 Map_(capacity);
2530ab22 151 return true;
94b0b3e5
JF
152 }
153
154 public:
155 File() :
156 file_(-1)
157 {
158 }
159
160 File(const char *path) :
161 file_(-1)
162 {
163 Open(path);
164 }
165
166 ~File() {
ffbb3bd5
JF
167 for (typename MappingVector_::const_iterator map(maps_.begin()); map != maps_.end(); ++map)
168 munmap(map->data_, map->size_);
94b0b3e5
JF
169 close(file_);
170 }
171
ffbb3bd5
JF
172 void Sync() {
173 for (typename MappingVector_::const_iterator map(maps_.begin()); map != maps_.end(); ++map)
174 msync(map->data_, map->size_, MS_SYNC);
175 }
176
94b0b3e5
JF
177 size_t Capacity() const {
178 return blocks_.size() * Block_;
179 }
180
2f722d4c 181 void Open(const char *path) { open:
94b0b3e5
JF
182 _assert(file_ == -1);
183 file_ = open(path, O_RDWR | O_CREAT | O_EXLOCK, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
2530ab22 184 _assert(file_ != -1);
94b0b3e5
JF
185
186 struct stat stat;
2530ab22 187 _assert(fstat(file_, &stat) == 0);
94b0b3e5
JF
188
189 size_t core(sizeof(Header) + sizeof(Base_));
190
191 size_t size(stat.st_size);
192 if (size == 0) {
7a6e17cf
JF
193 if (!Truncate_(core)) {
194 unlink(path);
195 _assert(false);
196 }
197
94b0b3e5
JF
198 Header_().magic_ = Magic;
199 Size_() = core;
2f722d4c
JF
200 } else if (size < core) {
201 close(file_);
202 file_ = -1;
203 unlink(path);
204 goto open;
94b0b3e5 205 } else {
2530ab22
JF
206 // XXX: this involves an unneccessary call to ftruncate()
207 _assert(Truncate_(size));
94b0b3e5
JF
208 _assert(Header_().magic_ == Magic);
209 _assert(Header_().version_ == 0);
210 }
211 }
212
2530ab22 213 bool Reserve(size_t capacity) {
94b0b3e5 214 if (capacity <= Capacity())
2530ab22
JF
215 return true;
216
217 uint8_t *block(blocks_.back());
94b0b3e5 218 blocks_.pop_back();
2530ab22
JF
219
220 if (Truncate_(capacity))
221 return true;
222 else {
223 blocks_.push_back(block);
224 return false;
225 }
94b0b3e5
JF
226 }
227
228 template <typename Target_>
229 Target_ &Get(uint32_t offset) {
2530ab22 230 return *reinterpret_cast<Target_ *>(offset == 0 ? NULL : blocks_[offset >> Shift_] + (offset & Mask_));
94b0b3e5
JF
231 }
232
233 template <typename Target_>
234 Target_ &Get(Offset<Target_> &ref) {
235 return Get<Target_>(ref.GetOffset());
236 }
237
238 Base_ *operator ->() {
239 return &Get<Base_>(sizeof(Header));
240 }
241
242 template <typename Target_>
243 Offset<Target_> New(size_t extra = 0) {
244 size_t size(sizeof(Target_) + extra);
245 size = Round(size, sizeof(uintptr_t));
2530ab22
JF
246
247 uint32_t offset;
248 if (!Reserve(Size_() + size))
249 offset = 0;
250 else {
251 offset = Size_();
252 Size_() += size;
253 }
254
94b0b3e5
JF
255 return Offset<Target_>(offset);
256 }
257};
258
259}
260
261#endif//CYTORE_HPP