blob: 3494db74226ed44b4c4d9370d79edbe344e407f3 [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
17#define LOG_TAG "RedactionInfo"
18
19#include "include/libfuse_jni/RedactionInfo.h"
20
21#include <android-base/logging.h>
22
23using std::unique_ptr;
24using std::vector;
25
26namespace mediaprovider {
27namespace fuse {
28
29/**
30 * Merges any overlapping ranges into 1 range.
31 *
32 * Given ranges should be sorted, and they remain sorted.
33 */
34static void mergeOverlappingRedactionRanges(vector<RedactionRange>& ranges) {
35 int newRangesSize = ranges.size();
36 for (int i = 0; i < ranges.size() - 1; ++i) {
37 if (ranges[i].second >= ranges[i + 1].first) {
38 ranges[i + 1].first = ranges[i].first;
39 ranges[i + 1].second = std::max(ranges[i].second, ranges[i + 1].second);
40 // Invalidate the redundant range
41 ranges[i].first = LONG_MAX;
42 ranges[i].second = LONG_MAX;
43 newRangesSize--;
44 }
45 }
46 if (newRangesSize < ranges.size()) {
47 // Move invalid ranges to end of array
48 std::sort(ranges.begin(), ranges.end());
49 ranges.resize(newRangesSize);
50 }
51}
52
53/**
54 * Determine whether the read request overlaps with the redaction ranges
55 * defined by the given RedactionInfo.
56 *
shafikcdb6b2b2019-09-30 12:49:26 +010057 * This function assumes redaction_ranges_ within RedactionInfo is sorted.
shafikc3f62672019-08-30 11:15:48 +010058 */
59bool RedactionInfo::hasOverlapWithReadRequest(size_t size, off64_t off) {
shafikcdb6b2b2019-09-30 12:49:26 +010060 if (!isRedactionNeeded() || off > redaction_ranges_.back().second ||
61 off + size < redaction_ranges_.front().first) {
shafikc3f62672019-08-30 11:15:48 +010062 return false;
63 }
64 return true;
65}
66
67/**
68 * Sets the redaction ranges in RedactionInfo, sort the ranges and merge
69 * overlapping ranges.
70 */
shafikcdb6b2b2019-09-30 12:49:26 +010071void RedactionInfo::processRedactionRanges(int redaction_ranges_num,
72 const off64_t* redaction_ranges) {
73 redaction_ranges_.resize(redaction_ranges_num);
shafikc3f62672019-08-30 11:15:48 +010074 for (int i = 0; i < redaction_ranges_num; ++i) {
shafikcdb6b2b2019-09-30 12:49:26 +010075 redaction_ranges_[i].first = static_cast<off64_t>(redaction_ranges[2 * i]);
76 redaction_ranges_[i].second = static_cast<off64_t>(redaction_ranges[2 * i + 1]);
shafikc3f62672019-08-30 11:15:48 +010077 }
shafikcdb6b2b2019-09-30 12:49:26 +010078 std::sort(redaction_ranges_.begin(), redaction_ranges_.end());
79 mergeOverlappingRedactionRanges(redaction_ranges_);
shafikc3f62672019-08-30 11:15:48 +010080}
81
82int RedactionInfo::size() {
shafikcdb6b2b2019-09-30 12:49:26 +010083 return redaction_ranges_.size();
shafikc3f62672019-08-30 11:15:48 +010084}
85
86bool RedactionInfo::isRedactionNeeded() {
87 return size() > 0;
88}
89
shafikcdb6b2b2019-09-30 12:49:26 +010090RedactionInfo::RedactionInfo(int redaction_ranges_num, const off64_t* redaction_ranges) {
shafikc3f62672019-08-30 11:15:48 +010091 if (redaction_ranges == 0) return;
92 processRedactionRanges(redaction_ranges_num, redaction_ranges);
93}
94
95unique_ptr<vector<RedactionRange>> RedactionInfo::getOverlappingRedactionRanges(size_t size,
96 off64_t off) {
97 LOG(DEBUG) << "Computing redaction ranges for request: sz = " << size << " off = " << off;
98 if (hasOverlapWithReadRequest(size, off)) {
shafikcdb6b2b2019-09-30 12:49:26 +010099 auto first_redaction = redaction_ranges_.end();
100 auto last_redaction = redaction_ranges_.end();
101 for (auto iter = redaction_ranges_.begin(); iter != redaction_ranges_.end(); ++iter) {
shafikc3f62672019-08-30 11:15:48 +0100102 RedactionRange& rr = *iter;
103 // Look for the first range that overlaps with the read request
shafikcdb6b2b2019-09-30 12:49:26 +0100104 if (first_redaction == redaction_ranges_.end() && off <= rr.second &&
105 off + size >= rr.first) {
shafikc3f62672019-08-30 11:15:48 +0100106 first_redaction = iter;
shafikcdb6b2b2019-09-30 12:49:26 +0100107 } else if (first_redaction != redaction_ranges_.end() && off + size < rr.first) {
shafikc3f62672019-08-30 11:15:48 +0100108 // Once we're in the read request range, we start checking if
109 // we're out of it so we can return the result to the caller
110 break;
111 }
112 last_redaction = iter;
113 }
shafikcdb6b2b2019-09-30 12:49:26 +0100114 if (first_redaction != redaction_ranges_.end()) {
shafikc3f62672019-08-30 11:15:48 +0100115 LOG(DEBUG) << "Returning " << (int)(last_redaction - first_redaction + 1)
116 << " redaction ranges!";
117 return std::make_unique<vector<RedactionRange>>(first_redaction, last_redaction + 1);
118 }
119 }
120 LOG(DEBUG) << "No relevant redaction ranges!";
121 return std::make_unique<vector<RedactionRange>>();
122}
123} // namespace fuse
124} // namespace mediaprovider