• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "io/file_manager.h"
17 
18 #include <algorithm>
19 
20 #include <core/io/intf_file_manager.h>
21 #include <core/log.h>
22 #include <core/namespace.h>
23 
24 #include "io/path_tools.h"
25 #include "io/proxy_filesystem.h"
26 #include "io/rofs_filesystem.h"
27 #include "io/std_directory.h"
28 
29 CORE_BEGIN_NAMESPACE()
30 using BASE_NS::make_unique;
31 using BASE_NS::string;
32 using BASE_NS::string_view;
33 using BASE_NS::Uid;
34 using BASE_NS::vector;
35 
FixPath(string_view pathIn) const36 string FileManager::FixPath(string_view pathIn) const
37 {
38     string_view protocol, path;
39     if (ParseUri(pathIn, protocol, path)) {
40         // Try to identify relative "file" uris, and convert them to absolute.
41         if (protocol == "file") {
42             if (path.empty()) {
43                 // so it's the base path then? (empty relative path)
44                 return protocol + "://" + basePath_;
45             }
46 #if _WIN32
47             // Handle win32 specific drive letters.
48             if (IsRelative(path)) {
49                 // might still be absolute (if it has drive letter)
50                 if ((path.size() > 1) && (path[1] == ':')) {
51                     // seems to start with drive letter so, it must be absolute?
52                     if (path.size() == 2) { // 2: path size
53                         // has only drive letter? consider it as root of drive then
54                         return protocol + ":///" + path + "/";
55                     }
56                     return protocol + ":///" + path;
57                 }
58                 // no drive letter so it's really relative.
59                 return protocol + "://" + NormalizePath(basePath_ + path);
60             }
61             // Even if it's "absolute" it might still be missing the drive letter.
62             if ((path.size() < 3) || (path[2] != ':')) { // 3: path size limit; 2: the third letter
63                 // seems to be missing the drive letter.
64                 return protocol + "://" + NormalizePath(basePath_.substr(0, 3) + path); // 3: substring size
65             }
66             if (path.size() == 3) { // 3: path size
67                 // has only drive letter? consider it as root of drive then
68                 return protocol + "://" + path + "/";
69             }
70             return protocol + "://" + NormalizePath(path);
71 #else
72             if (IsRelative(path)) {
73                 // normalize it with current path..
74                 return protocol + "://" + NormalizePath(basePath_ + path);
75             }
76             return protocol + "://" + NormalizePath(path);
77 #endif
78         }
79     }
80     return string(pathIn);
81 }
82 
FileManager()83 FileManager::FileManager() : basePath_(GetCurrentDirectory()) {}
84 
GetInterface(const Uid & uid) const85 const IInterface* FileManager::GetInterface(const Uid& uid) const
86 {
87     return const_cast<FileManager*>(this)->GetInterface(uid);
88 }
89 
GetInterface(const Uid & uid)90 IInterface* FileManager::GetInterface(const Uid& uid)
91 {
92     if ((uid == IInterface::UID) || (uid == IFileManager::UID)) {
93         return this;
94     }
95     return nullptr;
96 }
97 
Ref()98 void FileManager::Ref()
99 {
100     refCount_++;
101 }
102 
Unref()103 void FileManager::Unref()
104 {
105     if (--refCount_ == 0) {
106         delete this;
107     }
108 }
109 
OpenFile(const string_view uriIn)110 IFile::Ptr FileManager::OpenFile(const string_view uriIn)
111 {
112     string_view protocol, path;
113     auto uri = FixPath(uriIn);
114     if (ParseUri(uri, protocol, path)) {
115         IFilesystem* filesystem = GetFilesystem(protocol);
116         if (filesystem) {
117             return filesystem->OpenFile(path);
118         } else {
119             CORE_LOG_E("Failed to open file, no file system for uri: '%s'", string(uri).c_str());
120         }
121     } else {
122         CORE_LOG_E("Failed to open file, invalid uri: '%s'", string(uri).c_str());
123     }
124 
125     return IFile::Ptr();
126 }
127 
CreateFile(const string_view uriIn)128 IFile::Ptr FileManager::CreateFile(const string_view uriIn)
129 {
130     string_view protocol, path;
131     auto uri = FixPath(uriIn);
132     if (ParseUri(uri, protocol, path)) {
133         IFilesystem* filesystem = GetFilesystem(protocol);
134         if (filesystem) {
135             return filesystem->CreateFile(path);
136         } else {
137             CORE_LOG_E("Failed to create file, no file system for uri: '%s'", string(uri).c_str());
138         }
139     } else {
140         CORE_LOG_E("Failed to create file, invalid uri: '%s'", string(uri).c_str());
141     }
142 
143     return IFile::Ptr();
144 }
145 
DeleteFile(const string_view uriIn)146 bool FileManager::DeleteFile(const string_view uriIn)
147 {
148     string_view protocol, path;
149     auto uri = FixPath(uriIn);
150     if (ParseUri(uri, protocol, path)) {
151         IFilesystem* filesystem = GetFilesystem(protocol);
152         if (filesystem) {
153             return filesystem->DeleteFile(path);
154         }
155     }
156 
157     return false;
158 }
159 
Rename(const string_view fromUri,const string_view toUri)160 bool FileManager::Rename(const string_view fromUri, const string_view toUri)
161 {
162     string_view fromProtocol, fromPath;
163     string_view toProtocol, toPath;
164     auto from = FixPath(fromUri);
165     auto to = FixPath(toUri);
166 
167     if (ParseUri(from, fromProtocol, fromPath)) {
168         if (ParseUri(to, toProtocol, toPath)) {
169             if (fromProtocol == toProtocol) {
170                 IFilesystem* filesystem = GetFilesystem(fromProtocol);
171                 if (filesystem) {
172                     return filesystem->Rename(fromPath, toPath);
173                 }
174             } else {
175                 CORE_LOG_E("Rename requires both uris have same protocol");
176             }
177         }
178     }
179 
180     return false;
181 }
182 
GetEntry(const string_view uriIn)183 IDirectory::Entry FileManager::GetEntry(const string_view uriIn)
184 {
185     string_view protocol, path;
186     auto uri = FixPath(uriIn);
187     if (ParseUri(uri, protocol, path)) {
188         IFilesystem* filesystem = GetFilesystem(protocol);
189         if (filesystem) {
190             return filesystem->GetEntry(path);
191         } else {
192             CORE_LOG_E("Failed to get entry for uri, no file system for uri: '%s'", string(uri).c_str());
193         }
194     } else {
195         CORE_LOG_E("Failed to get entry for uri, invalid uri: '%s'", string(uri).c_str());
196     }
197 
198     return {};
199 }
OpenDirectory(const string_view uriIn)200 IDirectory::Ptr FileManager::OpenDirectory(const string_view uriIn)
201 {
202     string_view protocol, path;
203     auto uri = FixPath(uriIn);
204     if (ParseUri(uri, protocol, path)) {
205         IFilesystem* filesystem = GetFilesystem(protocol);
206         if (filesystem) {
207             return filesystem->OpenDirectory(path);
208         } else {
209             CORE_LOG_E("Failed to open directory, no file system for uri: '%s'", string(uri).c_str());
210         }
211     } else {
212         CORE_LOG_E("Failed to open directory, invalid uri: '%s'", string(uri).c_str());
213     }
214 
215     return IDirectory::Ptr();
216 }
217 
CreateDirectory(const string_view uriIn)218 IDirectory::Ptr FileManager::CreateDirectory(const string_view uriIn)
219 {
220     string_view protocol, path;
221     auto uri = FixPath(uriIn);
222     if (ParseUri(uri, protocol, path)) {
223         IFilesystem* filesystem = GetFilesystem(protocol);
224         if (filesystem) {
225             return filesystem->CreateDirectory(path);
226         } else {
227             CORE_LOG_E("Failed to create directory, no file system for uri: '%s'", string(uri).c_str());
228         }
229     } else {
230         CORE_LOG_E("Failed to create directory, invalid uri: '%s'", string(uri).c_str());
231     }
232 
233     return IDirectory::Ptr();
234 }
235 
DeleteDirectory(const string_view uriIn)236 bool FileManager::DeleteDirectory(const string_view uriIn)
237 {
238     string_view protocol, path;
239     auto uri = FixPath(uriIn);
240     if (ParseUri(uri, protocol, path)) {
241         IFilesystem* filesystem = GetFilesystem(protocol);
242         if (filesystem) {
243             return filesystem->DeleteDirectory(path);
244         }
245     }
246 
247     return false;
248 }
249 
RegisterFilesystem(const string_view protocol,IFilesystem::Ptr filesystem)250 void FileManager::RegisterFilesystem(const string_view protocol, IFilesystem::Ptr filesystem)
251 {
252     CORE_ASSERT_MSG(filesystems_.find(protocol) == filesystems_.end(), "File system already registered");
253 
254     filesystems_[protocol] = std::move(filesystem);
255 }
256 
UnregisterFilesystem(const string_view protocol)257 void FileManager::UnregisterFilesystem(const string_view protocol)
258 {
259     const auto iterator = filesystems_.find(protocol);
260     if (iterator != filesystems_.end()) {
261         filesystems_.erase(iterator);
262     }
263 }
264 
RegisterAssetPath(const string_view uriIn)265 void FileManager::RegisterAssetPath(const string_view uriIn)
266 {
267     auto uri = FixPath(uriIn);
268     RegisterPath("assets", uri, false);
269 }
270 
UnregisterAssetPath(const string_view uriIn)271 void FileManager::UnregisterAssetPath(const string_view uriIn)
272 {
273     auto uri = FixPath(uriIn);
274     UnregisterPath("assets", uri);
275 }
276 
GetAbsolutePaths(const string_view uriIn) const277 vector<string> FileManager::GetAbsolutePaths(const string_view uriIn) const
278 {
279     vector<string> ret;
280     string_view protocol, path;
281     auto uri = FixPath(uriIn);
282     if (ParseUri(uri, protocol, path)) {
283         const IFilesystem* filesystem = GetFilesystem(protocol);
284         if (filesystem) {
285             // a single URI path can be found in several paths in a proxy filesystem
286             auto uriPaths = filesystem->GetUriPaths(path);
287             for (auto& uriPath : uriPaths) {
288                 if (uriPath.find("file://") == string::npos) {
289                     auto tmp = GetAbsolutePaths(uriPath);
290                     ret.insert(ret.end(), tmp.begin(), tmp.end());
291                 } else {
292                     ret.emplace_back(std::move(uriPath));
293                 }
294             }
295         }
296     }
297     std::transform(ret.begin(), ret.end(), ret.begin(), [](const string& uri) {
298         string_view protocol, path;
299         if (ParseUri(uri, protocol, path)) {
300             return StdDirectory::ResolveAbsolutePath(path, true);
301         }
302         return uri;
303     });
304 
305     return ret;
306 }
307 
RegisterPath(const string_view protocol,const string_view uriIn,bool prepend)308 bool FileManager::RegisterPath(const string_view protocol, const string_view uriIn, bool prepend)
309 {
310     auto uri = FixPath(uriIn);
311     // Check if the proxy protocol exists already.
312     auto it = proxyFilesystems_.find(protocol);
313     if (it != proxyFilesystems_.end()) {
314         // Yes, add the new search path to it.
315         if (prepend) {
316             it->second->PrependSearchPath(uri);
317         } else {
318             it->second->AppendSearchPath(uri);
319         }
320         return true;
321     }
322 
323     // Check if the protocol is already declared..
324     const auto itp = filesystems_.find(protocol);
325     if (itp != filesystems_.end()) {
326         // Okay there is a protocol handler already, we can't add paths to non-proxy protocols.
327         CORE_LOG_W("Tried to register a path to non-proxy filesystem. protocol [%s] uriIn [%s]",
328             string(protocol).c_str(), string(uriIn).c_str());
329         return false;
330     }
331 
332     // Create new proxy protocol handler.
333     auto pfs = make_unique<ProxyFilesystem>(*this, uri);
334     proxyFilesystems_[protocol] = pfs.get();
335     RegisterFilesystem(protocol, IFilesystem::Ptr { pfs.release() });
336     return true;
337 }
338 
UnregisterPath(const string_view protocol,const string_view uriIn)339 void FileManager::UnregisterPath(const string_view protocol, const string_view uriIn)
340 {
341     auto uri = FixPath(uriIn);
342     auto it = proxyFilesystems_.find(protocol);
343     if (it != proxyFilesystems_.end()) {
344         it->second->RemoveSearchPath(uri);
345     }
346 }
347 
GetFilesystem(const string_view protocol) const348 IFilesystem* FileManager::GetFilesystem(const string_view protocol) const
349 {
350     const auto it = filesystems_.find(protocol);
351     if (it != filesystems_.end()) {
352         return it->second.get();
353     }
354 
355     return nullptr;
356 }
357 
CreateROFilesystem(const void * const data,uint64_t size)358 IFilesystem::Ptr FileManager::CreateROFilesystem(const void* const data, uint64_t size)
359 {
360     return IFilesystem::Ptr { new RoFileSystem(data, static_cast<size_t>(size)) };
361 }
362 CORE_END_NAMESPACE()
363