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 "copy_dir_ani.h"
17
18 #include <optional>
19
20 #include "ani_signature.h"
21 #include "copy_dir_core.h"
22 #include "error_handler.h"
23 #include "filemgmt_libhilog.h"
24 #include "type_converter.h"
25
26 namespace OHOS {
27 namespace FileManagement {
28 namespace ModuleFileIO {
29 namespace ANI {
30 using namespace std;
31 using namespace OHOS::FileManagement::ModuleFileIO;
32 using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature;
33
ToConflictFiles(ani_env * env,const ConflictFiles & files)34 static tuple<bool, ani_object> ToConflictFiles(ani_env *env, const ConflictFiles &files)
35 {
36 auto classDesc = FS::ConflictFilesInner::classDesc.c_str();
37 ani_class cls;
38 ani_status ret;
39 if ((ret = env->FindClass(classDesc, &cls)) != ANI_OK) {
40 HILOGE("Cannot find class %{public}s, err: %{public}d", classDesc, ret);
41 return { false, nullptr };
42 }
43
44 auto ctorDesc = FS::ConflictFilesInner::ctorDesc.c_str();
45 auto ctorSig = FS::ConflictFilesInner::ctorSig.c_str();
46 ani_method ctor;
47 if ((ret = env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) != ANI_OK) {
48 HILOGE("Cannot find class %{public}s constructor method, err: %{public}d", classDesc, ret);
49 return { false, nullptr };
50 }
51
52 auto [succSrc, src] = TypeConverter::ToAniString(env, files.srcFiles);
53 if (!succSrc) {
54 HILOGE("Convert ConflictFiles srcFiles to ani string failed!");
55 return { false, nullptr };
56 }
57
58 auto [succDest, dest] = TypeConverter::ToAniString(env, files.destFiles);
59 if (!succDest) {
60 HILOGE("Convert ConflictFiles destFiles to ani string failed!");
61 return { false, nullptr };
62 }
63
64 ani_object obj;
65 if ((ret = env->Object_New(cls, ctor, &obj, src, dest)) != ANI_OK) {
66 HILOGE("Create ConflictFiles object failed!, err: %{public}d", ret);
67 return { false, nullptr };
68 }
69
70 return { true, obj };
71 }
72
ToConflictFilesArray(ani_env * env,const optional<vector<struct ConflictFiles>> & errFiles)73 static tuple<bool, optional<ani_object>> ToConflictFilesArray(
74 ani_env *env, const optional<vector<struct ConflictFiles>> &errFiles)
75 {
76 if (!errFiles.has_value()) {
77 return { true, nullopt };
78 }
79 auto classDesc = BuiltInTypes::Array::classDesc.c_str();
80 ani_class cls = nullptr;
81 ani_status ret;
82
83 if ((ret = env->FindClass(classDesc, &cls)) != ANI_OK) {
84 HILOGE("Cannot find class %{public}s, err: %{public}d", classDesc, ret);
85 return { false, nullopt };
86 }
87
88 auto ctorDesc = BuiltInTypes::Array::ctorDesc.c_str();
89 auto ctorSig = BuiltInTypes::Array::ctorSig.c_str();
90 ani_method ctor;
91 if ((ret = env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) != ANI_OK) {
92 HILOGE("Cannot find class %{public}s constructor method, err: %{public}d", classDesc, ret);
93 return { false, nullopt };
94 }
95
96 ani_object arr;
97 auto files = errFiles.value();
98 if ((ret = env->Object_New(cls, ctor, &arr, files.size())) != ANI_OK) {
99 HILOGE("Create Array failed!, err: %{public}d", ret);
100 return { false, nullopt };
101 }
102
103 auto setterDesc = BuiltInTypes::Array::setterDesc.c_str();
104 auto setterSig = BuiltInTypes::Array::objectSetterSig.c_str();
105 ani_size index = 0;
106 for (const auto &errFile : files) {
107 auto [succ, fileObj] = ToConflictFiles(env, errFile);
108 if (!succ) {
109 return { false, nullopt };
110 }
111
112 if ((ret = env->Object_CallMethodByName_Void(arr, setterDesc, setterSig, index, fileObj)) != ANI_OK) {
113 HILOGE("Add element to Array failed, err: %{public}d", ret);
114 return { false, nullopt };
115 }
116 index++;
117 }
118
119 return { true, make_optional<ani_object>(move(arr)) };
120 }
121
CopyDirSync(ani_env * env,ani_class clazz,ani_string src,ani_string dest,ani_object mode)122 void CopyDirAni::CopyDirSync(
123 ani_env *env, [[maybe_unused]] ani_class clazz, ani_string src, ani_string dest, ani_object mode)
124 {
125 error_code errCode;
126
127 auto [succSrc, srcPath] = TypeConverter::ToUTF8String(env, src);
128 if (!succSrc) {
129 HILOGE("Invalid src, errCode = %{public}d", errCode.value());
130 ErrorHandler::Throw(env, EINVAL);
131 return;
132 }
133
134 auto [succDest, destPath] = TypeConverter::ToUTF8String(env, dest);
135 if (!succDest) {
136 HILOGE("Invalid dest, errCode = %{public}d", errCode.value());
137 ErrorHandler::Throw(env, EINVAL);
138 return;
139 }
140
141 auto [succMode, optMode] = TypeConverter::ToOptionalInt32(env, mode);
142 if (!succMode) {
143 HILOGE("Invalid mode");
144 ErrorHandler::Throw(env, EINVAL);
145 return;
146 }
147
148 auto [fsResult, errFiles] = CopyDirCore::DoCopyDir(srcPath, destPath, optMode);
149 if (!fsResult.IsSuccess()) {
150 HILOGE("DoCopyFile failed!");
151 auto [succ, errData] = ToConflictFilesArray(env, errFiles);
152 if (!succ) {
153 HILOGE("Convert conflict files array failed");
154 ErrorHandler::Throw(env, UNKNOWN_ERR);
155 return;
156 }
157 const FsError &err = fsResult.GetError();
158 ErrorHandler::Throw(env, err, errData);
159 return;
160 }
161 }
162
163 } // namespace ANI
164 } // namespace ModuleFileIO
165 } // namespace FileManagement
166 } // namespace OHOS