blob: ab693f68e76d308a2d7dcae912d0a72878939472 [file] [log] [blame]
Andreas Huber1aec3972016-08-26 09:26:32 -07001/*
2 * Copyright (C) 2016 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 specific language governing permissions and
14 * limitations under the License.
15 */
16
Andreas Huber5345ec22016-07-29 13:33:27 -070017#include "Coordinator.h"
18
Iliyan Malcheva72e0d22016-09-09 11:03:08 -070019#include <dirent.h>
Andreas Huberd2943e12016-08-05 11:59:31 -070020#include <sys/stat.h>
Andreas Huber5345ec22016-07-29 13:33:27 -070021
Yifan Hong78b38d12017-02-13 18:14:46 +000022#include <algorithm>
23#include <iterator>
24
25#include <android-base/logging.h>
Steven Moreland5bdfa702017-04-18 23:20:39 -070026#include <hidl-hash/Hash.h>
Yifan Hong78b38d12017-02-13 18:14:46 +000027#include <hidl-util/StringHelper.h>
Steven Morelandcbff5612017-10-11 17:01:54 -070028#include <iostream>
Yifan Hong78b38d12017-02-13 18:14:46 +000029
30#include "AST.h"
31#include "Interface.h"
Steven Moreland06a088b2018-02-20 12:34:47 -080032#include "hidl-gen_l.h"
Andreas Huber5345ec22016-07-29 13:33:27 -070033
Yifan Hong78b38d12017-02-13 18:14:46 +000034static bool existdir(const char *name) {
35 DIR *dir = opendir(name);
Yi Kong56758da2018-07-24 16:21:37 -070036 if (dir == nullptr) {
Yifan Hong78b38d12017-02-13 18:14:46 +000037 return false;
38 }
39 closedir(dir);
40 return true;
41}
42
Andreas Huber5345ec22016-07-29 13:33:27 -070043namespace android {
44
Steven Moreland47792c42017-09-20 10:03:20 -070045const std::string &Coordinator::getRootPath() const {
46 return mRootPath;
Andreas Huberdc981332016-07-29 15:46:54 -070047}
48
Steven Moreland47792c42017-09-20 10:03:20 -070049void Coordinator::setRootPath(const std::string &rootPath) {
50 mRootPath = rootPath;
Andreas Huber5345ec22016-07-29 13:33:27 -070051
Steven Moreland47792c42017-09-20 10:03:20 -070052 if (!mRootPath.empty() && !StringHelper::EndsWith(mRootPath, "/")) {
53 mRootPath += "/";
Steven Moreland25c81662017-05-12 14:57:36 -070054 }
55}
56
Steven Moreland6d3d3c82018-02-08 11:49:34 -080057void Coordinator::setOutputPath(const std::string& outputPath) {
58 mOutputPath = outputPath;
59}
60
Steven Moreland37c57ee2017-09-25 19:08:56 -070061void Coordinator::setVerbose(bool verbose) {
62 mVerbose = verbose;
63}
64
Andreas Huber308d8a22017-11-06 14:46:52 -080065bool Coordinator::isVerbose() const {
66 return mVerbose;
67}
68
Steven Moreland394af5c2018-02-09 14:41:46 -080069void Coordinator::setDepFile(const std::string& depFile) {
70 mDepFile = depFile;
71}
72
Steven Moreland89a9ebb2017-12-04 10:18:00 -080073const std::string& Coordinator::getOwner() const {
74 return mOwner;
75}
76void Coordinator::setOwner(const std::string& owner) {
77 mOwner = owner;
78}
79
Steven Moreland47792c42017-09-20 10:03:20 -070080status_t Coordinator::addPackagePath(const std::string& root, const std::string& path, std::string* error) {
81 FQName package = FQName(root, "0.0", "");
82 for (const PackageRoot &packageRoot : mPackageRoots) {
83 if (packageRoot.root.inPackage(root) || package.inPackage(packageRoot.root.package())) {
84 if (error != nullptr) {
85 *error = "ERROR: conflicting package roots " +
86 packageRoot.root.package() +
87 " and " +
88 root;
89 }
90
91 return UNKNOWN_ERROR;
92 }
93 }
94
Steven Moreland1a85fd92017-09-28 16:31:24 -070095 mPackageRoots.push_back({path, package});
Steven Moreland47792c42017-09-20 10:03:20 -070096 return OK;
97}
98void Coordinator::addDefaultPackagePath(const std::string& root, const std::string& path) {
99 addPackagePath(root, path, nullptr /* error */);
100}
101
Steven Moreland6d3d3c82018-02-08 11:49:34 -0800102Formatter Coordinator::getFormatter(const FQName& fqName, Location location,
103 const std::string& fileName) const {
Steven Moreland5abcf012018-02-08 18:50:18 -0800104 if (location == Location::STANDARD_OUT) {
105 return Formatter(stdout);
106 }
107
Steven Moreland255c9a12018-02-26 13:10:27 -0800108 std::string filepath;
109 status_t err = getFilepath(fqName, location, fileName, &filepath);
110 if (err != OK) {
111 return Formatter::invalid();
112 }
Steven Morelandf78c44d2017-09-25 18:41:45 -0700113
Steven Moreland37c57ee2017-09-25 19:08:56 -0700114 onFileAccess(filepath, "w");
115
Steven Morelandf78c44d2017-09-25 18:41:45 -0700116 if (!Coordinator::MakeParentHierarchy(filepath)) {
117 fprintf(stderr, "ERROR: could not make directories for %s.\n", filepath.c_str());
118 return Formatter::invalid();
119 }
120
121 FILE* file = fopen(filepath.c_str(), "w");
122
123 if (file == nullptr) {
124 fprintf(stderr, "ERROR: could not open file %s: %d\n", filepath.c_str(), errno);
125 return Formatter::invalid();
126 }
127
128 return Formatter(file);
129}
130
Steven Moreland255c9a12018-02-26 13:10:27 -0800131status_t Coordinator::getFilepath(const FQName& fqName, Location location,
132 const std::string& fileName, std::string* path) const {
133 status_t err;
134 std::string packagePath;
135 std::string packageRootPath;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700136
137 switch (location) {
138 case Location::DIRECT: { /* nothing */
Steven Moreland255c9a12018-02-26 13:10:27 -0800139 *path = mOutputPath + fileName;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700140 } break;
141 case Location::PACKAGE_ROOT: {
Steven Moreland255c9a12018-02-26 13:10:27 -0800142 err = getPackagePath(fqName, false /* relative */, false /* sanitized */, &packagePath);
143 if (err != OK) return err;
144
145 *path = mOutputPath + packagePath + fileName;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700146 } break;
147 case Location::GEN_OUTPUT: {
Steven Moreland255c9a12018-02-26 13:10:27 -0800148 err = convertPackageRootToPath(fqName, &packageRootPath);
149 if (err != OK) return err;
150 err = getPackagePath(fqName, true /* relative */, false /* sanitized */, &packagePath);
151 if (err != OK) return err;
152
153 *path = mOutputPath + packageRootPath + packagePath + fileName;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700154 } break;
155 case Location::GEN_SANITIZED: {
Steven Moreland255c9a12018-02-26 13:10:27 -0800156 err = convertPackageRootToPath(fqName, &packageRootPath);
157 if (err != OK) return err;
158 err = getPackagePath(fqName, true /* relative */, true /* sanitized */, &packagePath);
159 if (err != OK) return err;
160
161 *path = mOutputPath + packageRootPath + packagePath + fileName;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700162 } break;
163 default: { CHECK(false) << "Invalid location: " << static_cast<size_t>(location); }
164 }
165
Steven Moreland255c9a12018-02-26 13:10:27 -0800166 return OK;
Steven Morelandf78c44d2017-09-25 18:41:45 -0700167}
168
Steven Moreland37c57ee2017-09-25 19:08:56 -0700169void Coordinator::onFileAccess(const std::string& path, const std::string& mode) const {
Steven Moreland394af5c2018-02-09 14:41:46 -0800170 if (mode == "r") {
171 // This is a global list. It's not cleared when a second fqname is processed for
172 // two reasons:
173 // 1). If there is a bug in hidl-gen, the dependencies on the first project from
174 // the second would be required to recover correctly when the bug is fixed.
175 // 2). This option is never used in Android builds.
176 mReadFiles.insert(StringHelper::LTrim(path, mRootPath));
177 }
178
Steven Moreland37c57ee2017-09-25 19:08:56 -0700179 if (!mVerbose) {
180 return;
181 }
182
183 fprintf(stderr,
184 "VERBOSE: file access %s %s\n", path.c_str(), mode.c_str());
185}
186
Steven Moreland394af5c2018-02-09 14:41:46 -0800187status_t Coordinator::writeDepFile(const std::string& forFile) const {
188 // No dep file requested
189 if (mDepFile.empty()) return OK;
190
191 onFileAccess(mDepFile, "w");
192
193 FILE* file = fopen(mDepFile.c_str(), "w");
194 if (file == nullptr) {
195 fprintf(stderr, "ERROR: could not open dep file at %s.\n", mDepFile.c_str());
196 return UNKNOWN_ERROR;
197 }
198
199 Formatter out(file, 2 /* spacesPerIndent */);
200 out << StringHelper::LTrim(forFile, mOutputPath) << ": \\\n";
201 out.indent([&] {
202 for (const std::string& file : mReadFiles) {
203 out << StringHelper::LTrim(file, mRootPath) << " \\\n";
204 }
205 });
206 return OK;
207}
Steven Moreland37c57ee2017-09-25 19:08:56 -0700208
Steven Morelandc59326e2017-06-20 15:19:30 -0700209AST* Coordinator::parse(const FQName& fqName, std::set<AST*>* parsedASTs,
210 Enforce enforcement) const {
Steven Moreland71f09132018-02-20 12:24:30 -0800211 AST* ret;
212 status_t err = parseOptional(fqName, &ret, parsedASTs, enforcement);
213 if (err != OK) CHECK(ret == nullptr); // internal consistency
214
215 // only in a handful of places do we want to distinguish between
216 // a missing file and a bad AST. Everywhere else, we just want to
217 // throw an error if we expect an AST to be present but it is not.
218 return ret;
219}
220
221status_t Coordinator::parseOptional(const FQName& fqName, AST** ast, std::set<AST*>* parsedASTs,
222 Enforce enforcement) const {
Andreas Huber68f24592016-07-29 14:53:48 -0700223 CHECK(fqName.isFullyQualified());
224
Steven Morelandd537ab02016-09-12 10:32:01 -0700225 auto it = mCache.find(fqName);
226 if (it != mCache.end()) {
Steven Moreland71f09132018-02-20 12:24:30 -0800227 *ast = (*it).second;
Andreas Huber5345ec22016-07-29 13:33:27 -0700228
Steven Moreland71f09132018-02-20 12:24:30 -0800229 if (*ast != nullptr && parsedASTs != nullptr) {
230 parsedASTs->insert(*ast);
Andreas Huber39fa7182016-08-19 14:27:33 -0700231 }
232
Steven Moreland71f09132018-02-20 12:24:30 -0800233 if (*ast == nullptr) {
234 // circular import OR that AST has errors in it
235 return UNKNOWN_ERROR;
236 }
237
238 return OK;
Andreas Huber5345ec22016-07-29 13:33:27 -0700239 }
240
Andreas Huber68f24592016-07-29 14:53:48 -0700241 // Add this to the cache immediately, so we can discover circular imports.
Steven Morelandd537ab02016-09-12 10:32:01 -0700242 mCache[fqName] = nullptr;
Andreas Huber39fa7182016-08-19 14:27:33 -0700243
244 AST *typesAST = nullptr;
Andreas Huber68f24592016-07-29 14:53:48 -0700245
Andreas Huber68f24592016-07-29 14:53:48 -0700246 if (fqName.name() != "types") {
247 // Any interface file implicitly imports its package's types.hal.
Yifan Hongfece6ec2017-01-12 17:04:04 -0800248 FQName typesName = fqName.getTypesForPackage();
Steven Morelanda407b7d2017-08-25 16:56:39 -0700249 // Do not enforce on imports. Do not add imports' imports to this AST.
Steven Moreland71f09132018-02-20 12:24:30 -0800250 status_t err = parseOptional(typesName, &typesAST, nullptr, Enforce::NONE);
251 if (err != OK) return err;
Andreas Huber68f24592016-07-29 14:53:48 -0700252
253 // fall through.
254 }
255
Steven Moreland255c9a12018-02-26 13:10:27 -0800256 std::string packagePath;
257 status_t err =
258 getPackagePath(fqName, false /* relative */, false /* sanitized */, &packagePath);
259 if (err != OK) return err;
Andreas Huberdca261f2016-08-04 13:47:51 -0700260
Steven Moreland255c9a12018-02-26 13:10:27 -0800261 const std::string path = makeAbsolute(packagePath + fqName.name() + ".hal");
Andreas Huber5345ec22016-07-29 13:33:27 -0700262
Steven Moreland71f09132018-02-20 12:24:30 -0800263 *ast = new AST(this, &Hash::getHash(path));
Andreas Huber39fa7182016-08-19 14:27:33 -0700264
Yi Kong56758da2018-07-24 16:21:37 -0700265 if (typesAST != nullptr) {
Andreas Huber39fa7182016-08-19 14:27:33 -0700266 // If types.hal for this AST's package existed, make it's defined
267 // types available to the (about to be parsed) AST right away.
Steven Moreland71f09132018-02-20 12:24:30 -0800268 (*ast)->addImportedAST(typesAST);
Andreas Huber39fa7182016-08-19 14:27:33 -0700269 }
270
Steven Moreland161afb22018-02-20 14:22:44 -0800271 std::unique_ptr<FILE, std::function<void(FILE*)>> file(fopen(path.c_str(), "rb"), fclose);
Andreas Huber68f24592016-07-29 14:53:48 -0700272
Steven Moreland71f09132018-02-20 12:24:30 -0800273 if (file == nullptr) {
274 mCache.erase(fqName); // nullptr in cache is used to find circular imports
275 delete *ast;
276 *ast = nullptr;
277 return OK; // File does not exist, nullptr AST* == file doesn't exist.
Andreas Huber68f24592016-07-29 14:53:48 -0700278 }
279
Steven Moreland3d846992018-02-14 17:24:57 -0800280 onFileAccess(path, "r");
281
Steven Moreland71f09132018-02-20 12:24:30 -0800282 // parse file takes ownership of file
Steven Moreland161afb22018-02-20 14:22:44 -0800283 if (parseFile(*ast, std::move(file)) != OK || (*ast)->postParse() != OK) {
Steven Moreland71f09132018-02-20 12:24:30 -0800284 delete *ast;
285 *ast = nullptr;
286 return UNKNOWN_ERROR;
287 }
288
Steven Moreland71f09132018-02-20 12:24:30 -0800289 if ((*ast)->package().package() != fqName.package() ||
290 (*ast)->package().version() != fqName.version()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700291 fprintf(stderr,
292 "ERROR: File at '%s' does not match expected package and/or "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700293 "version.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700294 path.c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700295
296 err = UNKNOWN_ERROR;
297 } else {
Steven Moreland71f09132018-02-20 12:24:30 -0800298 if ((*ast)->isInterface()) {
Andreas Hubera2723d22016-07-29 15:36:07 -0700299 if (fqName.name() == "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700300 fprintf(stderr,
301 "ERROR: File at '%s' declares an interface '%s' "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700302 "instead of the expected types common to the package.\n",
Steven Moreland71f09132018-02-20 12:24:30 -0800303 path.c_str(), (*ast)->getInterface()->localName().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700304
305 err = UNKNOWN_ERROR;
Steven Moreland71f09132018-02-20 12:24:30 -0800306 } else if ((*ast)->getInterface()->localName() != fqName.name()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700307 fprintf(stderr,
308 "ERROR: File at '%s' does not declare interface type "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700309 "'%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700310 path.c_str(),
311 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700312
313 err = UNKNOWN_ERROR;
314 }
315 } else if (fqName.name() != "types") {
Andreas Huber70a59e12016-08-16 12:57:01 -0700316 fprintf(stderr,
317 "ERROR: File at '%s' declares types rather than the "
Andreas Huber0d0f9a22016-08-17 10:26:11 -0700318 "expected interface type '%s'.\n",
Andreas Huber70a59e12016-08-16 12:57:01 -0700319 path.c_str(),
320 fqName.name().c_str());
Andreas Hubera2723d22016-07-29 15:36:07 -0700321
322 err = UNKNOWN_ERROR;
Steven Morelandb47a2622018-07-11 09:04:25 -0700323 } else if ((*ast)->definesInterfaces()) {
Andreas Huber7c5ddfb2016-09-29 13:45:22 -0700324 fprintf(stderr,
325 "ERROR: types.hal file at '%s' declares at least one "
326 "interface type.\n",
327 path.c_str());
328
329 err = UNKNOWN_ERROR;
Andreas Hubera2723d22016-07-29 15:36:07 -0700330 }
331 }
332
333 if (err != OK) {
Steven Moreland71f09132018-02-20 12:24:30 -0800334 delete *ast;
335 *ast = nullptr;
336 return err;
Andreas Hubera2723d22016-07-29 15:36:07 -0700337 }
338
Steven Moreland71f09132018-02-20 12:24:30 -0800339 if (parsedASTs != nullptr) {
340 parsedASTs->insert(*ast);
341 }
Andreas Huber39fa7182016-08-19 14:27:33 -0700342
Yifan Hongfe07bff2017-02-15 14:55:48 -0800343 // put it into the cache now, so that enforceRestrictionsOnPackage can
344 // parse fqName.
Steven Moreland71f09132018-02-20 12:24:30 -0800345 mCache[fqName] = *ast;
Andreas Huber5345ec22016-07-29 13:33:27 -0700346
Steven Morelandc59326e2017-06-20 15:19:30 -0700347 // For each .hal file that hidl-gen parses, the whole package will be checked.
348 err = enforceRestrictionsOnPackage(fqName, enforcement);
349 if (err != OK) {
350 mCache[fqName] = nullptr;
Steven Moreland71f09132018-02-20 12:24:30 -0800351 delete *ast;
352 *ast = nullptr;
353 return err;
Yifan Hong78b38d12017-02-13 18:14:46 +0000354 }
355
Steven Moreland71f09132018-02-20 12:24:30 -0800356 return OK;
Andreas Huber5345ec22016-07-29 13:33:27 -0700357}
358
Steven Moreland255c9a12018-02-26 13:10:27 -0800359const Coordinator::PackageRoot* Coordinator::findPackageRoot(const FQName& fqName) const {
Andreas Huber5345ec22016-07-29 13:33:27 -0700360 CHECK(!fqName.package().empty());
Andreas Huber5345ec22016-07-29 13:33:27 -0700361
Andreas Huberdca261f2016-08-04 13:47:51 -0700362 // Find the right package prefix and path for this FQName. For
363 // example, if FQName is "android.hardware.nfc@1.0::INfc", and the
364 // prefix:root is set to [ "android.hardware:hardware/interfaces",
365 // "vendor.qcom.hardware:vendor/qcom"], then we will identify the
366 // prefix "android.hardware" and the package root
367 // "hardware/interfaces".
368
Steven Moreland62709d72017-01-18 10:14:51 -0800369 auto ret = mPackageRoots.end();
Steven Moreland47792c42017-09-20 10:03:20 -0700370 for (auto it = mPackageRoots.begin(); it != mPackageRoots.end(); it++) {
371 if (!fqName.inPackage(it->root.package())) {
Steven Moreland62709d72017-01-18 10:14:51 -0800372 continue;
Andreas Huberdca261f2016-08-04 13:47:51 -0700373 }
Steven Moreland62709d72017-01-18 10:14:51 -0800374
Steven Moreland255c9a12018-02-26 13:10:27 -0800375 if (ret != mPackageRoots.end()) {
376 std::cerr << "ERROR: Multiple package roots found for " << fqName.string() << " ("
377 << it->root.package() << " and " << ret->root.package() << ")\n";
378 return nullptr;
379 }
Steven Moreland62709d72017-01-18 10:14:51 -0800380
381 ret = it;
Andreas Huberdca261f2016-08-04 13:47:51 -0700382 }
Andreas Huberdca261f2016-08-04 13:47:51 -0700383
Steven Moreland255c9a12018-02-26 13:10:27 -0800384 if (ret == mPackageRoots.end()) {
385 std::cerr << "ERROR: Package root not specified for " << fqName.string() << "\n";
386 return nullptr;
387 }
388
389 return &(*ret);
Andreas Huberdca261f2016-08-04 13:47:51 -0700390}
391
Steven Moreland7a368042017-08-28 12:47:24 -0700392std::string Coordinator::makeAbsolute(const std::string& path) const {
393 if (StringHelper::StartsWith(path, "/") || mRootPath.empty()) {
394 return path;
Steven Morelandb90d3272017-05-26 10:02:39 -0700395 }
396
Steven Moreland47792c42017-09-20 10:03:20 -0700397 return mRootPath + path;
Steven Morelandb90d3272017-05-26 10:02:39 -0700398}
399
Steven Moreland255c9a12018-02-26 13:10:27 -0800400status_t Coordinator::getPackageRoot(const FQName& fqName, std::string* root) const {
401 const PackageRoot* packageRoot = findPackageRoot(fqName);
402 if (root == nullptr) {
403 return UNKNOWN_ERROR;
404 }
405 *root = packageRoot->root.package();
406 return OK;
Andreas Huberdca261f2016-08-04 13:47:51 -0700407}
408
Steven Moreland255c9a12018-02-26 13:10:27 -0800409status_t Coordinator::getPackageRootPath(const FQName& fqName, std::string* path) const {
410 const PackageRoot* packageRoot = findPackageRoot(fqName);
411 if (packageRoot == nullptr) {
412 return UNKNOWN_ERROR;
413 }
414 *path = packageRoot->path;
415 return OK;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700416}
417
Steven Moreland255c9a12018-02-26 13:10:27 -0800418status_t Coordinator::getPackagePath(const FQName& fqName, bool relative, bool sanitized,
419 std::string* path) const {
420 const PackageRoot* packageRoot = findPackageRoot(fqName);
421 if (packageRoot == nullptr) return UNKNOWN_ERROR;
Andreas Huberdca261f2016-08-04 13:47:51 -0700422
Steven Morelanda9387382017-09-18 15:09:36 -0700423 // Given FQName of "android.hardware.nfc.test@1.0::IFoo" and a prefix
Steven Moreland8f52c8a2017-09-19 08:45:53 -0700424 // "android.hardware", the suffix is "nfc.test".
Steven Moreland255c9a12018-02-26 13:10:27 -0800425 std::string suffix = StringHelper::LTrim(fqName.package(), packageRoot->root.package());
Steven Moreland80ba1742017-09-26 09:49:18 -0700426 suffix = StringHelper::LTrim(suffix, ".");
427
Steven Morelanda9387382017-09-18 15:09:36 -0700428 std::vector<std::string> suffixComponents;
429 StringHelper::SplitString(suffix, '.', &suffixComponents);
Andreas Huberdca261f2016-08-04 13:47:51 -0700430
Steven Morelanda9387382017-09-18 15:09:36 -0700431 std::vector<std::string> components;
Andreas Huber881227d2016-08-02 14:20:21 -0700432 if (!relative) {
Steven Moreland255c9a12018-02-26 13:10:27 -0800433 components.push_back(StringHelper::RTrimAll(packageRoot->path, "/"));
Andreas Huber881227d2016-08-02 14:20:21 -0700434 }
Steven Morelanda9387382017-09-18 15:09:36 -0700435 components.insert(components.end(), suffixComponents.begin(), suffixComponents.end());
436 components.push_back(sanitized ? fqName.sanitizedVersion() : fqName.version());
Andreas Huber5345ec22016-07-29 13:33:27 -0700437
Steven Moreland255c9a12018-02-26 13:10:27 -0800438 *path = StringHelper::JoinStrings(components, "/") + "/";
439 return OK;
Andreas Huber5345ec22016-07-29 13:33:27 -0700440}
441
Andreas Huberd2943e12016-08-05 11:59:31 -0700442status_t Coordinator::getPackageInterfaceFiles(
443 const FQName &package,
444 std::vector<std::string> *fileNames) const {
Steven Morelande7d32102018-12-03 17:03:36 -0800445 if (fileNames) fileNames->clear();
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700446
Steven Moreland255c9a12018-02-26 13:10:27 -0800447 std::string packagePath;
448 status_t err =
449 getPackagePath(package, false /* relative */, false /* sanitized */, &packagePath);
450 if (err != OK) return err;
Andreas Huberd2943e12016-08-05 11:59:31 -0700451
Steven Moreland255c9a12018-02-26 13:10:27 -0800452 const std::string path = makeAbsolute(packagePath);
Steven Morelande7d32102018-12-03 17:03:36 -0800453 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
Andreas Huberd2943e12016-08-05 11:59:31 -0700454
Yi Kong56758da2018-07-24 16:21:37 -0700455 if (dir == nullptr) {
Steven Moreland255c9a12018-02-26 13:10:27 -0800456 fprintf(stderr, "ERROR: Could not open package path %s for package %s:\n%s\n",
457 packagePath.c_str(), package.string().c_str(), path.c_str());
Andreas Huberd2943e12016-08-05 11:59:31 -0700458 return -errno;
459 }
460
Steven Morelande7d32102018-12-03 17:03:36 -0800461 if (fileNames == nullptr) {
462 return OK;
463 }
464
Andreas Huberd2943e12016-08-05 11:59:31 -0700465 struct dirent *ent;
Steven Morelande7d32102018-12-03 17:03:36 -0800466 while ((ent = readdir(dir.get())) != nullptr) {
Iris Chang1a92c582018-03-27 18:40:24 +0800467 // filesystems may not support d_type and return DT_UNKNOWN
468 if (ent->d_type == DT_UNKNOWN) {
469 struct stat sb;
470 const auto filename = packagePath + std::string(ent->d_name);
471 if (stat(filename.c_str(), &sb) == -1) {
472 fprintf(stderr, "ERROR: Could not stat %s\n", filename.c_str());
473 return -errno;
474 }
475 if ((sb.st_mode & S_IFMT) != S_IFREG) {
476 continue;
477 }
478 } else if (ent->d_type != DT_REG) {
479 continue;
Andreas Huber6cb08cf2016-08-03 15:44:51 -0700480 }
481
Andreas Huberd2943e12016-08-05 11:59:31 -0700482 const auto suffix = ".hal";
483 const auto suffix_len = std::strlen(suffix);
484 const auto d_namelen = strlen(ent->d_name);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700485
Andreas Huberd2943e12016-08-05 11:59:31 -0700486 if (d_namelen < suffix_len
487 || strcmp(ent->d_name + d_namelen - suffix_len, suffix)) {
488 continue;
Andreas Hubere61e3f72016-08-03 10:22:03 -0700489 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700490
491 fileNames->push_back(std::string(ent->d_name, d_namelen - suffix_len));
492 }
493
Iliyan Malchev5e8bcfa2016-09-09 16:19:57 -0700494 std::sort(fileNames->begin(), fileNames->end(),
495 [](const std::string& lhs, const std::string& rhs) -> bool {
496 if (lhs == "types") {
497 return true;
498 }
499 if (rhs == "types") {
500 return false;
501 }
502 return lhs < rhs;
503 });
504
Andreas Huberd2943e12016-08-05 11:59:31 -0700505 return OK;
506}
507
Steven Morelandaa186832016-09-26 13:51:43 -0700508status_t Coordinator::appendPackageInterfacesToVector(
Andreas Huberd2943e12016-08-05 11:59:31 -0700509 const FQName &package,
510 std::vector<FQName> *packageInterfaces) const {
511 packageInterfaces->clear();
512
513 std::vector<std::string> fileNames;
514 status_t err = getPackageInterfaceFiles(package, &fileNames);
515
516 if (err != OK) {
517 return err;
518 }
519
520 for (const auto &fileName : fileNames) {
Steven Morelande1b157e2018-03-06 14:18:32 -0800521 FQName subFQName(package.package(), package.version(), fileName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700522 packageInterfaces->push_back(subFQName);
Andreas Hubere61e3f72016-08-03 10:22:03 -0700523 }
524
525 return OK;
526}
527
Steven Moreland255c9a12018-02-26 13:10:27 -0800528status_t Coordinator::convertPackageRootToPath(const FQName& fqName, std::string* path) const {
529 std::string packageRoot;
530 status_t err = getPackageRoot(fqName, &packageRoot);
531 if (err != OK) return err;
Andreas Huberd2943e12016-08-05 11:59:31 -0700532
533 if (*(packageRoot.end()--) != '.') {
534 packageRoot += '.';
535 }
536
537 std::replace(packageRoot.begin(), packageRoot.end(), '.', '/');
538
Steven Moreland255c9a12018-02-26 13:10:27 -0800539 *path = packageRoot; // now converted to a path
540 return OK;
Andreas Huberd2943e12016-08-05 11:59:31 -0700541}
542
Steven Moreland87b26d72017-10-11 09:35:42 -0700543status_t Coordinator::isTypesOnlyPackage(const FQName& package, bool* result) const {
544 std::vector<FQName> packageInterfaces;
545
546 status_t err = appendPackageInterfacesToVector(package, &packageInterfaces);
547
548 if (err != OK) {
549 *result = false;
550 return err;
551 }
552
553 *result = packageInterfaces.size() == 1 && packageInterfaces[0].name() == "types";
554 return OK;
555}
556
Steven Moreland40b86352018-02-01 16:03:30 -0800557status_t Coordinator::addUnreferencedTypes(const std::vector<FQName>& packageInterfaces,
558 std::set<FQName>* unreferencedDefinitions,
Steven Morelandb65e5d92018-02-08 12:44:51 -0800559 std::set<FQName>* unreferencedImports) const {
Steven Moreland40b86352018-02-01 16:03:30 -0800560 CHECK(unreferencedDefinitions != nullptr);
561 CHECK(unreferencedImports != nullptr);
562
563 std::set<FQName> packageDefinedTypes;
564 std::set<FQName> packageReferencedTypes;
565 std::set<FQName> packageImportedTypes;
566 std::set<FQName> typesDefinedTypes; // only types.hal types
567
568 for (const auto& fqName : packageInterfaces) {
569 AST* ast = parse(fqName);
570 if (!ast) {
571 std::cerr << "ERROR: Could not parse " << fqName.string() << ". Aborting." << std::endl;
572
573 return UNKNOWN_ERROR;
574 }
575
576 ast->addDefinedTypes(&packageDefinedTypes);
577 ast->addReferencedTypes(&packageReferencedTypes);
578 ast->getAllImportedNamesGranular(&packageImportedTypes);
579
580 if (fqName.name() == "types") {
581 ast->addDefinedTypes(&typesDefinedTypes);
582 }
583 }
584
585#if 0
586 for (const auto &fqName : packageDefinedTypes) {
587 std::cout << "VERBOSE: DEFINED " << fqName.string() << std::endl;
588 }
589
590 for (const auto &fqName : packageImportedTypes) {
591 std::cout << "VERBOSE: IMPORTED " << fqName.string() << std::endl;
592 }
593
594 for (const auto &fqName : packageReferencedTypes) {
595 std::cout << "VERBOSE: REFERENCED " << fqName.string() << std::endl;
596 }
597
598 for (const auto &fqName : typesDefinedTypes) {
599 std::cout << "VERBOSE: DEFINED in types.hal " << fqName.string() << std::endl;
600 }
601#endif
602
603 for (const auto& fqName : packageReferencedTypes) {
604 packageDefinedTypes.erase(fqName);
605 packageImportedTypes.erase(fqName);
606 }
607
608 // A package implicitly imports its own types.hal, only track them in one set.
609 for (const auto& fqName : typesDefinedTypes) {
610 packageImportedTypes.erase(fqName);
611 }
612
613 // defined but not referenced
614 unreferencedDefinitions->insert(packageDefinedTypes.begin(), packageDefinedTypes.end());
615 // imported but not referenced
616 unreferencedImports->insert(packageImportedTypes.begin(), packageImportedTypes.end());
617 return OK;
618}
619
Steven Morelandc59326e2017-06-20 15:19:30 -0700620status_t Coordinator::enforceRestrictionsOnPackage(const FQName& fqName,
621 Enforce enforcement) const {
622 CHECK(enforcement == Enforce::FULL || enforcement == Enforce::NO_HASH ||
623 enforcement == Enforce::NONE);
Yifan Hong78b38d12017-02-13 18:14:46 +0000624
Yifan Hong78b38d12017-02-13 18:14:46 +0000625 // need fqName to be something like android.hardware.foo@1.0.
626 // name and valueName is ignored.
627 if (fqName.package().empty() || fqName.version().empty()) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700628 std::cerr << "ERROR: Cannot enforce restrictions on package " << fqName.string()
629 << ": package or version is missing." << std::endl;
Yifan Hong78b38d12017-02-13 18:14:46 +0000630 return BAD_VALUE;
631 }
Steven Morelandc59326e2017-06-20 15:19:30 -0700632
633 if (enforcement == Enforce::NONE) {
634 return OK;
635 }
636
Yifan Hong78b38d12017-02-13 18:14:46 +0000637 FQName package = fqName.getPackageAndVersion();
638 // look up cache.
639 if (mPackagesEnforced.find(package) != mPackagesEnforced.end()) {
640 return OK;
641 }
642
643 // enforce all rules.
Steven Moreland218625a2017-04-18 22:31:50 -0700644 status_t err;
645
Steven Moreland51b02f42018-03-14 15:43:29 -0700646 err = enforceMinorVersionUprevs(package, enforcement);
Steven Moreland218625a2017-04-18 22:31:50 -0700647 if (err != OK) {
648 return err;
649 }
650
Steven Morelandc59326e2017-06-20 15:19:30 -0700651 if (enforcement != Enforce::NO_HASH) {
652 err = enforceHashes(package);
653 if (err != OK) {
654 return err;
655 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000656 }
657
658 // cache it so that it won't need to be enforced again.
659 mPackagesEnforced.insert(package);
660 return OK;
661}
662
Steven Moreland51b02f42018-03-14 15:43:29 -0700663status_t Coordinator::enforceMinorVersionUprevs(const FQName& currentPackage,
664 Enforce enforcement) const {
Yifan Hong78b38d12017-02-13 18:14:46 +0000665 if(!currentPackage.hasVersion()) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700666 std::cerr << "ERROR: Cannot enforce minor version uprevs for " << currentPackage.string()
667 << ": missing version." << std::endl;
Yifan Hong78b38d12017-02-13 18:14:46 +0000668 return UNKNOWN_ERROR;
669 }
670
671 if (currentPackage.getPackageMinorVersion() == 0) {
672 return OK; // ignore for @x.0
673 }
674
675 bool hasPrevPackage = false;
Steven Morelandad79f562017-05-11 14:36:54 -0700676 FQName prevPackage = currentPackage;
677 while (prevPackage.getPackageMinorVersion() > 0) {
678 prevPackage = prevPackage.downRev();
Steven Moreland255c9a12018-02-26 13:10:27 -0800679
680 std::string prevPackagePath;
681 status_t err = getPackagePath(prevPackage, false /* relative */, false /* sanitized */,
682 &prevPackagePath);
683 if (err != OK) return err;
684
685 if (existdir(makeAbsolute(prevPackagePath).c_str())) {
Yifan Hong78b38d12017-02-13 18:14:46 +0000686 hasPrevPackage = true;
687 break;
688 }
689 }
690 if (!hasPrevPackage) {
691 // no @x.z, where z < y, exist.
692 return OK;
693 }
694
Steven Morelandad79f562017-05-11 14:36:54 -0700695 if (prevPackage != currentPackage.downRev()) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700696 std::cerr << "ERROR: Cannot enforce minor version uprevs for " << currentPackage.string()
697 << ": Found package " << prevPackage.string() << " but missing "
698 << currentPackage.downRev().string() << "; you cannot skip a minor version."
699 << std::endl;
Yifan Hong78b38d12017-02-13 18:14:46 +0000700 return UNKNOWN_ERROR;
701 }
702
Steven Moreland87b26d72017-10-11 09:35:42 -0700703 bool prevIsTypesOnly;
704 status_t err = isTypesOnlyPackage(prevPackage, &prevIsTypesOnly);
705 if (err != OK) return err;
706
707 if (prevIsTypesOnly) {
708 // A types only package can be extended in any way.
709 return OK;
710 }
711
Yifan Hong78b38d12017-02-13 18:14:46 +0000712 std::vector<FQName> packageInterfaces;
713 err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
714 if (err != OK) {
715 return err;
716 }
717
Yifan Hongfe07bff2017-02-15 14:55:48 -0800718 bool extendedInterface = false;
Yifan Hong78b38d12017-02-13 18:14:46 +0000719 for (const FQName &currentFQName : packageInterfaces) {
720 if (currentFQName.name() == "types") {
721 continue; // ignore types.hal
722 }
Steven Morelandad79f562017-05-11 14:36:54 -0700723
Yifan Hong78b38d12017-02-13 18:14:46 +0000724 const Interface *iface = nullptr;
Steven Moreland51b02f42018-03-14 15:43:29 -0700725 AST* currentAST = parse(currentFQName, nullptr /* parsedASTs */, enforcement);
Yifan Hong78b38d12017-02-13 18:14:46 +0000726 if (currentAST != nullptr) {
727 iface = currentAST->getInterface();
728 }
729 if (iface == nullptr) {
Yifan Hongfe07bff2017-02-15 14:55:48 -0800730 if (currentAST == nullptr) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700731 std::cerr << "WARNING: Skipping " << currentFQName.string()
732 << " because it could not be found or parsed"
733 << " or " << currentPackage.string() << " doesn't pass all requirements."
734 << std::endl;
Yifan Hongfe07bff2017-02-15 14:55:48 -0800735 } else {
Steven Morelandcbff5612017-10-11 17:01:54 -0700736 std::cerr << "WARNING: Skipping " << currentFQName.string()
737 << " because the file might contain more than one interface."
738 << std::endl;
Yifan Hongfe07bff2017-02-15 14:55:48 -0800739 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000740 continue;
741 }
742
Yifan Hong78b38d12017-02-13 18:14:46 +0000743 if (iface->superType() == nullptr) {
Steven Morelandad79f562017-05-11 14:36:54 -0700744 CHECK(iface->isIBase());
Yifan Hong78b38d12017-02-13 18:14:46 +0000745 continue;
746 }
747
Steven Morelandad79f562017-05-11 14:36:54 -0700748 // Assume that currentFQName == android.hardware.foo@2.2::IFoo.
749 FQName lastFQName(prevPackage.package(), prevPackage.version(),
750 currentFQName.name());
751 AST *lastAST = parse(lastFQName);
752
753 for (; lastFQName.getPackageMinorVersion() > 0 &&
754 (lastAST == nullptr || lastAST->getInterface() == nullptr)
755 ; lastFQName = lastFQName.downRev(), lastAST = parse(lastFQName)) {
756 // nothing
757 }
758
759 // Then lastFQName == android.hardware.foo@2.1::IFoo or
760 // lastFQName == android.hardware.foo@2.0::IFoo if 2.1 doesn't exist.
761
762 bool lastFQNameExists = lastAST != nullptr && lastAST->getInterface() != nullptr;
763
Steven Moreland87757152017-11-09 08:57:59 -0800764 if (!lastFQNameExists) {
765 continue;
766 }
767
768 if (iface->superType()->fqName() != lastFQName) {
Steven Morelandcbff5612017-10-11 17:01:54 -0700769 std::cerr << "ERROR: Cannot enforce minor version uprevs for "
770 << currentPackage.string() << ": " << iface->fqName().string() << " extends "
771 << iface->superType()->fqName().string()
772 << ", which is not allowed. It must extend " << lastFQName.string()
773 << std::endl;
Steven Morelandad79f562017-05-11 14:36:54 -0700774 return UNKNOWN_ERROR;
775 }
776
777 // at least one interface must extend the previous version
Steven Moreland87757152017-11-09 08:57:59 -0800778 // @2.0::IFoo does not work. It must be @2.1::IFoo for at least one interface.
Steven Morelandad79f562017-05-11 14:36:54 -0700779 if (lastFQName.getPackageAndVersion() == prevPackage.getPackageAndVersion()) {
780 extendedInterface = true;
781 }
782
Steven Morelandcbff5612017-10-11 17:01:54 -0700783 if (mVerbose) {
784 std::cout << "VERBOSE: EnforceMinorVersionUprevs: " << currentFQName.string()
785 << " passes." << std::endl;
786 }
Yifan Hong78b38d12017-02-13 18:14:46 +0000787 }
788
Yifan Hongfe07bff2017-02-15 14:55:48 -0800789 if (!extendedInterface) {
790 // No interface extends the interface with the same name in @x.(y-1).
Steven Morelandcbff5612017-10-11 17:01:54 -0700791 std::cerr << "ERROR: " << currentPackage.string()
792 << " doesn't pass minor version uprev requirement. "
793 << "Requires at least one interface to extend an interface with the same name "
794 << "from " << prevPackage.string() << "." << std::endl;
Yifan Hongfe07bff2017-02-15 14:55:48 -0800795 return UNKNOWN_ERROR;
796 }
797
798 return OK;
Yifan Hong78b38d12017-02-13 18:14:46 +0000799}
800
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800801Coordinator::HashStatus Coordinator::checkHash(const FQName& fqName) const {
802 AST* ast = parse(fqName);
803 if (ast == nullptr) return HashStatus::ERROR;
804
Steven Moreland255c9a12018-02-26 13:10:27 -0800805 std::string rootPath;
806 status_t err = getPackageRootPath(fqName, &rootPath);
807 if (err != OK) return HashStatus::ERROR;
808
809 std::string hashPath = makeAbsolute(rootPath) + "/current.txt";
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800810 std::string error;
Steven Moreland566b0e92018-02-16 13:51:33 -0800811 bool fileExists;
812 std::vector<std::string> frozen =
813 Hash::lookupHash(hashPath, fqName.string(), &error, &fileExists);
814 if (fileExists) onFileAccess(hashPath, "r");
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800815
816 if (error.size() > 0) {
817 std::cerr << "ERROR: " << error << std::endl;
818 return HashStatus::ERROR;
819 }
820
821 // hash not defined, interface not frozen
822 if (frozen.size() == 0) {
823 // This ensures that it can be detected.
824 Hash::clearHash(ast->getFilename());
825
826 return HashStatus::UNFROZEN;
827 }
828
Steven Moreland04dea8d2018-02-06 13:11:24 -0800829 std::string currentHash = ast->getFileHash()->hexString();
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800830
831 if (std::find(frozen.begin(), frozen.end(), currentHash) == frozen.end()) {
832 std::cerr << "ERROR: " << fqName.string() << " has hash " << currentHash
833 << " which does not match hash on record. This interface has "
834 << "been frozen. Do not change it!" << std::endl;
835 return HashStatus::CHANGED;
836 }
837
838 return HashStatus::FROZEN;
839}
840
841status_t Coordinator::getUnfrozenDependencies(const FQName& fqName,
842 std::set<FQName>* result) const {
843 CHECK(result != nullptr);
844
845 AST* ast = parse(fqName);
846 if (ast == nullptr) return UNKNOWN_ERROR;
847
848 std::set<FQName> imported;
849 ast->getImportedPackages(&imported);
850
851 // no circular dependency is already guaranteed by parsing
852 // indirect dependencies will be checked when the imported interface frozen checks are done
853 for (const FQName& importedPackage : imported) {
854 std::vector<FQName> packageInterfaces;
855 status_t err = appendPackageInterfacesToVector(importedPackage, &packageInterfaces);
856 if (err != OK) {
857 return err;
858 }
859
860 for (const FQName& importedName : packageInterfaces) {
861 HashStatus status = checkHash(importedName);
Steven Morelandfc32bf22019-02-11 21:02:10 -0800862 switch (status) {
863 case HashStatus::CHANGED:
864 case HashStatus::ERROR:
865 return UNKNOWN_ERROR;
866 case HashStatus::FROZEN:
867 continue;
868 case HashStatus::UNFROZEN:
869 result->insert(importedName);
870 continue;
871 default:
872 LOG(FATAL) << static_cast<uint64_t>(status);
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800873 }
874 }
875 }
876
877 return OK;
878}
879
880status_t Coordinator::enforceHashes(const FQName& currentPackage) const {
Steven Moreland218625a2017-04-18 22:31:50 -0700881 std::vector<FQName> packageInterfaces;
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800882 status_t err = appendPackageInterfacesToVector(currentPackage, &packageInterfaces);
Steven Moreland218625a2017-04-18 22:31:50 -0700883 if (err != OK) {
884 return err;
885 }
886
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800887 for (const FQName& currentFQName : packageInterfaces) {
888 HashStatus status = checkHash(currentFQName);
Steven Morelandfc32bf22019-02-11 21:02:10 -0800889 switch (status) {
890 case HashStatus::CHANGED:
891 case HashStatus::ERROR:
Steven Moreland2d3ff5c2018-01-18 17:22:45 -0800892 return UNKNOWN_ERROR;
Steven Morelandfc32bf22019-02-11 21:02:10 -0800893 case HashStatus::FROZEN: {
894 std::set<FQName> unfrozenDependencies;
895 err = getUnfrozenDependencies(currentFQName, &unfrozenDependencies);
896 if (err != OK) return err;
Steven Moreland218625a2017-04-18 22:31:50 -0700897
Steven Morelandfc32bf22019-02-11 21:02:10 -0800898 if (!unfrozenDependencies.empty()) {
899 std::cerr << "ERROR: Frozen interface " << currentFQName.string()
900 << " cannot depend on unfrozen thing(s):" << std::endl;
901 for (const FQName& name : unfrozenDependencies) {
902 std::cerr << " (unfrozen) " << name.string() << std::endl;
903 }
904 return UNKNOWN_ERROR;
905 }
906 }
907 continue;
908 case HashStatus::UNFROZEN:
909 continue;
910 default:
911 LOG(FATAL) << static_cast<uint64_t>(status);
912 }
Steven Moreland218625a2017-04-18 22:31:50 -0700913 }
914
915 return err;
916}
917
Andreas Huberd2943e12016-08-05 11:59:31 -0700918bool Coordinator::MakeParentHierarchy(const std::string &path) {
919 static const mode_t kMode = 0755;
920
921 size_t start = 1; // Ignore leading '/'
922 size_t slashPos;
Chih-Hung Hsieh8c90cc52017-08-03 14:51:13 -0700923 while ((slashPos = path.find('/', start)) != std::string::npos) {
Andreas Huberd2943e12016-08-05 11:59:31 -0700924 std::string partial = path.substr(0, slashPos);
925
926 struct stat st;
927 if (stat(partial.c_str(), &st) < 0) {
928 if (errno != ENOENT) {
929 return false;
930 }
931
932 int res = mkdir(partial.c_str(), kMode);
933 if (res < 0) {
934 return false;
935 }
936 } else if (!S_ISDIR(st.st_mode)) {
937 return false;
938 }
939
940 start = slashPos + 1;
941 }
942
943 return true;
944}
945
Andreas Huber5345ec22016-07-29 13:33:27 -0700946} // namespace android
947