1 /*
2 * Copyright (c) 2025 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 #include "read_text_core.h"
16
17 #include <cinttypes>
18 #include <fcntl.h>
19 #include <tuple>
20 #include <unistd.h>
21 #include <sys/stat.h>
22
23 #include "file_utils.h"
24 #include "filemgmt_libhilog.h"
25
26 namespace OHOS {
27 namespace FileManagement {
28 namespace ModuleFileIO {
29 using namespace std;
30
ValidReadTextArg(const std::optional<ReadTextOptions> & options)31 static tuple<bool, int64_t, bool, int64_t, unique_ptr<char[]>> ValidReadTextArg(
32 const std::optional<ReadTextOptions> &options)
33 {
34 int64_t offset = -1;
35 int64_t len = 0;
36 bool hasLen = false;
37 unique_ptr<char[]> encoding { new char[]{ "utf-8" } };
38
39 if (!options.has_value()) {
40 return { true, offset, hasLen, len, move(encoding) };
41 }
42
43 ReadTextOptions op = options.value();
44 if (op.offset.has_value()) {
45 offset = op.offset.value();
46 if (offset < 0) {
47 HILOGE("Illegal option.offset parameter");
48 return { false, offset, hasLen, len, nullptr };
49 }
50 }
51
52 if (op.length.has_value()) {
53 len = op.length.value();
54 if (len < 0 || len > UINT_MAX) {
55 HILOGE("Illegal option.length parameter");
56 return { false, offset, hasLen, len, nullptr };
57 }
58 hasLen = true;
59 }
60
61 if (op.encoding.has_value()) {
62 auto encoding = op.encoding.value();
63 if (encoding != "utf-8") {
64 HILOGE("Illegal option.encoding parameter");
65 return { false, offset, hasLen, len, nullptr };
66 }
67 }
68
69 return { true, offset, hasLen, len, move(encoding) };
70 }
71
OpenFile(const std::string & path)72 static int OpenFile(const std::string& path)
73 {
74 std::unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup)*> openReq = {
75 new uv_fs_t, FsUtils::FsReqCleanup
76 };
77 if (openReq == nullptr) {
78 HILOGE("Failed to request heap memory.");
79 return -ENOMEM;
80 }
81
82 return uv_fs_open(nullptr, openReq.get(), path.c_str(), O_RDONLY,
83 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, nullptr);
84 }
85
ReadFromFile(int fd,int64_t offset,string & buffer)86 static int ReadFromFile(int fd, int64_t offset, string& buffer)
87 {
88 uv_buf_t readbuf = uv_buf_init(const_cast<char *>(buffer.c_str()), static_cast<unsigned int>(buffer.size()));
89 std::unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup)*> readReq = {
90 new uv_fs_t, FsUtils::FsReqCleanup };
91 if (readReq == nullptr) {
92 HILOGE("Failed to request heap memory.");
93 return -ENOMEM;
94 }
95 return uv_fs_read(nullptr, readReq.get(), fd, &readbuf, 1, offset, nullptr);
96 }
97
DoReadText(const std::string & path,const std::optional<ReadTextOptions> & options)98 FsResult<tuple<string, int64_t>> ReadTextCore::DoReadText(const std::string &path,
99 const std::optional<ReadTextOptions> &options)
100 {
101 auto [resGetReadTextArg, offset, hasLen, len, encoding] = ValidReadTextArg(options);
102 if (!resGetReadTextArg) {
103 return FsResult<tuple<string, int64_t>>::Error(EINVAL);
104 }
105
106 OHOS::DistributedFS::FDGuard sfd;
107 int fd = OpenFile(path);
108 if (fd < 0) {
109 HILOGD("Failed to open file by ret: %{public}d", fd);
110 return FsResult<tuple<string, int64_t>>::Error(fd);
111 }
112 sfd.SetFD(fd);
113
114 struct stat statbf;
115 if ((!sfd) || (fstat(sfd.GetFD(), &statbf) < 0)) {
116 HILOGE("Failed to get stat of file by fd: %{public}d", sfd.GetFD());
117 return FsResult<tuple<string, int64_t>>::Error(errno);
118 }
119
120 if (offset > statbf.st_size) {
121 HILOGE("Invalid offset: %{public}" PRIu64, offset);
122 return FsResult<tuple<string, int64_t>>::Error(EINVAL);
123 }
124
125 len = (!hasLen || len > statbf.st_size) ? statbf.st_size : len;
126 string buffer(len, '\0');
127 int readRet = ReadFromFile(sfd.GetFD(), offset, buffer);
128 if (readRet < 0) {
129 HILOGE("Failed to read file by fd: %{public}d", fd);
130 return FsResult<tuple<string, int64_t>>::Error(readRet);
131 }
132
133 return FsResult<tuple<string, int64_t>>::Success(make_tuple(move(buffer), readRet));
134 }
135
136 } // namespace ModuleFileIO
137 } // namespace FileManagement
138 } // namespace OHOS