1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "storage.h"
17 #include "serializer/serializer.h"
18 #include "utils/logger.h"
19
20 #include <dirent.h>
21 #include <fstream>
22 #include <memory>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26
27 namespace ark::dprof {
28 /* static */
CreateByParams(const std::string & name,uint64_t hash,uint32_t pid,FeaturesMap && featuresMap)29 std::unique_ptr<AppData> AppData::CreateByParams(const std::string &name, uint64_t hash, uint32_t pid,
30 FeaturesMap &&featuresMap)
31 {
32 // CC-OFFNXT(G.RES.09) private constructor
33 std::unique_ptr<AppData> appData(new AppData);
34
35 appData->commonInfo_.name = name;
36 appData->commonInfo_.hash = hash;
37 appData->commonInfo_.pid = pid;
38 appData->featuresMap_ = std::move(featuresMap);
39
40 return appData;
41 }
42
43 /* static */
CreateByBuffer(const std::vector<uint8_t> & buffer)44 std::unique_ptr<AppData> AppData::CreateByBuffer(const std::vector<uint8_t> &buffer)
45 {
46 // CC-OFFNXT(G.RES.09) private constructor
47 std::unique_ptr<AppData> appData(new AppData);
48
49 const uint8_t *data = buffer.data();
50 size_t size = buffer.size();
51 auto r = serializer::RawBufferToStruct<3>(data, size, appData->commonInfo_); // 3
52 if (!r) {
53 LOG(ERROR, DPROF) << "Cannot deserialize buffer to common_info. Error: " << r.Error();
54 return nullptr;
55 }
56 ASSERT(r.Value() <= size);
57 data = serializer::ToUint8tPtr(serializer::ToUintPtr(data) + r.Value());
58 size -= r.Value();
59
60 r = serializer::BufferToType(data, size, appData->featuresMap_);
61 if (!r) {
62 LOG(ERROR, DPROF) << "Cannot deserialize features_map. Error: " << r.Error();
63 return nullptr;
64 }
65 ASSERT(r.Value() <= size);
66 size -= r.Value();
67 if (size != 0) {
68 LOG(ERROR, DPROF) << "Cannot deserialize all buffer, unused buffer size: " << size;
69 return nullptr;
70 }
71
72 return appData;
73 }
74
ToBuffer(std::vector<uint8_t> & buffer) const75 bool AppData::ToBuffer(std::vector<uint8_t> &buffer) const
76 {
77 // 3
78 if (!serializer::StructToBuffer<3>(commonInfo_, buffer)) {
79 LOG(ERROR, DPROF) << "Cannot serialize common_info";
80 return false;
81 }
82 auto ret = serializer::TypeToBuffer(featuresMap_, buffer);
83 if (!ret) {
84 LOG(ERROR, DPROF) << "Cannot serialize features_map. Error: " << ret.Error();
85 return false;
86 }
87 return true;
88 }
89
90 /* static */
Create(const std::string & storageDir,bool createDir)91 std::unique_ptr<AppDataStorage> AppDataStorage::Create(const std::string &storageDir, bool createDir)
92 {
93 if (storageDir.empty()) {
94 LOG(ERROR, DPROF) << "Storage directory is not set";
95 return nullptr;
96 }
97
98 struct stat statBuffer {};
99 if (::stat(storageDir.c_str(), &statBuffer) == 0) {
100 // NOLINTNEXTLINE(hicpp-signed-bitwise)
101 if (S_ISDIR(statBuffer.st_mode)) {
102 // CC-OFFNXT(G.RES.09) private constructor
103 return std::unique_ptr<AppDataStorage>(new AppDataStorage(storageDir));
104 }
105
106 LOG(ERROR, DPROF) << storageDir << " is already exists and it is neither directory";
107 return nullptr;
108 }
109
110 if (createDir) {
111 // NOLINTNEXTLINE(hicpp-signed-bitwise)
112 if (::mkdir(storageDir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
113 PLOG(ERROR, DPROF) << "mkdir() failed";
114 return nullptr;
115 }
116 // CC-OFFNXT(G.RES.09) private constructor
117 return std::unique_ptr<AppDataStorage>(new AppDataStorage(storageDir));
118 }
119
120 return nullptr;
121 }
122
SaveAppData(const AppData & appData)123 bool AppDataStorage::SaveAppData(const AppData &appData)
124 {
125 std::vector<uint8_t> buffer;
126 if (!appData.ToBuffer(buffer)) {
127 LOG(ERROR, DPROF) << "Cannot serialize AppData to buffer";
128 return false;
129 }
130
131 // Save buffer to file
132 std::string fileName = MakeAppPath(appData.GetName(), appData.GetHash(), appData.GetPid());
133 std::ofstream file(fileName, std::ios::binary);
134 if (!file.is_open()) {
135 LOG(ERROR, DPROF) << "Cannot open file: " << fileName;
136 return false;
137 }
138 file.write(reinterpret_cast<const char *>(buffer.data()), buffer.size());
139 if (file.bad()) {
140 LOG(ERROR, DPROF) << "Cannot write AppData to file: " << fileName;
141 return false;
142 }
143
144 LOG(DEBUG, DPROF) << "Save AppData to file: " << fileName;
145 return true;
146 }
147
DoReadDir(DIR * dirp)148 struct dirent *DoReadDir(DIR *dirp)
149 {
150 errno = 0;
151 return ::readdir(dirp);
152 }
153
ForEachApps(const std::function<bool (std::unique_ptr<AppData> &&)> & callback) const154 void AppDataStorage::ForEachApps(const std::function<bool(std::unique_ptr<AppData> &&)> &callback) const
155 {
156 using UniqueDir = std::unique_ptr<DIR, void (*)(DIR *)>;
157 UniqueDir dir(::opendir(storageDir_.c_str()), [](DIR *directory) {
158 if (::closedir(directory) == -1) {
159 PLOG(FATAL, DPROF) << "closedir() failed";
160 }
161 });
162 if (dir.get() == nullptr) {
163 PLOG(FATAL, DPROF) << "opendir() failed, dir=" << storageDir_;
164 return;
165 }
166
167 struct dirent *ent;
168 while ((ent = DoReadDir(dir.get())) != nullptr) {
169 if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
170 // Skip a valid name
171 continue;
172 }
173
174 if (ent->d_type != DT_REG) {
175 LOG(ERROR, DPROF) << "Not a regular file: " << ent->d_name;
176 continue;
177 }
178
179 std::string path = storageDir_ + "/" + ent->d_name;
180 struct stat statbuf {};
181 if (stat(path.c_str(), &statbuf) == -1) {
182 PLOG(ERROR, DPROF) << "stat() failed, path=" << path;
183 continue;
184 }
185 size_t fileSize = statbuf.st_size;
186
187 if (fileSize > MAX_BUFFER_SIZE) {
188 LOG(ERROR, DPROF) << "File is to large: " << path;
189 continue;
190 }
191
192 // Read file
193 std::ifstream file(path, std::ios::binary);
194 if (!file.is_open()) {
195 LOG(ERROR, DPROF) << "Cannot open file: " << path;
196 continue;
197 }
198 std::vector<uint8_t> buffer;
199 buffer.reserve(fileSize);
200 buffer.assign(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>());
201
202 auto appData = AppData::CreateByBuffer(buffer);
203 if (!appData) {
204 LOG(ERROR, DPROF) << "Cannot deserialize file: " << path;
205 continue;
206 }
207
208 if (!callback(std::move(appData))) {
209 break;
210 }
211 }
212 }
213
MakeAppPath(const std::string & name,uint64_t hash,uint32_t pid) const214 std::string AppDataStorage::MakeAppPath(const std::string &name, uint64_t hash, uint32_t pid) const
215 {
216 ASSERT(!storageDir_.empty());
217 ASSERT(!name.empty());
218
219 std::stringstream str;
220 str << storageDir_ << "/" << name << "@" << pid << "@" << hash;
221 return str.str();
222 }
223 } // namespace ark::dprof
224