• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "utils/file_utils.h"
17 
18 #include <cerrno>
19 #include <fstream>
20 #include <unistd.h>
21 #include <cstring>
22 #include <dirent.h>
23 #include <cstdlib>
24 #include <fcntl.h>
25 #include <cerrno>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28 #include <sys/types.h>
29 
30 #include "string_ex.h"
31 #include "securec.h"
32 #include "storage_service_errno.h"
33 #include "storage_service_log.h"
34 
35 namespace OHOS {
36 namespace StorageDaemon {
37 constexpr uint32_t ALL_PERMS = (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
38 const int BUF_LEN = 1024;
39 
ChMod(const std::string & path,mode_t mode)40 int32_t ChMod(const std::string &path, mode_t mode)
41 {
42     return TEMP_FAILURE_RETRY(chmod(path.c_str(), mode));
43 }
44 
ChOwn(const std::string & path,uid_t uid,gid_t gid)45 int32_t ChOwn(const std::string &path, uid_t uid, gid_t gid)
46 {
47     return TEMP_FAILURE_RETRY(chown(path.c_str(), uid, gid));
48 }
49 
MkDir(const std::string & path,mode_t mode)50 int32_t MkDir(const std::string &path, mode_t mode)
51 {
52     return TEMP_FAILURE_RETRY(mkdir(path.c_str(), mode));
53 }
54 
RmDir(const std::string & path)55 int32_t RmDir(const std::string &path)
56 {
57     return TEMP_FAILURE_RETRY(rmdir(path.c_str()));
58 }
59 
Mount(const std::string & source,const std::string & target,const char * type,unsigned long flags,const void * data)60 int32_t Mount(const std::string &source, const std::string &target, const char *type,
61               unsigned long flags, const void *data)
62 {
63     return TEMP_FAILURE_RETRY(mount(source.c_str(), target.c_str(), type, flags, data));
64 }
65 
UMount(const std::string & path)66 int32_t UMount(const std::string &path)
67 {
68     return TEMP_FAILURE_RETRY(umount(path.c_str()));
69 }
70 
UMount2(const std::string & path,int flag)71 int32_t UMount2(const std::string &path, int flag)
72 {
73     return TEMP_FAILURE_RETRY(umount2(path.c_str(), flag));
74 }
75 
IsDir(const std::string & path)76 bool IsDir(const std::string &path)
77 {
78     // check whether the path exists
79     struct stat st;
80     int ret = TEMP_FAILURE_RETRY(lstat(path.c_str(), &st));
81     if (ret) {
82         return false;
83     }
84 
85     return S_ISDIR(st.st_mode);
86 }
87 
MkDirRecurse(const std::string & path,mode_t mode)88 bool MkDirRecurse(const std::string& path, mode_t mode)
89 {
90     std::string::size_type index = 0;
91     do {
92         std::string subPath = path;
93         index = path.find('/', index + 1);
94         if (index != std::string::npos) {
95             subPath = path.substr(0, index);
96         }
97 
98         if (TEMP_FAILURE_RETRY(access(subPath.c_str(), F_OK)) != 0) {
99             if (MkDir(subPath, mode) != 0 && errno != EEXIST) {
100                 return false;
101             }
102         }
103     } while (index != std::string::npos);
104 
105     return TEMP_FAILURE_RETRY(access(path.c_str(), F_OK)) == 0;
106 }
107 
108 // On success, true is returned.  On error, false is returned, and errno is set appropriately.
PrepareDir(const std::string & path,mode_t mode,uid_t uid,gid_t gid)109 bool PrepareDir(const std::string &path, mode_t mode, uid_t uid, gid_t gid)
110 {
111     LOGI("prepare for %{public}s", path.c_str());
112 
113     // check whether the path exists
114     struct stat st;
115     if (TEMP_FAILURE_RETRY(lstat(path.c_str(), &st)) == E_ERR) {
116         if (errno != ENOENT) {
117             LOGE("failed to lstat, errno %{public}d", errno);
118             return false;
119         }
120     } else {
121         if (!S_ISDIR(st.st_mode)) {
122             LOGE("%{public}s exists and is not a directory", path.c_str());
123             return false;
124         }
125 
126         if (((st.st_mode & ALL_PERMS) != mode) && ChMod(path, mode)) {
127             LOGE("dir exists and failed to chmod, errno %{public}d", errno);
128             return false;
129         }
130 
131         if (((st.st_uid != uid) || (st.st_gid != gid)) && ChOwn(path, uid, gid)) {
132             LOGE("dir exists and failed to chown, errno %{public}d", errno);
133             return false;
134         }
135 
136         return true;
137     }
138 
139     mode_t mask = umask(0);
140     if (MkDir(path, mode)) {
141         LOGE("failed to mkdir, errno %{public}d", errno);
142         umask(mask);
143         return false;
144     }
145     umask(mask);
146 
147     if (ChMod(path, mode)) {
148         LOGE("failed to chmod, errno %{public}d", errno);
149         return false;
150     }
151 
152     if (ChOwn(path, uid, gid)) {
153         LOGE("failed to chown, errno %{public}d", errno);
154         return false;
155     }
156 
157     return true;
158 }
159 
RmDirRecurse(const std::string & path)160 bool RmDirRecurse(const std::string &path)
161 {
162     LOGI("rm dir %{public}s", path.c_str());
163 
164     DIR *dir = opendir(path.c_str());
165     if (!dir) {
166         if (errno == ENOENT) {
167             return true;
168         }
169 
170         LOGE("failed to open dir %{public}s, errno %{public}d", path.c_str(), errno);
171         return false;
172     }
173 
174     for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
175         if (ent->d_type == DT_DIR) {
176             if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
177                 continue;
178             }
179 
180             if (!RmDirRecurse(path + "/" + ent->d_name)) {
181                 closedir(dir);
182                 return false;
183             }
184         } else {
185             if (unlink((path + "/" + ent->d_name).c_str())) {
186                 LOGE("failed to unlink file %{public}s, errno %{public}d", ent->d_name, errno);
187                 closedir(dir);
188                 return false;
189             }
190         }
191     }
192 
193     closedir(dir);
194     if (rmdir(path.c_str())) {
195         LOGE("failed to rm dir %{public}s, errno %{public}d", path.c_str(), errno);
196         return false;
197     }
198 
199     return true;
200 }
201 
TravelChmod(std::string path,mode_t mode)202 void TravelChmod(std::string path, mode_t mode)
203 {
204     struct stat st;
205     DIR *d = NULL;
206     struct dirent *dp = NULL;
207     const char *skip1 = ".";
208     const char *skip2 = "..";
209 
210     if (stat(path.c_str(), &st) < 0 || !S_ISDIR(st.st_mode)) {
211         LOGE("invalid path");
212         return;
213     }
214 
215     ChMod(path, mode);
216     if (!(d = opendir(path.c_str()))) {
217         LOGE("opendir failed");
218         return;
219     }
220 
221     while ((dp = readdir(d)) != NULL) {
222         if ((!strncmp(dp->d_name, skip1, strlen(skip1))) || (!strncmp(dp->d_name, skip2, strlen(skip2))))
223             continue;
224 
225         std::string subpath = path + "/" + dp->d_name;
226         stat(subpath.c_str(), &st);
227         ChMod(subpath, mode);
228         if (S_ISDIR(st.st_mode))
229             TravelChmod(subpath, mode);
230     }
231     closedir(d);
232 }
233 
StringToUint32(const std::string & str,uint32_t & num)234 bool StringToUint32(const std::string &str, uint32_t &num)
235 {
236     if (str.empty()) {
237         return false;
238     }
239     if (!IsNumericStr(str)) {
240         LOGE("Not numeric entry");
241         return false;
242     }
243 
244     int value;
245     if (!StrToInt(str, value)) {
246         LOGE("String to int convert failed");
247         return false;
248     }
249     num = static_cast<uint32_t>(value);
250 
251     return true;
252 }
253 
GetSubDirs(const std::string & path,std::vector<std::string> & dirList)254 void GetSubDirs(const std::string &path, std::vector<std::string> &dirList)
255 {
256     dirList.clear();
257 
258     struct stat st;
259     int ret = TEMP_FAILURE_RETRY(lstat(path.c_str(), &st));
260     if (ret != 0 || ((st.st_mode & S_IFDIR) != S_IFDIR)) {
261         LOGE("path is not dir");
262         return;
263     }
264 
265     DIR *dir = opendir(path.c_str());
266     if (!dir) {
267         LOGE("failed to open dir %{public}s, errno %{public}d", path.c_str(), errno);
268         return;
269     }
270 
271     for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
272         if ((ent->d_type != DT_DIR) ||
273             (strcmp(ent->d_name, ".") == 0) ||
274             (strcmp(ent->d_name, "..") == 0)) {
275             continue;
276         }
277         dirList.push_back(ent->d_name);
278     }
279 
280     closedir(dir);
281 }
282 
ReadDigitDir(const std::string & path,std::vector<FileList> & dirInfo)283 void ReadDigitDir(const std::string &path, std::vector<FileList> &dirInfo)
284 {
285     struct stat st;
286     int ret = TEMP_FAILURE_RETRY(lstat(path.c_str(), &st));
287     if (ret != 0 || ((st.st_mode & S_IFDIR) != S_IFDIR)) {
288         LOGE("path is not dir");
289         return;
290     }
291 
292     DIR *dir = opendir(path.c_str());
293     if (!dir) {
294         LOGE("failed to open dir %{public}s, errno %{public}d", path.c_str(), errno);
295         return;
296     }
297 
298     for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
299         if ((ent->d_type != DT_DIR) ||
300             (strcmp(ent->d_name, ".") == 0) ||
301             (strcmp(ent->d_name, "..") == 0)) {
302             continue;
303         }
304 
305         uint32_t userId;
306         std::string name(ent->d_name);
307         if (!StringToUint32(name, userId)) {
308             continue;
309         }
310         FileList entry = {
311             .userId = userId,
312             .path = path + "/" + name
313         };
314         dirInfo.push_back(entry);
315     }
316 
317     closedir(dir);
318 }
319 
ReadFile(std::string path,std::string * str)320 bool ReadFile(std::string path, std::string *str)
321 {
322     std::ifstream infile;
323     int cnt = 0;
324     infile.open(path.c_str());
325     if (!infile) {
326         LOGE("Cannot open file");
327         return false;
328     }
329 
330     while (1) {
331         std::string subStr;
332         infile >> subStr;
333         if (subStr == "") {
334             break;
335         }
336         cnt++;
337         *str = *str + subStr + '\n';
338     }
339 
340     infile.close();
341     return cnt == 0 ? false : true;
342 }
343 
FromatCmd(std::vector<std::string> & cmd)344 static std::vector<char*> FromatCmd(std::vector<std::string> &cmd)
345 {
346     std::vector<char*>res;
347     res.reserve(cmd.size() + 1);
348 
349     for (auto& line : cmd) {
350         LOGI("cmd %{public}s", line.c_str());
351         res.emplace_back(const_cast<char*>(line.c_str()));
352     }
353     res.emplace_back(nullptr);
354 
355     return res;
356 }
357 
ForkExec(std::vector<std::string> & cmd,std::vector<std::string> * output)358 int ForkExec(std::vector<std::string> &cmd, std::vector<std::string> *output)
359 {
360     int pipe_fd[2];
361     pid_t pid;
362     int status;
363     auto args = FromatCmd(cmd);
364 
365     if (pipe(pipe_fd) < 0) {
366         LOGE("creat pipe failed");
367         return E_ERR;
368     }
369 
370     pid = fork();
371     if (pid == -1) {
372         LOGE("fork failed");
373         return E_ERR;
374     } else if (pid == 0) {
375         close(pipe_fd[0]);
376         if (dup2(pipe_fd[1], STDOUT_FILENO) == -1) {
377             LOGE("dup2 failed");
378             exit(1);
379         }
380         close(pipe_fd[1]);
381         execvp(args[0], const_cast<char **>(args.data()));
382         exit(0);
383     } else {
384         close(pipe_fd[1]);
385         if (output) {
386             char buf[BUF_LEN] = { 0 };
387             (void)memset_s(buf, sizeof(buf), 0, sizeof(buf));
388             output->clear();
389             while (read(pipe_fd[0], buf, BUF_LEN - 1) > 0) {
390                 LOGI("get result %{public}s", buf);
391                 output->push_back(buf);
392             }
393             return E_OK;
394         }
395 
396         waitpid(pid, &status, 0);
397         if (errno == ECHILD) {
398             return E_NO_CHILD;
399         }
400         if (!WIFEXITED(status)) {
401             LOGE("Process exits abnormally");
402             return E_ERR;
403         }
404     }
405     return E_OK;
406 }
407 
TraverseDirUevent(const std::string & path,bool flag)408 void TraverseDirUevent(const std::string &path, bool flag)
409 {
410     DIR *dir = opendir(path.c_str());
411     if (dir == nullptr) {
412         return;
413     }
414 
415     int dirFd = dirfd(dir);
416     int fd = openat(dirFd, "uevent", O_WRONLY | O_CLOEXEC);
417     if (fd >= 0) {
418         std::string writeStr = "add\n";
419         int writeStrLen = writeStr.length();
420         write(fd, writeStr.c_str(), writeStrLen);
421         close(fd);
422     }
423 
424     for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
425         if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
426             continue;
427         }
428 
429         if (ent->d_type != DT_DIR && !flag) {
430             continue;
431         }
432 
433         TraverseDirUevent(path + "/" + ent->d_name, false);
434     }
435 
436     closedir(dir);
437 }
438 } // STORAGE_DAEMON
439 } // OHOS
440