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 "proxy_filesystem.h"
17 
18 #include <algorithm>
19 #include <cstring>
20 
21 #include <base/containers/iterator.h>
22 #include <base/containers/string.h>
23 #include <base/containers/string_view.h>
24 #include <base/containers/type_traits.h>
25 #include <base/containers/unique_ptr.h>
26 #include <base/containers/vector.h>
27 #include <base/namespace.h>
28 #include <core/io/intf_directory.h>
29 #include <core/io/intf_file.h>
30 #include <core/namespace.h>
31 
32 #include "file_manager.h"
33 #include "path_tools.h"
34 #include "proxy_directory.h"
35 
36 CORE_BEGIN_NAMESPACE()
37 using BASE_NS::move;
38 using BASE_NS::string;
39 using BASE_NS::string_view;
40 using BASE_NS::vector;
41 
ProxyFilesystem(FileManager & fileManager,const string_view destination)42 ProxyFilesystem::ProxyFilesystem(FileManager& fileManager, const string_view destination)
43     : fileManager_(fileManager), destinations_()
44 {
45     AppendSearchPath(destination);
46 }
47 
AppendSearchPath(string_view path)48 void ProxyFilesystem::AppendSearchPath(string_view path)
49 {
50     if (path.back() == '/') {
51         path.remove_suffix(1);
52     }
53     destinations_.emplace_back(path);
54 }
55 
PrependSearchPath(string_view path)56 void ProxyFilesystem::PrependSearchPath(string_view path)
57 {
58     if (path.back() == '/') {
59         path.remove_suffix(1);
60     }
61     destinations_.emplace(destinations_.begin(), path);
62 }
63 
RemoveSearchPath(string_view destination)64 void ProxyFilesystem::RemoveSearchPath(string_view destination)
65 {
66     if (destination.back() == '/') {
67         destination.remove_suffix(1);
68     }
69     const auto it = std::find(destinations_.cbegin(), destinations_.cend(), destination);
70     if (it != destinations_.cend()) {
71         destinations_.erase(it);
72     }
73 }
74 
GetEntry(const string_view path)75 IDirectory::Entry ProxyFilesystem::GetEntry(const string_view path)
76 {
77     auto normalizedPath = NormalizePath(path);
78     if (!normalizedPath.empty()) {
79         for (auto&& destination : destinations_) {
80             auto file = fileManager_.GetEntry(destination + normalizedPath);
81             if (file.type != IDirectory::Entry::UNKNOWN) {
82                 return file;
83             }
84         }
85     }
86     return {};
87 }
OpenFile(const string_view path)88 IFile::Ptr ProxyFilesystem::OpenFile(const string_view path)
89 {
90     auto normalizedPath = NormalizePath(path);
91     if (!normalizedPath.empty()) {
92         for (auto&& destination : destinations_) {
93             auto file = fileManager_.OpenFile(destination + normalizedPath);
94             if (file) {
95                 return file;
96             }
97         }
98     }
99 
100     return IFile::Ptr();
101 }
102 
CreateFile(const string_view path)103 IFile::Ptr ProxyFilesystem::CreateFile(const string_view path)
104 {
105     auto normalizedPath = NormalizePath(path);
106     if (!normalizedPath.empty()) {
107         for (auto&& destination : destinations_) {
108             auto file = fileManager_.CreateFile(destination + normalizedPath);
109             if (file) {
110                 return file;
111             }
112         }
113     }
114 
115     return IFile::Ptr();
116 }
117 
DeleteFile(const string_view path)118 bool ProxyFilesystem::DeleteFile(const string_view path)
119 {
120     auto normalizedPath = NormalizePath(path);
121     if (!normalizedPath.empty()) {
122         for (auto&& destination : destinations_) {
123             if (fileManager_.DeleteFile(destination + normalizedPath)) {
124                 return true;
125             }
126         }
127     }
128 
129     return false;
130 }
131 
OpenDirectory(const string_view path)132 IDirectory::Ptr ProxyFilesystem::OpenDirectory(const string_view path)
133 {
134     IDirectory::Ptr proxyDirectory;
135     vector<IDirectory::Ptr> directories;
136     auto normalizedPath = NormalizePath(path);
137     if (!normalizedPath.empty()) {
138         for (auto&& destination : destinations_) {
139             auto directory = fileManager_.OpenDirectory(destination + normalizedPath);
140             if (directory) {
141                 directories.push_back(move(directory));
142             }
143         }
144     }
145 
146     if (!directories.empty()) {
147         proxyDirectory.reset(new ProxyDirectory(move(directories)));
148     }
149 
150     return proxyDirectory;
151 }
152 
CreateDirectory(const string_view path)153 IDirectory::Ptr ProxyFilesystem::CreateDirectory(const string_view path)
154 {
155     auto normalizedPath = NormalizePath(path);
156     if (!normalizedPath.empty()) {
157         for (auto&& destination : destinations_) {
158             auto directory = fileManager_.CreateDirectory(destination + normalizedPath);
159             if (directory) {
160                 return directory;
161             }
162         }
163     }
164 
165     return IDirectory::Ptr();
166 }
167 
DeleteDirectory(const string_view path)168 bool ProxyFilesystem::DeleteDirectory(const string_view path)
169 {
170     auto normalizedPath = NormalizePath(path);
171     if (!normalizedPath.empty()) {
172         for (auto&& destination : destinations_) {
173             if (fileManager_.DeleteDirectory(destination + normalizedPath)) {
174                 return true;
175             }
176         }
177     }
178 
179     return false;
180 }
181 
Rename(const string_view fromPath,const string_view toPath)182 bool ProxyFilesystem::Rename(const string_view fromPath, const string_view toPath)
183 {
184     if (!fromPath.empty() && !toPath.empty()) {
185         auto pathFrom = NormalizePath(fromPath);
186         auto pathTo = NormalizePath(toPath);
187         for (auto&& destination : destinations_) {
188             if (fileManager_.Rename(destination + pathFrom, destination + pathTo)) {
189                 return true;
190             }
191         }
192     }
193 
194     return false;
195 }
196 
GetUriPaths(const string_view uri) const197 vector<string> ProxyFilesystem::GetUriPaths(const string_view uri) const
198 {
199     vector<string> paths;
200 
201     auto path = NormalizePath(uri);
202     if (!path.empty()) {
203         for (auto&& destination : destinations_) {
204             auto directory = fileManager_.OpenDirectory(destination + path);
205             if (directory) {
206                 paths.push_back(destination + path);
207             }
208         }
209     }
210 
211     return paths;
212 }
213 CORE_END_NAMESPACE()
214