1 /*
2  * Copyright (c) 2022 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 #include "file_util.h"
16 
17 #include <dirent.h>
18 #include <fstream>
19 #include <iostream>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <sys/xattr.h>
23 #include <unistd.h>
24 
25 namespace OHOS {
26 namespace HiviewDFX {
27 namespace FileUtil {
28 namespace {
29 const char PATH_DELIMITER = '/';
30 constexpr mode_t FILE_PERM_600 = S_IRUSR | S_IWUSR;
31 }
IsFileExists(const std::string & file)32 bool IsFileExists(const std::string& file)
33 {
34     return access(file.c_str(), F_OK) == 0;
35 }
36 
IsFile(const std::string & file)37 bool IsFile(const std::string& file)
38 {
39     struct stat statBuf {};
40     return lstat(file.c_str(), &statBuf) == 0 ? S_ISREG(statBuf.st_mode) : false;
41 }
42 
IsDirectory(const std::string & dir)43 bool IsDirectory(const std::string& dir)
44 {
45     struct stat statBuf {};
46     return lstat(dir.c_str(), &statBuf) == 0 ? S_ISDIR(statBuf.st_mode) : false;
47 }
48 
RemoveFile(const std::string & file)49 bool RemoveFile(const std::string& file)
50 {
51     return !IsFileExists(file) || (remove(file.c_str()) == 0);
52 }
53 
RemoveDirectory(const std::string & dir)54 bool RemoveDirectory(const std::string& dir)
55 {
56     return !IsFileExists(dir) || (rmdir(dir.c_str()) == 0);
57 }
58 
ForceCreateDirectory(const std::string & dir)59 bool ForceCreateDirectory(const std::string& dir)
60 {
61     std::string::size_type index = 0;
62     do {
63         std::string subPath;
64         index = dir.find('/', index + 1); // (index + 1) means the next char traversed
65         if (index == std::string::npos) {
66             subPath = dir;
67         } else {
68             subPath = dir.substr(0, index);
69         }
70 
71         if (!IsFileExists(subPath) && mkdir(subPath.c_str(), S_IRWXU) != 0) {
72             return false;
73         }
74     } while (index != std::string::npos);
75     return IsFileExists(dir);
76 }
77 
ForceRemoveDirectory(const std::string & dir,bool isDeleteSelf)78 bool ForceRemoveDirectory(const std::string& dir, bool isDeleteSelf)
79 {
80     if (IsFile(dir)) {
81         return RemoveFile(dir);
82     } else if (IsDirectory(dir)) {
83         DIR* dirPtr = opendir(dir.c_str());
84         if (dirPtr == nullptr) {
85             return false;
86         }
87         struct dirent* dirInfo = nullptr;
88         while ((dirInfo = readdir(dirPtr)) != nullptr) {
89             // do not process the special dir
90             if (strcmp(dirInfo->d_name, ".") == 0 || strcmp(dirInfo->d_name, "..") == 0) {
91                 continue;
92             }
93             std::string filePath = GetFilePathByDir(dir, dirInfo->d_name);
94             if (!ForceRemoveDirectory(filePath)) {
95                 closedir(dirPtr);
96                 return false;
97             }
98         }
99         closedir(dirPtr);
100         if (isDeleteSelf && !RemoveDirectory(dir)) {
101             return false;
102         }
103     } else {
104         return false;
105     }
106     return true;
107 }
108 
GetDirFiles(const std::string & dir,std::vector<std::string> & files)109 void GetDirFiles(const std::string& dir, std::vector<std::string>& files)
110 {
111     DIR* dirPtr = opendir(dir.c_str());
112     if (dirPtr == nullptr) {
113         return;
114     }
115 
116     struct dirent* ent = nullptr;
117     while ((ent = readdir(dirPtr)) != nullptr) {
118         if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
119             continue;
120         }
121         std::string filePath = GetFilePathByDir(dir, ent->d_name);
122         if (IsFile(filePath)) { // do not process subdirectory
123             files.push_back(filePath);
124         }
125     }
126     closedir(dirPtr);
127 }
128 
GetDirSize(const std::string & dir)129 uint64_t GetDirSize(const std::string& dir)
130 {
131     std::vector<std::string> files;
132     GetDirFiles(dir, files);
133     uint64_t totalSize = 0;
134     struct stat statBuf {};
135     for (auto& file : files) {
136         if (stat(file.c_str(), &statBuf) == 0) {
137             totalSize += static_cast<uint64_t>(statBuf.st_size);
138         }
139     }
140     return totalSize;
141 }
142 
GetFileSize(const std::string & file)143 uint64_t GetFileSize(const std::string& file)
144 {
145     struct stat statBuf {};
146     return stat(file.c_str(), &statBuf) == 0 ? static_cast<uint64_t>(statBuf.st_size) : 0;
147 }
148 
ChangeMode(const std::string & file,const mode_t & mode)149 bool ChangeMode(const std::string& file, const mode_t& mode)
150 {
151     return (chmod(file.c_str(), mode) == 0);
152 }
153 
CreateFile(const std::string & file,const mode_t & mode)154 bool CreateFile(const std::string& file, const mode_t& mode)
155 {
156     if (IsFileExists(file)) {
157         return true;
158     }
159     std::ofstream fout(file);
160     if (!fout.is_open()) {
161         return false;
162     }
163     fout.flush();
164     fout.close();
165     return ChangeMode(file, mode);
166 }
167 
SaveStringToFile(const std::string & file,const std::string & content,bool isTrunc)168 bool SaveStringToFile(const std::string& file, const std::string& content, bool isTrunc)
169 {
170     if (content.empty()) {
171         return true;
172     }
173 
174     if (!CreateFile(file, FILE_PERM_600)) {
175         return false;
176     }
177     std::ofstream os;
178     if (isTrunc) {
179         os.open(file.c_str(), std::ios::out | std::ios::trunc);
180     } else {
181         os.open(file.c_str(), std::ios::out | std::ios::app);
182     }
183     if (!os.is_open()) {
184         return false;
185     }
186 
187     os.write(content.c_str(), content.length());
188     if (os.fail()) {
189         os.close();
190         return false;
191     }
192     os.close();
193     return true;
194 }
195 
GetFilePathByDir(const std::string & dir,const std::string & fileName)196 std::string GetFilePathByDir(const std::string& dir, const std::string& fileName)
197 {
198     if (dir.empty()) {
199         return fileName;
200     }
201     std::string filePath = dir;
202     if (filePath.back() != '/') {
203         filePath.push_back(PATH_DELIMITER);
204     }
205     filePath.append(fileName);
206     return filePath;
207 }
208 
LoadLinesFromFile(const std::string & filePath,std::vector<std::string> & lines)209 bool LoadLinesFromFile(const std::string& filePath, std::vector<std::string>& lines)
210 {
211     std::ifstream file(filePath);
212     if (file.is_open()) {
213         std::string line;
214         while (std::getline(file, line)) {
215             lines.emplace_back(line);
216         }
217         file.close();
218         return true;
219     }
220     return false;
221 }
222 
SetDirXattr(const std::string & dir,const std::string & name,const std::string & value)223 bool SetDirXattr(const std::string& dir, const std::string& name, const std::string& value)
224 {
225     return setxattr(dir.c_str(), name.c_str(), value.c_str(), strlen(value.c_str()), 0) == 0;
226 }
227 } // namespace FileUtil
228 } // namespace HiviewDFX
229 } // namespace OHOS
230