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 <cstddef>
17 #include <cstdint>
18 
19 #include <base/containers/string.h>
20 #include <base/containers/string_view.h>
21 #include <base/containers/type_traits.h>
22 #include <base/containers/unique_ptr.h>
23 #include <base/containers/vector.h>
24 #include <base/namespace.h>
25 #include <base/util/uid.h>
26 #include <core/implementation_uids.h>
27 #include <core/io/intf_directory.h>
28 #include <core/io/intf_file_manager.h>
29 #include <core/io/intf_file_monitor.h>
30 #include <core/io/intf_file_system.h>
31 #include <core/io/intf_filesystem_api.h>
32 #include <core/namespace.h>
33 #include <core/plugin/intf_class_factory.h>
34 #include <core/plugin/intf_interface.h>
35 #include <core/plugin/intf_plugin.h>
36 
37 #include "dev/file_monitor.h"
38 #include "io/file_manager.h"
39 #include "io/memory_filesystem.h"
40 #include "io/path_tools.h"
41 #include "io/rofs_filesystem.h"
42 #include "io/std_filesystem.h"
43 #include "util/string_util.h"
44 
45 CORE_BEGIN_NAMESPACE();
46 namespace {
47 using BASE_NS::string;
48 using BASE_NS::string_view;
49 using BASE_NS::Uid;
50 using BASE_NS::vector;
51 
52 class FileMonitorImpl final : public IFileMonitor {
53 public:
54     const IInterface* GetInterface(const Uid& uid) const override;
55     IInterface* GetInterface(const Uid& uid) override;
56     void Ref() override;
57     void Unref() override;
58 
59     void Initialize(IFileManager&) override;
60     bool AddPath(const string_view path) override;
61     bool RemovePath(const string_view path) override;
62     void ScanModifications(vector<string>& added, vector<string>& removed, vector<string>& modified) override;
63 
64     FileMonitorImpl() = default;
FileMonitorImpl(IFileManager & manager)65     explicit FileMonitorImpl(IFileManager& manager)
66     {
67         Initialize(manager);
68     }
69 
70     BASE_NS::unique_ptr<FileMonitor> fileMonitor_;
71     uint32_t refCount_ { 0 };
72 };
73 
74 class FilesystemApi final : public IFileSystemApi {
75 public:
76     string basePath_;
77     IFilesystem::Ptr rootFs_;
FilesystemApi()78     FilesystemApi() : basePath_(GetCurrentDirectory()), rootFs_(CreateStdFileSystem()) {}
79 
GetInterface(const Uid & uid) const80     const IInterface* GetInterface(const Uid& uid) const override
81     {
82         return const_cast<FilesystemApi*>(this)->GetInterface(uid);
83     }
GetInterface(const Uid & uid)84     IInterface* GetInterface(const Uid& uid) override
85     {
86         if ((uid == IFileSystemApi::UID) || (uid == IClassFactory::UID) || (uid == IInterface::UID)) {
87             return this;
88         }
89         return nullptr;
90     }
Ref()91     void Ref() override {}
Unref()92     void Unref() override {}
93 
CreateInstance(const Uid & uid)94     IInterface::Ptr CreateInstance(const Uid& uid) override
95     {
96         if (uid == UID_FILE_MONITOR) {
97             return IInterface::Ptr(new FileMonitorImpl());
98         }
99         if (uid == UID_FILE_MANAGER) {
100             return IInterface::Ptr(new FileManager());
101         }
102         return IInterface::Ptr();
103     }
104 
CreateFilemanager()105     IFileManager::Ptr CreateFilemanager() override
106     {
107         return IInterface::Ptr(new FileManager());
108     }
CreateFilemonitor(IFileManager & manager)109     IFileMonitor::Ptr CreateFilemonitor(IFileManager& manager) override
110     {
111         return IInterface::Ptr(new FileMonitorImpl(manager));
112     }
ResolvePath(string_view inPathRaw) const113     string ResolvePath(string_view inPathRaw) const
114     {
115 #if _WIN32
116         string_view curDrive;
117         string_view curPath;
118         string_view curFilename;
119         string_view curExt;
120         SplitPath(basePath_, curDrive, curPath, curFilename, curExt);
121 
122         if (inPathRaw.empty()) {
123             return {};
124         }
125         // fix slashes. (just change \\ to /)
126         string_view pathIn = inPathRaw;
127         string tmp;
128         if (pathIn.find("\\") != string_view::npos) {
129             tmp = pathIn;
130             StringUtil::FindAndReplaceAll(tmp, "\\", "/");
131             pathIn = tmp;
132         }
133 
134         string_view drive;
135         string_view path;
136         string_view filename;
137         string_view ext;
138         SplitPath(pathIn, drive, path, filename, ext);
139         string res = "/";
140         if (drive.empty()) {
141             // relative to current drive then
142             res += curDrive;
143         } else {
144             res += drive;
145         }
146         res += ":";
147         string normalizedPath;
148         if (path.empty()) {
149             return "";
150         }
151         if (path[0] != '/') {
152             // relative path.
153             normalizedPath = NormalizePath(curPath + path);
154         } else {
155             normalizedPath = NormalizePath(path);
156         }
157         if (normalizedPath.empty()) {
158             return "";
159         }
160         return res + normalizedPath;
161 #else
162         if (IsRelative(inPathRaw)) {
163             return NormalizePath(basePath_ + inPathRaw);
164         }
165         return NormalizePath(inPathRaw);
166 #endif
167     }
168 
CreateStdFileSystem()169     IFilesystem::Ptr CreateStdFileSystem() override
170     {
171         return IFilesystem::Ptr(new StdFilesystem("/"));
172     }
173 
CreateStdFileSystem(string_view rootPathIn)174     IFilesystem::Ptr CreateStdFileSystem(string_view rootPathIn) override
175     {
176         string_view protocol;
177         string_view path;
178         if (ParseUri(rootPathIn, protocol, path)) {
179             if (protocol != "file") {
180                 return {};
181             }
182             rootPathIn = path;
183         }
184         auto rootPath = ResolvePath(rootPathIn);
185         if (!rootPath.empty()) {
186             auto entry = rootFs_->GetEntry(rootPath);
187             if (entry.type == IDirectory::Entry::DIRECTORY) {
188                 return IFilesystem::Ptr(new StdFilesystem(rootPath));
189             }
190         }
191         return {};
192     }
CreateMemFileSystem()193     IFilesystem::Ptr CreateMemFileSystem() override
194     {
195         return IFilesystem::Ptr(new MemoryFilesystem());
196     }
CreateROFilesystem(const void * const data,uint64_t size)197     IFilesystem::Ptr CreateROFilesystem(const void* const data, uint64_t size) override
198     {
199         return IFilesystem::Ptr { new RoFileSystem(data, static_cast<size_t>(size)) };
200     }
201 };
202 } // namespace
203 
GetInterface(const Uid & uid) const204 const IInterface* FileMonitorImpl::GetInterface(const Uid& uid) const
205 {
206     if ((uid == IFileMonitor::UID) || (uid == IInterface::UID)) {
207         return this;
208     }
209     return nullptr;
210 }
211 
GetInterface(const Uid & uid)212 IInterface* FileMonitorImpl::GetInterface(const Uid& uid)
213 {
214     if ((uid == IFileMonitor::UID) || (uid == IInterface::UID)) {
215         return this;
216     }
217     return nullptr;
218 }
219 
Ref()220 void FileMonitorImpl::Ref()
221 {
222     refCount_++;
223 }
224 
Unref()225 void FileMonitorImpl::Unref()
226 {
227     if (--refCount_ == 0) {
228         delete this;
229     }
230 }
231 
Initialize(IFileManager & manager)232 void FileMonitorImpl::Initialize(IFileManager& manager)
233 {
234     fileMonitor_ = BASE_NS::make_unique<FileMonitor>(manager);
235 }
236 
AddPath(const string_view path)237 bool FileMonitorImpl::AddPath(const string_view path)
238 {
239     if (fileMonitor_) {
240         return fileMonitor_->AddPath(path);
241     }
242     return false;
243 }
244 
RemovePath(const string_view path)245 bool FileMonitorImpl::RemovePath(const string_view path)
246 {
247     if (fileMonitor_) {
248         return fileMonitor_->RemovePath(path);
249     }
250     return false;
251 }
252 
ScanModifications(vector<string> & added,vector<string> & removed,vector<string> & modified)253 void FileMonitorImpl::ScanModifications(vector<string>& added, vector<string>& removed, vector<string>& modified)
254 {
255     added.clear();
256     removed.clear();
257     modified.clear();
258     if (fileMonitor_) {
259         fileMonitor_->ScanModifications(added, removed, modified);
260     }
261 }
262 
CreateFileMonitor(IClassFactory &,PluginToken)263 IInterface* CreateFileMonitor(IClassFactory& /* registry */, PluginToken /* token */)
264 {
265     return new FileMonitorImpl();
266 }
GetFileApiFactory(IClassRegister &,PluginToken)267 IInterface* GetFileApiFactory(IClassRegister& /* registry */, PluginToken /* token */)
268 {
269     static FilesystemApi fact;
270     return &fact;
271 }
272 CORE_END_NAMESPACE()
273