1*61c4878aSAndroid Build Coastguard Worker // Copyright 2021 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #define PW_LOG_MODULE_NAME "FS"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include "pw_file/flat_file_system.h"
18*61c4878aSAndroid Build Coastguard Worker
19*61c4878aSAndroid Build Coastguard Worker #include <cstddef>
20*61c4878aSAndroid Build Coastguard Worker #include <cstdint>
21*61c4878aSAndroid Build Coastguard Worker #include <string_view>
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/span.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_file/file.pwpb.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/decoder.h"
28*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/encoder.h"
29*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/serialized_size.h"
30*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/raw/server_reader_writer.h"
31*61c4878aSAndroid Build Coastguard Worker #include "pw_span/span.h"
32*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status.h"
33*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status_with_size.h"
34*61c4878aSAndroid Build Coastguard Worker
35*61c4878aSAndroid Build Coastguard Worker namespace pw::file {
36*61c4878aSAndroid Build Coastguard Worker
37*61c4878aSAndroid Build Coastguard Worker using Entry = FlatFileSystemService::Entry;
38*61c4878aSAndroid Build Coastguard Worker
EnumerateFile(Entry & entry,pwpb::ListResponse::StreamEncoder & output_encoder)39*61c4878aSAndroid Build Coastguard Worker Status FlatFileSystemService::EnumerateFile(
40*61c4878aSAndroid Build Coastguard Worker Entry& entry, pwpb::ListResponse::StreamEncoder& output_encoder) {
41*61c4878aSAndroid Build Coastguard Worker StatusWithSize sws = entry.Name(file_name_buffer_);
42*61c4878aSAndroid Build Coastguard Worker if (!sws.ok()) {
43*61c4878aSAndroid Build Coastguard Worker return sws.status();
44*61c4878aSAndroid Build Coastguard Worker }
45*61c4878aSAndroid Build Coastguard Worker {
46*61c4878aSAndroid Build Coastguard Worker pwpb::Path::StreamEncoder encoder = output_encoder.GetPathsEncoder();
47*61c4878aSAndroid Build Coastguard Worker
48*61c4878aSAndroid Build Coastguard Worker encoder
49*61c4878aSAndroid Build Coastguard Worker .WritePath(reinterpret_cast<const char*>(file_name_buffer_.data()),
50*61c4878aSAndroid Build Coastguard Worker sws.size())
51*61c4878aSAndroid Build Coastguard Worker .IgnoreError();
52*61c4878aSAndroid Build Coastguard Worker encoder.WriteSizeBytes(entry.SizeBytes()).IgnoreError();
53*61c4878aSAndroid Build Coastguard Worker encoder.WritePermissions(entry.Permissions()).IgnoreError();
54*61c4878aSAndroid Build Coastguard Worker encoder.WriteFileId(entry.FileId()).IgnoreError();
55*61c4878aSAndroid Build Coastguard Worker }
56*61c4878aSAndroid Build Coastguard Worker return output_encoder.status();
57*61c4878aSAndroid Build Coastguard Worker }
58*61c4878aSAndroid Build Coastguard Worker
EnumerateAllFiles(RawServerWriter & writer)59*61c4878aSAndroid Build Coastguard Worker void FlatFileSystemService::EnumerateAllFiles(RawServerWriter& writer) {
60*61c4878aSAndroid Build Coastguard Worker for (Entry* entry : entries_) {
61*61c4878aSAndroid Build Coastguard Worker PW_DCHECK_NOTNULL(entry);
62*61c4878aSAndroid Build Coastguard Worker // For now, don't try to pack entries.
63*61c4878aSAndroid Build Coastguard Worker pwpb::ListResponse::MemoryEncoder encoder(encoding_buffer_);
64*61c4878aSAndroid Build Coastguard Worker if (Status status = EnumerateFile(*entry, encoder); !status.ok()) {
65*61c4878aSAndroid Build Coastguard Worker if (status != Status::NotFound()) {
66*61c4878aSAndroid Build Coastguard Worker PW_LOG_ERROR("Failed to enumerate file (id: %u) with status %d",
67*61c4878aSAndroid Build Coastguard Worker static_cast<unsigned>(entry->FileId()),
68*61c4878aSAndroid Build Coastguard Worker static_cast<int>(status.code()));
69*61c4878aSAndroid Build Coastguard Worker }
70*61c4878aSAndroid Build Coastguard Worker continue;
71*61c4878aSAndroid Build Coastguard Worker }
72*61c4878aSAndroid Build Coastguard Worker
73*61c4878aSAndroid Build Coastguard Worker Status write_status = writer.Write(encoder);
74*61c4878aSAndroid Build Coastguard Worker if (!write_status.ok()) {
75*61c4878aSAndroid Build Coastguard Worker writer.Finish(write_status)
76*61c4878aSAndroid Build Coastguard Worker .IgnoreError(); // TODO: b/242598609 - Handle Status properly
77*61c4878aSAndroid Build Coastguard Worker return;
78*61c4878aSAndroid Build Coastguard Worker }
79*61c4878aSAndroid Build Coastguard Worker }
80*61c4878aSAndroid Build Coastguard Worker writer.Finish(OkStatus())
81*61c4878aSAndroid Build Coastguard Worker .IgnoreError(); // TODO: b/242598609 - Handle Status properly
82*61c4878aSAndroid Build Coastguard Worker }
83*61c4878aSAndroid Build Coastguard Worker
List(ConstByteSpan request,RawServerWriter & writer)84*61c4878aSAndroid Build Coastguard Worker void FlatFileSystemService::List(ConstByteSpan request,
85*61c4878aSAndroid Build Coastguard Worker RawServerWriter& writer) {
86*61c4878aSAndroid Build Coastguard Worker protobuf::Decoder decoder(request);
87*61c4878aSAndroid Build Coastguard Worker // If a file name was provided, try and find and enumerate the file.
88*61c4878aSAndroid Build Coastguard Worker while (decoder.Next().ok()) {
89*61c4878aSAndroid Build Coastguard Worker if (decoder.FieldNumber() !=
90*61c4878aSAndroid Build Coastguard Worker static_cast<uint32_t>(pwpb::ListRequest::Fields::kPath)) {
91*61c4878aSAndroid Build Coastguard Worker continue;
92*61c4878aSAndroid Build Coastguard Worker }
93*61c4878aSAndroid Build Coastguard Worker
94*61c4878aSAndroid Build Coastguard Worker std::string_view file_name_view;
95*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadString(&file_name_view).ok() || file_name_view.empty()) {
96*61c4878aSAndroid Build Coastguard Worker writer.Finish(Status::DataLoss())
97*61c4878aSAndroid Build Coastguard Worker .IgnoreError(); // TODO: b/242598609 - Handle Status properly
98*61c4878aSAndroid Build Coastguard Worker return;
99*61c4878aSAndroid Build Coastguard Worker }
100*61c4878aSAndroid Build Coastguard Worker
101*61c4878aSAndroid Build Coastguard Worker // Find and enumerate the file requested.
102*61c4878aSAndroid Build Coastguard Worker Result<Entry*> result = FindFile(file_name_view);
103*61c4878aSAndroid Build Coastguard Worker if (!result.ok()) {
104*61c4878aSAndroid Build Coastguard Worker writer.Finish(result.status())
105*61c4878aSAndroid Build Coastguard Worker .IgnoreError(); // TODO: b/242598609 - Handle Status properly
106*61c4878aSAndroid Build Coastguard Worker return;
107*61c4878aSAndroid Build Coastguard Worker }
108*61c4878aSAndroid Build Coastguard Worker
109*61c4878aSAndroid Build Coastguard Worker pwpb::ListResponse::MemoryEncoder encoder(encoding_buffer_);
110*61c4878aSAndroid Build Coastguard Worker Status proto_encode_status = EnumerateFile(*result.value(), encoder);
111*61c4878aSAndroid Build Coastguard Worker if (!proto_encode_status.ok()) {
112*61c4878aSAndroid Build Coastguard Worker writer.Finish(proto_encode_status)
113*61c4878aSAndroid Build Coastguard Worker .IgnoreError(); // TODO: b/242598609 - Handle Status properly
114*61c4878aSAndroid Build Coastguard Worker return;
115*61c4878aSAndroid Build Coastguard Worker }
116*61c4878aSAndroid Build Coastguard Worker
117*61c4878aSAndroid Build Coastguard Worker writer.Finish(writer.Write(encoder))
118*61c4878aSAndroid Build Coastguard Worker .IgnoreError(); // TODO: b/242598609 - Handle Status properly
119*61c4878aSAndroid Build Coastguard Worker return;
120*61c4878aSAndroid Build Coastguard Worker }
121*61c4878aSAndroid Build Coastguard Worker
122*61c4878aSAndroid Build Coastguard Worker // If no path was provided in the ListRequest, just enumerate everything.
123*61c4878aSAndroid Build Coastguard Worker EnumerateAllFiles(writer);
124*61c4878aSAndroid Build Coastguard Worker }
125*61c4878aSAndroid Build Coastguard Worker
Delete(ConstByteSpan request,rpc::RawUnaryResponder & responder)126*61c4878aSAndroid Build Coastguard Worker void FlatFileSystemService::Delete(ConstByteSpan request,
127*61c4878aSAndroid Build Coastguard Worker rpc::RawUnaryResponder& responder) {
128*61c4878aSAndroid Build Coastguard Worker protobuf::Decoder decoder(request);
129*61c4878aSAndroid Build Coastguard Worker while (decoder.Next().ok()) {
130*61c4878aSAndroid Build Coastguard Worker if (decoder.FieldNumber() !=
131*61c4878aSAndroid Build Coastguard Worker static_cast<uint32_t>(pwpb::DeleteRequest::Fields::kPath)) {
132*61c4878aSAndroid Build Coastguard Worker continue;
133*61c4878aSAndroid Build Coastguard Worker }
134*61c4878aSAndroid Build Coastguard Worker
135*61c4878aSAndroid Build Coastguard Worker std::string_view file_name_view;
136*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadString(&file_name_view).ok()) {
137*61c4878aSAndroid Build Coastguard Worker responder.Finish({}, Status::DataLoss()).IgnoreError();
138*61c4878aSAndroid Build Coastguard Worker return;
139*61c4878aSAndroid Build Coastguard Worker }
140*61c4878aSAndroid Build Coastguard Worker responder.Finish({}, FindAndDeleteFile(file_name_view)).IgnoreError();
141*61c4878aSAndroid Build Coastguard Worker return;
142*61c4878aSAndroid Build Coastguard Worker }
143*61c4878aSAndroid Build Coastguard Worker responder.Finish({}, Status::InvalidArgument()).IgnoreError();
144*61c4878aSAndroid Build Coastguard Worker }
145*61c4878aSAndroid Build Coastguard Worker
FindFile(std::string_view file_name)146*61c4878aSAndroid Build Coastguard Worker Result<Entry*> FlatFileSystemService::FindFile(std::string_view file_name) {
147*61c4878aSAndroid Build Coastguard Worker Status search_status;
148*61c4878aSAndroid Build Coastguard Worker for (Entry* entry : entries_) {
149*61c4878aSAndroid Build Coastguard Worker PW_DCHECK_NOTNULL(entry);
150*61c4878aSAndroid Build Coastguard Worker StatusWithSize sws = entry->Name(file_name_buffer_);
151*61c4878aSAndroid Build Coastguard Worker
152*61c4878aSAndroid Build Coastguard Worker // If there not an exact file name length match, don't try and check against
153*61c4878aSAndroid Build Coastguard Worker // a prefix.
154*61c4878aSAndroid Build Coastguard Worker if (!sws.ok() || file_name.length() != sws.size()) {
155*61c4878aSAndroid Build Coastguard Worker if (sws.status() != Status::NotFound()) {
156*61c4878aSAndroid Build Coastguard Worker PW_LOG_ERROR("Failed to read file name (id: %u) with status %d",
157*61c4878aSAndroid Build Coastguard Worker static_cast<unsigned>(entry->FileId()),
158*61c4878aSAndroid Build Coastguard Worker static_cast<int>(sws.status().code()));
159*61c4878aSAndroid Build Coastguard Worker }
160*61c4878aSAndroid Build Coastguard Worker continue;
161*61c4878aSAndroid Build Coastguard Worker }
162*61c4878aSAndroid Build Coastguard Worker
163*61c4878aSAndroid Build Coastguard Worker if (memcmp(file_name.data(), file_name_buffer_.data(), file_name.size()) ==
164*61c4878aSAndroid Build Coastguard Worker 0) {
165*61c4878aSAndroid Build Coastguard Worker return entry;
166*61c4878aSAndroid Build Coastguard Worker }
167*61c4878aSAndroid Build Coastguard Worker }
168*61c4878aSAndroid Build Coastguard Worker
169*61c4878aSAndroid Build Coastguard Worker search_status.Update(Status::NotFound());
170*61c4878aSAndroid Build Coastguard Worker return search_status;
171*61c4878aSAndroid Build Coastguard Worker }
172*61c4878aSAndroid Build Coastguard Worker
FindAndDeleteFile(std::string_view file_name)173*61c4878aSAndroid Build Coastguard Worker Status FlatFileSystemService::FindAndDeleteFile(std::string_view file_name) {
174*61c4878aSAndroid Build Coastguard Worker Result<Entry*> result = FindFile(file_name);
175*61c4878aSAndroid Build Coastguard Worker if (!result.ok()) {
176*61c4878aSAndroid Build Coastguard Worker return result.status();
177*61c4878aSAndroid Build Coastguard Worker }
178*61c4878aSAndroid Build Coastguard Worker
179*61c4878aSAndroid Build Coastguard Worker return result.value()->Delete();
180*61c4878aSAndroid Build Coastguard Worker }
181*61c4878aSAndroid Build Coastguard Worker
182*61c4878aSAndroid Build Coastguard Worker } // namespace pw::file
183