xref: /aosp_15_r20/external/pigweed/pw_file/flat_file_system.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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