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