• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #include "include/libfuse_jni/RedactionInfo.h"
18 
19 #include <android-base/logging.h>
20 
21 #include <algorithm>
22 
23 using std::unique_ptr;
24 using std::vector;
25 
26 namespace mediaprovider {
27 namespace fuse {
28 
29 /**
30  * Merges any overlapping ranges into 1 range.
31  *
32  * Given ranges should be sorted, and they remain sorted.
33  */
mergeOverlappingRedactionRanges(vector<RedactionRange> & ranges)34 static void mergeOverlappingRedactionRanges(vector<RedactionRange>& ranges) {
35     if (ranges.size() == 0) return;
36     int newRangesSize = ranges.size();
37     for (int i = 0; i < ranges.size() - 1; ++i) {
38         if (ranges[i].second >= ranges[i + 1].first) {
39             ranges[i + 1].first = ranges[i].first;
40             ranges[i + 1].second = std::max(ranges[i].second, ranges[i + 1].second);
41             // Invalidate the redundant range
42             ranges[i].first = LONG_MAX;
43             ranges[i].second = LONG_MAX;
44             newRangesSize--;
45         }
46     }
47     if (newRangesSize < ranges.size()) {
48         // Move invalid ranges to end of array
49         std::sort(ranges.begin(), ranges.end());
50         ranges.resize(newRangesSize);
51     }
52 }
53 
54 /**
55  * Removes any range with zero size.
56  *
57  * If ranges are modified, it will be guaranteed to be sorted.
58  */
removeZeroSizeRedactionRanges(vector<RedactionRange> & ranges)59 static void removeZeroSizeRedactionRanges(vector<RedactionRange>& ranges) {
60     int newRangesSize = ranges.size();
61     for (int i = 0; i < ranges.size(); ++i) {
62         if (ranges[i].first == ranges[i].second) {
63             // This redaction range is of length zero, hence we don't have anything
64             // to redact in this range, so remove it from the redaction_ranges_.
65             ranges[i].first = LONG_MAX;
66             ranges[i].second = LONG_MAX;
67             newRangesSize--;
68         }
69     }
70     if (newRangesSize < ranges.size()) {
71         // Move invalid ranges to end of array
72         std::sort(ranges.begin(), ranges.end());
73         ranges.resize(newRangesSize);
74     }
75 }
76 
77 /**
78  * Determine whether the read request overlaps with the redaction ranges
79  * defined by the given RedactionInfo.
80  *
81  * This function assumes redaction_ranges_ within RedactionInfo is sorted.
82  */
hasOverlapWithReadRequest(size_t size,off64_t off) const83 bool RedactionInfo::hasOverlapWithReadRequest(size_t size, off64_t off) const {
84     if (!isRedactionNeeded() || off >= redaction_ranges_.back().second ||
85         off + size <= redaction_ranges_.front().first) {
86         return false;
87     }
88     return true;
89 }
90 
91 /**
92  * Sets the redaction ranges in RedactionInfo, sort the ranges and merge
93  * overlapping ranges.
94  */
processRedactionRanges(int redaction_ranges_num,const off64_t * redaction_ranges)95 void RedactionInfo::processRedactionRanges(int redaction_ranges_num,
96                                            const off64_t* redaction_ranges) {
97     redaction_ranges_.resize(redaction_ranges_num);
98     for (int i = 0; i < redaction_ranges_num; ++i) {
99         redaction_ranges_[i].first = static_cast<off64_t>(redaction_ranges[2 * i]);
100         redaction_ranges_[i].second = static_cast<off64_t>(redaction_ranges[2 * i + 1]);
101     }
102     std::sort(redaction_ranges_.begin(), redaction_ranges_.end());
103     removeZeroSizeRedactionRanges(redaction_ranges_);
104     mergeOverlappingRedactionRanges(redaction_ranges_);
105 }
106 
size() const107 int RedactionInfo::size() const {
108     return redaction_ranges_.size();
109 }
110 
isRedactionNeeded() const111 bool RedactionInfo::isRedactionNeeded() const {
112     return size() > 0;
113 }
114 
RedactionInfo(int redaction_ranges_num,const off64_t * redaction_ranges)115 RedactionInfo::RedactionInfo(int redaction_ranges_num, const off64_t* redaction_ranges) {
116     if (redaction_ranges == 0) return;
117     processRedactionRanges(redaction_ranges_num, redaction_ranges);
118 }
119 
getOverlappingRedactionRanges(size_t size,off64_t off) const120 unique_ptr<vector<RedactionRange>> RedactionInfo::getOverlappingRedactionRanges(size_t size,
121                                                                                 off64_t off) const {
122     if (hasOverlapWithReadRequest(size, off)) {
123         const off64_t start = off;
124         const off64_t end = static_cast<off64_t>(off + size);
125 
126         auto first_redaction = redaction_ranges_.end();
127         auto last_redaction = redaction_ranges_.begin();
128         for (auto iter = redaction_ranges_.begin(); iter != redaction_ranges_.end(); ++iter) {
129             if (iter->second > start && iter->first < end) {
130                 if (iter < first_redaction) first_redaction = iter;
131                 if (iter > last_redaction) last_redaction = iter;
132             }
133 
134             if (iter->first >= end) {
135                 break;
136             }
137         }
138 
139         if (first_redaction != redaction_ranges_.end()) {
140             CHECK(first_redaction <= last_redaction);
141             return std::make_unique<vector<RedactionRange>>(first_redaction, last_redaction + 1);
142         }
143     }
144     return std::make_unique<vector<RedactionRange>>();
145 }
146 
getReadRanges(off64_t off,size_t size,std::vector<ReadRange> * out) const147 void RedactionInfo::getReadRanges(off64_t off, size_t size, std::vector<ReadRange>* out) const {
148     const auto rr = getOverlappingRedactionRanges(size, off);
149     const size_t num_ranges = rr->size();
150     if (num_ranges == 0) {
151         return;
152     }
153 
154     const off64_t read_start = off;
155     const off64_t read_end = static_cast<off64_t>(read_start + size);
156 
157     // The algorithm for computing redaction ranges is very simple.
158     // Given a set of overlapping redaction ranges [s1, e1) [s2, e2) .. [sN, eN) for a read
159     // [s, e)
160     //
161     // We can construct a series of indices that we know will be the starts of every read range
162     // that we intend to return. Then, it's relatively simple to compute the lengths of the ranges.
163     // Also note that the read ranges we return always alternate in whether they're redacting or
164     // not. i.e, we will never return two consecutive redacting ranges or non redacting ranges.
165     std::vector<off64_t> sorted_indices;
166 
167     // Compute the list of indices -- this list will always contain { e1, s2, e2... sN }
168     // In addition, it may contain s or both (s and s1), depending on the start index.
169     // In addition, it may contain e or both (e and eN), depending on the end index.
170     //
171     // For a concrete example, consider ranges [10, 20) and [30, 40)
172     // For a read [0, 60) : sorted_indices will be { 0, 10, 20, 30, 40, 60 } is_first = false
173     // For a read [15, 60) : sorted_indices will be { 15, 20, 30, 40, 60 } is_first = true
174     // For a read [0, 35) : sorted_indices will be { 0, 10, 20, 30, 35 } is_first = false
175     // For a read [15, 35) : sorted_indices will be { 15, 20, 30, 35 } is_first = true
176     for (int i = 0; i < num_ranges; ++i) {
177         sorted_indices.push_back(rr->at(i).first);
178         sorted_indices.push_back(rr->at(i).second);
179     }
180 
181     // Find the right position for read_start in sorted_indices
182     // Either insert at the beginning or replace s1 with read_start
183     bool is_first_range_redaction = true;
184     if (read_start < rr->at(0).first) {
185         is_first_range_redaction = false;
186         sorted_indices.insert(sorted_indices.begin(), read_start);
187     } else {
188         sorted_indices.front() = read_start;
189     }
190 
191     // Find the right position for read_end in sorted_indices
192     // Either insert at the end or replace eN with read_end
193     if (read_end > rr->at(num_ranges - 1).second) {
194         sorted_indices.push_back(read_end);
195     } else {
196         sorted_indices.back() = read_end;
197     }
198 
199     bool is_redaction = is_first_range_redaction;
200     for (int i = 0; i < (sorted_indices.size() - 1); ++i) {
201         const off64_t read_size = sorted_indices[i + 1] - sorted_indices[i];
202         CHECK(read_size > 0);
203         out->push_back(ReadRange(sorted_indices[i], read_size, is_redaction));
204         is_redaction = !is_redaction;
205     }
206 }
207 
208 }  // namespace fuse
209 }  // namespace mediaprovider
210