1 #include <sys/mman.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <errno.h>
5 #include <string.h>
6 
7 #include "rust/cxx.h"
8 #include "aconfig_storage/lib.rs.h"
9 #include "aconfig_storage/aconfig_storage_read_api.hpp"
10 
11 namespace aconfig_storage {
12 
13 /// Storage location pb file
14 static constexpr char kStorageDir[] = "/metadata/aconfig";
15 
16 /// destructor
~MappedStorageFile()17 MappedStorageFile::~MappedStorageFile() {
18   munmap(file_ptr, file_size);
19 }
20 
21 /// Get storage file path
find_storage_file(std::string const & storage_dir,std::string const & container,StorageFileType file_type)22 static Result<std::string> find_storage_file(
23     std::string const& storage_dir,
24     std::string const& container,
25     StorageFileType file_type) {
26   switch(file_type) {
27     case StorageFileType::package_map:
28       return storage_dir + "/maps/" + container + ".package.map";
29     case StorageFileType::flag_map:
30       return storage_dir + "/maps/" + container + ".flag.map";
31     case StorageFileType::flag_val:
32       return storage_dir + "/boot/" + container + ".val";
33     case StorageFileType::flag_info:
34       return storage_dir + "/boot/" + container + ".info";
35     default:
36       auto result = Result<std::string>();
37       result.errmsg = "Invalid storage file type";
38       return result;
39   }
40 }
41 
42 namespace private_internal_api {
43 
44 /// Get mapped file implementation.
get_mapped_file_impl(std::string const & storage_dir,std::string const & container,StorageFileType file_type)45 Result<MappedStorageFile*> get_mapped_file_impl(
46     std::string const& storage_dir,
47     std::string const& container,
48     StorageFileType file_type) {
49   auto file_result = find_storage_file(storage_dir, container, file_type);
50   if (!file_result.ok()) {
51     auto result = Result<MappedStorageFile*>();
52     result.errmsg = file_result.error();
53     return result;
54   }
55   return map_storage_file(*file_result);
56 }
57 
58 } // namespace private internal api
59 
60 /// Map a storage file
map_storage_file(std::string const & file)61 Result<MappedStorageFile*> map_storage_file(std::string const& file) {
62   int fd = open(file.c_str(), O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
63   if (fd == -1) {
64     auto result = Result<MappedStorageFile*>();
65     result.errmsg = std::string("failed to open ") + file + ": " + strerror(errno);
66     return result;
67   };
68 
69   struct stat fd_stat;
70   if (fstat(fd, &fd_stat) < 0) {
71     auto result = Result<MappedStorageFile*>();
72     result.errmsg = std::string("fstat failed: ") + strerror(errno);
73     return result;
74   }
75   size_t file_size = fd_stat.st_size;
76 
77   void* const map_result = mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0);
78   if (map_result == MAP_FAILED) {
79     auto result = Result<MappedStorageFile*>();
80     result.errmsg = std::string("mmap failed: ") + strerror(errno);
81     return result;
82   }
83 
84   auto mapped_file = new MappedStorageFile();
85   mapped_file->file_ptr = map_result;
86   mapped_file->file_size = file_size;
87 
88   return mapped_file;
89 }
90 
91 /// Map from StoredFlagType to FlagValueType
map_to_flag_value_type(StoredFlagType stored_type)92 Result<FlagValueType> map_to_flag_value_type(
93     StoredFlagType stored_type) {
94   switch (stored_type) {
95     case StoredFlagType::ReadWriteBoolean:
96     case StoredFlagType::ReadOnlyBoolean:
97     case StoredFlagType::FixedReadOnlyBoolean:
98       return FlagValueType::Boolean;
99     default:
100       auto result = Result<FlagValueType>();
101       result.errmsg = "Unsupported stored flag type";
102       return result;
103   }
104 }
105 
106 /// Get mapped storage file
get_mapped_file(std::string const & container,StorageFileType file_type)107 Result<MappedStorageFile*> get_mapped_file(
108     std::string const& container,
109     StorageFileType file_type) {
110   return private_internal_api::get_mapped_file_impl(
111       kStorageDir, container, file_type);
112 }
113 
114 /// Get storage file version number
get_storage_file_version(std::string const & file_path)115 Result<uint32_t> get_storage_file_version(
116     std::string const& file_path) {
117   auto version_cxx = get_storage_file_version_cxx(
118       rust::Str(file_path.c_str()));
119   if (version_cxx.query_success) {
120     return version_cxx.version_number;
121   } else {
122     auto result = Result<uint32_t>();
123     result.errmsg = version_cxx.error_message.c_str();
124     return result;
125   }
126 }
127 
128 /// Get package context
get_package_read_context(MappedStorageFile const & file,std::string const & package)129 Result<PackageReadContext> get_package_read_context(
130     MappedStorageFile const& file,
131     std::string const& package) {
132   auto content = rust::Slice<const uint8_t>(
133       static_cast<uint8_t*>(file.file_ptr), file.file_size);
134   auto context_cxx = get_package_read_context_cxx(content, rust::Str(package.c_str()));
135   if (context_cxx.query_success) {
136     auto context = PackageReadContext();
137     context.package_exists = context_cxx.package_exists;
138     context.package_id = context_cxx.package_id;
139     context.boolean_start_index = context_cxx.boolean_start_index;
140     return context;
141   } else {
142     auto result = Result<PackageReadContext>();
143     result.errmsg = context_cxx.error_message.c_str();
144     return result;
145   }
146 }
147 
148 /// Get flag read context
get_flag_read_context(MappedStorageFile const & file,uint32_t package_id,std::string const & flag_name)149 Result<FlagReadContext> get_flag_read_context(
150     MappedStorageFile const& file,
151     uint32_t package_id,
152     std::string const& flag_name){
153   auto content = rust::Slice<const uint8_t>(
154       static_cast<uint8_t*>(file.file_ptr), file.file_size);
155   auto context_cxx = get_flag_read_context_cxx(content, package_id, rust::Str(flag_name.c_str()));
156   if (context_cxx.query_success) {
157     auto context = FlagReadContext();
158     context.flag_exists = context_cxx.flag_exists;
159     context.flag_type = static_cast<StoredFlagType>(context_cxx.flag_type);
160     context.flag_index = context_cxx.flag_index;
161     return context;
162   } else {
163     auto result = Result<FlagReadContext>();
164     result.errmsg = context_cxx.error_message.c_str();
165     return result;
166   }
167 }
168 
169 /// Get boolean flag value
get_boolean_flag_value(MappedStorageFile const & file,uint32_t index)170 Result<bool> get_boolean_flag_value(
171     MappedStorageFile const& file,
172     uint32_t index) {
173   auto content = rust::Slice<const uint8_t>(
174       static_cast<uint8_t*>(file.file_ptr), file.file_size);
175   auto value_cxx = get_boolean_flag_value_cxx(content, index);
176   if (value_cxx.query_success) {
177     return value_cxx.flag_value;
178   } else {
179     auto result = Result<bool>();
180     result.errmsg = value_cxx.error_message.c_str();
181     return result;
182   }
183 }
184 
185 /// Get boolean flag attribute
get_flag_attribute(MappedStorageFile const & file,FlagValueType value_type,uint32_t index)186 Result<uint8_t> get_flag_attribute(
187     MappedStorageFile const& file,
188     FlagValueType value_type,
189     uint32_t index) {
190   auto content = rust::Slice<const uint8_t>(
191       static_cast<uint8_t*>(file.file_ptr), file.file_size);
192   auto info_cxx = get_flag_attribute_cxx(
193       content, static_cast<uint16_t>(value_type), index);
194   if (info_cxx.query_success) {
195     return info_cxx.flag_attribute;
196   } else {
197     auto result = Result<uint8_t>();
198     result.errmsg = info_cxx.error_message.c_str();
199     return result;
200   }
201 }
202 } // namespace aconfig_storage
203