• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 #pragma once
15 
16 #include <cstddef>
17 #include <cstdint>
18 #include <string_view>
19 
20 #include "pw_bytes/span.h"
21 #include "pw_file/file.pwpb.h"
22 #include "pw_file/file.raw_rpc.pb.h"
23 #include "pw_protobuf/serialized_size.h"
24 #include "pw_result/result.h"
25 #include "pw_rpc/raw/server_reader_writer.h"
26 #include "pw_span/span.h"
27 #include "pw_status/status.h"
28 #include "pw_status/status_with_size.h"
29 
30 namespace pw::file {
31 
32 // This implements the pw.file.FileSystem RPC service. This implementation
33 // has a strict limitation that everything is treated as if the file system
34 // was "flat" (i.e. no directories). This means there's no concept of logical
35 // directories, despite any "path like" naming that may be employed by a user.
36 class FlatFileSystemService
37     : public pw_rpc::raw::FileSystem::Service<FlatFileSystemService> {
38  public:
39   class Entry {
40    public:
41     using FilePermissions = ::pw::file::pwpb::Path::Permissions;
42     using Id = uint32_t;
43 
44     Entry() = default;
45     virtual ~Entry() = default;
46 
47     // All readable files MUST be named, and names must be globally unique to
48     // prevent ambiguity. Unnamed file entries will NOT be enumerated by a
49     // FlatFileSystemService. The returned status must indicate the length
50     // of the string written to `dest`, and should NOT include any null
51     // terminator that may have been written.
52     //
53     // Note: The bounded string written to `dest` is not expected to be
54     // null-terminated, and should be treated like a std::string_view.
55     //
56     // Returns:
57     //   OK - Successfully read file name to `dest`.
58     //   NOT_FOUND - No file to enumerate for this entry.
59     //   RESOURCE_EXHAUSTED - `dest` buffer too small to fit the full file name.
60     virtual StatusWithSize Name(span<char> dest) = 0;
61 
62     virtual size_t SizeBytes() = 0;
63     virtual FilePermissions Permissions() const = 0;
64 
65     // Deleting a file, if allowed, should cause the backing data store to be
66     // cleared. Read-only files should also no longer enumerate (i.e. Name()
67     // should return NOT_FOUND). Write-only and read/write files may still
68     // enumerate but with SizeBytes() reporting zero.
69     virtual Status Delete() = 0;
70 
71     // File IDs must be globally unique, and map to a pw_transfer
72     // TransferService read/write handler.
73     virtual Id FileId() const = 0;
74   };
75 
76   // Returns the size of encoding buffer guaranteed to support encoding
77   // minimum_entries paths with file names up max_file_name_length.
78   static constexpr size_t EncodingBufferSizeBytes(size_t max_file_name_length,
79                                                   size_t minimum_entries = 1) {
80     return minimum_entries *
81            protobuf::SizeOfDelimitedField(
82                pwpb::ListResponse::Fields::kPaths,
83                EncodedPathProtoSizeBytes(max_file_name_length));
84   }
85 
86   // Constructs a flat file system from a static list of file entries.
87   //
88   // Args:
89   //   entry_list - A list of pointers to all Entry objects that may
90   //     contain files. These pointers may not be null. The span's underlying
91   //     buffer must outlive this object.
92   //   encoding_buffer - Used internally by this class to encode its responses.
93   //   file_name_buffer - Used internally by this class to find and enumerate
94   //     files. Should be large enough to hold the longest expected file name.
95   //     The span's underlying buffer must outlive this object.
96   //   max_file_name_length - Number of bytes to reserve for the file name.
FlatFileSystemService(span<Entry * > entry_list,span<std::byte> encoding_buffer,span<char> file_name_buffer)97   constexpr FlatFileSystemService(span<Entry*> entry_list,
98                                   span<std::byte> encoding_buffer,
99                                   span<char> file_name_buffer)
100       : encoding_buffer_(encoding_buffer),
101         file_name_buffer_(file_name_buffer),
102         entries_(entry_list) {}
103 
104   // Method definitions for pw.file.FileSystem.
105   void List(ConstByteSpan request, RawServerWriter& writer);
106 
107   // Returns:
108   //   OK - File successfully deleted.
109   //   NOT_FOUND - Could not find
110   void Delete(ConstByteSpan request, rpc::RawUnaryResponder& responder);
111 
112  private:
113   // Returns the maximum size of a single encoded Path proto.
EncodedPathProtoSizeBytes(size_t max_file_name_length)114   static constexpr size_t EncodedPathProtoSizeBytes(
115       size_t max_file_name_length) {
116     return protobuf::SizeOfFieldString(pwpb::Path::Fields::kPath,
117                                        max_file_name_length) +
118            protobuf::SizeOfFieldEnum(pwpb::Path::Fields::kPermissions,
119                                      pwpb::Path::Permissions::READ_AND_WRITE) +
120            protobuf::SizeOfFieldUint32(pwpb::Path::Fields::kSizeBytes) +
121            protobuf::SizeOfFieldUint32(pwpb::Path::Fields::kFileId);
122   }
123 
124   Result<Entry*> FindFile(std::string_view file_name);
125   Status FindAndDeleteFile(std::string_view file_name);
126 
127   Status EnumerateFile(Entry& entry,
128                        pwpb::ListResponse::StreamEncoder& output_encoder);
129   void EnumerateAllFiles(RawServerWriter& writer);
130 
131   const span<std::byte> encoding_buffer_;
132   const span<char> file_name_buffer_;
133   const span<Entry*> entries_;
134 };
135 
136 // Provides the encoding and file name buffers to a FlatFileSystemService.
137 template <unsigned kMaxFileNameLength,
138           unsigned kMinGuaranteedEntriesPerResponse = 1>
139 class FlatFileSystemServiceWithBuffer : public FlatFileSystemService {
140  public:
FlatFileSystemServiceWithBuffer(span<Entry * > entry_list)141   constexpr FlatFileSystemServiceWithBuffer(span<Entry*> entry_list)
142       : FlatFileSystemService(entry_list, encoding_buffer_, file_name_buffer_) {
143   }
144 
145  private:
146   static_assert(kMaxFileNameLength > 0u);
147 
148   std::byte encoding_buffer_[EncodingBufferSizeBytes(
149       kMaxFileNameLength, kMinGuaranteedEntriesPerResponse)];
150   char file_name_buffer_[kMaxFileNameLength];
151 };
152 }  // namespace pw::file
153