1*9190c2a8SAndroid Build Coastguard Worker /*
2*9190c2a8SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*9190c2a8SAndroid Build Coastguard Worker *
4*9190c2a8SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*9190c2a8SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*9190c2a8SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*9190c2a8SAndroid Build Coastguard Worker *
8*9190c2a8SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*9190c2a8SAndroid Build Coastguard Worker *
10*9190c2a8SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*9190c2a8SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*9190c2a8SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9190c2a8SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*9190c2a8SAndroid Build Coastguard Worker * limitations under the License.
15*9190c2a8SAndroid Build Coastguard Worker */
16*9190c2a8SAndroid Build Coastguard Worker
17*9190c2a8SAndroid Build Coastguard Worker #include "path.h"
18*9190c2a8SAndroid Build Coastguard Worker
19*9190c2a8SAndroid Build Coastguard Worker #include <android-base/logging.h>
20*9190c2a8SAndroid Build Coastguard Worker
21*9190c2a8SAndroid Build Coastguard Worker #include <memory>
22*9190c2a8SAndroid Build Coastguard Worker
23*9190c2a8SAndroid Build Coastguard Worker #include <dirent.h>
24*9190c2a8SAndroid Build Coastguard Worker #include <errno.h>
25*9190c2a8SAndroid Build Coastguard Worker #include <limits.h>
26*9190c2a8SAndroid Build Coastguard Worker #include <stdlib.h>
27*9190c2a8SAndroid Build Coastguard Worker #include <sys/stat.h>
28*9190c2a8SAndroid Build Coastguard Worker #include <unistd.h>
29*9190c2a8SAndroid Build Coastguard Worker
30*9190c2a8SAndroid Build Coastguard Worker using namespace std::literals;
31*9190c2a8SAndroid Build Coastguard Worker
32*9190c2a8SAndroid Build Coastguard Worker namespace android::incfs::path {
33*9190c2a8SAndroid Build Coastguard Worker
34*9190c2a8SAndroid Build Coastguard Worker namespace {
35*9190c2a8SAndroid Build Coastguard Worker
36*9190c2a8SAndroid Build Coastguard Worker class CStrWrapper {
37*9190c2a8SAndroid Build Coastguard Worker public:
CStrWrapper(std::string_view sv)38*9190c2a8SAndroid Build Coastguard Worker CStrWrapper(std::string_view sv) {
39*9190c2a8SAndroid Build Coastguard Worker if (sv[sv.size()] == '\0') {
40*9190c2a8SAndroid Build Coastguard Worker mCstr = sv.data();
41*9190c2a8SAndroid Build Coastguard Worker } else {
42*9190c2a8SAndroid Build Coastguard Worker mCopy.emplace(sv);
43*9190c2a8SAndroid Build Coastguard Worker mCstr = mCopy->c_str();
44*9190c2a8SAndroid Build Coastguard Worker }
45*9190c2a8SAndroid Build Coastguard Worker }
46*9190c2a8SAndroid Build Coastguard Worker
47*9190c2a8SAndroid Build Coastguard Worker CStrWrapper(const CStrWrapper&) = delete;
48*9190c2a8SAndroid Build Coastguard Worker void operator=(const CStrWrapper&) = delete;
49*9190c2a8SAndroid Build Coastguard Worker CStrWrapper(CStrWrapper&&) = delete;
50*9190c2a8SAndroid Build Coastguard Worker void operator=(CStrWrapper&&) = delete;
51*9190c2a8SAndroid Build Coastguard Worker
get() const52*9190c2a8SAndroid Build Coastguard Worker const char* get() const { return mCstr; }
operator const char*() const53*9190c2a8SAndroid Build Coastguard Worker operator const char*() const { return get(); }
54*9190c2a8SAndroid Build Coastguard Worker
55*9190c2a8SAndroid Build Coastguard Worker private:
56*9190c2a8SAndroid Build Coastguard Worker const char* mCstr;
57*9190c2a8SAndroid Build Coastguard Worker std::optional<std::string> mCopy;
58*9190c2a8SAndroid Build Coastguard Worker };
59*9190c2a8SAndroid Build Coastguard Worker
c_str(std::string_view sv)60*9190c2a8SAndroid Build Coastguard Worker inline CStrWrapper c_str(std::string_view sv) {
61*9190c2a8SAndroid Build Coastguard Worker return {sv};
62*9190c2a8SAndroid Build Coastguard Worker }
63*9190c2a8SAndroid Build Coastguard Worker
64*9190c2a8SAndroid Build Coastguard Worker } // namespace
65*9190c2a8SAndroid Build Coastguard Worker
isAbsolute(std::string_view path)66*9190c2a8SAndroid Build Coastguard Worker bool isAbsolute(std::string_view path) {
67*9190c2a8SAndroid Build Coastguard Worker return !path.empty() && path[0] == '/';
68*9190c2a8SAndroid Build Coastguard Worker }
69*9190c2a8SAndroid Build Coastguard Worker
normalize(std::string_view path)70*9190c2a8SAndroid Build Coastguard Worker std::string normalize(std::string_view path) {
71*9190c2a8SAndroid Build Coastguard Worker if (path.empty()) {
72*9190c2a8SAndroid Build Coastguard Worker return {};
73*9190c2a8SAndroid Build Coastguard Worker }
74*9190c2a8SAndroid Build Coastguard Worker if (path.starts_with("../"sv)) {
75*9190c2a8SAndroid Build Coastguard Worker return {};
76*9190c2a8SAndroid Build Coastguard Worker }
77*9190c2a8SAndroid Build Coastguard Worker
78*9190c2a8SAndroid Build Coastguard Worker std::string result;
79*9190c2a8SAndroid Build Coastguard Worker if (isAbsolute(path)) {
80*9190c2a8SAndroid Build Coastguard Worker path.remove_prefix(1);
81*9190c2a8SAndroid Build Coastguard Worker } else {
82*9190c2a8SAndroid Build Coastguard Worker char buffer[PATH_MAX];
83*9190c2a8SAndroid Build Coastguard Worker if (!::getcwd(buffer, sizeof(buffer))) {
84*9190c2a8SAndroid Build Coastguard Worker return {};
85*9190c2a8SAndroid Build Coastguard Worker }
86*9190c2a8SAndroid Build Coastguard Worker result += buffer;
87*9190c2a8SAndroid Build Coastguard Worker }
88*9190c2a8SAndroid Build Coastguard Worker
89*9190c2a8SAndroid Build Coastguard Worker size_t start = 0;
90*9190c2a8SAndroid Build Coastguard Worker size_t end = 0;
91*9190c2a8SAndroid Build Coastguard Worker for (; end != path.npos; start = end + 1) {
92*9190c2a8SAndroid Build Coastguard Worker end = path.find('/', start);
93*9190c2a8SAndroid Build Coastguard Worker // Next component, excluding the separator
94*9190c2a8SAndroid Build Coastguard Worker auto part = path.substr(start, end - start);
95*9190c2a8SAndroid Build Coastguard Worker if (part.empty() || part == "."sv) {
96*9190c2a8SAndroid Build Coastguard Worker continue;
97*9190c2a8SAndroid Build Coastguard Worker }
98*9190c2a8SAndroid Build Coastguard Worker if (part == ".."sv) {
99*9190c2a8SAndroid Build Coastguard Worker if (result.empty()) {
100*9190c2a8SAndroid Build Coastguard Worker return {};
101*9190c2a8SAndroid Build Coastguard Worker }
102*9190c2a8SAndroid Build Coastguard Worker auto lastPos = result.rfind('/');
103*9190c2a8SAndroid Build Coastguard Worker if (lastPos == result.npos) {
104*9190c2a8SAndroid Build Coastguard Worker result.clear();
105*9190c2a8SAndroid Build Coastguard Worker } else {
106*9190c2a8SAndroid Build Coastguard Worker result.resize(lastPos);
107*9190c2a8SAndroid Build Coastguard Worker }
108*9190c2a8SAndroid Build Coastguard Worker continue;
109*9190c2a8SAndroid Build Coastguard Worker }
110*9190c2a8SAndroid Build Coastguard Worker result += '/';
111*9190c2a8SAndroid Build Coastguard Worker result += part;
112*9190c2a8SAndroid Build Coastguard Worker }
113*9190c2a8SAndroid Build Coastguard Worker
114*9190c2a8SAndroid Build Coastguard Worker return result;
115*9190c2a8SAndroid Build Coastguard Worker }
116*9190c2a8SAndroid Build Coastguard Worker
117*9190c2a8SAndroid Build Coastguard Worker static constexpr char fdNameFormat[] = "/proc/self/fd/%d";
118*9190c2a8SAndroid Build Coastguard Worker
procfsForFd(int fd)119*9190c2a8SAndroid Build Coastguard Worker std::string procfsForFd(int fd) {
120*9190c2a8SAndroid Build Coastguard Worker char fdNameBuffer[std::size(fdNameFormat) + 11 + 1]; // max int length + '\0'
121*9190c2a8SAndroid Build Coastguard Worker snprintf(fdNameBuffer, std::size(fdNameBuffer), fdNameFormat, fd);
122*9190c2a8SAndroid Build Coastguard Worker return fdNameBuffer;
123*9190c2a8SAndroid Build Coastguard Worker }
124*9190c2a8SAndroid Build Coastguard Worker
fromFd(int fd)125*9190c2a8SAndroid Build Coastguard Worker std::string fromFd(int fd) {
126*9190c2a8SAndroid Build Coastguard Worker char fdNameBuffer[std::size(fdNameFormat) + 11 + 1]; // max int length + '\0'
127*9190c2a8SAndroid Build Coastguard Worker snprintf(fdNameBuffer, std::size(fdNameBuffer), fdNameFormat, fd);
128*9190c2a8SAndroid Build Coastguard Worker
129*9190c2a8SAndroid Build Coastguard Worker return readlink(fdNameBuffer);
130*9190c2a8SAndroid Build Coastguard Worker }
131*9190c2a8SAndroid Build Coastguard Worker
readlink(std::string_view path)132*9190c2a8SAndroid Build Coastguard Worker std::string readlink(std::string_view path) {
133*9190c2a8SAndroid Build Coastguard Worker static constexpr auto kDeletedSuffix = " (deleted)"sv;
134*9190c2a8SAndroid Build Coastguard Worker
135*9190c2a8SAndroid Build Coastguard Worker auto cPath = c_str(path);
136*9190c2a8SAndroid Build Coastguard Worker std::string res;
137*9190c2a8SAndroid Build Coastguard Worker // We used to call lstat() here to preallocate the buffer to the exact required size; turns out
138*9190c2a8SAndroid Build Coastguard Worker // that call is significantly more expensive than anything else, so doing a couple extra
139*9190c2a8SAndroid Build Coastguard Worker // iterations is worth the savings.
140*9190c2a8SAndroid Build Coastguard Worker auto bufSize = 256;
141*9190c2a8SAndroid Build Coastguard Worker for (;;) {
142*9190c2a8SAndroid Build Coastguard Worker res.resize(bufSize - 1, '\0');
143*9190c2a8SAndroid Build Coastguard Worker auto size = ::readlink(cPath, &res[0], res.size());
144*9190c2a8SAndroid Build Coastguard Worker if (size < 0) {
145*9190c2a8SAndroid Build Coastguard Worker PLOG(ERROR) << "readlink failed for " << path;
146*9190c2a8SAndroid Build Coastguard Worker return {};
147*9190c2a8SAndroid Build Coastguard Worker }
148*9190c2a8SAndroid Build Coastguard Worker if (size >= ssize_t(res.size())) {
149*9190c2a8SAndroid Build Coastguard Worker // can't tell if the name is exactly that long, or got truncated - just repeat the call.
150*9190c2a8SAndroid Build Coastguard Worker bufSize *= 2;
151*9190c2a8SAndroid Build Coastguard Worker continue;
152*9190c2a8SAndroid Build Coastguard Worker }
153*9190c2a8SAndroid Build Coastguard Worker res.resize(size);
154*9190c2a8SAndroid Build Coastguard Worker if (res.ends_with(kDeletedSuffix)) {
155*9190c2a8SAndroid Build Coastguard Worker res.resize(size - kDeletedSuffix.size());
156*9190c2a8SAndroid Build Coastguard Worker }
157*9190c2a8SAndroid Build Coastguard Worker return res;
158*9190c2a8SAndroid Build Coastguard Worker }
159*9190c2a8SAndroid Build Coastguard Worker }
160*9190c2a8SAndroid Build Coastguard Worker
preparePathComponent(std::string_view & path,bool trimAll)161*9190c2a8SAndroid Build Coastguard Worker static void preparePathComponent(std::string_view& path, bool trimAll) {
162*9190c2a8SAndroid Build Coastguard Worker // need to check for double front slash as a single one has a separate meaning in front
163*9190c2a8SAndroid Build Coastguard Worker while (!path.empty() && path.front() == '/' &&
164*9190c2a8SAndroid Build Coastguard Worker (trimAll || (path.size() > 1 && path[1] == '/'))) {
165*9190c2a8SAndroid Build Coastguard Worker path.remove_prefix(1);
166*9190c2a8SAndroid Build Coastguard Worker }
167*9190c2a8SAndroid Build Coastguard Worker // for the back we don't care about double-vs-single slash difference
168*9190c2a8SAndroid Build Coastguard Worker while (path.size() > !trimAll && path.back() == '/') {
169*9190c2a8SAndroid Build Coastguard Worker path.remove_suffix(1);
170*9190c2a8SAndroid Build Coastguard Worker }
171*9190c2a8SAndroid Build Coastguard Worker }
172*9190c2a8SAndroid Build Coastguard Worker
relativize(std::string_view parent,std::string_view nested)173*9190c2a8SAndroid Build Coastguard Worker std::string_view relativize(std::string_view parent, std::string_view nested) {
174*9190c2a8SAndroid Build Coastguard Worker if (!nested.starts_with(parent)) {
175*9190c2a8SAndroid Build Coastguard Worker return nested;
176*9190c2a8SAndroid Build Coastguard Worker }
177*9190c2a8SAndroid Build Coastguard Worker if (nested.size() == parent.size()) {
178*9190c2a8SAndroid Build Coastguard Worker return {};
179*9190c2a8SAndroid Build Coastguard Worker }
180*9190c2a8SAndroid Build Coastguard Worker if (nested[parent.size()] != '/') {
181*9190c2a8SAndroid Build Coastguard Worker return nested;
182*9190c2a8SAndroid Build Coastguard Worker }
183*9190c2a8SAndroid Build Coastguard Worker auto relative = nested.substr(parent.size());
184*9190c2a8SAndroid Build Coastguard Worker while (relative.front() == '/') {
185*9190c2a8SAndroid Build Coastguard Worker relative.remove_prefix(1);
186*9190c2a8SAndroid Build Coastguard Worker }
187*9190c2a8SAndroid Build Coastguard Worker return relative;
188*9190c2a8SAndroid Build Coastguard Worker }
189*9190c2a8SAndroid Build Coastguard Worker
appendNextPath(std::string & res,std::string_view path)190*9190c2a8SAndroid Build Coastguard Worker void details::appendNextPath(std::string& res, std::string_view path) {
191*9190c2a8SAndroid Build Coastguard Worker preparePathComponent(path, !res.empty());
192*9190c2a8SAndroid Build Coastguard Worker if (path.empty()) {
193*9190c2a8SAndroid Build Coastguard Worker return;
194*9190c2a8SAndroid Build Coastguard Worker }
195*9190c2a8SAndroid Build Coastguard Worker if (!res.empty() && !res.ends_with('/')) {
196*9190c2a8SAndroid Build Coastguard Worker res.push_back('/');
197*9190c2a8SAndroid Build Coastguard Worker }
198*9190c2a8SAndroid Build Coastguard Worker res += path;
199*9190c2a8SAndroid Build Coastguard Worker }
200*9190c2a8SAndroid Build Coastguard Worker
splitDirBase(std::string & full)201*9190c2a8SAndroid Build Coastguard Worker std::pair<std::string_view, std::string_view> splitDirBase(std::string& full) {
202*9190c2a8SAndroid Build Coastguard Worker auto res = std::pair(dirName(full), baseName(full));
203*9190c2a8SAndroid Build Coastguard Worker if (res.first.data() == full.data()) {
204*9190c2a8SAndroid Build Coastguard Worker full[res.first.size()] = 0;
205*9190c2a8SAndroid Build Coastguard Worker }
206*9190c2a8SAndroid Build Coastguard Worker return res;
207*9190c2a8SAndroid Build Coastguard Worker }
208*9190c2a8SAndroid Build Coastguard Worker
isEmptyDir(std::string_view dir)209*9190c2a8SAndroid Build Coastguard Worker int isEmptyDir(std::string_view dir) {
210*9190c2a8SAndroid Build Coastguard Worker const auto d = std::unique_ptr<DIR, decltype(&::closedir)>{::opendir(c_str(dir)), ::closedir};
211*9190c2a8SAndroid Build Coastguard Worker if (!d) {
212*9190c2a8SAndroid Build Coastguard Worker return -errno;
213*9190c2a8SAndroid Build Coastguard Worker }
214*9190c2a8SAndroid Build Coastguard Worker while (const auto entry = ::readdir(d.get())) {
215*9190c2a8SAndroid Build Coastguard Worker if (entry->d_type != DT_DIR) {
216*9190c2a8SAndroid Build Coastguard Worker return -ENOTEMPTY;
217*9190c2a8SAndroid Build Coastguard Worker }
218*9190c2a8SAndroid Build Coastguard Worker if (entry->d_name != "."sv && entry->d_name != ".."sv) {
219*9190c2a8SAndroid Build Coastguard Worker return -ENOTEMPTY;
220*9190c2a8SAndroid Build Coastguard Worker }
221*9190c2a8SAndroid Build Coastguard Worker }
222*9190c2a8SAndroid Build Coastguard Worker return 0;
223*9190c2a8SAndroid Build Coastguard Worker }
224*9190c2a8SAndroid Build Coastguard Worker
startsWith(std::string_view path,std::string_view prefix)225*9190c2a8SAndroid Build Coastguard Worker bool startsWith(std::string_view path, std::string_view prefix) {
226*9190c2a8SAndroid Build Coastguard Worker if (!path.starts_with(prefix)) {
227*9190c2a8SAndroid Build Coastguard Worker return false;
228*9190c2a8SAndroid Build Coastguard Worker }
229*9190c2a8SAndroid Build Coastguard Worker return path.size() == prefix.size() || path[prefix.size()] == '/';
230*9190c2a8SAndroid Build Coastguard Worker }
231*9190c2a8SAndroid Build Coastguard Worker
endsWith(std::string_view path,std::string_view suffix)232*9190c2a8SAndroid Build Coastguard Worker bool endsWith(std::string_view path, std::string_view suffix) {
233*9190c2a8SAndroid Build Coastguard Worker if (!path.ends_with(suffix)) {
234*9190c2a8SAndroid Build Coastguard Worker return false;
235*9190c2a8SAndroid Build Coastguard Worker }
236*9190c2a8SAndroid Build Coastguard Worker return path.size() == suffix.size() || path[path.size() - suffix.size() - 1] == '/';
237*9190c2a8SAndroid Build Coastguard Worker }
238*9190c2a8SAndroid Build Coastguard Worker
239*9190c2a8SAndroid Build Coastguard Worker } // namespace android::incfs::path
240