1 /*
2  * Copyright (c) 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 #ifndef FILEMANAGEMENT_FILE_API_COPY_H
17 #define FILEMANAGEMENT_FILE_API_COPY_H
18 
19 #include <set>
20 #include <sys/inotify.h>
21 #include <thread>
22 #include <chrono>
23 
24 #include "bundle_mgr_client_impl.h"
25 #include "common_func.h"
26 #include "filemgmt_libn.h"
27 #include "n_async/n_ref.h"
28 #include "task_signal.h"
29 #include "class_tasksignal/task_signal_entity.h"
30 
31 namespace OHOS {
32 namespace FileManagement {
33 namespace ModuleFileIO {
34 using namespace std;
35 using namespace OHOS::FileManagement::LibN;
36 using namespace OHOS::AppExecFwk;
37 using namespace DistributedFS::ModuleTaskSignal;
38 const uint64_t MAX_VALUE = 0x7FFFFFFFFFFFFFFF;
39 
40 struct ReceiveInfo {
41     std::string path;                         // dir name
42     std::map<std::string, uint64_t> fileList; // filename, proceededSize
43 };
44 struct JsCallbackObject {
45     napi_env env = nullptr;
46     LibN::NRef nRef;
47     int32_t notifyFd = -1;
48     int32_t eventFd = -1;
49     std::vector<std::pair<int, std::shared_ptr<ReceiveInfo>>> wds;
50     uint64_t totalSize = 0;
51     uint64_t progressSize = 0;
52     uint64_t maxProgressSize = 0;
53     int32_t errorCode = 0;
54     std::thread notifyHandler;
JsCallbackObjectJsCallbackObject55     explicit JsCallbackObject(napi_env env, LibN::NVal jsVal) : env(env), nRef(jsVal) {}
56 
CloseFdJsCallbackObject57     void CloseFd()
58     {
59         if (eventFd != -1) {
60             close(eventFd);
61             eventFd = -1;
62         }
63         if (notifyFd == -1) {
64             return;
65         }
66         for (auto item : wds) {
67             inotify_rm_watch(notifyFd, item.first);
68         }
69         close(notifyFd);
70         notifyFd = -1;
71     }
72 
~JsCallbackObjectJsCallbackObject73     ~JsCallbackObject()
74     {
75         CloseFd();
76     }
77 };
78 
79 struct FileInfos {
80     std::string srcUri;
81     std::string destUri;
82     std::string srcPath;
83     std::string destPath;
84     bool isFile = false;
85     std::chrono::steady_clock::time_point notifyTime;
86     int32_t notifyFd = -1;
87     int32_t eventFd = -1;
88     bool run = true;
89     bool hasListener = false;
90     napi_env env;
91     NVal listener;
92     NVal copySignal;
93     std::shared_ptr<TaskSignal> taskSignal = nullptr;
94     std::set<std::string> filePaths;
95     int exceptionCode = ERRNO_NOERR;    // notify copy thread or listener thread has exceptions.
96     bool operator==(const FileInfos &infos) const
97     {
98         return (srcUri == infos.srcUri && destUri == infos.destUri);
99     }
100     bool operator<(const FileInfos &infos) const
101     {
102         if (srcUri == infos.srcUri) {
103             return destUri < infos.destUri;
104         }
105         return srcUri < infos.srcUri;
106     }
107 };
108 
109 struct UvEntry {
110     std::shared_ptr<JsCallbackObject> callback;
111     std::shared_ptr<FileInfos> fileInfos;
112     uint64_t progressSize = 0;
113     uint64_t totalSize = 0;
UvEntryUvEntry114     UvEntry(const std::shared_ptr<JsCallbackObject> &cb, std::shared_ptr<FileInfos> fileInfos)
115         : callback(cb), fileInfos(fileInfos)
116     {
117     }
UvEntryUvEntry118     explicit UvEntry(const std::shared_ptr<JsCallbackObject> &cb) : callback(cb) {}
119 };
120 
121 class Copy final {
122 public:
123     static napi_value Async(napi_env env, napi_callback_info info);
124     static std::map<FileInfos, std::shared_ptr<JsCallbackObject>> jsCbMap_;
125     static void UnregisterListener(std::shared_ptr<FileInfos> fileInfos);
126     static std::recursive_mutex mutex_;
127 
128 private:
129     // operator of napi
130     static tuple<bool, std::string> ParseJsOperand(napi_env env, NVal pathOrFdFromJsArg);
131     static tuple<bool, NVal> GetListenerFromOptionArg(napi_env env, const NFuncArg &funcArg);
132     static tuple<bool, NVal> GetCopySignalFromOptionArg(napi_env env, const NFuncArg &funcArg);
133     static int CheckOrCreatePath(const std::string &destPath);
134     static int ParseJsParam(napi_env env, NFuncArg &funcArg, std::shared_ptr<FileInfos> &fileInfos);
135 
136     // operator of local listener
137     static int ExecLocal(std::shared_ptr<FileInfos> infos, std::shared_ptr<JsCallbackObject> callback);
138     static void CopyComplete(std::shared_ptr<FileInfos> infos, std::shared_ptr<JsCallbackObject> callback);
139     static void WaitNotifyFinished(std::shared_ptr<JsCallbackObject> callback);
140     static void ReadNotifyEvent(std::shared_ptr<FileInfos> infos);
141     static int SubscribeLocalListener(std::shared_ptr<FileInfos> infos, std::shared_ptr<JsCallbackObject> callback);
142     static std::shared_ptr<JsCallbackObject> RegisterListener(napi_env env, const std::shared_ptr<FileInfos> &infos);
143     static void OnFileReceive(std::shared_ptr<FileInfos> infos);
144     static void GetNotifyEvent(std::shared_ptr<FileInfos> infos);
145     static void StartNotify(std::shared_ptr<FileInfos> infos, std::shared_ptr<JsCallbackObject> callback);
146     static uv_work_t *GetUVwork(std::shared_ptr<FileInfos> infos);
147     static void ReceiveComplete(uv_work_t *work, int stat);
148     static std::shared_ptr<JsCallbackObject> GetRegisteredListener(std::shared_ptr<FileInfos> infos);
149     static void CloseNotifyFd(std::shared_ptr<FileInfos> infos, std::shared_ptr<JsCallbackObject> callback);
150 
151     // operator of file
152     static int RecurCopyDir(const string &srcPath, const string &destPath, std::shared_ptr<FileInfos> infos);
153     static tuple<int, uint64_t> GetFileSize(const std::string &path);
154     static uint64_t GetDirSize(std::shared_ptr<FileInfos> infos, std::string path);
155     static int CopyFile(const string &src, const string &dest, std::shared_ptr<FileInfos> infos);
156     static int MakeDir(const string &path);
157     static int CopySubDir(const string &srcPath, const string &destPath, std::shared_ptr<FileInfos> infos);
158     static int CopyDirFunc(const string &src, const string &dest, std::shared_ptr<FileInfos> infos);
159     static tuple<int, std::shared_ptr<FileInfos>> CreateFileInfos(
160         const std::string &srcUri, const std::string &destUri, NVal &listener, NVal copySignal);
161     static int ExecCopy(std::shared_ptr<FileInfos> infos);
162 
163     // operator of file size
164     static int UpdateProgressSize(const std::string &filePath,
165                                   std::shared_ptr<ReceiveInfo> receivedInfo,
166                                   std::shared_ptr<JsCallbackObject> callback);
167     static tuple<bool, int, bool> HandleProgress(
168         inotify_event *event, std::shared_ptr<FileInfos> infos, std::shared_ptr<JsCallbackObject> callback);
169     static std::shared_ptr<ReceiveInfo> GetReceivedInfo(int wd, std::shared_ptr<JsCallbackObject> callback);
170     static bool CheckFileValid(const std::string &filePath, std::shared_ptr<FileInfos> infos);
171 
172     // operator of uri or path
173     static bool IsValidUri(const std::string &uri);
174     static bool IsRemoteUri(const std::string &uri);
175     static bool IsDirectory(const std::string &path);
176     static bool IsFile(const std::string &path);
177     static bool IsMediaUri(const std::string &uriPath);
178     static std::string ConvertUriToPath(const std::string &uri);
179     static std::string GetRealPath(const std::string& path);
180 };
181 } // namespace ModuleFileIO
182 } // namespace FileManagement
183 } // namespace OHOS
184 
185 #endif // FILEMANAGEMENT_FILE_API_COPY_H