1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker * Copyright (C) 2008 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker * All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker *
5*8d67ca89SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*8d67ca89SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
7*8d67ca89SAndroid Build Coastguard Worker * are met:
8*8d67ca89SAndroid Build Coastguard Worker * * Redistributions of source code must retain the above copyright
9*8d67ca89SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
10*8d67ca89SAndroid Build Coastguard Worker * * Redistributions in binary form must reproduce the above copyright
11*8d67ca89SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in
12*8d67ca89SAndroid Build Coastguard Worker * the documentation and/or other materials provided with the
13*8d67ca89SAndroid Build Coastguard Worker * distribution.
14*8d67ca89SAndroid Build Coastguard Worker *
15*8d67ca89SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*8d67ca89SAndroid Build Coastguard Worker * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*8d67ca89SAndroid Build Coastguard Worker * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*8d67ca89SAndroid Build Coastguard Worker * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*8d67ca89SAndroid Build Coastguard Worker * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*8d67ca89SAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*8d67ca89SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*8d67ca89SAndroid Build Coastguard Worker * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*8d67ca89SAndroid Build Coastguard Worker * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*8d67ca89SAndroid Build Coastguard Worker * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*8d67ca89SAndroid Build Coastguard Worker * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*8d67ca89SAndroid Build Coastguard Worker * SUCH DAMAGE.
27*8d67ca89SAndroid Build Coastguard Worker */
28*8d67ca89SAndroid Build Coastguard Worker
29*8d67ca89SAndroid Build Coastguard Worker #include "system_properties/prop_area.h"
30*8d67ca89SAndroid Build Coastguard Worker
31*8d67ca89SAndroid Build Coastguard Worker #include <errno.h>
32*8d67ca89SAndroid Build Coastguard Worker #include <fcntl.h>
33*8d67ca89SAndroid Build Coastguard Worker #include <stdlib.h>
34*8d67ca89SAndroid Build Coastguard Worker #include <sys/cdefs.h>
35*8d67ca89SAndroid Build Coastguard Worker #include <sys/stat.h>
36*8d67ca89SAndroid Build Coastguard Worker #include <sys/types.h>
37*8d67ca89SAndroid Build Coastguard Worker #include <sys/xattr.h>
38*8d67ca89SAndroid Build Coastguard Worker #include <unistd.h>
39*8d67ca89SAndroid Build Coastguard Worker
40*8d67ca89SAndroid Build Coastguard Worker #include <new>
41*8d67ca89SAndroid Build Coastguard Worker
42*8d67ca89SAndroid Build Coastguard Worker #include <async_safe/log.h>
43*8d67ca89SAndroid Build Coastguard Worker
44*8d67ca89SAndroid Build Coastguard Worker #ifdef LARGE_SYSTEM_PROPERTY_NODE
45*8d67ca89SAndroid Build Coastguard Worker constexpr size_t PA_SIZE = 1024 * 1024;
46*8d67ca89SAndroid Build Coastguard Worker #else
47*8d67ca89SAndroid Build Coastguard Worker constexpr size_t PA_SIZE = 128 * 1024;
48*8d67ca89SAndroid Build Coastguard Worker #endif
49*8d67ca89SAndroid Build Coastguard Worker constexpr uint32_t PROP_AREA_MAGIC = 0x504f5250;
50*8d67ca89SAndroid Build Coastguard Worker constexpr uint32_t PROP_AREA_VERSION = 0xfc6ed0ab;
51*8d67ca89SAndroid Build Coastguard Worker
52*8d67ca89SAndroid Build Coastguard Worker size_t prop_area::pa_size_ = 0;
53*8d67ca89SAndroid Build Coastguard Worker size_t prop_area::pa_data_size_ = 0;
54*8d67ca89SAndroid Build Coastguard Worker
map_prop_area_rw(const char * filename,const char * context,bool * fsetxattr_failed)55*8d67ca89SAndroid Build Coastguard Worker prop_area* prop_area::map_prop_area_rw(const char* filename, const char* context,
56*8d67ca89SAndroid Build Coastguard Worker bool* fsetxattr_failed) {
57*8d67ca89SAndroid Build Coastguard Worker /* dev is a tmpfs that we can use to carve a shared workspace
58*8d67ca89SAndroid Build Coastguard Worker * out of, so let's do that...
59*8d67ca89SAndroid Build Coastguard Worker */
60*8d67ca89SAndroid Build Coastguard Worker const int fd = open(filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
61*8d67ca89SAndroid Build Coastguard Worker
62*8d67ca89SAndroid Build Coastguard Worker if (fd < 0) {
63*8d67ca89SAndroid Build Coastguard Worker if (errno == EACCES) {
64*8d67ca89SAndroid Build Coastguard Worker /* for consistency with the case where the process has already
65*8d67ca89SAndroid Build Coastguard Worker * mapped the page in and segfaults when trying to write to it
66*8d67ca89SAndroid Build Coastguard Worker */
67*8d67ca89SAndroid Build Coastguard Worker abort();
68*8d67ca89SAndroid Build Coastguard Worker }
69*8d67ca89SAndroid Build Coastguard Worker return nullptr;
70*8d67ca89SAndroid Build Coastguard Worker }
71*8d67ca89SAndroid Build Coastguard Worker
72*8d67ca89SAndroid Build Coastguard Worker if (context) {
73*8d67ca89SAndroid Build Coastguard Worker if (fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) {
74*8d67ca89SAndroid Build Coastguard Worker async_safe_format_log(ANDROID_LOG_ERROR, "libc",
75*8d67ca89SAndroid Build Coastguard Worker "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
76*8d67ca89SAndroid Build Coastguard Worker /*
77*8d67ca89SAndroid Build Coastguard Worker * fsetxattr() will fail during system properties tests due to selinux policy.
78*8d67ca89SAndroid Build Coastguard Worker * We do not want to create a custom policy for the tester, so we will continue in
79*8d67ca89SAndroid Build Coastguard Worker * this function but set a flag that an error has occurred.
80*8d67ca89SAndroid Build Coastguard Worker * Init, which is the only daemon that should ever call this function will abort
81*8d67ca89SAndroid Build Coastguard Worker * when this error occurs.
82*8d67ca89SAndroid Build Coastguard Worker * Otherwise, the tester will ignore it and continue, albeit without any selinux
83*8d67ca89SAndroid Build Coastguard Worker * property separation.
84*8d67ca89SAndroid Build Coastguard Worker */
85*8d67ca89SAndroid Build Coastguard Worker if (fsetxattr_failed) {
86*8d67ca89SAndroid Build Coastguard Worker *fsetxattr_failed = true;
87*8d67ca89SAndroid Build Coastguard Worker }
88*8d67ca89SAndroid Build Coastguard Worker }
89*8d67ca89SAndroid Build Coastguard Worker }
90*8d67ca89SAndroid Build Coastguard Worker
91*8d67ca89SAndroid Build Coastguard Worker if (ftruncate(fd, PA_SIZE) < 0) {
92*8d67ca89SAndroid Build Coastguard Worker close(fd);
93*8d67ca89SAndroid Build Coastguard Worker return nullptr;
94*8d67ca89SAndroid Build Coastguard Worker }
95*8d67ca89SAndroid Build Coastguard Worker
96*8d67ca89SAndroid Build Coastguard Worker pa_size_ = PA_SIZE;
97*8d67ca89SAndroid Build Coastguard Worker pa_data_size_ = pa_size_ - sizeof(prop_area);
98*8d67ca89SAndroid Build Coastguard Worker
99*8d67ca89SAndroid Build Coastguard Worker void* const memory_area = mmap(nullptr, pa_size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
100*8d67ca89SAndroid Build Coastguard Worker if (memory_area == MAP_FAILED) {
101*8d67ca89SAndroid Build Coastguard Worker close(fd);
102*8d67ca89SAndroid Build Coastguard Worker return nullptr;
103*8d67ca89SAndroid Build Coastguard Worker }
104*8d67ca89SAndroid Build Coastguard Worker
105*8d67ca89SAndroid Build Coastguard Worker prop_area* pa = new (memory_area) prop_area(PROP_AREA_MAGIC, PROP_AREA_VERSION);
106*8d67ca89SAndroid Build Coastguard Worker
107*8d67ca89SAndroid Build Coastguard Worker close(fd);
108*8d67ca89SAndroid Build Coastguard Worker return pa;
109*8d67ca89SAndroid Build Coastguard Worker }
110*8d67ca89SAndroid Build Coastguard Worker
map_fd_ro(const int fd)111*8d67ca89SAndroid Build Coastguard Worker prop_area* prop_area::map_fd_ro(const int fd) {
112*8d67ca89SAndroid Build Coastguard Worker struct stat fd_stat;
113*8d67ca89SAndroid Build Coastguard Worker if (fstat(fd, &fd_stat) < 0) {
114*8d67ca89SAndroid Build Coastguard Worker return nullptr;
115*8d67ca89SAndroid Build Coastguard Worker }
116*8d67ca89SAndroid Build Coastguard Worker
117*8d67ca89SAndroid Build Coastguard Worker if ((fd_stat.st_uid != 0) || (fd_stat.st_gid != 0) ||
118*8d67ca89SAndroid Build Coastguard Worker ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0) ||
119*8d67ca89SAndroid Build Coastguard Worker (fd_stat.st_size < static_cast<off_t>(sizeof(prop_area)))) {
120*8d67ca89SAndroid Build Coastguard Worker return nullptr;
121*8d67ca89SAndroid Build Coastguard Worker }
122*8d67ca89SAndroid Build Coastguard Worker
123*8d67ca89SAndroid Build Coastguard Worker pa_size_ = fd_stat.st_size;
124*8d67ca89SAndroid Build Coastguard Worker pa_data_size_ = pa_size_ - sizeof(prop_area);
125*8d67ca89SAndroid Build Coastguard Worker
126*8d67ca89SAndroid Build Coastguard Worker void* const map_result = mmap(nullptr, pa_size_, PROT_READ, MAP_SHARED, fd, 0);
127*8d67ca89SAndroid Build Coastguard Worker if (map_result == MAP_FAILED) {
128*8d67ca89SAndroid Build Coastguard Worker return nullptr;
129*8d67ca89SAndroid Build Coastguard Worker }
130*8d67ca89SAndroid Build Coastguard Worker
131*8d67ca89SAndroid Build Coastguard Worker prop_area* pa = reinterpret_cast<prop_area*>(map_result);
132*8d67ca89SAndroid Build Coastguard Worker if ((pa->magic() != PROP_AREA_MAGIC) || (pa->version() != PROP_AREA_VERSION)) {
133*8d67ca89SAndroid Build Coastguard Worker munmap(pa, pa_size_);
134*8d67ca89SAndroid Build Coastguard Worker return nullptr;
135*8d67ca89SAndroid Build Coastguard Worker }
136*8d67ca89SAndroid Build Coastguard Worker
137*8d67ca89SAndroid Build Coastguard Worker return pa;
138*8d67ca89SAndroid Build Coastguard Worker }
139*8d67ca89SAndroid Build Coastguard Worker
map_prop_area(const char * filename)140*8d67ca89SAndroid Build Coastguard Worker prop_area* prop_area::map_prop_area(const char* filename) {
141*8d67ca89SAndroid Build Coastguard Worker int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
142*8d67ca89SAndroid Build Coastguard Worker if (fd == -1) return nullptr;
143*8d67ca89SAndroid Build Coastguard Worker
144*8d67ca89SAndroid Build Coastguard Worker prop_area* map_result = map_fd_ro(fd);
145*8d67ca89SAndroid Build Coastguard Worker close(fd);
146*8d67ca89SAndroid Build Coastguard Worker
147*8d67ca89SAndroid Build Coastguard Worker return map_result;
148*8d67ca89SAndroid Build Coastguard Worker }
149*8d67ca89SAndroid Build Coastguard Worker
allocate_obj(const size_t size,uint_least32_t * const off)150*8d67ca89SAndroid Build Coastguard Worker void* prop_area::allocate_obj(const size_t size, uint_least32_t* const off) {
151*8d67ca89SAndroid Build Coastguard Worker const size_t aligned = __BIONIC_ALIGN(size, sizeof(uint_least32_t));
152*8d67ca89SAndroid Build Coastguard Worker if (bytes_used_ + aligned > pa_data_size_) {
153*8d67ca89SAndroid Build Coastguard Worker return nullptr;
154*8d67ca89SAndroid Build Coastguard Worker }
155*8d67ca89SAndroid Build Coastguard Worker
156*8d67ca89SAndroid Build Coastguard Worker *off = bytes_used_;
157*8d67ca89SAndroid Build Coastguard Worker bytes_used_ += aligned;
158*8d67ca89SAndroid Build Coastguard Worker return data_ + *off;
159*8d67ca89SAndroid Build Coastguard Worker }
160*8d67ca89SAndroid Build Coastguard Worker
new_prop_trie_node(const char * name,uint32_t namelen,uint_least32_t * const off)161*8d67ca89SAndroid Build Coastguard Worker prop_trie_node* prop_area::new_prop_trie_node(const char* name, uint32_t namelen,
162*8d67ca89SAndroid Build Coastguard Worker uint_least32_t* const off) {
163*8d67ca89SAndroid Build Coastguard Worker uint_least32_t new_offset;
164*8d67ca89SAndroid Build Coastguard Worker void* const p = allocate_obj(sizeof(prop_trie_node) + namelen + 1, &new_offset);
165*8d67ca89SAndroid Build Coastguard Worker if (p == nullptr) return nullptr;
166*8d67ca89SAndroid Build Coastguard Worker
167*8d67ca89SAndroid Build Coastguard Worker prop_trie_node* node = new (p) prop_trie_node(name, namelen);
168*8d67ca89SAndroid Build Coastguard Worker *off = new_offset;
169*8d67ca89SAndroid Build Coastguard Worker return node;
170*8d67ca89SAndroid Build Coastguard Worker }
171*8d67ca89SAndroid Build Coastguard Worker
new_prop_info(const char * name,uint32_t namelen,const char * value,uint32_t valuelen,uint_least32_t * const off)172*8d67ca89SAndroid Build Coastguard Worker prop_info* prop_area::new_prop_info(const char* name, uint32_t namelen, const char* value,
173*8d67ca89SAndroid Build Coastguard Worker uint32_t valuelen, uint_least32_t* const off) {
174*8d67ca89SAndroid Build Coastguard Worker uint_least32_t new_offset;
175*8d67ca89SAndroid Build Coastguard Worker void* const p = allocate_obj(sizeof(prop_info) + namelen + 1, &new_offset);
176*8d67ca89SAndroid Build Coastguard Worker if (p == nullptr) return nullptr;
177*8d67ca89SAndroid Build Coastguard Worker
178*8d67ca89SAndroid Build Coastguard Worker prop_info* info;
179*8d67ca89SAndroid Build Coastguard Worker if (valuelen >= PROP_VALUE_MAX) {
180*8d67ca89SAndroid Build Coastguard Worker uint32_t long_value_offset = 0;
181*8d67ca89SAndroid Build Coastguard Worker char* long_location = reinterpret_cast<char*>(allocate_obj(valuelen + 1, &long_value_offset));
182*8d67ca89SAndroid Build Coastguard Worker if (!long_location) return nullptr;
183*8d67ca89SAndroid Build Coastguard Worker
184*8d67ca89SAndroid Build Coastguard Worker memcpy(long_location, value, valuelen);
185*8d67ca89SAndroid Build Coastguard Worker long_location[valuelen] = '\0';
186*8d67ca89SAndroid Build Coastguard Worker
187*8d67ca89SAndroid Build Coastguard Worker // Both new_offset and long_value_offset are offsets based off of data_, however prop_info
188*8d67ca89SAndroid Build Coastguard Worker // does not know what data_ is, so we change this offset to be an offset from the prop_info
189*8d67ca89SAndroid Build Coastguard Worker // pointer that contains it.
190*8d67ca89SAndroid Build Coastguard Worker long_value_offset -= new_offset;
191*8d67ca89SAndroid Build Coastguard Worker
192*8d67ca89SAndroid Build Coastguard Worker info = new (p) prop_info(name, namelen, long_value_offset);
193*8d67ca89SAndroid Build Coastguard Worker } else {
194*8d67ca89SAndroid Build Coastguard Worker info = new (p) prop_info(name, namelen, value, valuelen);
195*8d67ca89SAndroid Build Coastguard Worker }
196*8d67ca89SAndroid Build Coastguard Worker *off = new_offset;
197*8d67ca89SAndroid Build Coastguard Worker return info;
198*8d67ca89SAndroid Build Coastguard Worker }
199*8d67ca89SAndroid Build Coastguard Worker
to_prop_obj(uint_least32_t off)200*8d67ca89SAndroid Build Coastguard Worker void* prop_area::to_prop_obj(uint_least32_t off) {
201*8d67ca89SAndroid Build Coastguard Worker if (off > pa_data_size_) return nullptr;
202*8d67ca89SAndroid Build Coastguard Worker
203*8d67ca89SAndroid Build Coastguard Worker return (data_ + off);
204*8d67ca89SAndroid Build Coastguard Worker }
205*8d67ca89SAndroid Build Coastguard Worker
to_prop_trie_node(atomic_uint_least32_t * off_p)206*8d67ca89SAndroid Build Coastguard Worker inline prop_trie_node* prop_area::to_prop_trie_node(atomic_uint_least32_t* off_p) {
207*8d67ca89SAndroid Build Coastguard Worker uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
208*8d67ca89SAndroid Build Coastguard Worker return reinterpret_cast<prop_trie_node*>(to_prop_obj(off));
209*8d67ca89SAndroid Build Coastguard Worker }
210*8d67ca89SAndroid Build Coastguard Worker
to_prop_info(atomic_uint_least32_t * off_p)211*8d67ca89SAndroid Build Coastguard Worker inline prop_info* prop_area::to_prop_info(atomic_uint_least32_t* off_p) {
212*8d67ca89SAndroid Build Coastguard Worker uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
213*8d67ca89SAndroid Build Coastguard Worker return reinterpret_cast<prop_info*>(to_prop_obj(off));
214*8d67ca89SAndroid Build Coastguard Worker }
215*8d67ca89SAndroid Build Coastguard Worker
root_node()216*8d67ca89SAndroid Build Coastguard Worker inline prop_trie_node* prop_area::root_node() {
217*8d67ca89SAndroid Build Coastguard Worker return reinterpret_cast<prop_trie_node*>(to_prop_obj(0));
218*8d67ca89SAndroid Build Coastguard Worker }
219*8d67ca89SAndroid Build Coastguard Worker
cmp_prop_name(const char * one,uint32_t one_len,const char * two,uint32_t two_len)220*8d67ca89SAndroid Build Coastguard Worker static int cmp_prop_name(const char* one, uint32_t one_len, const char* two, uint32_t two_len) {
221*8d67ca89SAndroid Build Coastguard Worker if (one_len < two_len)
222*8d67ca89SAndroid Build Coastguard Worker return -1;
223*8d67ca89SAndroid Build Coastguard Worker else if (one_len > two_len)
224*8d67ca89SAndroid Build Coastguard Worker return 1;
225*8d67ca89SAndroid Build Coastguard Worker else
226*8d67ca89SAndroid Build Coastguard Worker return strncmp(one, two, one_len);
227*8d67ca89SAndroid Build Coastguard Worker }
228*8d67ca89SAndroid Build Coastguard Worker
find_prop_trie_node(prop_trie_node * const trie,const char * name,uint32_t namelen,bool alloc_if_needed)229*8d67ca89SAndroid Build Coastguard Worker prop_trie_node* prop_area::find_prop_trie_node(prop_trie_node* const trie, const char* name,
230*8d67ca89SAndroid Build Coastguard Worker uint32_t namelen, bool alloc_if_needed) {
231*8d67ca89SAndroid Build Coastguard Worker prop_trie_node* current = trie;
232*8d67ca89SAndroid Build Coastguard Worker while (true) {
233*8d67ca89SAndroid Build Coastguard Worker if (!current) {
234*8d67ca89SAndroid Build Coastguard Worker return nullptr;
235*8d67ca89SAndroid Build Coastguard Worker }
236*8d67ca89SAndroid Build Coastguard Worker
237*8d67ca89SAndroid Build Coastguard Worker const int ret = cmp_prop_name(name, namelen, current->name, current->namelen);
238*8d67ca89SAndroid Build Coastguard Worker if (ret == 0) {
239*8d67ca89SAndroid Build Coastguard Worker return current;
240*8d67ca89SAndroid Build Coastguard Worker }
241*8d67ca89SAndroid Build Coastguard Worker
242*8d67ca89SAndroid Build Coastguard Worker if (ret < 0) {
243*8d67ca89SAndroid Build Coastguard Worker uint_least32_t left_offset = atomic_load_explicit(¤t->left, memory_order_relaxed);
244*8d67ca89SAndroid Build Coastguard Worker if (left_offset != 0) {
245*8d67ca89SAndroid Build Coastguard Worker current = to_prop_trie_node(¤t->left);
246*8d67ca89SAndroid Build Coastguard Worker } else {
247*8d67ca89SAndroid Build Coastguard Worker if (!alloc_if_needed) {
248*8d67ca89SAndroid Build Coastguard Worker return nullptr;
249*8d67ca89SAndroid Build Coastguard Worker }
250*8d67ca89SAndroid Build Coastguard Worker
251*8d67ca89SAndroid Build Coastguard Worker uint_least32_t new_offset;
252*8d67ca89SAndroid Build Coastguard Worker prop_trie_node* new_node = new_prop_trie_node(name, namelen, &new_offset);
253*8d67ca89SAndroid Build Coastguard Worker if (new_node) {
254*8d67ca89SAndroid Build Coastguard Worker atomic_store_explicit(¤t->left, new_offset, memory_order_release);
255*8d67ca89SAndroid Build Coastguard Worker }
256*8d67ca89SAndroid Build Coastguard Worker return new_node;
257*8d67ca89SAndroid Build Coastguard Worker }
258*8d67ca89SAndroid Build Coastguard Worker } else {
259*8d67ca89SAndroid Build Coastguard Worker uint_least32_t right_offset = atomic_load_explicit(¤t->right, memory_order_relaxed);
260*8d67ca89SAndroid Build Coastguard Worker if (right_offset != 0) {
261*8d67ca89SAndroid Build Coastguard Worker current = to_prop_trie_node(¤t->right);
262*8d67ca89SAndroid Build Coastguard Worker } else {
263*8d67ca89SAndroid Build Coastguard Worker if (!alloc_if_needed) {
264*8d67ca89SAndroid Build Coastguard Worker return nullptr;
265*8d67ca89SAndroid Build Coastguard Worker }
266*8d67ca89SAndroid Build Coastguard Worker
267*8d67ca89SAndroid Build Coastguard Worker uint_least32_t new_offset;
268*8d67ca89SAndroid Build Coastguard Worker prop_trie_node* new_node = new_prop_trie_node(name, namelen, &new_offset);
269*8d67ca89SAndroid Build Coastguard Worker if (new_node) {
270*8d67ca89SAndroid Build Coastguard Worker atomic_store_explicit(¤t->right, new_offset, memory_order_release);
271*8d67ca89SAndroid Build Coastguard Worker }
272*8d67ca89SAndroid Build Coastguard Worker return new_node;
273*8d67ca89SAndroid Build Coastguard Worker }
274*8d67ca89SAndroid Build Coastguard Worker }
275*8d67ca89SAndroid Build Coastguard Worker }
276*8d67ca89SAndroid Build Coastguard Worker }
277*8d67ca89SAndroid Build Coastguard Worker
find_property(prop_trie_node * const trie,const char * name,uint32_t namelen,const char * value,uint32_t valuelen,bool alloc_if_needed)278*8d67ca89SAndroid Build Coastguard Worker const prop_info* prop_area::find_property(prop_trie_node* const trie, const char* name,
279*8d67ca89SAndroid Build Coastguard Worker uint32_t namelen, const char* value, uint32_t valuelen,
280*8d67ca89SAndroid Build Coastguard Worker bool alloc_if_needed) {
281*8d67ca89SAndroid Build Coastguard Worker if (!trie) return nullptr;
282*8d67ca89SAndroid Build Coastguard Worker
283*8d67ca89SAndroid Build Coastguard Worker const char* remaining_name = name;
284*8d67ca89SAndroid Build Coastguard Worker prop_trie_node* current = trie;
285*8d67ca89SAndroid Build Coastguard Worker while (true) {
286*8d67ca89SAndroid Build Coastguard Worker const char* sep = strchr(remaining_name, '.');
287*8d67ca89SAndroid Build Coastguard Worker const bool want_subtree = (sep != nullptr);
288*8d67ca89SAndroid Build Coastguard Worker const uint32_t substr_size = (want_subtree) ? sep - remaining_name : strlen(remaining_name);
289*8d67ca89SAndroid Build Coastguard Worker
290*8d67ca89SAndroid Build Coastguard Worker if (!substr_size) {
291*8d67ca89SAndroid Build Coastguard Worker return nullptr;
292*8d67ca89SAndroid Build Coastguard Worker }
293*8d67ca89SAndroid Build Coastguard Worker
294*8d67ca89SAndroid Build Coastguard Worker prop_trie_node* root = nullptr;
295*8d67ca89SAndroid Build Coastguard Worker uint_least32_t children_offset = atomic_load_explicit(¤t->children, memory_order_relaxed);
296*8d67ca89SAndroid Build Coastguard Worker if (children_offset != 0) {
297*8d67ca89SAndroid Build Coastguard Worker root = to_prop_trie_node(¤t->children);
298*8d67ca89SAndroid Build Coastguard Worker } else if (alloc_if_needed) {
299*8d67ca89SAndroid Build Coastguard Worker uint_least32_t new_offset;
300*8d67ca89SAndroid Build Coastguard Worker root = new_prop_trie_node(remaining_name, substr_size, &new_offset);
301*8d67ca89SAndroid Build Coastguard Worker if (root) {
302*8d67ca89SAndroid Build Coastguard Worker atomic_store_explicit(¤t->children, new_offset, memory_order_release);
303*8d67ca89SAndroid Build Coastguard Worker }
304*8d67ca89SAndroid Build Coastguard Worker }
305*8d67ca89SAndroid Build Coastguard Worker
306*8d67ca89SAndroid Build Coastguard Worker if (!root) {
307*8d67ca89SAndroid Build Coastguard Worker return nullptr;
308*8d67ca89SAndroid Build Coastguard Worker }
309*8d67ca89SAndroid Build Coastguard Worker
310*8d67ca89SAndroid Build Coastguard Worker current = find_prop_trie_node(root, remaining_name, substr_size, alloc_if_needed);
311*8d67ca89SAndroid Build Coastguard Worker if (!current) {
312*8d67ca89SAndroid Build Coastguard Worker return nullptr;
313*8d67ca89SAndroid Build Coastguard Worker }
314*8d67ca89SAndroid Build Coastguard Worker
315*8d67ca89SAndroid Build Coastguard Worker if (!want_subtree) break;
316*8d67ca89SAndroid Build Coastguard Worker
317*8d67ca89SAndroid Build Coastguard Worker remaining_name = sep + 1;
318*8d67ca89SAndroid Build Coastguard Worker }
319*8d67ca89SAndroid Build Coastguard Worker
320*8d67ca89SAndroid Build Coastguard Worker uint_least32_t prop_offset = atomic_load_explicit(¤t->prop, memory_order_relaxed);
321*8d67ca89SAndroid Build Coastguard Worker if (prop_offset != 0) {
322*8d67ca89SAndroid Build Coastguard Worker return to_prop_info(¤t->prop);
323*8d67ca89SAndroid Build Coastguard Worker } else if (alloc_if_needed) {
324*8d67ca89SAndroid Build Coastguard Worker uint_least32_t new_offset;
325*8d67ca89SAndroid Build Coastguard Worker prop_info* new_info = new_prop_info(name, namelen, value, valuelen, &new_offset);
326*8d67ca89SAndroid Build Coastguard Worker if (new_info) {
327*8d67ca89SAndroid Build Coastguard Worker atomic_store_explicit(¤t->prop, new_offset, memory_order_release);
328*8d67ca89SAndroid Build Coastguard Worker }
329*8d67ca89SAndroid Build Coastguard Worker
330*8d67ca89SAndroid Build Coastguard Worker return new_info;
331*8d67ca89SAndroid Build Coastguard Worker } else {
332*8d67ca89SAndroid Build Coastguard Worker return nullptr;
333*8d67ca89SAndroid Build Coastguard Worker }
334*8d67ca89SAndroid Build Coastguard Worker }
335*8d67ca89SAndroid Build Coastguard Worker
foreach_property(prop_trie_node * const trie,void (* propfn)(const prop_info * pi,void * cookie),void * cookie)336*8d67ca89SAndroid Build Coastguard Worker bool prop_area::foreach_property(prop_trie_node* const trie,
337*8d67ca89SAndroid Build Coastguard Worker void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
338*8d67ca89SAndroid Build Coastguard Worker if (!trie) return false;
339*8d67ca89SAndroid Build Coastguard Worker
340*8d67ca89SAndroid Build Coastguard Worker uint_least32_t left_offset = atomic_load_explicit(&trie->left, memory_order_relaxed);
341*8d67ca89SAndroid Build Coastguard Worker if (left_offset != 0) {
342*8d67ca89SAndroid Build Coastguard Worker if (!foreach_property(to_prop_trie_node(&trie->left), propfn, cookie)) return false;
343*8d67ca89SAndroid Build Coastguard Worker }
344*8d67ca89SAndroid Build Coastguard Worker uint_least32_t prop_offset = atomic_load_explicit(&trie->prop, memory_order_relaxed);
345*8d67ca89SAndroid Build Coastguard Worker if (prop_offset != 0) {
346*8d67ca89SAndroid Build Coastguard Worker prop_info* info = to_prop_info(&trie->prop);
347*8d67ca89SAndroid Build Coastguard Worker if (!info) return false;
348*8d67ca89SAndroid Build Coastguard Worker propfn(info, cookie);
349*8d67ca89SAndroid Build Coastguard Worker }
350*8d67ca89SAndroid Build Coastguard Worker uint_least32_t children_offset = atomic_load_explicit(&trie->children, memory_order_relaxed);
351*8d67ca89SAndroid Build Coastguard Worker if (children_offset != 0) {
352*8d67ca89SAndroid Build Coastguard Worker if (!foreach_property(to_prop_trie_node(&trie->children), propfn, cookie)) return false;
353*8d67ca89SAndroid Build Coastguard Worker }
354*8d67ca89SAndroid Build Coastguard Worker uint_least32_t right_offset = atomic_load_explicit(&trie->right, memory_order_relaxed);
355*8d67ca89SAndroid Build Coastguard Worker if (right_offset != 0) {
356*8d67ca89SAndroid Build Coastguard Worker if (!foreach_property(to_prop_trie_node(&trie->right), propfn, cookie)) return false;
357*8d67ca89SAndroid Build Coastguard Worker }
358*8d67ca89SAndroid Build Coastguard Worker
359*8d67ca89SAndroid Build Coastguard Worker return true;
360*8d67ca89SAndroid Build Coastguard Worker }
361*8d67ca89SAndroid Build Coastguard Worker
find(const char * name)362*8d67ca89SAndroid Build Coastguard Worker const prop_info* prop_area::find(const char* name) {
363*8d67ca89SAndroid Build Coastguard Worker return find_property(root_node(), name, strlen(name), nullptr, 0, false);
364*8d67ca89SAndroid Build Coastguard Worker }
365*8d67ca89SAndroid Build Coastguard Worker
add(const char * name,unsigned int namelen,const char * value,unsigned int valuelen)366*8d67ca89SAndroid Build Coastguard Worker bool prop_area::add(const char* name, unsigned int namelen, const char* value,
367*8d67ca89SAndroid Build Coastguard Worker unsigned int valuelen) {
368*8d67ca89SAndroid Build Coastguard Worker return find_property(root_node(), name, namelen, value, valuelen, true);
369*8d67ca89SAndroid Build Coastguard Worker }
370*8d67ca89SAndroid Build Coastguard Worker
foreach(void (* propfn)(const prop_info * pi,void * cookie),void * cookie)371*8d67ca89SAndroid Build Coastguard Worker bool prop_area::foreach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) {
372*8d67ca89SAndroid Build Coastguard Worker return foreach_property(root_node(), propfn, cookie);
373*8d67ca89SAndroid Build Coastguard Worker }
374