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#ifndef OHOS_FILE_FS_COPY_H
17#define OHOS_FILE_FS_COPY_H
18
19#include <chrono>
20#include <cstring>
21#include <map>
22#include <memory>
23#include <mutex>
24#include <set>
25#include <sys/inotify.h>
26#include <thread>
27#include "utils.h"
28#include "cj_lambda.h"
29#include "ffi_remote_data.h"
30#include "macro.h"
31#include "task_signal.h"
32#include "task_signal_impl.h"
33#include "uni_error.h"
34
35extern "C" {
36struct CProgress {
37    uint64_t processedSize;
38    uint64_t totalSize;
39};
40}
41
42namespace OHOS {
43namespace CJSystemapi {
44const uint64_t MAX_VALUE = 0x7FFFFFFFFFFFFFFF;
45struct ReceiveInfo {
46    std::string path;
47    std::map<std::string, uint64_t> fileList;
48};
49
50struct CjCallbackObject {
51    int64_t callbackId = 0;
52    int32_t notifyFd = -1;
53    int32_t eventFd = -1;
54    std::function<void(CProgress)> callback;
55    std::vector<std::pair<int, std::shared_ptr<ReceiveInfo>>> wds;
56    uint64_t totalSize = 0;
57    uint64_t progressSize = 0;
58    uint64_t maxProgressSize = 0;
59    int32_t errorCode = 0;
60    std::thread notifyHandler;
61    explicit CjCallbackObject(int64_t id) : callbackId(id)
62    {
63        if (callbackId == 0) {
64            callback = nullptr;
65            return;
66        }
67        callback = CJLambda::Create(reinterpret_cast<void(*)(CProgress)>(callbackId));
68    }
69    void CloseFd()
70    {
71        if (eventFd != -1) {
72            close(eventFd);
73            eventFd = -1;
74        }
75        if (notifyFd == -1) {
76            return;
77        }
78        for (auto item : wds) {
79            inotify_rm_watch(notifyFd, item.first);
80        }
81        close(notifyFd);
82        notifyFd = -1;
83    }
84    ~CjCallbackObject()
85    {
86        CloseFd();
87    }
88};
89
90struct FileInfos {
91    std::string srcUri;
92    std::string destUri;
93    std::string srcPath;
94    std::string destPath;
95    std::chrono::steady_clock::time_point notifyTime;
96    int32_t notifyFd = -1;
97    int32_t eventFd = -1;
98    bool run = true;
99    bool hasListener = false;
100    int64_t listenerId = 0;
101    int64_t copySignalId = 0;
102    int64_t exceptionCode = FileFs::ERRNO_NOERR;
103    std::shared_ptr<DistributedFS::ModuleTaskSignal::TaskSignal> taskSignal = nullptr;
104    std::set<std::string> filePaths;
105    bool operator==(const FileInfos &infos) const
106    {
107        return (srcUri == infos.srcUri && destUri == infos.destUri);
108    }
109    bool operator<(const FileInfos &infos) const
110    {
111        if (srcUri == infos.srcUri) {
112            return destUri < infos.destUri;
113        }
114        return srcUri < infos.srcUri;
115    }
116};
117
118class CopyInfo : public OHOS::FFI::FFIData {
119    friend class CopyImpl;
120public:
121    CopyInfo(int64_t listener, int64_t signal) : listenerId(listener), signalId(signal) {}
122    ~CopyInfo();
123private:
124    int64_t listenerId = 0;
125    int64_t signalId = 0;
126};
127
128class CopyImpl final {
129public:
130    static std::map<FileInfos, std::shared_ptr<CjCallbackObject>> cjCbMap_;
131    static std::recursive_mutex mutex_;
132    static void UnregisterListener(std::shared_ptr<FileInfos> fileInfos);
133    static void Copy(const char* srcUri, const char* destUri, sptr<CopyInfo> info);
134private:
135    static int UpdateProgressSize(const std::string &filePath,
136                                  std::shared_ptr<ReceiveInfo> receivedInfo,
137                                  std::shared_ptr<CjCallbackObject> callback);
138    static void StartNotify(std::shared_ptr<FileInfos> infos, std::shared_ptr<CjCallbackObject> callback);
139    static bool IsRemoteUri(const std::string& uri);
140    static int64_t DoCopy(std::shared_ptr<FileInfos> infos, std::shared_ptr<CjCallbackObject> callback);
141    static int64_t ExecLocal(std::shared_ptr<FileInfos>& infos, std::shared_ptr<CjCallbackObject>& callback);
142    static void CloseNotifyFd(std::shared_ptr<FileInfos>& infos, std::shared_ptr<CjCallbackObject>& callback);
143    static void WaitNotifyFinished(std::shared_ptr<CjCallbackObject>& callback);
144    static void CopyComplete(std::shared_ptr<FileInfos>& infos, std::shared_ptr<CjCallbackObject>& callback);
145    static std::shared_ptr<FileInfos> InitCjFileInfo(
146        const std::string& srcUri, const std::string& destUri, sptr<CopyInfo> info);
147    static std::shared_ptr<CjCallbackObject> RegisterListener(std::shared_ptr<FileInfos>& infos);
148    static bool IsFile(const std::string &path);
149    static void CheckOrCreatePath(const std::string &destPath);
150    static int64_t SubscribeLocalListener(std::shared_ptr<FileInfos>& infos,
151                                          std::shared_ptr<CjCallbackObject>& callback);
152    static int ExecCopy(std::shared_ptr<FileInfos> infos);
153    static int CopyFile(const std::string &src, const std::string &dest, std::shared_ptr<FileInfos> infos);
154    static bool IsDirectory(const std::string &path);
155    static std::tuple<int, uint64_t> GetFileSize(const std::string &path);
156    static int MakeDir(const std::string &path);
157    static int CopySubDir(const std::string &srcPath, const std::string &destPath, std::shared_ptr<FileInfos> infos);
158    static int CopyDirFunc(const std::string &src, const std::string &dest, std::shared_ptr<FileInfos> infos);
159    static uint64_t GetDirSize(std::shared_ptr<FileInfos> infos, std::string path);
160    static int RecurCopyDir(const std::string &srcPath, const std::string &destPath, std::shared_ptr<FileInfos> infos);
161    static void GetNotifyEvent(std::shared_ptr<FileInfos> infos);
162    static bool CheckFileValid(const std::string &filePath, std::shared_ptr<FileInfos> infos);
163    static void OnFileReceive(std::shared_ptr<FileInfos> infos);
164    static std::shared_ptr<CjCallbackObject> GetRegisteredListener(std::shared_ptr<FileInfos> infos);
165    static std::shared_ptr<ReceiveInfo> GetReceivedInfo(int wd, std::shared_ptr<CjCallbackObject> callback);
166    static void ReadNotifyEvent(std::shared_ptr<FileInfos> infos);
167    static std::string GetRealPath(const std::string& path);
168    static std::tuple<bool, int, bool> HandleProgress(inotify_event *event,
169                                                 std::shared_ptr<FileInfos> infos,
170                                                 std::shared_ptr<CjCallbackObject> callback);
171    static void ReceiveComplete(CProgress data,
172                                std::shared_ptr<FileInfos> infos,
173                                std::shared_ptr<CjCallbackObject> callback);
174};
175}
176}
177
178#endif // OHOS_FILE_FS_COPY_H
179