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