1 /*
2 * Copyright (C) 2024 The Android Open Source Project
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 //! flag value update module defines the flag value file write to mapped bytes
18
19 use aconfig_storage_file::{AconfigStorageError, FlagValueHeader, MAX_SUPPORTED_FILE_VERSION};
20 use anyhow::anyhow;
21
22 /// Set flag value
update_boolean_flag_value( buf: &mut [u8], flag_index: u32, flag_value: bool, ) -> Result<usize, AconfigStorageError>23 pub fn update_boolean_flag_value(
24 buf: &mut [u8],
25 flag_index: u32,
26 flag_value: bool,
27 ) -> Result<usize, AconfigStorageError> {
28 let interpreted_header = FlagValueHeader::from_bytes(buf)?;
29 if interpreted_header.version > MAX_SUPPORTED_FILE_VERSION {
30 return Err(AconfigStorageError::HigherStorageFileVersion(anyhow!(
31 "Cannot write to storage file with a higher version of {} with lib version {}",
32 interpreted_header.version,
33 MAX_SUPPORTED_FILE_VERSION
34 )));
35 }
36
37 // get byte offset to the flag
38 let head = (interpreted_header.boolean_value_offset + flag_index) as usize;
39 if head >= interpreted_header.file_size as usize {
40 return Err(AconfigStorageError::InvalidStorageFileOffset(anyhow!(
41 "Flag value offset goes beyond the end of the file."
42 )));
43 }
44
45 buf[head] = u8::from(flag_value).to_le_bytes()[0];
46 Ok(head)
47 }
48
49 #[cfg(test)]
50 mod tests {
51 use super::*;
52 use aconfig_storage_file::{test_utils::create_test_flag_value_list, DEFAULT_FILE_VERSION};
53
54 #[test]
55 // this test point locks down flag value update
test_boolean_flag_value_update()56 fn test_boolean_flag_value_update() {
57 let flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION);
58 let value_offset = flag_value_list.header.boolean_value_offset;
59 let mut content = flag_value_list.into_bytes();
60 let true_byte = u8::from(true).to_le_bytes()[0];
61 let false_byte = u8::from(false).to_le_bytes()[0];
62
63 for i in 0..flag_value_list.header.num_flags {
64 let offset = (value_offset + i) as usize;
65 update_boolean_flag_value(&mut content, i, true).unwrap();
66 assert_eq!(content[offset], true_byte);
67 update_boolean_flag_value(&mut content, i, false).unwrap();
68 assert_eq!(content[offset], false_byte);
69 }
70 }
71
72 #[test]
73 // this test point locks down update beyond the end of boolean section
test_boolean_out_of_range()74 fn test_boolean_out_of_range() {
75 let mut flag_value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION).into_bytes();
76 let error = update_boolean_flag_value(&mut flag_value_list[..], 8, true).unwrap_err();
77 assert_eq!(
78 format!("{:?}", error),
79 "InvalidStorageFileOffset(Flag value offset goes beyond the end of the file.)"
80 );
81 }
82
83 #[test]
84 // this test point locks down query error when file has a higher version
test_higher_version_storage_file()85 fn test_higher_version_storage_file() {
86 let mut value_list = create_test_flag_value_list(DEFAULT_FILE_VERSION);
87 value_list.header.version = MAX_SUPPORTED_FILE_VERSION + 1;
88 let mut flag_value = value_list.into_bytes();
89 let error = update_boolean_flag_value(&mut flag_value[..], 4, true).unwrap_err();
90 assert_eq!(
91 format!("{:?}", error),
92 format!(
93 "HigherStorageFileVersion(Cannot write to storage file with a higher version of {} with lib version {})",
94 MAX_SUPPORTED_FILE_VERSION + 1,
95 MAX_SUPPORTED_FILE_VERSION
96 )
97 );
98 }
99 }
100