blob: ac9d67e12296d0357b217165f85ccd5d4177ca8a [file] [log] [blame]
Kelvin Zhang446989a2021-12-08 13:49:07 -08001//
2// Copyright (C) 2021 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
17#include <string>
18
19#include <erofs/dir.h>
20
21#include "update_engine/common/utils.h"
22
23// The only way to pass extra information to callback function is to use a
24// wrapper type for erofs_dir_context. So here we go
25struct erofs_iterate_dir_context {
26 struct erofs_dir_context ctx;
27 std::string path;
28 void* arg;
29};
30
31// Dear compiler, please don't reoder fields inside erofs_iterate_dir_context.
32// Because EROFS expects us to pass a wrapper type. So |ctx| member of
33// erofs_iterate_dir_context must be put at 0 offset.
34static_assert(offsetof(erofs_iterate_dir_context, ctx) == 0);
35
36// Callable shold be a functor like
37// std::function<int(struct erofs_inode_info *)>
38template <typename Callable>
39int erofs_iterate_root_dir(const struct erofs_sb_info* sbi, Callable cb) {
40 struct erofs_inode dir {
41 .nid = sbi->root_nid
42 };
43 int err = erofs_read_inode_from_disk(&dir);
44 if (err) {
45 LOG(ERROR) << "Failed to read inode " << sbi->root_nid << " from disk";
46 return err;
47 }
48 struct erofs_iterate_dir_context param {
49 .ctx.dir = &dir, .ctx.pnid = sbi->root_nid,
50 .ctx.cb = [](struct erofs_dir_context* arg) -> int {
51 auto ctx = reinterpret_cast<erofs_iterate_dir_context*>(arg);
52 auto& path = ctx->path;
53 const auto len = path.size();
54 path.push_back('/');
55 path.insert(
56 path.end(), ctx->ctx.dname, ctx->ctx.dname + ctx->ctx.de_namelen);
57 auto cb = static_cast<Callable*>(ctx->arg);
58 const auto err = (*cb)(ctx);
59 if (!err && !ctx->ctx.dot_dotdot && ctx->ctx.de_ftype == EROFS_FT_DIR) {
60 // recursively walk into subdirectories
61 erofs_inode dir{.nid = ctx->ctx.de_nid};
62 if (const int err = erofs_read_inode_from_disk(&dir); err) {
63 return err;
64 }
65 ctx->ctx.dir = &dir;
66 if (const auto err = erofs_iterate_dir(&ctx->ctx, false); err) {
67 return err;
68 }
69 }
70 path.resize(len);
71 return err;
72 },
73 .arg = &cb,
74 };
75 return erofs_iterate_dir(&param.ctx, false);
76}