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