blob: 384e59fed9051192069bf4d355f6f478bebde936 [file] [log] [blame]
shafikc3f62672019-08-30 11:15:48 +01001/*
2 * Copyright (C) 2019 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 specic language governing permissions and
14 * limitations under the License.
15 */
16
shafikc3f62672019-08-30 11:15:48 +010017#include "include/libfuse_jni/RedactionInfo.h"
18
Narayan Kamath11700c02020-10-06 09:15:34 +010019#include <android-base/logging.h>
20
shafikc3f62672019-08-30 11:15:48 +010021using std::unique_ptr;
22using std::vector;
23
24namespace mediaprovider {
25namespace fuse {
26
27/**
28 * Merges any overlapping ranges into 1 range.
29 *
30 * Given ranges should be sorted, and they remain sorted.
31 */
32static void mergeOverlappingRedactionRanges(vector<RedactionRange>& ranges) {
Sahana Rao8a1db672020-10-25 00:00:11 +010033 if (ranges.size() == 0) return;
shafikc3f62672019-08-30 11:15:48 +010034 int newRangesSize = ranges.size();
35 for (int i = 0; i < ranges.size() - 1; ++i) {
36 if (ranges[i].second >= ranges[i + 1].first) {
37 ranges[i + 1].first = ranges[i].first;
38 ranges[i + 1].second = std::max(ranges[i].second, ranges[i + 1].second);
39 // Invalidate the redundant range
40 ranges[i].first = LONG_MAX;
41 ranges[i].second = LONG_MAX;
42 newRangesSize--;
43 }
44 }
45 if (newRangesSize < ranges.size()) {
46 // Move invalid ranges to end of array
47 std::sort(ranges.begin(), ranges.end());
48 ranges.resize(newRangesSize);
49 }
50}
51
52/**
Sahana Rao8a1db672020-10-25 00:00:11 +010053 * Removes any range with zero size.
54 *
55 * If ranges are modified, it will be guaranteed to be sorted.
56 */
57static void removeZeroSizeRedactionRanges(vector<RedactionRange>& ranges) {
58 int newRangesSize = ranges.size();
59 for (int i = 0; i < ranges.size(); ++i) {
60 if (ranges[i].first == ranges[i].second) {
61 // This redaction range is of length zero, hence we don't have anything
62 // to redact in this range, so remove it from the redaction_ranges_.
63 ranges[i].first = LONG_MAX;
64 ranges[i].second = LONG_MAX;
65 newRangesSize--;
66 }
67 }
68 if (newRangesSize < ranges.size()) {
69 // Move invalid ranges to end of array
70 std::sort(ranges.begin(), ranges.end());
71 ranges.resize(newRangesSize);
72 }
73}
74
75/**
shafikc3f62672019-08-30 11:15:48 +010076 * Determine whether the read request overlaps with the redaction ranges
77 * defined by the given RedactionInfo.
78 *
shafikcdb6b2b2019-09-30 12:49:26 +010079 * This function assumes redaction_ranges_ within RedactionInfo is sorted.
shafikc3f62672019-08-30 11:15:48 +010080 */
Narayan Kamathbd22bb02020-01-08 16:02:50 +000081bool RedactionInfo::hasOverlapWithReadRequest(size_t size, off64_t off) const {
Narayan Kamath11700c02020-10-06 09:15:34 +010082 if (!isRedactionNeeded() || off >= redaction_ranges_.back().second ||
83 off + size <= redaction_ranges_.front().first) {
shafikc3f62672019-08-30 11:15:48 +010084 return false;
85 }
86 return true;
87}
88
89/**
90 * Sets the redaction ranges in RedactionInfo, sort the ranges and merge
91 * overlapping ranges.
92 */
shafikcdb6b2b2019-09-30 12:49:26 +010093void RedactionInfo::processRedactionRanges(int redaction_ranges_num,
94 const off64_t* redaction_ranges) {
95 redaction_ranges_.resize(redaction_ranges_num);
shafikc3f62672019-08-30 11:15:48 +010096 for (int i = 0; i < redaction_ranges_num; ++i) {
shafikcdb6b2b2019-09-30 12:49:26 +010097 redaction_ranges_[i].first = static_cast<off64_t>(redaction_ranges[2 * i]);
98 redaction_ranges_[i].second = static_cast<off64_t>(redaction_ranges[2 * i + 1]);
shafikc3f62672019-08-30 11:15:48 +010099 }
shafikcdb6b2b2019-09-30 12:49:26 +0100100 std::sort(redaction_ranges_.begin(), redaction_ranges_.end());
Sahana Rao8a1db672020-10-25 00:00:11 +0100101 removeZeroSizeRedactionRanges(redaction_ranges_);
shafikcdb6b2b2019-09-30 12:49:26 +0100102 mergeOverlappingRedactionRanges(redaction_ranges_);
shafikc3f62672019-08-30 11:15:48 +0100103}
104
Narayan Kamathbd22bb02020-01-08 16:02:50 +0000105int RedactionInfo::size() const {
shafikcdb6b2b2019-09-30 12:49:26 +0100106 return redaction_ranges_.size();
shafikc3f62672019-08-30 11:15:48 +0100107}
108
Narayan Kamathbd22bb02020-01-08 16:02:50 +0000109bool RedactionInfo::isRedactionNeeded() const {
shafikc3f62672019-08-30 11:15:48 +0100110 return size() > 0;
111}
112
shafikcdb6b2b2019-09-30 12:49:26 +0100113RedactionInfo::RedactionInfo(int redaction_ranges_num, const off64_t* redaction_ranges) {
shafikc3f62672019-08-30 11:15:48 +0100114 if (redaction_ranges == 0) return;
115 processRedactionRanges(redaction_ranges_num, redaction_ranges);
116}
117
118unique_ptr<vector<RedactionRange>> RedactionInfo::getOverlappingRedactionRanges(size_t size,
Narayan Kamathbd22bb02020-01-08 16:02:50 +0000119 off64_t off) const {
shafikc3f62672019-08-30 11:15:48 +0100120 if (hasOverlapWithReadRequest(size, off)) {
Narayan Kamath11700c02020-10-06 09:15:34 +0100121 const off64_t start = off;
122 const off64_t end = static_cast<off64_t>(off + size);
123
shafikcdb6b2b2019-09-30 12:49:26 +0100124 auto first_redaction = redaction_ranges_.end();
Narayan Kamath11700c02020-10-06 09:15:34 +0100125 auto last_redaction = redaction_ranges_.begin();
shafikcdb6b2b2019-09-30 12:49:26 +0100126 for (auto iter = redaction_ranges_.begin(); iter != redaction_ranges_.end(); ++iter) {
Sahana Rao8a1db672020-10-25 00:00:11 +0100127 if (iter->second > start && iter->first < end) {
Narayan Kamath11700c02020-10-06 09:15:34 +0100128 if (iter < first_redaction) first_redaction = iter;
129 if (iter > last_redaction) last_redaction = iter;
130 }
131
132 if (iter->first >= end) {
shafikc3f62672019-08-30 11:15:48 +0100133 break;
134 }
shafikc3f62672019-08-30 11:15:48 +0100135 }
Narayan Kamath11700c02020-10-06 09:15:34 +0100136
Hyoungho Choi446de542020-10-22 23:07:57 +0900137 if (first_redaction != redaction_ranges_.end()) {
138 CHECK(first_redaction <= last_redaction);
139 return std::make_unique<vector<RedactionRange>>(first_redaction, last_redaction + 1);
140 }
shafikc3f62672019-08-30 11:15:48 +0100141 }
shafikc3f62672019-08-30 11:15:48 +0100142 return std::make_unique<vector<RedactionRange>>();
143}
Narayan Kamath11700c02020-10-06 09:15:34 +0100144
145void RedactionInfo::getReadRanges(off64_t off, size_t size, std::vector<ReadRange>* out) const {
Sahana Rao8a1db672020-10-25 00:00:11 +0100146 const auto rr = getOverlappingRedactionRanges(size, off);
147 const size_t num_ranges = rr->size();
148 if (num_ranges == 0) {
Narayan Kamath11700c02020-10-06 09:15:34 +0100149 return;
150 }
151
Sahana Rao8a1db672020-10-25 00:00:11 +0100152 const off64_t read_start = off;
153 const off64_t read_end = static_cast<off64_t>(read_start + size);
Narayan Kamath11700c02020-10-06 09:15:34 +0100154
Sahana Rao8a1db672020-10-25 00:00:11 +0100155 // The algorithm for computing redaction ranges is very simple.
156 // Given a set of overlapping redaction ranges [s1, e1) [s2, e2) .. [sN, eN) for a read
157 // [s, e)
158 //
159 // We can construct a series of indices that we know will be the starts of every read range
160 // that we intend to return. Then, it's relatively simple to compute the lengths of the ranges.
161 // Also note that the read ranges we return always alternate in whether they're redacting or
162 // not. i.e, we will never return two consecutive redacting ranges or non redacting ranges.
163 std::vector<off64_t> sorted_indices;
Narayan Kamath11700c02020-10-06 09:15:34 +0100164
Sahana Rao8a1db672020-10-25 00:00:11 +0100165 // Compute the list of indices -- this list will always contain { e1, s2, e2... sN }
166 // In addition, it may contain s or both (s and s1), depending on the start index.
167 // In addition, it may contain e or both (e and eN), depending on the end index.
168 //
169 // For a concrete example, consider ranges [10, 20) and [30, 40)
170 // For a read [0, 60) : sorted_indices will be { 0, 10, 20, 30, 40, 60 } is_first = false
171 // For a read [15, 60) : sorted_indices will be { 15, 20, 30, 40, 60 } is_first = true
172 // For a read [0, 35) : sorted_indices will be { 0, 10, 20, 30, 35 } is_first = false
173 // For a read [15, 35) : sorted_indices will be { 15, 20, 30, 35 } is_first = true
174 for (int i = 0; i < num_ranges; ++i) {
175 sorted_indices.push_back(rr->at(i).first);
176 sorted_indices.push_back(rr->at(i).second);
177 }
Narayan Kamath11700c02020-10-06 09:15:34 +0100178
Sahana Rao8a1db672020-10-25 00:00:11 +0100179 // Find the right position for read_start in sorted_indices
180 // Either insert at the beginning or replace s1 with read_start
181 bool is_first_range_redaction = true;
182 if (read_start < rr->at(0).first) {
183 is_first_range_redaction = false;
184 sorted_indices.insert(sorted_indices.begin(), read_start);
185 } else {
186 sorted_indices.front() = read_start;
187 }
188
189 // Find the right position for read_end in sorted_indices
190 // Either insert at the end or replace eN with read_end
191 if (read_end > rr->at(num_ranges - 1).second) {
192 sorted_indices.push_back(read_end);
193 } else {
194 sorted_indices.back() = read_end;
195 }
196
197 bool is_redaction = is_first_range_redaction;
198 for (int i = 0; i < (sorted_indices.size() - 1); ++i) {
199 const off64_t read_size = sorted_indices[i + 1] - sorted_indices[i];
200 CHECK(read_size > 0);
201 out->push_back(ReadRange(sorted_indices[i], read_size, is_redaction));
202 is_redaction = !is_redaction;
Narayan Kamath11700c02020-10-06 09:15:34 +0100203 }
204}
205
shafikc3f62672019-08-30 11:15:48 +0100206} // namespace fuse
Narayan Kamathbd22bb02020-01-08 16:02:50 +0000207} // namespace mediaprovider