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
16 #include "write_core.h"
17
18 #include <cstring>
19 #include <ctime>
20 #include <iostream>
21 #include <memory>
22 #include <sstream>
23 #include <unistd.h>
24
25 #ifdef FILE_API_TRACE
26 #include "hitrace_meter.h"
27 #endif
28
29 namespace OHOS {
30 namespace FileManagement {
31 namespace ModuleFileIO {
32 using namespace std;
33
ValidWriteArg(void * buffer,const size_t bufLen,const optional<WriteOptions> & options)34 static tuple<bool, void *, size_t, int64_t> ValidWriteArg(
35 void *buffer, const size_t bufLen, const optional<WriteOptions> &options)
36 {
37 size_t retLen = 0;
38 int64_t offset = -1;
39 bool succ = false;
40
41 if (bufLen > UINT_MAX) {
42 HILOGE("The Size of buffer is too large");
43 return { false, nullptr, 0, offset };
44 }
45
46 optional<size_t> lengthOp = nullopt;
47 optional<int64_t> offsetOp = nullopt;
48 if (options.has_value()) {
49 WriteOptions op = options.value();
50 lengthOp = op.length;
51 offsetOp = op.offset;
52 }
53
54 tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp);
55 if (!succ) {
56 HILOGE("Failed to get actual length");
57 return { false, nullptr, 0, offset };
58 }
59
60 if (offsetOp.has_value()) {
61 offset = offsetOp.value();
62 if (offset < 0) {
63 HILOGE("option.offset shall be positive number");
64 return { false, nullptr, 0, offset };
65 }
66 }
67 return { true, buffer, retLen, offset };
68 }
69
DoWrite(const int32_t fd,const string & buffer,const optional<WriteOptions> & options)70 FsResult<int64_t> WriteCore::DoWrite(const int32_t fd, const string &buffer, const optional<WriteOptions> &options)
71 {
72 if (fd < 0) {
73 HILOGE("Invalid fd from JS first argument");
74 return FsResult<int64_t>::Error(EINVAL);
75 }
76
77 bool succ = false;
78 size_t len = 0;
79 int64_t offset = -1;
80 void *buf = const_cast<void *>(static_cast<const void *>(buffer.c_str()));
81 size_t bufLen = static_cast<size_t>(buffer.length());
82
83 tie(succ, buf, len, offset) = ValidWriteArg(buf, bufLen, options);
84 if (!succ) {
85 HILOGE("Failed to resolve buf and options");
86 return FsResult<int64_t>::Error(EINVAL);
87 }
88
89 return DoWrite(fd, buf, len, offset);
90 }
91
DoWrite(const int32_t fd,const ArrayBuffer & buffer,const optional<WriteOptions> & options)92 FsResult<int64_t> WriteCore::DoWrite(const int32_t fd, const ArrayBuffer &buffer, const optional<WriteOptions> &options)
93 {
94 if (fd < 0) {
95 HILOGE("Invalid fd from JS first argument");
96 return FsResult<int64_t>::Error(EINVAL);
97 }
98
99 bool succ = false;
100 size_t len = 0;
101 int64_t offset = -1;
102 void *buf = nullptr;
103
104 tie(succ, buf, len, offset) = ValidWriteArg(buffer.buf, buffer.length, options);
105 if (!succ) {
106 HILOGE("Failed to resolve buf and options");
107 return FsResult<int64_t>::Error(EINVAL);
108 }
109
110 return DoWrite(fd, buf, len, offset);
111 }
112
DoWrite(const int32_t fd,void * buf,const size_t len,const int64_t offset)113 FsResult<int64_t> WriteCore::DoWrite(const int32_t fd, void *buf, const size_t len, const int64_t offset)
114 {
115 uv_buf_t buffer = uv_buf_init(static_cast<char *>(buf), static_cast<unsigned int>(len));
116 unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup) *> writeReq = { new uv_fs_t, FsUtils::FsReqCleanup };
117 if (!writeReq) {
118 return FsResult<int64_t>::Error(ENOMEM);
119 }
120 int ret = uv_fs_write(nullptr, writeReq.get(), fd, &buffer, 1, offset, nullptr);
121 if (ret < 0) {
122 HILOGE("Failed to write file for %{public}d", ret);
123 return FsResult<int64_t>::Error(ret);
124 }
125 return FsResult<int64_t>::Success(static_cast<int64_t>(ret));
126 }
127
128 } // namespace ModuleFileIO
129 } // namespace FileManagement
130 } // namespace OHOS