diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq index f48cb85..5da582e 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq @@ -1,5 +1,6 @@ interface VFS { method OpenFile(OpenFileRequest) -> (OpenFileResponse); + method GetDirectory(GetDirectoryRequest) -> (Directory); } message OpenFileRequest { @@ -11,3 +12,12 @@ message OpenFileResponse { u64 size; capability memory; } + +message GetDirectoryRequest { + string path; +} + +message Directory { + // , separated list of filenames until we have repeated strings. + string filenames; +} diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp index 21af098..2375b15 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp @@ -39,3 +39,35 @@ glcr::ErrorCode VFSClient::OpenFile(const OpenFileRequest& request, OpenFileResp } + +glcr::ErrorCode VFSClient::GetDirectory(const GetDirectoryRequest& request, Directory& response) { + uint64_t buffer_size = kBufferSize; + uint64_t cap_size = kCapBufferSize; + + const uint32_t kSentinel = 0xBEEFDEAD; + buffer_.WriteAt(0, kSentinel); + buffer_.WriteAt(8, 1); + + cap_buffer_.Reset(); + uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); + buffer_.WriteAt(4, 16 + length); + + z_cap_t reply_port_cap; + RET_ERR(ZEndpointSend(endpoint_, 16 + length, buffer_.RawPtr(), cap_buffer_.UsedSlots(), cap_buffer_.RawPtr(), &reply_port_cap)); + + // FIXME: Add a way to zero out the first buffer. + RET_ERR(ZReplyPortRecv(reply_port_cap, &buffer_size, buffer_.RawPtr(), &cap_size, cap_buffer_.RawPtr())); + + if (buffer_.At(0) != kSentinel) { + return glcr::INVALID_RESPONSE; + } + + // Check Response Code. + RET_ERR(buffer_.At(8)); + + response.ParseFromBytes(buffer_, 16, cap_buffer_); + + return glcr::OK; +} + + diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.h b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.h index cf28c33..94910f3 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.h +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.h @@ -19,6 +19,8 @@ class VFSClient { [[nodiscard]] glcr::ErrorCode OpenFile(const OpenFileRequest& request, OpenFileResponse& response); + [[nodiscard]] glcr::ErrorCode GetDirectory(const GetDirectoryRequest& request, Directory& response); + private: z_cap_t endpoint_; uint64_t kBufferSize = 0x1000; diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp index 7be8c6c..155616f 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp @@ -164,5 +164,123 @@ uint64_t OpenFileResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t of // The next extension pointer is the length of the message. WriteHeader(bytes, offset, core_size, next_extension); + return next_extension; +} +void GetDirectoryRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + ParseFromBytesInternal(bytes, offset); +} + +void GetDirectoryRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + ParseFromBytesInternal(bytes, offset); +} + +void GetDirectoryRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + CheckHeader(bytes); + // Parse path. + auto path_pointer = bytes.At(offset + header_size + (8 * 0)); + + set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length)); + +} + +uint64_t GetDirectoryRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + // Write path. + ExtPointer path_ptr{ + .offset = next_extension, + // FIXME: Check downcast of str length. + .length = (uint32_t)path().length(), + }; + + bytes.WriteStringAt(offset + next_extension, path()); + next_extension += path_ptr.length; + + bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); + + // The next extension pointer is the length of the message. + WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} + +uint64_t GetDirectoryRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + uint64_t next_cap = 0; + // Write path. + ExtPointer path_ptr{ + .offset = next_extension, + // FIXME: Check downcast of str length. + .length = (uint32_t)path().length(), + }; + + bytes.WriteStringAt(offset + next_extension, path()); + next_extension += path_ptr.length; + + bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); + + // The next extension pointer is the length of the message. + WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} +void Directory::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + ParseFromBytesInternal(bytes, offset); +} + +void Directory::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + ParseFromBytesInternal(bytes, offset); +} + +void Directory::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + CheckHeader(bytes); + // Parse filenames. + auto filenames_pointer = bytes.At(offset + header_size + (8 * 0)); + + set_filenames(bytes.StringAt(offset + filenames_pointer.offset, filenames_pointer.length)); + +} + +uint64_t Directory::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + // Write filenames. + ExtPointer filenames_ptr{ + .offset = next_extension, + // FIXME: Check downcast of str length. + .length = (uint32_t)filenames().length(), + }; + + bytes.WriteStringAt(offset + next_extension, filenames()); + next_extension += filenames_ptr.length; + + bytes.WriteAt(offset + header_size + (8 * 0), filenames_ptr); + + // The next extension pointer is the length of the message. + WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} + +uint64_t Directory::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + uint64_t next_cap = 0; + // Write filenames. + ExtPointer filenames_ptr{ + .offset = next_extension, + // FIXME: Check downcast of str length. + .length = (uint32_t)filenames().length(), + }; + + bytes.WriteStringAt(offset + next_extension, filenames()); + next_extension += filenames_ptr.length; + + bytes.WriteAt(offset + header_size + (8 * 0), filenames_ptr); + + // The next extension pointer is the length of the message. + WriteHeader(bytes, offset, core_size, next_extension); + return next_extension; } \ No newline at end of file diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h index baa88d1..01a7537 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h @@ -49,6 +49,46 @@ class OpenFileResponse { uint64_t size_; z_cap_t memory_; + // Parses everything except for caps. + void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); +}; +class GetDirectoryRequest { + public: + GetDirectoryRequest() {} + // Delete copy and move until implemented. + GetDirectoryRequest(const GetDirectoryRequest&) = delete; + GetDirectoryRequest(GetDirectoryRequest&&) = delete; + + void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); + void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const; + uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; + const glcr::String& path() const { return path_; } + void set_path(const glcr::String& value) { path_ = value; } + + private: + glcr::String path_; + + // Parses everything except for caps. + void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); +}; +class Directory { + public: + Directory() {} + // Delete copy and move until implemented. + Directory(const Directory&) = delete; + Directory(Directory&&) = delete; + + void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); + void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const; + uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; + const glcr::String& filenames() const { return filenames_; } + void set_filenames(const glcr::String& value) { filenames_ = value; } + + private: + glcr::String filenames_; + // Parses everything except for caps. void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); }; \ No newline at end of file diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp index cdafc39..75dba40 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp @@ -97,6 +97,17 @@ glcr::ErrorCode VFSServerBase::HandleRequest(const glcr::ByteBuffer& request, resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps); break; } + case 1: { + GetDirectoryRequest yunq_request; + Directory yunq_response; + + yunq_request.ParseFromBytes(request, kHeaderSize, req_caps); + + RET_ERR(HandleGetDirectory(yunq_request, yunq_response)); + + resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps); + break; + } default: { return glcr::UNIMPLEMENTED; } diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.h b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.h index 9734c27..7490959 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.h +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.h @@ -23,6 +23,8 @@ class VFSServerBase { [[nodiscard]] virtual glcr::ErrorCode HandleOpenFile(const OpenFileRequest&, OpenFileResponse&) = 0; + [[nodiscard]] virtual glcr::ErrorCode HandleGetDirectory(const GetDirectoryRequest&, Directory&) = 0; + private: z_cap_t endpoint_; diff --git a/sys/victoriafalls/victoriafalls_server.cpp b/sys/victoriafalls/victoriafalls_server.cpp index 36628bc..3f54d38 100644 --- a/sys/victoriafalls/victoriafalls_server.cpp +++ b/sys/victoriafalls/victoriafalls_server.cpp @@ -63,3 +63,48 @@ glcr::ErrorCode VFSServer::HandleOpenFile(const OpenFileRequest& request, response.set_size(inode->size); return glcr::OK; } + +glcr::ErrorCode VFSServer::HandleGetDirectory( + const GetDirectoryRequest& request, Directory& response) { + auto path_tokens = glcr::StrSplit(request.path(), '/'); + + if (path_tokens.at(0) != "") { + return glcr::INVALID_ARGUMENT; + } + + // If there is a trailing slash we can get rid of the empty string. + if (path_tokens.at(path_tokens.size() - 1) == "") { + path_tokens.PopBack(); + } + + ASSIGN_OR_RETURN(auto files, driver_.ReadDirectory(2)); + for (uint64_t i = 1; i < path_tokens.size(); i++) { + bool found_token = false; + for (uint64_t j = 0; j < files.size() && !found_token; j++) { + if (path_tokens.at(i) == + glcr::StringView(files.at(j).name, files.at(j).name_len)) { + ASSIGN_OR_RETURN(files, driver_.ReadDirectory(files.at(j).inode)); + found_token = true; + } + } + if (!found_token) { + dbgln("Directory '{}' not found.", + glcr::String(path_tokens.at(i)).cstr()); + return glcr::NOT_FOUND; + } + } + + glcr::VariableStringBuilder filelist; + for (uint64_t i = 0; i < files.size(); i++) { + filelist.PushBack(glcr::StringView(files.at(i).name, files.at(i).name_len)); + filelist.PushBack(','); + } + // Remove trailing comma. + if (filelist.size() > 0) { + filelist.DeleteLast(); + } + + response.set_filenames(filelist.ToString()); + + return glcr::OK; +} diff --git a/sys/victoriafalls/victoriafalls_server.h b/sys/victoriafalls/victoriafalls_server.h index 4b8b0e3..d94cef0 100644 --- a/sys/victoriafalls/victoriafalls_server.h +++ b/sys/victoriafalls/victoriafalls_server.h @@ -12,6 +12,9 @@ class VFSServer : public VFSServerBase { glcr::ErrorCode HandleOpenFile(const OpenFileRequest&, OpenFileResponse&) override; + glcr::ErrorCode HandleGetDirectory(const GetDirectoryRequest&, + Directory&) override; + private: // FIXME: Don't store this as a reference. Ext2Driver& driver_;