forked from LineageOS/android_art
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathodr_fs_utils.cc
144 lines (130 loc) · 4.35 KB
/
odr_fs_utils.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "odr_fs_utils.h"
#include <dirent.h>
#include <ftw.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <unistd.h>
#include <iosfwd>
#include <memory>
#include <ostream>
#include <queue>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/strings.h>
#include <base/os.h>
namespace art {
namespace odrefresh {
// Callback for use with nftw(3) to assist with clearing files and sub-directories.
// This method removes files and directories below the top-level directory passed to nftw().
static int NftwCleanUpCallback(const char* fpath,
const struct stat* sb ATTRIBUTE_UNUSED,
int typeflag,
struct FTW* ftwbuf) {
switch (typeflag) {
case FTW_F:
return unlink(fpath);
case FTW_DP:
return (ftwbuf->level == 0) ? 0 : rmdir(fpath);
default:
return -1;
}
}
WARN_UNUSED bool RemoveDirectory(const std::string& dir_path) {
if (!OS::DirectoryExists(dir_path.c_str())) {
return true;
}
static constexpr int kMaxDescriptors = 4; // Limit the need for nftw() to re-open descriptors.
if (nftw(dir_path.c_str(), NftwCleanUpCallback, kMaxDescriptors, FTW_DEPTH | FTW_MOUNT) != 0) {
LOG(ERROR) << "Failed to clean-up '" << dir_path << "'";
return false;
}
if (rmdir(dir_path.c_str()) != 0) {
LOG(ERROR) << "Failed to delete '" << dir_path << "'";
return false;
}
return true;
}
WARN_UNUSED bool EnsureDirectoryExists(const std::string& absolute_path) {
if (absolute_path.empty() || absolute_path[0] != '/') {
LOG(ERROR) << "Path not absolute '" << absolute_path << "'";
return false;
}
std::string path;
for (const std::string& directory : android::base::Split(absolute_path, "/")) {
path.append("/").append(directory);
if (!OS::DirectoryExists(path.c_str())) {
static constexpr mode_t kDirectoryMode = S_IRWXU | S_IRGRP | S_IXGRP| S_IROTH | S_IXOTH;
if (mkdir(path.c_str(), kDirectoryMode) != 0) {
PLOG(ERROR) << "Could not create directory: " << path;
return false;
}
}
}
return true;
}
bool GetFreeSpace(const std::string& path, uint64_t* bytes) {
struct statvfs sv;
if (statvfs(path.c_str(), &sv) != 0) {
PLOG(ERROR) << "statvfs '" << path << "'";
return false;
}
*bytes = sv.f_bfree * sv.f_bsize;
return true;
}
bool GetUsedSpace(const std::string& path, uint64_t* bytes) {
static constexpr std::string_view kCurrentDirectory{"."};
static constexpr std::string_view kParentDirectory{".."};
static constexpr size_t kBytesPerBlock = 512; // see manual page for stat(2).
uint64_t file_bytes = 0;
std::queue<std::string> unvisited;
unvisited.push(path);
while (!unvisited.empty()) {
std::string current = unvisited.front();
unvisited.pop();
std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(current.c_str()), closedir);
if (!dir) {
continue;
}
for (auto entity = readdir(dir.get()); entity != nullptr; entity = readdir(dir.get())) {
std::string_view name{entity->d_name};
if (name == kCurrentDirectory || name == kParentDirectory) {
continue;
}
std::string entity_name = current + "/" + entity->d_name;
if (entity->d_type == DT_DIR) {
unvisited.push(entity_name.c_str());
} else if (entity->d_type == DT_REG) {
struct stat sb;
if (stat(entity_name.c_str(), &sb) != 0) {
PLOG(ERROR) << "Failed to stat() file " << entity_name;
continue;
}
file_bytes += sb.st_blocks * kBytesPerBlock;
}
}
}
*bytes = file_bytes;
return true;
}
} // namespace odrefresh
} // namespace art