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