1 /*
2 * Copyright (c) 2022-2023 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
30 namespace OHOS::FileManagement::Backup {
31 using namespace std;
32
ReadFile(const UniqueFd & fd)33 unique_ptr<char[]> BFile::ReadFile(const UniqueFd &fd)
34 {
35 if (lseek(fd, 0, SEEK_SET) == -1) {
36 throw BError(errno);
37 }
38
39 struct stat stat = {};
40 if (fstat(fd, &stat) == -1) {
41 throw BError(errno);
42 }
43 off_t fileSize = stat.st_size;
44 if (fileSize == 0) {
45 HILOGI("Deserialized an empty file");
46 return make_unique<char[]>(1);
47 }
48
49 auto buf = make_unique<char[]>(fileSize + 1);
50 if (read(fd, buf.get(), fileSize) == -1) {
51 throw BError(errno);
52 }
53 return buf;
54 }
55
SendFile(int outFd,int inFd)56 void BFile::SendFile(int outFd, int inFd)
57 {
58 off_t offset = 0;
59 long ret = 0;
60 if (lseek(outFd, 0, SEEK_SET) == -1) {
61 throw BError(errno);
62 }
63 if (lseek(inFd, 0, SEEK_SET) == -1) {
64 throw BError(errno);
65 }
66 struct stat stat = {};
67 if (fstat(inFd, &stat) == -1) {
68 throw BError(errno);
69 }
70 while ((ret = sendfile(outFd, inFd, &offset, stat.st_size)) > 0) {
71 };
72
73 if (ret == -1) {
74 throw BError(errno);
75 }
76 ret = ftruncate(outFd, offset);
77 if (ret == -1) {
78 throw BError(errno);
79 }
80 }
81
Write(const UniqueFd & fd,const string & str)82 void BFile::Write(const UniqueFd &fd, const string &str)
83 {
84 int ret = pwrite(fd, str.c_str(), str.length(), 0);
85 if (ret == -1) {
86 throw BError(errno);
87 }
88 if (ftruncate(fd, ret) == -1) {
89 throw BError(errno);
90 }
91 }
92
CopyFile(const string & from,const string & to)93 bool BFile::CopyFile(const string &from, const string &to)
94 {
95 if (from == to) {
96 return true;
97 }
98
99 try {
100 auto resolvedPath = make_unique<char[]>(PATH_MAX);
101 if (!realpath(from.data(), resolvedPath.get())) {
102 HILOGI("failed to real path for the file %{public}s", from.c_str());
103 return false;
104 }
105 string oldPath(resolvedPath.get());
106 UniqueFd fdFrom(open(oldPath.data(), O_RDONLY));
107 if (fdFrom == -1) {
108 HILOGE("failed to open the file %{public}s", from.c_str());
109 throw BError(errno);
110 }
111
112 unique_ptr<char, function<void(void *p)>> dir {strdup(to.data()), free};
113 if (!dir) {
114 throw BError(errno);
115 }
116 if (!realpath(dirname(dir.get()), resolvedPath.get())) {
117 HILOGI("failed to real path for %{public}s", to.c_str());
118 return false;
119 }
120 string newPath(resolvedPath.get());
121 unique_ptr<char, function<void(void *p)>> name {strdup(to.data()), free};
122 if (!name) {
123 throw BError(errno);
124 }
125 newPath.append("/").append(basename(name.get()));
126 UniqueFd fdTo(open(newPath.data(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR));
127 if (fdTo == -1) {
128 HILOGE("failed to open the file %{public}s", to.c_str());
129 throw BError(errno);
130 }
131
132 SendFile(fdTo, fdFrom);
133 return true;
134 } catch (const BError &e) {
135 HILOGE("%{public}s", e.what());
136 } catch (const exception &e) {
137 HILOGE("%{public}s", e.what());
138 } catch (...) {
139 HILOGE("");
140 }
141 return false;
142 }
143 } // namespace OHOS::FileManagement::Backup