• 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 <cstdlib>
20 #include <cstring>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <fstream>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
28 #include "securec.h"
29 #include "storage_service_errno.h"
30 #include "storage_service_log.h"
31 #include "string_ex.h"
32 #ifdef USE_LIBRESTORECON
33 #include "policycoreutils.h"
34 #endif
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 #ifdef USE_LIBRESTORECON
158     int err = Restorecon(path.c_str());
159     if (err) {
160         LOGE("failed to restorecon, err:%{public}d", err);
161         return false;
162     }
163 #endif
164 
165     return true;
166 }
167 
RmDirRecurse(const std::string & path)168 bool RmDirRecurse(const std::string &path)
169 {
170     LOGI("rm dir %{public}s", path.c_str());
171 
172     DIR *dir = opendir(path.c_str());
173     if (!dir) {
174         if (errno == ENOENT) {
175             return true;
176         }
177 
178         LOGE("failed to open dir %{public}s, errno %{public}d", path.c_str(), errno);
179         return false;
180     }
181 
182     for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
183         if (ent->d_type == DT_DIR) {
184             if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
185                 continue;
186             }
187 
188             if (!RmDirRecurse(path + "/" + ent->d_name)) {
189                 (void)closedir(dir);
190                 return false;
191             }
192         } else {
193             if (unlink((path + "/" + ent->d_name).c_str())) {
194                 LOGE("failed to unlink file %{public}s, errno %{public}d", ent->d_name, errno);
195                 (void)closedir(dir);
196                 return false;
197             }
198         }
199     }
200 
201     (void)closedir(dir);
202     if (rmdir(path.c_str())) {
203         LOGE("failed to rm dir %{public}s, errno %{public}d", path.c_str(), errno);
204         return false;
205     }
206 
207     return true;
208 }
209 
TravelChmod(std::string path,mode_t mode)210 void TravelChmod(std::string path, mode_t mode)
211 {
212     struct stat st;
213     DIR *d = NULL;
214     struct dirent *dp = NULL;
215     const char *skip1 = ".";
216     const char *skip2 = "..";
217 
218     if (stat(path.c_str(), &st) < 0 || !S_ISDIR(st.st_mode)) {
219         LOGE("invalid path");
220         return;
221     }
222 
223     (void)ChMod(path, mode);
224     if (!(d = opendir(path.c_str()))) {
225         LOGE("opendir failed");
226         return;
227     }
228 
229     while ((dp = readdir(d)) != NULL) {
230         if ((!strncmp(dp->d_name, skip1, strlen(skip1))) || (!strncmp(dp->d_name, skip2, strlen(skip2))))
231             continue;
232 
233         std::string subpath = path + "/" + dp->d_name;
234         stat(subpath.c_str(), &st);
235         (void)ChMod(subpath, mode);
236         if (S_ISDIR(st.st_mode))
237             TravelChmod(subpath, mode);
238     }
239     (void)closedir(d);
240 }
241 
StringToUint32(const std::string & str,uint32_t & num)242 bool StringToUint32(const std::string &str, uint32_t &num)
243 {
244     if (str.empty()) {
245         return false;
246     }
247     if (!IsNumericStr(str)) {
248         LOGE("Not numeric entry");
249         return false;
250     }
251 
252     int value;
253     if (!StrToInt(str, value)) {
254         LOGE("String to int convert failed");
255         return false;
256     }
257     num = static_cast<uint32_t>(value);
258 
259     return true;
260 }
261 
GetSubDirs(const std::string & path,std::vector<std::string> & dirList)262 void GetSubDirs(const std::string &path, std::vector<std::string> &dirList)
263 {
264     dirList.clear();
265 
266     struct stat st;
267     int ret = TEMP_FAILURE_RETRY(lstat(path.c_str(), &st));
268     if (ret != 0 || ((st.st_mode & S_IFDIR) != S_IFDIR)) {
269         LOGE("path is not dir");
270         return;
271     }
272 
273     DIR *dir = opendir(path.c_str());
274     if (!dir) {
275         LOGE("failed to open dir %{public}s, errno %{public}d", path.c_str(), errno);
276         return;
277     }
278 
279     for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
280         if ((ent->d_type != DT_DIR) ||
281             (strcmp(ent->d_name, ".") == 0) ||
282             (strcmp(ent->d_name, "..") == 0)) {
283             continue;
284         }
285         dirList.push_back(ent->d_name);
286     }
287 
288     (void)closedir(dir);
289 }
290 
ReadDigitDir(const std::string & path,std::vector<FileList> & dirInfo)291 void ReadDigitDir(const std::string &path, std::vector<FileList> &dirInfo)
292 {
293     struct stat st;
294     int ret = TEMP_FAILURE_RETRY(lstat(path.c_str(), &st));
295     if (ret != 0 || ((st.st_mode & S_IFDIR) != S_IFDIR)) {
296         LOGE("path is not dir");
297         return;
298     }
299 
300     DIR *dir = opendir(path.c_str());
301     if (!dir) {
302         LOGE("failed to open dir %{public}s, errno %{public}d", path.c_str(), errno);
303         return;
304     }
305 
306     for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
307         if ((ent->d_type != DT_DIR) ||
308             (strcmp(ent->d_name, ".") == 0) ||
309             (strcmp(ent->d_name, "..") == 0)) {
310             continue;
311         }
312 
313         uint32_t userId;
314         std::string name(ent->d_name);
315         if (!StringToUint32(name, userId)) {
316             continue;
317         }
318         FileList entry = {
319             .userId = userId,
320             .path = path + "/" + name
321         };
322         dirInfo.push_back(entry);
323     }
324 
325     (void)closedir(dir);
326 }
327 
OpenSubFile(const std::string & path,std::vector<std::string> & file)328 void OpenSubFile(const std::string &path, std::vector<std::string>  &file)
329 {
330     struct stat st;
331     int ret = TEMP_FAILURE_RETRY(lstat(path.c_str(), &st));
332     if (ret != 0 || ((st.st_mode & S_IFDIR) != S_IFDIR)) {
333         LOGI("path is not dir");
334         return;
335     }
336 
337     DIR *dir = opendir(path.c_str());
338     if (!dir) {
339         LOGI("failed to open dir %{public}s, errno %{public}d", path.c_str(), errno);
340         return;
341     }
342     for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
343         if ((ent->d_type != DT_DIR)) {
344             std::string name(ent->d_name);
345             std::string filePath = path + "/" + name;
346             LOGI("filePath is %{public}s", filePath.c_str());
347             file.push_back(filePath);
348             continue;
349         } else {
350             if ((strcmp(ent->d_name, ".") == 0) || (strcmp(ent->d_name, "..") == 0)) {
351                 continue;
352             }
353             std::string name(ent->d_name);
354             std::string filePath = path + "/" + name;
355             OpenSubFile(filePath, file);
356         }
357     }
358     (void)closedir(dir);
359 }
360 
ReadFile(std::string path,std::string * str)361 bool ReadFile(std::string path, std::string *str)
362 {
363     std::ifstream infile;
364     int cnt = 0;
365 
366     std::string rpath(PATH_MAX + 1, '\0');
367     if ((path.length() > PATH_MAX) || (realpath(path.c_str(), rpath.data()) == nullptr)) {
368         LOGE("realpath failed");
369         return false;
370     }
371 
372     infile.open(rpath.c_str());
373     if (!infile) {
374         LOGE("Cannot open file");
375         return false;
376     }
377 
378     while (1) {
379         std::string subStr;
380         infile >> subStr;
381         if (subStr == "") {
382             break;
383         }
384         cnt++;
385         *str = *str + subStr + '\n';
386     }
387 
388     infile.close();
389     return cnt == 0 ? false : true;
390 }
391 
FromatCmd(std::vector<std::string> & cmd)392 static std::vector<char*> FromatCmd(std::vector<std::string> &cmd)
393 {
394     std::vector<char*>res;
395     res.reserve(cmd.size() + 1);
396 
397     for (auto& line : cmd) {
398         LOGI("cmd %{public}s", line.c_str());
399         res.emplace_back(const_cast<char*>(line.c_str()));
400     }
401     res.emplace_back(nullptr);
402 
403     return res;
404 }
405 
ForkExec(std::vector<std::string> & cmd,std::vector<std::string> * output)406 int ForkExec(std::vector<std::string> &cmd, std::vector<std::string> *output)
407 {
408     int pipe_fd[2];
409     pid_t pid;
410     int status;
411     auto args = FromatCmd(cmd);
412 
413     if (pipe(pipe_fd) < 0) {
414         LOGE("creat pipe failed");
415         return E_ERR;
416     }
417 
418     pid = fork();
419     if (pid == -1) {
420         LOGE("fork failed");
421         return E_ERR;
422     } else if (pid == 0) {
423         (void)close(pipe_fd[0]);
424         if (dup2(pipe_fd[1], STDOUT_FILENO) == -1) {
425             LOGE("dup2 failed");
426             exit(1);
427         }
428         (void)close(pipe_fd[1]);
429         execvp(args[0], const_cast<char **>(args.data()));
430         LOGE("execvp failed errno: %{public}d", errno);
431         exit(0);
432     } else {
433         (void)close(pipe_fd[1]);
434         if (output) {
435             char buf[BUF_LEN] = { 0 };
436             (void)memset_s(buf, sizeof(buf), 0, sizeof(buf));
437             output->clear();
438             while (read(pipe_fd[0], buf, BUF_LEN - 1) > 0) {
439                 LOGI("get result %{public}s", buf);
440                 output->push_back(buf);
441             }
442             return E_OK;
443         }
444 
445         waitpid(pid, &status, 0);
446         if (errno == ECHILD) {
447             return E_NO_CHILD;
448         }
449         if (!WIFEXITED(status)) {
450             LOGE("Process exits abnormally");
451             return E_ERR;
452         }
453     }
454     return E_OK;
455 }
456 
TraverseDirUevent(const std::string & path,bool flag)457 void TraverseDirUevent(const std::string &path, bool flag)
458 {
459     DIR *dir = opendir(path.c_str());
460     if (dir == nullptr) {
461         return;
462     }
463 
464     int dirFd = dirfd(dir);
465     int fd = openat(dirFd, "uevent", O_WRONLY | O_CLOEXEC);
466     if (fd >= 0) {
467         std::string writeStr = "add\n";
468         write(fd, writeStr.c_str(), writeStr.length());
469         (void)close(fd);
470     }
471 
472     for (struct dirent *ent = readdir(dir); ent != nullptr; ent = readdir(dir)) {
473         if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
474             continue;
475         }
476 
477         if (ent->d_type != DT_DIR && !flag) {
478             continue;
479         }
480 
481         TraverseDirUevent(path + "/" + ent->d_name, false);
482     }
483 
484     (void)closedir(dir);
485 }
486 
IsSameGidUid(const std::string dir,uid_t uid,gid_t gid)487 int IsSameGidUid(const std::string dir, uid_t uid, gid_t gid)
488 {
489     struct stat st;
490     if (TEMP_FAILURE_RETRY(lstat(dir.c_str(), &st)) == E_ERR) {
491         LOGE("failed to lstat, errno %{public}d", errno);
492         if (errno == ENOENT) {
493             return E_NON_EXIST;
494         }
495         return E_SYS_ERR;
496     }
497     return (st.st_uid == uid) && (st.st_gid == gid) ? E_OK : E_DIFF_UID_GID;
498 }
499 
MoveDataShell(const std::string & from,const std::string & to)500 bool MoveDataShell(const std::string &from, const std::string &to)
501 {
502     LOGI("MoveDataShell start");
503     if (TEMP_FAILURE_RETRY(access(from.c_str(), F_OK)) != 0) {
504         return true;
505     }
506     std::vector<std::string> cmd = {
507         "/system/bin/mv",
508         from,
509         to
510     };
511     std::vector<std::string> out;
512     int32_t err = ForkExec(cmd, &out);
513     if (err != 0) {
514         LOGE("MoveDataShell failed err:%{public}d", err);
515     }
516     return true;
517 }
518 
MoveFileManagerData(const std::string & filesPath)519 void MoveFileManagerData(const std::string &filesPath)
520 {
521     std::string docsPath = filesPath + "Docs/";
522     MoveDataShell(filesPath + "Download/", docsPath);
523     MoveDataShell(filesPath + "Documents/", docsPath);
524     MoveDataShell(filesPath + "Desktop/", docsPath);
525     MoveDataShell(filesPath + ".Trash/", docsPath);
526 }
527 
ChownRecursion(const std::string dir,uid_t uid,gid_t gid)528 void ChownRecursion(const std::string dir, uid_t uid, gid_t gid)
529 {
530     std::vector<std::string> cmd = {
531         "/system/bin/chown",
532         "-R",
533         std::to_string(uid) + ":" + std::to_string(gid),
534         dir
535     };
536     std::vector<std::string> out;
537     int32_t err = ForkExec(cmd, &out);
538     if (err != 0) {
539         LOGE("path: %{public}s chown failed err:%{public}d", cmd.back().c_str(), err);
540     }
541 }
542 
543 } // STORAGE_DAEMON
544 } // OHOS
545