blob: 758fa4ccf94971e84fa5af68a28e1a22faee9969 [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) {
33 int newRangesSize = ranges.size();
34 for (int i = 0; i < ranges.size() - 1; ++i) {
35 if (ranges[i].second >= ranges[i + 1].first) {
36 ranges[i + 1].first = ranges[i].first;
37 ranges[i + 1].second = std::max(ranges[i].second, ranges[i + 1].second);
38 // Invalidate the redundant range
39 ranges[i].first = LONG_MAX;
40 ranges[i].second = LONG_MAX;
41 newRangesSize--;
42 }
43 }
44 if (newRangesSize < ranges.size()) {
45 // Move invalid ranges to end of array
46 std::sort(ranges.begin(), ranges.end());
47 ranges.resize(newRangesSize);
48 }
49}
50
51/**
52 * Determine whether the read request overlaps with the redaction ranges
53 * defined by the given RedactionInfo.
54 *
shafikcdb6b2b2019-09-30 12:49:26 +010055 * This function assumes redaction_ranges_ within RedactionInfo is sorted.
shafikc3f62672019-08-30 11:15:48 +010056 */
Narayan Kamathbd22bb02020-01-08 16:02:50 +000057bool RedactionInfo::hasOverlapWithReadRequest(size_t size, off64_t off) const {
Narayan Kamath11700c02020-10-06 09:15:34 +010058 if (!isRedactionNeeded() || off >= redaction_ranges_.back().second ||
59 off + size <= redaction_ranges_.front().first) {
shafikc3f62672019-08-30 11:15:48 +010060 return false;
61 }
62 return true;
63}
64
65/**
66 * Sets the redaction ranges in RedactionInfo, sort the ranges and merge
67 * overlapping ranges.
68 */
shafikcdb6b2b2019-09-30 12:49:26 +010069void RedactionInfo::processRedactionRanges(int redaction_ranges_num,
70 const off64_t* redaction_ranges) {
71 redaction_ranges_.resize(redaction_ranges_num);
shafikc3f62672019-08-30 11:15:48 +010072 for (int i = 0; i < redaction_ranges_num; ++i) {
shafikcdb6b2b2019-09-30 12:49:26 +010073 redaction_ranges_[i].first = static_cast<off64_t>(redaction_ranges[2 * i]);
74 redaction_ranges_[i].second = static_cast<off64_t>(redaction_ranges[2 * i + 1]);
shafikc3f62672019-08-30 11:15:48 +010075 }
shafikcdb6b2b2019-09-30 12:49:26 +010076 std::sort(redaction_ranges_.begin(), redaction_ranges_.end());
77 mergeOverlappingRedactionRanges(redaction_ranges_);
shafikc3f62672019-08-30 11:15:48 +010078}
79
Narayan Kamathbd22bb02020-01-08 16:02:50 +000080int RedactionInfo::size() const {
shafikcdb6b2b2019-09-30 12:49:26 +010081 return redaction_ranges_.size();
shafikc3f62672019-08-30 11:15:48 +010082}
83
Narayan Kamathbd22bb02020-01-08 16:02:50 +000084bool RedactionInfo::isRedactionNeeded() const {
shafikc3f62672019-08-30 11:15:48 +010085 return size() > 0;
86}
87
shafikcdb6b2b2019-09-30 12:49:26 +010088RedactionInfo::RedactionInfo(int redaction_ranges_num, const off64_t* redaction_ranges) {
shafikc3f62672019-08-30 11:15:48 +010089 if (redaction_ranges == 0) return;
90 processRedactionRanges(redaction_ranges_num, redaction_ranges);
91}
92
93unique_ptr<vector<RedactionRange>> RedactionInfo::getOverlappingRedactionRanges(size_t size,
Narayan Kamathbd22bb02020-01-08 16:02:50 +000094 off64_t off) const {
shafikc3f62672019-08-30 11:15:48 +010095 if (hasOverlapWithReadRequest(size, off)) {
Narayan Kamath11700c02020-10-06 09:15:34 +010096 const off64_t start = off;
97 const off64_t end = static_cast<off64_t>(off + size);
98
shafikcdb6b2b2019-09-30 12:49:26 +010099 auto first_redaction = redaction_ranges_.end();
Narayan Kamath11700c02020-10-06 09:15:34 +0100100 auto last_redaction = redaction_ranges_.begin();
shafikcdb6b2b2019-09-30 12:49:26 +0100101 for (auto iter = redaction_ranges_.begin(); iter != redaction_ranges_.end(); ++iter) {
Narayan Kamath11700c02020-10-06 09:15:34 +0100102 if (iter->second >= start && iter->first < end) {
103 if (iter < first_redaction) first_redaction = iter;
104 if (iter > last_redaction) last_redaction = iter;
105 }
106
107 if (iter->first >= end) {
shafikc3f62672019-08-30 11:15:48 +0100108 break;
109 }
shafikc3f62672019-08-30 11:15:48 +0100110 }
Narayan Kamath11700c02020-10-06 09:15:34 +0100111
112 CHECK(first_redaction <= last_redaction);
113 return std::make_unique<vector<RedactionRange>>(first_redaction, last_redaction + 1);
shafikc3f62672019-08-30 11:15:48 +0100114 }
shafikc3f62672019-08-30 11:15:48 +0100115 return std::make_unique<vector<RedactionRange>>();
116}
Narayan Kamath11700c02020-10-06 09:15:34 +0100117
118void RedactionInfo::getReadRanges(off64_t off, size_t size, std::vector<ReadRange>* out) const {
119 auto rr = getOverlappingRedactionRanges(size, off);
120 if (rr->size() == 0) {
121 return;
122 }
123
124 // Add a sentinel redaction range to make sure we don't go out of vector
125 // limits when computing the end of the last non-redacted range.
126 // This ranges is invalid because its starting point is larger than it's ending point.
127 rr->push_back(RedactionRange(LLONG_MAX, LLONG_MAX - 1));
128
129 int rr_idx = 0;
130 off64_t start = off;
131 const off64_t read_end = static_cast<off64_t>(start + size);
132
133 while (true) {
134 const auto& current_redaction = rr->at(rr_idx);
135 off64_t end;
136 if (current_redaction.first <= start && start < current_redaction.second) {
137 // |start| is within a redaction range, so we must serve a redacted read.
138 end = std::min(read_end, current_redaction.second);
139 out->push_back(ReadRange(start, (end - start), true /* is_redaction */));
140 rr_idx++;
141 } else {
142 // |start| is either before the current redaction range, or beyond the end
143 // of the last redaction range, in which case redaction.first is LLONG_MAX.
144 end = std::min(read_end, current_redaction.first);
145 out->push_back(ReadRange(start, (end - start), false /* is_redaction */));
146 }
147
148 start = end;
149 // If we've done things correctly, start must point at |off + size| once we're
150 // through computing all of our redaction ranges.
151 if (start == read_end) {
152 break;
153 }
154 // If we're continuing iteration, the start of the next range must always be within
155 // the read bounds.
156 CHECK(start < read_end);
157 }
158}
159
shafikc3f62672019-08-30 11:15:48 +0100160} // namespace fuse
Narayan Kamathbd22bb02020-01-08 16:02:50 +0000161} // namespace mediaprovider