1 /*
2 * Copyright (c) 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 "xattr.h"
17
18 #include <memory>
19 #include <optional>
20 #include <sys/xattr.h>
21
22 #include "file_utils.h"
23 #include "filemgmt_libhilog.h"
24 #include "n_error.h"
25
26 namespace OHOS {
27 namespace FileManagement {
28 namespace ModuleFileIO {
29 using namespace OHOS::FileManagement::LibN;
30 using namespace std;
31 constexpr size_t MAX_XATTR_SIZE = 4096;
32
IsIllegalXattr(const char * key,const char * value)33 static bool IsIllegalXattr(const char *key, const char *value)
34 {
35 bool isIllegalKey = strnlen(key, MAX_XATTR_SIZE + 1) > MAX_XATTR_SIZE;
36 if (isIllegalKey) {
37 HILOGE("key is too long");
38 }
39 bool isIllegalValue = strnlen(value, MAX_XATTR_SIZE + 1) > MAX_XATTR_SIZE;
40 if (isIllegalValue) {
41 HILOGE("value is too long");
42 }
43 return isIllegalKey || isIllegalValue;
44 }
45
GetXattrCore(const char * path,const char * key,std::shared_ptr<string> result)46 static int32_t GetXattrCore(const char *path,
47 const char *key,
48 std::shared_ptr<string> result)
49 {
50 ssize_t xAttrSize = getxattr(path, key, nullptr, 0);
51 if (xAttrSize == -1 || xAttrSize == 0) {
52 *result = "";
53 return ERRNO_NOERR;
54 }
55 auto xattrValue = CreateUniquePtr<char[]>(static_cast<long>(xAttrSize) + 1);
56 xAttrSize = getxattr(path, key, xattrValue.get(), static_cast<size_t>(xAttrSize));
57 if (xAttrSize == -1) {
58 return errno;
59 }
60 xattrValue[xAttrSize] = '\0';
61 *result = std::string(xattrValue.get());
62 return ERRNO_NOERR;
63 }
64
SetSync(napi_env env,napi_callback_info info)65 napi_value Xattr::SetSync(napi_env env, napi_callback_info info)
66 {
67 NFuncArg funcArg(env, info);
68 if (!funcArg.InitArgs(static_cast<int>(NARG_CNT::THREE))) {
69 HILOGE("Number of arguments unmatched");
70 NError(EINVAL).ThrowErr(env);
71 return nullptr;
72 }
73 bool succ = false;
74 std::unique_ptr<char[]> path;
75 std::unique_ptr<char[]> key;
76 std::unique_ptr<char[]> value;
77 tie(succ, path, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::FIRST)]).ToUTF8StringPath();
78 if (!succ) {
79 HILOGE("Invalid path");
80 NError(EINVAL).ThrowErr(env);
81 return nullptr;
82 }
83 tie(succ, key, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::SECOND)]).ToUTF8String();
84 if (!succ) {
85 HILOGE("Invalid xattr key");
86 NError(EINVAL).ThrowErr(env);
87 return nullptr;
88 }
89 tie(succ, value, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::THIRD)]).ToUTF8String();
90 if (!succ || IsIllegalXattr(key.get(), value.get())) {
91 HILOGE("Invalid xattr value");
92 NError(EINVAL).ThrowErr(env);
93 return nullptr;
94 }
95 if (setxattr(path.get(), key.get(), value.get(), strnlen(value.get(), MAX_XATTR_SIZE), 0) < 0) {
96 HILOGE("setxattr fail, errno is %{public}d", errno);
97 NError(errno).ThrowErr(env);
98 return nullptr;
99 }
100 return NVal::CreateUndefined(env).val_;
101 }
102
GetSync(napi_env env,napi_callback_info info)103 napi_value Xattr::GetSync(napi_env env, napi_callback_info info)
104 {
105 NFuncArg funcArg(env, info);
106 if (!funcArg.InitArgs(static_cast<int>(NARG_CNT::TWO))) {
107 HILOGE("Number of arguments unmatched");
108 NError(EINVAL).ThrowErr(env);
109 return nullptr;
110 }
111
112 bool succ = false;
113 std::unique_ptr<char[]> path;
114 std::unique_ptr<char[]> key;
115 tie(succ, path, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::FIRST)]).ToUTF8StringPath();
116 if (!succ) {
117 HILOGE("Invalid path");
118 NError(EINVAL).ThrowErr(env);
119 return nullptr;
120 }
121 tie(succ, key, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::SECOND)]).ToUTF8String();
122 if (!succ) {
123 HILOGE("Invalid xattr key");
124 NError(EINVAL).ThrowErr(env);
125 return nullptr;
126 }
127 auto result = make_shared<std::string>();
128 int32_t ret = GetXattrCore(path.get(), key.get(), result);
129 if (ret != ERRNO_NOERR) {
130 HILOGE("Invalid getxattr");
131 NError(ret).ThrowErr(env);
132 return nullptr;
133 }
134 return NVal::CreateUTF8String(env, *result).val_;
135 }
136
GetAsync(napi_env env,napi_callback_info info)137 napi_value Xattr::GetAsync(napi_env env, napi_callback_info info)
138 {
139 NFuncArg funcArg(env, info);
140 if (!funcArg.InitArgs(static_cast<int>(NARG_CNT::TWO))) {
141 HILOGE("Number of arguments unmatched");
142 NError(EINVAL).ThrowErr(env);
143 return nullptr;
144 }
145 bool succ = false;
146 std::unique_ptr<char[]> path;
147 std::unique_ptr<char[]> key;
148 tie(succ, path, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::FIRST)]).ToUTF8StringPath();
149 if (!succ) {
150 HILOGE("Invalid path");
151 NError(EINVAL).ThrowErr(env);
152 return nullptr;
153 }
154 tie(succ, key, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::SECOND)]).ToUTF8String();
155 if (!succ) {
156 HILOGE("Invalid xattr key");
157 NError(EINVAL).ThrowErr(env);
158 return nullptr;
159 }
160 auto result = make_shared<std::string>();
161 string pathString(path.get());
162 string keyString(key.get());
163 auto cbExec = [path = move(pathString), key = move(keyString), result]() -> NError {
164 int ret = GetXattrCore(path.c_str(), key.c_str(), result);
165 return NError(ret);
166 };
167 auto cbComplete = [result](napi_env env, NError err) -> NVal {
168 if (err) {
169 return {env, err.GetNapiErr(env)};
170 }
171 return {NVal::CreateUTF8String(env, *result)};
172 };
173 static const std::string PROCEDURE_NAME = "GetXattr";
174 NVal thisVar(env, funcArg.GetThisVar());
175 return NAsyncWorkPromise(env, thisVar)
176 .Schedule(PROCEDURE_NAME, cbExec, cbComplete)
177 .val_;
178 }
179
180
SetAsync(napi_env env,napi_callback_info info)181 napi_value Xattr::SetAsync(napi_env env, napi_callback_info info)
182 {
183 NFuncArg funcArg(env, info);
184 if (!funcArg.InitArgs(static_cast<int>(NARG_CNT::THREE))) {
185 HILOGE("Number of arguments unmatched");
186 NError(EINVAL).ThrowErr(env);
187 return nullptr;
188 }
189 bool succ = false;
190 std::unique_ptr<char[]> path;
191 std::unique_ptr<char[]> key;
192 std::unique_ptr<char[]> value;
193 tie(succ, path, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::FIRST)]).ToUTF8StringPath();
194 if (!succ) {
195 HILOGE("Invalid path");
196 NError(EINVAL).ThrowErr(env);
197 return nullptr;
198 }
199 tie(succ, key, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::SECOND)]).ToUTF8String();
200 if (!succ) {
201 HILOGE("Invalid xattr key");
202 NError(EINVAL).ThrowErr(env);
203 return nullptr;
204 }
205 tie(succ, value, std::ignore) = NVal(env, funcArg[static_cast<int>(NARG_POS::THIRD)]).ToUTF8String();
206 if (!succ || IsIllegalXattr(key.get(), value.get())) {
207 HILOGE("Invalid xattr value");
208 NError(EINVAL).ThrowErr(env);
209 return nullptr;
210 }
211 string pathString(path.get());
212 string keyString(key.get());
213 string valueString(value.get());
214 auto cbExec = [path = move(pathString), key = move(keyString), value = move(valueString)]() -> NError {
215 if (setxattr(path.c_str(), key.c_str(), value.c_str(), strnlen(value.c_str(), MAX_XATTR_SIZE), 0) < 0) {
216 HILOGE("setxattr fail, errno is %{public}d", errno);
217 return NError(errno);
218 }
219 return NError(ERRNO_NOERR);
220 };
221 auto cbComplete = [](napi_env env, NError err) -> NVal {
222 if (err) {
223 return {env, err.GetNapiErr(env)};
224 }
225 return NVal::CreateUndefined(env);
226 };
227 static const std::string PROCEDURE_NAME = "SetXattr";
228 NVal thisVar(env, funcArg.GetThisVar());
229 return NAsyncWorkPromise(env, thisVar)
230 .Schedule(PROCEDURE_NAME, cbExec, cbComplete).val_;
231 }
232 } // namespace ModuleFileIO
233 } // namespace FileManagement
234 } // namespace OHOS