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 "symlink.h"
17 
18 #include <cstring>
19 #include <fcntl.h>
20 #include <tuple>
21 #include <unistd.h>
22 
23 #include "common_func.h"
24 #include "filemgmt_libhilog.h"
25 
26 namespace OHOS {
27 namespace FileManagement {
28 namespace ModuleFileIO {
29 using namespace std;
30 using namespace OHOS::FileManagement::LibN;
31 
GetSymlinkArg(napi_env env,const NFuncArg & funcArg)32 static tuple<bool, string, string> GetSymlinkArg(napi_env env, const NFuncArg &funcArg)
33 {
34     auto [resGetFirstArg, src, unused] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
35     if (!resGetFirstArg) {
36         return { false, "", "" };
37     }
38 
39     auto [resGetSecondArg, dest, useless] = NVal(env, funcArg[NARG_POS::SECOND]).ToUTF8StringPath();
40     if (!resGetSecondArg) {
41         return { false, "", "" };
42     }
43 
44     return { true, src.get(), dest.get() };
45 }
46 
Sync(napi_env env,napi_callback_info info)47 napi_value Symlink::Sync(napi_env env, napi_callback_info info)
48 {
49     NFuncArg funcArg(env, info);
50     if (!funcArg.InitArgs(NARG_CNT::TWO)) {
51         HILOGE("Number of arguments unmatched");
52         NError(EINVAL).ThrowErr(env);
53         return nullptr;
54     }
55 
56     auto [resGetSymlinkArg, oldPath, newPath] = GetSymlinkArg(env, funcArg);
57     if (!resGetSymlinkArg) {
58         HILOGE("Failed to get symlink arguments");
59         NError(EINVAL).ThrowErr(env);
60         return nullptr;
61     }
62 
63     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> symlink_req = {
64         new uv_fs_t, CommonFunc::fs_req_cleanup };
65     if (!symlink_req) {
66         HILOGE("Failed to request heap memory.");
67         NError(ENOMEM).ThrowErr(env);
68         return nullptr;
69     }
70     int ret = uv_fs_symlink(nullptr, symlink_req.get(), oldPath.c_str(), newPath.c_str(), 0, nullptr);
71     if (ret < 0) {
72         HILOGE("Failed to create a link for old path");
73         NError(ret).ThrowErr(env);
74         return nullptr;
75     }
76 
77     return NVal::CreateUndefined(env).val_;
78 }
79 
Async(napi_env env,napi_callback_info info)80 napi_value Symlink::Async(napi_env env, napi_callback_info info)
81 {
82     NFuncArg funcArg(env, info);
83     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) {
84         HILOGE("Number of arguments unmatched");
85         NError(EINVAL).ThrowErr(env);
86         return nullptr;
87     }
88 
89     auto [resGetSymlinkArg, oldPath, newPath] = GetSymlinkArg(env, funcArg);
90     if (!resGetSymlinkArg) {
91         HILOGE("Failed to get symlink arguments");
92         NError(EINVAL).ThrowErr(env);
93         return nullptr;
94     }
95 
96     auto cbExec = [oldPath = move(oldPath), newPath = move(newPath)]() -> NError {
97         std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> symlink_req = {
98             new uv_fs_t, CommonFunc::fs_req_cleanup };
99         if (!symlink_req) {
100             HILOGE("Failed to request heap memory.");
101             return NError(ENOMEM);
102         }
103         int ret = uv_fs_symlink(nullptr, symlink_req.get(), oldPath.c_str(), newPath.c_str(), 0, nullptr);
104         if (ret < 0) {
105             HILOGE("Failed to create a link for old path");
106             return NError(ret);
107         }
108         return NError(ERRNO_NOERR);
109     };
110 
111     auto cbComplCallback = [](napi_env env, NError err) -> NVal {
112         if (err) {
113             return { env, err.GetNapiErr(env) };
114         }
115         return { NVal::CreateUndefined(env) };
116     };
117 
118     NVal thisVar(env, funcArg.GetThisVar());
119     size_t argc = funcArg.GetArgc();
120     if (argc == NARG_CNT::TWO) {
121         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_SYMLINK_NAME, cbExec, cbComplCallback).val_;
122     } else {
123         NVal cb(env, funcArg[NARG_POS::THIRD]);
124         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_SYMLINK_NAME, cbExec, cbComplCallback).val_;
125     }
126 }
127 } // namespace ModuleFileIO
128 } // namespace FileManagement
129 } // namespace OHOS
130