• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "rofs_filesystem.h"
17 
18 #include <algorithm>
19 #include <cstdint>
20 
21 #include <base/containers/allocator.h>
22 #include <base/containers/array_view.h>
23 #include <base/containers/iterator.h>
24 #include <base/containers/string.h>
25 #include <base/containers/string_view.h>
26 #include <base/containers/type_traits.h>
27 #include <base/containers/vector.h>
28 #include <base/namespace.h>
29 #include <core/io/intf_directory.h>
30 #include <core/io/intf_file.h>
31 #include <core/log.h>
32 #include <core/namespace.h>
33 
34 CORE_BEGIN_NAMESPACE()
35 namespace {
36 using BASE_NS::array_view;
37 using BASE_NS::CloneData;
38 using BASE_NS::move;
39 using BASE_NS::string;
40 using BASE_NS::string_view;
41 using BASE_NS::vector;
42 
43 struct FsEntry {
44     const char fname[256];
45     const uint64_t offset;
46     const uint64_t size;
47 };
48 
49 /** Read-only memory file. */
50 class ROFSMemoryFile final : public IFile {
51 public:
52     ~ROFSMemoryFile() override = default;
ROFSMemoryFile(const uint8_t * const data,const size_t size)53     ROFSMemoryFile(const uint8_t* const data, const size_t size) : data_(data), size_(size) {}
54     ROFSMemoryFile(const ROFSMemoryFile&) = delete;
55     ROFSMemoryFile(ROFSMemoryFile&&) = delete;
56     ROFSMemoryFile& operator=(const ROFSMemoryFile&) = delete;
57     ROFSMemoryFile& operator=(ROFSMemoryFile&&) = delete;
58 
GetMode() const59     Mode GetMode() const override
60     {
61         return IFile::Mode::READ_ONLY;
62     }
63 
Close()64     void Close() override {}
65 
Read(void * buffer,uint64_t count)66     uint64_t Read(void* buffer, uint64_t count) override
67     {
68         uint64_t toRead = count;
69         if ((index_ + toRead) > size_) {
70             toRead = size_ - index_;
71         }
72 
73         if (toRead > 0) {
74             if (toRead <= SIZE_MAX) {
75                 if (CloneData(buffer, static_cast<size_t>(count), data_ + index_, static_cast<size_t>(toRead))) {
76                     index_ += toRead;
77                 }
78             } else {
79                 CORE_ASSERT_MSG(false, "Unable to read chunks bigger than (SIZE_MAX) bytes.");
80                 toRead = 0;
81             }
82         }
83 
84         return toRead;
85     }
86 
Write(const void *,uint64_t)87     uint64_t Write(const void* /* buffer */, uint64_t /* count */) override
88     {
89         return 0;
90     }
91 
Append(const void *,uint64_t,uint64_t)92     uint64_t Append(const void* /* buffer */, uint64_t /* count */, uint64_t /* chunkSize */) override
93     {
94         return 0;
95     }
96 
GetLength() const97     uint64_t GetLength() const override
98     {
99         return size_;
100     }
101 
Seek(uint64_t offset)102     bool Seek(uint64_t offset) override
103     {
104         if (offset < size_) {
105             index_ = offset;
106             return true;
107         }
108 
109         return false;
110     }
111 
GetPosition() const112     uint64_t GetPosition() const override
113     {
114         return index_;
115     }
116 
117 protected:
Destroy()118     void Destroy() override
119     {
120         delete this;
121     }
122 
123 private:
124     uint64_t index_ { 0 };
125     const uint8_t* const data_;
126     const size_t size_;
127 };
128 
129 class ROFSMemoryDirectory final : public IDirectory {
130 public:
131     ~ROFSMemoryDirectory() override = default;
132 
ROFSMemoryDirectory(const vector<IDirectory::Entry> & contents)133     explicit ROFSMemoryDirectory(const vector<IDirectory::Entry>& contents) : contents_(contents) {}
134 
135     ROFSMemoryDirectory(const ROFSMemoryDirectory&) = delete;
136     ROFSMemoryDirectory(ROFSMemoryDirectory&&) = delete;
137     ROFSMemoryDirectory& operator=(const ROFSMemoryDirectory&) = delete;
138     ROFSMemoryDirectory& operator=(ROFSMemoryDirectory&&) = delete;
139 
Close()140     void Close() override {}
141 
GetEntries() const142     vector<Entry> GetEntries() const override
143     {
144         return contents_;
145     }
146 
147 protected:
Destroy()148     void Destroy() override
149     {
150         delete this;
151     }
152 
153 private:
154     const vector<IDirectory::Entry>& contents_;
155 };
156 
Trim(string_view path)157 string_view Trim(string_view path)
158 {
159     // remove leading and trailing slash..
160     if (!path.empty()) {
161         if (path.back() == '/') {
162             path.remove_suffix(1U);
163         }
164     }
165     if (!path.empty()) {
166         if (path.front() == '/') {
167             path.remove_prefix(1);
168         }
169     }
170     return path;
171 }
172 } // namespace
173 
RoFileSystem(const void * const blob,size_t blobSize)174 RoFileSystem::RoFileSystem(const void* const blob, size_t blobSize)
175 {
176     for (const auto& romEntry : array_view(static_cast<const FsEntry*>(blob), blobSize)) {
177         if (romEntry.fname[0] == 0) {
178             break;
179         }
180         IDirectory::Entry entry;
181         const string_view tmp = romEntry.fname;
182         size_t t = 0;
183         string path;
184         // parse the rom entry name and add all missing directories.
185         for (;;) {
186             const size_t t2 = tmp.find_first_of('/', t);
187             if (t2 == string_view::npos) {
188                 break;
189             }
190             t = t2;
191             const auto pathLength = path.length();
192             entry.name = tmp.substr(pathLength, t - pathLength);
193             path.reserve(pathLength + entry.name.length() + 1U);
194             path += entry.name;
195             path += '/';
196             ++t;
197             if (directories_.find(path) != directories_.end()) {
198                 continue;
199             }
200             // new directory seen
201             entry.type = IDirectory::Entry::DIRECTORY;
202             const auto& parentDir = Trim(path.substr(0, pathLength));
203             if (const auto pos = directories_.find(parentDir); pos != directories_.cend()) {
204                 // add each subdirectory only once
205                 if (std::none_of(pos->second.cbegin(), pos->second.cend(), [&entry](const IDirectory::Entry& child) {
206                         return child.type == entry.type && child.name == entry.name;
207                     })) {
208                     pos->second.push_back(move(entry));
209                 }
210             } else {
211                 directories_[parentDir].push_back(move(entry));
212             }
213             directories_[path.substr(0, path.length() - 1)].reserve(1);
214         }
215         // add the file entry..
216         entry.name = tmp.substr(t);
217         entry.type = IDirectory::Entry::FILE;
218         const auto pathLength = path.length();
219         path.reserve(pathLength + entry.name.length());
220         path += entry.name;
221         directories_[Trim(path.substr(0, pathLength))].push_back(move(entry));
222         auto* data = reinterpret_cast<const uint8_t*>(blob) + romEntry.offset;
223         files_[move(path)] = array_view(data, static_cast<size_t>(romEntry.size));
224     }
225 }
226 
GetEntry(const string_view uri)227 IDirectory::Entry RoFileSystem::GetEntry(const string_view uri)
228 {
229     const string_view t = Trim(uri);
230     // check if it's a file first...
231     const auto it = files_.find(t);
232     if (it != files_.end()) {
233         return { IDirectory::Entry::FILE, string(uri), 0 };
234     }
235     // is it a directory then
236     const auto it2 = directories_.find(t);
237     if (it2 != directories_.end()) {
238         return { IDirectory::Entry::DIRECTORY, string(uri), 0 };
239     }
240     // nope. does not exist.
241     return {};
242 }
243 
OpenFile(const string_view path,const IFile::Mode mode)244 IFile::Ptr RoFileSystem::OpenFile(const string_view path, const IFile::Mode mode)
245 {
246     if (mode == IFile::Mode::READ_ONLY) {
247         auto it = files_.find(Trim(path));
248         if (it != files_.end()) {
249             return IFile::Ptr { new ROFSMemoryFile(it->second.data(), it->second.size()) };
250         }
251     }
252     return {};
253 }
254 
CreateFile(const string_view)255 IFile::Ptr RoFileSystem::CreateFile(const string_view /* path */)
256 {
257     return {};
258 }
259 
DeleteFile(const string_view)260 bool RoFileSystem::DeleteFile(const string_view /* path */)
261 {
262     return false;
263 }
264 
FileExists(const string_view path) const265 bool RoFileSystem::FileExists(const string_view path) const
266 {
267     return files_.contains(Trim(path));
268 }
269 
OpenDirectory(const string_view path)270 IDirectory::Ptr RoFileSystem::OpenDirectory(const string_view path)
271 {
272     auto it = directories_.find(Trim(path));
273     if (it != directories_.end()) {
274         return IDirectory::Ptr { new ROFSMemoryDirectory(it->second) };
275     }
276     return {};
277 }
278 
CreateDirectory(const string_view)279 IDirectory::Ptr RoFileSystem::CreateDirectory(const string_view /* path */)
280 {
281     return {};
282 }
283 
DeleteDirectory(const string_view)284 bool RoFileSystem::DeleteDirectory(const string_view /* path */)
285 {
286     return false;
287 }
288 
DirectoryExists(const string_view path) const289 bool RoFileSystem::DirectoryExists(const string_view path) const
290 {
291     return directories_.contains(Trim(path));
292 }
293 
Rename(const string_view,const string_view)294 bool RoFileSystem::Rename(const string_view /* fromPath */, const string_view /* toPath */)
295 {
296     return false;
297 }
298 
GetUriPaths(const string_view) const299 vector<string> RoFileSystem::GetUriPaths(const string_view) const
300 {
301     return {};
302 }
303 CORE_END_NAMESPACE()
304