1 /*
2  * Copyright (c) 2022-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 "b_filesystem/b_file.h"
17 
18 #include <cstring>
19 #include <fcntl.h>
20 #include <libgen.h>
21 #include <sys/sendfile.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <system_error>
25 #include <unistd.h>
26 
27 #include "b_error/b_error.h"
28 #include "filemgmt_libhilog.h"
29 #include "securec.h"
30 
31 namespace OHOS::FileManagement::Backup {
32 using namespace std;
33 
ReadFile(const UniqueFd & fd)34 unique_ptr<char[]> BFile::ReadFile(const UniqueFd &fd)
35 {
36     if (lseek(fd, 0, SEEK_SET) == -1) {
37         throw BError(errno);
38     }
39 
40     struct stat stat = {};
41     if (fstat(fd, &stat) == -1) {
42         throw BError(errno);
43     }
44     off_t fileSize = stat.st_size;
45     if (fileSize == 0) {
46         HILOGI("Deserialized an empty file");
47         return make_unique<char[]>(1);
48     }
49 
50     auto buf = make_unique<char[]>(fileSize + 1);
51     if (read(fd, buf.get(), fileSize) == -1) {
52         throw BError(errno);
53     }
54     return buf;
55 }
56 
SendFile(int outFd,int inFd)57 void BFile::SendFile(int outFd, int inFd)
58 {
59     off_t offset = 0;
60     long ret = 0;
61     if (lseek(outFd, 0, SEEK_SET) == -1) {
62         throw BError(errno);
63     }
64     if (lseek(inFd, 0, SEEK_SET) == -1) {
65         throw BError(errno);
66     }
67     struct stat stat = {};
68     if (fstat(inFd, &stat) == -1) {
69         throw BError(errno);
70     }
71     while ((ret = sendfile(outFd, inFd, &offset, stat.st_size)) > 0) {
72     };
73 
74     if (ret == -1) {
75         throw BError(errno);
76     }
77     ret = ftruncate(outFd, offset);
78     if (ret == -1) {
79         throw BError(errno);
80     }
81 }
82 
Write(const UniqueFd & fd,const string & str)83 void BFile::Write(const UniqueFd &fd, const string &str)
84 {
85     int ret = pwrite(fd, str.c_str(), str.length(), 0);
86     if (ret == -1) {
87         throw BError(errno);
88     }
89     if (ftruncate(fd, ret) == -1) {
90         throw BError(errno);
91     }
92 }
93 
CopyFile(const string & from,const string & to)94 bool BFile::CopyFile(const string &from, const string &to)
95 {
96     if (from == to) {
97         return true;
98     }
99 
100     try {
101         auto resolvedPath = make_unique<char[]>(PATH_MAX + 1); // 1: size for '\0'
102         if (!realpath(from.data(), resolvedPath.get())) {
103             HILOGI("failed to real path for the file %{public}s", from.c_str());
104             return false;
105         }
106         string oldPath(resolvedPath.get());
107         UniqueFd fdFrom(open(oldPath.data(), O_RDONLY));
108         if (fdFrom == -1) { // -1: fd error code
109             HILOGE("failed to open the file %{public}s", from.c_str());
110             throw BError(errno);
111         }
112 
113         unique_ptr<char, function<void(void *p)>> dir {strdup(to.data()), free};
114         if (!dir) {
115             throw BError(errno);
116         }
117         if (!realpath(dirname(dir.get()), resolvedPath.get())) {
118             HILOGE("failed to real path for %{public}s", to.c_str());
119             return false;
120         }
121         string newPath(resolvedPath.get());
122         unique_ptr<char, function<void(void *p)>> name {strdup(to.data()), free};
123         if (!name) {
124             throw BError(errno);
125         }
126         newPath.append("/").append(basename(name.get()));
127         UniqueFd fdTo(open(newPath.data(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR));
128         if (fdTo == -1) { // -1: fd error code
129             HILOGE("failed to open the file %{public}s", to.c_str());
130             throw BError(errno);
131         }
132 
133         SendFile(fdTo, fdFrom);
134         return true;
135     } catch (const BError &e) {
136         HILOGE("%{public}s", e.what());
137     } catch (const exception &e) {
138         HILOGE("%{public}s", e.what());
139     } catch (...) {
140         HILOGE("");
141     }
142     return false;
143 }
144 
GetRealPath(const string & path,string & realPath)145 bool BFile::GetRealPath(const string &path, string &realPath)
146 {
147     auto tmpPath = make_unique<char[]>(PATH_MAX + 1);
148     int ret = memset_s(tmpPath.get(), PATH_MAX + 1, 0, PATH_MAX + 1);
149     if (ret != EOK) {
150         HILOGE("Failed to call path memset_s, err = %{public}d", ret);
151         return false;
152     }
153     if (!realpath(path.c_str(), tmpPath.get())) {
154         HILOGE("failed to real path for the file %{public}s, errno: %{public}d",
155             GetAnonyPath(path).c_str(), errno);
156         return false;
157     }
158     realPath = string(tmpPath.get());
159     return true;
160 }
161 
MoveFile(const string & from,const string & to)162 bool BFile::MoveFile(const string &from, const string &to)
163 {
164     if (from.size() >= PATH_MAX || to.size() >= PATH_MAX) {
165         HILOGE("from or to path err (Exceeding the maximum length)");
166         return false;
167     }
168     if (from == to) {
169         return true;
170     }
171     try {
172         std::string oldPath = "";
173         if (!GetRealPath(from, oldPath)) {
174             return false;
175         }
176         unique_ptr<char, function<void(void *p)>> dir {strdup(to.data()), free};
177         if (!dir) {
178             throw BError(errno);
179         }
180         std::string newPath = "";
181         if (!GetRealPath(dirname(dir.get()), newPath)) {
182             return false;
183         }
184         unique_ptr<char, function<void(void *p)>> name {strdup(to.data()), free};
185         if (!name) {
186             throw BError(errno);
187         }
188         newPath.append("/").append(basename(name.get()));
189         if (rename(oldPath.c_str(), newPath.c_str()) != 0) {
190             HILOGI("rename err,try copy errno: %{public}d", errno);
191             UniqueFd fdFrom(open(oldPath.data(), O_RDONLY));
192             if (fdFrom == -1) { // -1: fd error code
193                 HILOGE("failed to open the file %{public}s", GetAnonyPath(from).c_str());
194                 throw BError(errno);
195             }
196             UniqueFd fdTo(open(newPath.data(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR));
197             if (fdTo == -1) { // -1: fd error code
198                 HILOGE("failed to open the file %{public}s", GetAnonyPath(to).c_str());
199                 throw BError(errno);
200             }
201             SendFile(fdTo, fdFrom);
202         }
203         return true;
204     } catch (const BError &e) {
205         HILOGE("%{public}s", e.what());
206     } catch (const exception &e) {
207         HILOGE("%{public}s", e.what());
208     } catch (...) {
209         HILOGE("unknow error");
210     }
211     return false;
212 }
213 
EndsWith(const string & str,const string & suffix)214 bool BFile::EndsWith(const string &str, const string &suffix)
215 {
216     if (suffix.length() > str.length()) {
217         return false;
218     }
219     return (str.rfind(suffix) == (str.length() - suffix.length()));
220 }
221 } // namespace OHOS::FileManagement::Backup