xref: /aosp_15_r20/frameworks/base/services/incremental/path.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #include "path.h"
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include <android-base/strings.h>
20*d57664e9SAndroid Build Coastguard Worker #include <android-base/logging.h>
21*d57664e9SAndroid Build Coastguard Worker 
22*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
23*d57664e9SAndroid Build Coastguard Worker #include <iterator>
24*d57664e9SAndroid Build Coastguard Worker #include <limits>
25*d57664e9SAndroid Build Coastguard Worker #include <memory>
26*d57664e9SAndroid Build Coastguard Worker 
27*d57664e9SAndroid Build Coastguard Worker #include <dirent.h>
28*d57664e9SAndroid Build Coastguard Worker #include <stdlib.h>
29*d57664e9SAndroid Build Coastguard Worker #include <sys/types.h>
30*d57664e9SAndroid Build Coastguard Worker #include <unistd.h>
31*d57664e9SAndroid Build Coastguard Worker 
32*d57664e9SAndroid Build Coastguard Worker using namespace std::literals;
33*d57664e9SAndroid Build Coastguard Worker 
34*d57664e9SAndroid Build Coastguard Worker namespace android::incremental::path {
35*d57664e9SAndroid Build Coastguard Worker 
operator ()(char l,char r) const36*d57664e9SAndroid Build Coastguard Worker bool PathCharsLess::operator()(char l, char r) const {
37*d57664e9SAndroid Build Coastguard Worker     int ll = l == '/' ? std::numeric_limits<char>::min() - 1 : l;
38*d57664e9SAndroid Build Coastguard Worker     int rr = r == '/' ? std::numeric_limits<char>::min() - 1 : r;
39*d57664e9SAndroid Build Coastguard Worker     return ll < rr;
40*d57664e9SAndroid Build Coastguard Worker }
41*d57664e9SAndroid Build Coastguard Worker 
operator ()(std::string_view l,std::string_view r) const42*d57664e9SAndroid Build Coastguard Worker bool PathLess::operator()(std::string_view l, std::string_view r) const {
43*d57664e9SAndroid Build Coastguard Worker     return std::lexicographical_compare(std::begin(l), std::end(l), std::begin(r), std::end(r),
44*d57664e9SAndroid Build Coastguard Worker                                         PathCharsLess());
45*d57664e9SAndroid Build Coastguard Worker }
46*d57664e9SAndroid Build Coastguard Worker 
preparePathComponent(std::string_view & path,bool trimAll)47*d57664e9SAndroid Build Coastguard Worker static void preparePathComponent(std::string_view& path, bool trimAll) {
48*d57664e9SAndroid Build Coastguard Worker     // need to check for double front slash as a single one has a separate meaning in front
49*d57664e9SAndroid Build Coastguard Worker     while (!path.empty() && path.front() == '/' &&
50*d57664e9SAndroid Build Coastguard Worker            (trimAll || (path.size() > 1 && path[1] == '/'))) {
51*d57664e9SAndroid Build Coastguard Worker         path.remove_prefix(1);
52*d57664e9SAndroid Build Coastguard Worker     }
53*d57664e9SAndroid Build Coastguard Worker     // for the back we don't care about double-vs-single slash difference
54*d57664e9SAndroid Build Coastguard Worker     while (path.size() > !trimAll && path.back() == '/') {
55*d57664e9SAndroid Build Coastguard Worker         path.remove_suffix(1);
56*d57664e9SAndroid Build Coastguard Worker     }
57*d57664e9SAndroid Build Coastguard Worker }
58*d57664e9SAndroid Build Coastguard Worker 
append_next_path(std::string & target,std::string_view path)59*d57664e9SAndroid Build Coastguard Worker void details::append_next_path(std::string& target, std::string_view path) {
60*d57664e9SAndroid Build Coastguard Worker     preparePathComponent(path, !target.empty());
61*d57664e9SAndroid Build Coastguard Worker     if (path.empty()) {
62*d57664e9SAndroid Build Coastguard Worker         return;
63*d57664e9SAndroid Build Coastguard Worker     }
64*d57664e9SAndroid Build Coastguard Worker     if (!target.empty() && !target.ends_with('/')) {
65*d57664e9SAndroid Build Coastguard Worker         target.push_back('/');
66*d57664e9SAndroid Build Coastguard Worker     }
67*d57664e9SAndroid Build Coastguard Worker     target += path;
68*d57664e9SAndroid Build Coastguard Worker }
69*d57664e9SAndroid Build Coastguard Worker 
relativize(std::string_view parent,std::string_view nested)70*d57664e9SAndroid Build Coastguard Worker std::string_view relativize(std::string_view parent, std::string_view nested) {
71*d57664e9SAndroid Build Coastguard Worker     if (!nested.starts_with(parent)) {
72*d57664e9SAndroid Build Coastguard Worker         return nested;
73*d57664e9SAndroid Build Coastguard Worker     }
74*d57664e9SAndroid Build Coastguard Worker     if (nested.size() == parent.size()) {
75*d57664e9SAndroid Build Coastguard Worker         return {};
76*d57664e9SAndroid Build Coastguard Worker     }
77*d57664e9SAndroid Build Coastguard Worker     if (nested[parent.size()] != '/') {
78*d57664e9SAndroid Build Coastguard Worker         return nested;
79*d57664e9SAndroid Build Coastguard Worker     }
80*d57664e9SAndroid Build Coastguard Worker     auto relative = nested.substr(parent.size());
81*d57664e9SAndroid Build Coastguard Worker     while (relative.front() == '/') {
82*d57664e9SAndroid Build Coastguard Worker         relative.remove_prefix(1);
83*d57664e9SAndroid Build Coastguard Worker     }
84*d57664e9SAndroid Build Coastguard Worker     return relative;
85*d57664e9SAndroid Build Coastguard Worker }
86*d57664e9SAndroid Build Coastguard Worker 
isAbsolute(std::string_view path)87*d57664e9SAndroid Build Coastguard Worker bool isAbsolute(std::string_view path) {
88*d57664e9SAndroid Build Coastguard Worker     return !path.empty() && path[0] == '/';
89*d57664e9SAndroid Build Coastguard Worker }
90*d57664e9SAndroid Build Coastguard Worker 
normalize(std::string_view path)91*d57664e9SAndroid Build Coastguard Worker std::string normalize(std::string_view path) {
92*d57664e9SAndroid Build Coastguard Worker     if (path.empty()) {
93*d57664e9SAndroid Build Coastguard Worker         return {};
94*d57664e9SAndroid Build Coastguard Worker     }
95*d57664e9SAndroid Build Coastguard Worker     if (path.starts_with("../"sv)) {
96*d57664e9SAndroid Build Coastguard Worker         return {};
97*d57664e9SAndroid Build Coastguard Worker     }
98*d57664e9SAndroid Build Coastguard Worker 
99*d57664e9SAndroid Build Coastguard Worker     std::string result;
100*d57664e9SAndroid Build Coastguard Worker     if (isAbsolute(path)) {
101*d57664e9SAndroid Build Coastguard Worker         path.remove_prefix(1);
102*d57664e9SAndroid Build Coastguard Worker     } else {
103*d57664e9SAndroid Build Coastguard Worker         char buffer[PATH_MAX];
104*d57664e9SAndroid Build Coastguard Worker         if (!::getcwd(buffer, sizeof(buffer))) {
105*d57664e9SAndroid Build Coastguard Worker             return {};
106*d57664e9SAndroid Build Coastguard Worker         }
107*d57664e9SAndroid Build Coastguard Worker         result += buffer;
108*d57664e9SAndroid Build Coastguard Worker     }
109*d57664e9SAndroid Build Coastguard Worker 
110*d57664e9SAndroid Build Coastguard Worker     size_t start = 0;
111*d57664e9SAndroid Build Coastguard Worker     size_t end = 0;
112*d57664e9SAndroid Build Coastguard Worker     for (; end != path.npos; start = end + 1) {
113*d57664e9SAndroid Build Coastguard Worker         end = path.find('/', start);
114*d57664e9SAndroid Build Coastguard Worker         // Next component, excluding the separator
115*d57664e9SAndroid Build Coastguard Worker         auto part = path.substr(start, end - start);
116*d57664e9SAndroid Build Coastguard Worker         if (part.empty() || part == "."sv) {
117*d57664e9SAndroid Build Coastguard Worker             continue;
118*d57664e9SAndroid Build Coastguard Worker         }
119*d57664e9SAndroid Build Coastguard Worker         if (part == ".."sv) {
120*d57664e9SAndroid Build Coastguard Worker             if (result.empty()) {
121*d57664e9SAndroid Build Coastguard Worker                 return {};
122*d57664e9SAndroid Build Coastguard Worker             }
123*d57664e9SAndroid Build Coastguard Worker             auto lastPos = result.rfind('/');
124*d57664e9SAndroid Build Coastguard Worker             if (lastPos == result.npos) {
125*d57664e9SAndroid Build Coastguard Worker                 result.clear();
126*d57664e9SAndroid Build Coastguard Worker             } else {
127*d57664e9SAndroid Build Coastguard Worker                 result.resize(lastPos);
128*d57664e9SAndroid Build Coastguard Worker             }
129*d57664e9SAndroid Build Coastguard Worker             continue;
130*d57664e9SAndroid Build Coastguard Worker         }
131*d57664e9SAndroid Build Coastguard Worker         result += '/';
132*d57664e9SAndroid Build Coastguard Worker         result += part;
133*d57664e9SAndroid Build Coastguard Worker     }
134*d57664e9SAndroid Build Coastguard Worker 
135*d57664e9SAndroid Build Coastguard Worker     return result;
136*d57664e9SAndroid Build Coastguard Worker }
137*d57664e9SAndroid Build Coastguard Worker 
basename(std::string_view path)138*d57664e9SAndroid Build Coastguard Worker std::string_view basename(std::string_view path) {
139*d57664e9SAndroid Build Coastguard Worker     if (path.empty()) {
140*d57664e9SAndroid Build Coastguard Worker         return {};
141*d57664e9SAndroid Build Coastguard Worker     }
142*d57664e9SAndroid Build Coastguard Worker     if (path == "/"sv) {
143*d57664e9SAndroid Build Coastguard Worker         return "/"sv;
144*d57664e9SAndroid Build Coastguard Worker     }
145*d57664e9SAndroid Build Coastguard Worker     auto pos = path.rfind('/');
146*d57664e9SAndroid Build Coastguard Worker     while (!path.empty() && pos == path.size() - 1) {
147*d57664e9SAndroid Build Coastguard Worker         path.remove_suffix(1);
148*d57664e9SAndroid Build Coastguard Worker         pos = path.rfind('/');
149*d57664e9SAndroid Build Coastguard Worker     }
150*d57664e9SAndroid Build Coastguard Worker     if (pos == path.npos) {
151*d57664e9SAndroid Build Coastguard Worker         return path.empty() ? "/"sv : path;
152*d57664e9SAndroid Build Coastguard Worker     }
153*d57664e9SAndroid Build Coastguard Worker     return path.substr(pos + 1);
154*d57664e9SAndroid Build Coastguard Worker }
155*d57664e9SAndroid Build Coastguard Worker 
dirname(std::string_view path)156*d57664e9SAndroid Build Coastguard Worker std::string_view dirname(std::string_view path) {
157*d57664e9SAndroid Build Coastguard Worker     if (path.empty()) {
158*d57664e9SAndroid Build Coastguard Worker         return {};
159*d57664e9SAndroid Build Coastguard Worker     }
160*d57664e9SAndroid Build Coastguard Worker     if (path == "/"sv) {
161*d57664e9SAndroid Build Coastguard Worker         return "/"sv;
162*d57664e9SAndroid Build Coastguard Worker     }
163*d57664e9SAndroid Build Coastguard Worker     const auto pos = path.rfind('/');
164*d57664e9SAndroid Build Coastguard Worker     if (pos == 0) {
165*d57664e9SAndroid Build Coastguard Worker         return "/"sv;
166*d57664e9SAndroid Build Coastguard Worker     }
167*d57664e9SAndroid Build Coastguard Worker     if (pos == path.npos) {
168*d57664e9SAndroid Build Coastguard Worker         return "."sv;
169*d57664e9SAndroid Build Coastguard Worker     }
170*d57664e9SAndroid Build Coastguard Worker     return path.substr(0, pos);
171*d57664e9SAndroid Build Coastguard Worker }
172*d57664e9SAndroid Build Coastguard Worker 
CStrWrapper(std::string_view sv)173*d57664e9SAndroid Build Coastguard Worker details::CStrWrapper::CStrWrapper(std::string_view sv) {
174*d57664e9SAndroid Build Coastguard Worker     if (!sv.data()) {
175*d57664e9SAndroid Build Coastguard Worker         mCstr = "";
176*d57664e9SAndroid Build Coastguard Worker     } else if (sv[sv.size()] == '\0') {
177*d57664e9SAndroid Build Coastguard Worker         mCstr = sv.data();
178*d57664e9SAndroid Build Coastguard Worker     } else {
179*d57664e9SAndroid Build Coastguard Worker         mCopy.emplace(sv);
180*d57664e9SAndroid Build Coastguard Worker         mCstr = mCopy->c_str();
181*d57664e9SAndroid Build Coastguard Worker     }
182*d57664e9SAndroid Build Coastguard Worker }
183*d57664e9SAndroid Build Coastguard Worker 
isEmptyDir(std::string_view dir)184*d57664e9SAndroid Build Coastguard Worker std::optional<bool> isEmptyDir(std::string_view dir) {
185*d57664e9SAndroid Build Coastguard Worker     const auto d = std::unique_ptr<DIR, decltype(&::closedir)>{::opendir(c_str(dir)), ::closedir};
186*d57664e9SAndroid Build Coastguard Worker     if (!d) {
187*d57664e9SAndroid Build Coastguard Worker         if (errno == EPERM || errno == EACCES) {
188*d57664e9SAndroid Build Coastguard Worker             return std::nullopt;
189*d57664e9SAndroid Build Coastguard Worker         }
190*d57664e9SAndroid Build Coastguard Worker         return false;
191*d57664e9SAndroid Build Coastguard Worker     }
192*d57664e9SAndroid Build Coastguard Worker     while (auto entry = ::readdir(d.get())) {
193*d57664e9SAndroid Build Coastguard Worker         if (entry->d_type != DT_DIR) {
194*d57664e9SAndroid Build Coastguard Worker             return false;
195*d57664e9SAndroid Build Coastguard Worker         }
196*d57664e9SAndroid Build Coastguard Worker         if (entry->d_name != "."sv && entry->d_name != ".."sv) {
197*d57664e9SAndroid Build Coastguard Worker             return false;
198*d57664e9SAndroid Build Coastguard Worker         }
199*d57664e9SAndroid Build Coastguard Worker     }
200*d57664e9SAndroid Build Coastguard Worker     return true;
201*d57664e9SAndroid Build Coastguard Worker }
202*d57664e9SAndroid Build Coastguard Worker 
startsWith(std::string_view path,std::string_view prefix)203*d57664e9SAndroid Build Coastguard Worker bool startsWith(std::string_view path, std::string_view prefix) {
204*d57664e9SAndroid Build Coastguard Worker     if (!base::StartsWith(path, prefix)) {
205*d57664e9SAndroid Build Coastguard Worker         return false;
206*d57664e9SAndroid Build Coastguard Worker     }
207*d57664e9SAndroid Build Coastguard Worker     return path.size() == prefix.size() || path[prefix.size()] == '/';
208*d57664e9SAndroid Build Coastguard Worker }
209*d57664e9SAndroid Build Coastguard Worker 
210*d57664e9SAndroid Build Coastguard Worker } // namespace android::incremental::path
211