• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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