blob: 48aaf6952470a7649f7b6ab2f9d6656d77635703 [file] [log] [blame]
Armando Montanez5be54582021-09-02 13:58:52 -07001// Copyright 2021 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://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, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15#define PW_LOG_MODULE_NAME "FS"
16
17#include "pw_file/flat_file_system.h"
18
19#include <cstddef>
20#include <cstdint>
21#include <span>
22#include <string_view>
23
24#include "pw_assert/check.h"
25#include "pw_bytes/span.h"
26#include "pw_file/file.pwpb.h"
27#include "pw_log/log.h"
28#include "pw_protobuf/decoder.h"
29#include "pw_protobuf/encoder.h"
30#include "pw_protobuf/serialized_size.h"
31#include "pw_rpc/raw/server_reader_writer.h"
32#include "pw_status/status.h"
33#include "pw_status/status_with_size.h"
34
35namespace pw::file {
36
Armando Montanezc1d79202021-09-30 15:25:49 -070037using Entry = FlatFileSystemService::Entry;
Armando Montanez5be54582021-09-02 13:58:52 -070038
39Status FlatFileSystemService::EnumerateFile(
Armando Montanezc1d79202021-09-30 15:25:49 -070040 Entry& entry, pw::file::ListResponse::StreamEncoder& output_encoder) {
Armando Montanez5be54582021-09-02 13:58:52 -070041 StatusWithSize sws = entry.Name(file_name_buffer_);
42 if (!sws.ok()) {
43 return sws.status();
44 }
45 {
46 pw::file::Path::StreamEncoder encoder = output_encoder.GetPathsEncoder();
47
Wyatt Heplerbad6d272022-02-16 07:15:07 -080048 encoder
49 .WritePath(reinterpret_cast<const char*>(file_name_buffer_.data()),
50 sws.size())
51 .IgnoreError();
52 encoder.WriteSizeBytes(entry.SizeBytes()).IgnoreError();
53 encoder.WritePermissions(entry.Permissions()).IgnoreError();
54 encoder.WriteFileId(entry.FileId()).IgnoreError();
Armando Montanez5be54582021-09-02 13:58:52 -070055 }
56 return output_encoder.status();
57}
58
59void FlatFileSystemService::EnumerateAllFiles(RawServerWriter& writer) {
Armando Montanezc1d79202021-09-30 15:25:49 -070060 for (Entry* entry : entries_) {
Armando Montanez5be54582021-09-02 13:58:52 -070061 PW_DCHECK_NOTNULL(entry);
62 // For now, don't try to pack entries.
Wyatt Heplerf5216e42022-01-26 17:13:07 -080063 pw::file::ListResponse::MemoryEncoder encoder(encoding_buffer_);
Armando Montanez5be54582021-09-02 13:58:52 -070064 if (Status status = EnumerateFile(*entry, encoder); !status.ok()) {
Armando Montaneze2e23282021-11-10 18:00:27 -080065 if (status != Status::NotFound()) {
66 PW_LOG_ERROR("Failed to enumerate file (id: %u) with status %d",
67 static_cast<unsigned>(entry->FileId()),
68 static_cast<int>(status.code()));
69 }
Armando Montanez5be54582021-09-02 13:58:52 -070070 continue;
71 }
72
73 Status write_status = writer.Write(encoder);
74 if (!write_status.ok()) {
Wyatt Heplerbad6d272022-02-16 07:15:07 -080075 writer.Finish(write_status)
76 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
Armando Montanez5be54582021-09-02 13:58:52 -070077 return;
78 }
79 }
Wyatt Heplerbad6d272022-02-16 07:15:07 -080080 writer.Finish(OkStatus())
81 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
Armando Montanez5be54582021-09-02 13:58:52 -070082}
83
Wyatt Hepler8e756e32021-11-18 09:59:27 -080084void FlatFileSystemService::List(ConstByteSpan request,
Armando Montanez5be54582021-09-02 13:58:52 -070085 RawServerWriter& writer) {
86 protobuf::Decoder decoder(request);
87 // If a file name was provided, try and find and enumerate the file.
88 while (decoder.Next().ok()) {
89 if (decoder.FieldNumber() !=
90 static_cast<uint32_t>(pw::file::ListRequest::Fields::PATH)) {
91 continue;
92 }
93
94 std::string_view file_name_view;
95 if (!decoder.ReadString(&file_name_view).ok() ||
96 file_name_view.length() == 0) {
Wyatt Heplerbad6d272022-02-16 07:15:07 -080097 writer.Finish(Status::DataLoss())
98 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
Armando Montanez5be54582021-09-02 13:58:52 -070099 return;
100 }
101
102 // Find and enumerate the file requested.
Armando Montanezc1d79202021-09-30 15:25:49 -0700103 Result<Entry*> result = FindFile(file_name_view);
Armando Montanez5be54582021-09-02 13:58:52 -0700104 if (!result.ok()) {
Wyatt Heplerbad6d272022-02-16 07:15:07 -0800105 writer.Finish(result.status())
106 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
Armando Montanez5be54582021-09-02 13:58:52 -0700107 return;
108 }
109
Wyatt Heplerf5216e42022-01-26 17:13:07 -0800110 pw::file::ListResponse::MemoryEncoder encoder(encoding_buffer_);
Armando Montanez5be54582021-09-02 13:58:52 -0700111 Status proto_encode_status = EnumerateFile(*result.value(), encoder);
112 if (!proto_encode_status.ok()) {
Wyatt Heplerbad6d272022-02-16 07:15:07 -0800113 writer.Finish(proto_encode_status)
114 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
Armando Montanez5be54582021-09-02 13:58:52 -0700115 return;
116 }
117
Wyatt Heplerbad6d272022-02-16 07:15:07 -0800118 writer.Finish(writer.Write(encoder))
119 .IgnoreError(); // TODO(pwbug/387): Handle Status properly
Armando Montanez5be54582021-09-02 13:58:52 -0700120 return;
121 }
122
123 // If no path was provided in the ListRequest, just enumerate everything.
124 EnumerateAllFiles(writer);
125}
126
Wyatt Heplerb15c55b2022-02-11 09:26:05 -0800127void FlatFileSystemService::Delete(ConstByteSpan request,
128 rpc::RawUnaryResponder& responder) {
Armando Montanez5be54582021-09-02 13:58:52 -0700129 protobuf::Decoder decoder(request);
130 while (decoder.Next().ok()) {
131 if (decoder.FieldNumber() !=
132 static_cast<uint32_t>(pw::file::DeleteRequest::Fields::PATH)) {
133 continue;
134 }
135
136 std::string_view file_name_view;
137 if (!decoder.ReadString(&file_name_view).ok()) {
Wyatt Heplerb15c55b2022-02-11 09:26:05 -0800138 responder.Finish({}, Status::DataLoss()).IgnoreError();
139 return;
Armando Montanez5be54582021-09-02 13:58:52 -0700140 }
Wyatt Heplerb15c55b2022-02-11 09:26:05 -0800141 responder.Finish({}, FindAndDeleteFile(file_name_view)).IgnoreError();
142 return;
Armando Montanez5be54582021-09-02 13:58:52 -0700143 }
Wyatt Heplerb15c55b2022-02-11 09:26:05 -0800144 responder.Finish({}, Status::InvalidArgument()).IgnoreError();
Armando Montanez5be54582021-09-02 13:58:52 -0700145}
146
Armando Montanezc1d79202021-09-30 15:25:49 -0700147Result<Entry*> FlatFileSystemService::FindFile(std::string_view file_name) {
Armando Montanez5be54582021-09-02 13:58:52 -0700148 Status search_status;
Armando Montanezc1d79202021-09-30 15:25:49 -0700149 for (Entry* entry : entries_) {
Armando Montanez5be54582021-09-02 13:58:52 -0700150 PW_DCHECK_NOTNULL(entry);
151 StatusWithSize sws = entry->Name(file_name_buffer_);
152
153 // If there not an exact file name length match, don't try and check against
154 // a prefix.
155 if (!sws.ok() || file_name.length() != sws.size()) {
156 if (sws.status() != Status::NotFound()) {
157 PW_LOG_ERROR("Failed to read file name (id: %u) with status %d",
158 static_cast<unsigned>(entry->FileId()),
159 static_cast<int>(sws.status().code()));
160 }
161 continue;
162 }
163
164 if (memcmp(file_name.data(), file_name_buffer_.data(), file_name.size()) ==
165 0) {
166 return entry;
167 }
168 }
169
170 search_status.Update(Status::NotFound());
171 return search_status;
172}
173
174Status FlatFileSystemService::FindAndDeleteFile(std::string_view file_name) {
Armando Montanezc1d79202021-09-30 15:25:49 -0700175 Result<Entry*> result = FindFile(file_name);
Armando Montanez5be54582021-09-02 13:58:52 -0700176 if (!result.ok()) {
177 return result.status();
178 }
179
180 return result.value()->Delete();
181}
182
183} // namespace pw::file