1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/fuchsia/mem_buffer_util.h"
6
7 #include <lib/fdio/io.h>
8
9 #include <lib/zx/vmo.h>
10 #include <string>
11 #include <utility>
12
13 #include "base/files/file.h"
14 #include "base/fuchsia/fuchsia_logging.h"
15 #include "base/numerics/safe_conversions.h"
16 #include "base/strings/string_piece.h"
17 #include "base/strings/utf_string_conversions.h"
18
19 namespace base {
20
ReadUTF8FromVMOAsUTF16(const fuchsia::mem::Buffer & buffer)21 absl::optional<std::u16string> ReadUTF8FromVMOAsUTF16(
22 const fuchsia::mem::Buffer& buffer) {
23 absl::optional<std::string> output_utf8 = StringFromMemBuffer(buffer);
24 if (!output_utf8)
25 return absl::nullopt;
26 std::u16string output;
27 return UTF8ToUTF16(&output_utf8->front(), output_utf8->size(), &output)
28 ? absl::optional<std::u16string>(std::move(output))
29 : absl::nullopt;
30 }
31
VmoFromString(StringPiece data,StringPiece name)32 zx::vmo VmoFromString(StringPiece data, StringPiece name) {
33 zx::vmo vmo;
34
35 // The `ZX_PROP_VMO_CONTENT_SIZE` property is automatically set on VMO
36 // creation.
37 zx_status_t status = zx::vmo::create(data.size(), 0, &vmo);
38 ZX_CHECK(status == ZX_OK, status) << "zx_vmo_create";
39 status = vmo.set_property(ZX_PROP_NAME, name.data(), name.size());
40 ZX_DCHECK(status == ZX_OK, status);
41 if (data.size() > 0) {
42 status = vmo.write(data.data(), 0, data.size());
43 ZX_CHECK(status == ZX_OK, status) << "zx_vmo_write";
44 }
45 return vmo;
46 }
47
MemBufferFromString(StringPiece data,StringPiece name)48 fuchsia::mem::Buffer MemBufferFromString(StringPiece data, StringPiece name) {
49 fuchsia::mem::Buffer buffer;
50 buffer.vmo = VmoFromString(data, name);
51 buffer.size = data.size();
52 return buffer;
53 }
54
MemBufferFromString16(StringPiece16 data,StringPiece name)55 fuchsia::mem::Buffer MemBufferFromString16(StringPiece16 data,
56 StringPiece name) {
57 return MemBufferFromString(
58 StringPiece(reinterpret_cast<const char*>(data.data()),
59 data.size() * sizeof(char16_t)),
60 name);
61 }
62
StringFromVmo(const zx::vmo & vmo)63 absl::optional<std::string> StringFromVmo(const zx::vmo& vmo) {
64 std::string result;
65
66 size_t size;
67 zx_status_t status = vmo.get_prop_content_size(&size);
68 if (status != ZX_OK) {
69 ZX_LOG(ERROR, status) << "zx::vmo::get_prop_content_size";
70 return absl::nullopt;
71 }
72
73 if (size == 0)
74 return result;
75
76 result.resize(size);
77 status = vmo.read(&result[0], 0, size);
78 if (status == ZX_OK)
79 return result;
80
81 ZX_LOG(ERROR, status) << "zx_vmo_read";
82 return absl::nullopt;
83 }
84
StringFromMemBuffer(const fuchsia::mem::Buffer & buffer)85 absl::optional<std::string> StringFromMemBuffer(
86 const fuchsia::mem::Buffer& buffer) {
87 std::string result;
88
89 if (buffer.size == 0)
90 return result;
91
92 result.resize(buffer.size);
93 zx_status_t status = buffer.vmo.read(&result[0], 0, buffer.size);
94 if (status == ZX_OK)
95 return result;
96
97 ZX_LOG(ERROR, status) << "zx_vmo_read";
98 return absl::nullopt;
99 }
100
StringFromMemData(const fuchsia::mem::Data & data)101 absl::optional<std::string> StringFromMemData(const fuchsia::mem::Data& data) {
102 switch (data.Which()) {
103 case fuchsia::mem::Data::kBytes: {
104 const std::vector<uint8_t>& bytes = data.bytes();
105 return std::string(bytes.begin(), bytes.end());
106 }
107 case fuchsia::mem::Data::kBuffer:
108 return StringFromMemBuffer(data.buffer());
109 case fuchsia::mem::Data::kUnknown:
110 case fuchsia::mem::Data::Invalid:
111 // TODO(fxbug.dev/66155): Determine whether to use a default case instead.
112 break;
113 }
114
115 return absl::nullopt;
116 }
117
MemBufferFromFile(File file)118 fuchsia::mem::Buffer MemBufferFromFile(File file) {
119 if (!file.IsValid())
120 return {};
121
122 zx::vmo vmo;
123 zx_status_t status =
124 fdio_get_vmo_copy(file.GetPlatformFile(), vmo.reset_and_get_address());
125 if (status != ZX_OK) {
126 ZX_LOG(ERROR, status) << "fdio_get_vmo_copy";
127 return {};
128 }
129
130 fuchsia::mem::Buffer output;
131 output.vmo = std::move(vmo);
132 output.size = checked_cast<uint64_t>(file.GetLength());
133 return output;
134 }
135
CloneBuffer(const fuchsia::mem::Buffer & buffer,StringPiece name)136 fuchsia::mem::Buffer CloneBuffer(const fuchsia::mem::Buffer& buffer,
137 StringPiece name) {
138 fuchsia::mem::Buffer output;
139 output.size = buffer.size;
140 zx_status_t status = buffer.vmo.create_child(
141 ZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITE, 0, buffer.size, &output.vmo);
142 ZX_CHECK(status == ZX_OK, status) << "zx_vmo_create_child";
143
144 status = output.vmo.set_property(ZX_PROP_NAME, name.data(), name.size());
145 ZX_DCHECK(status == ZX_OK, status);
146
147 return output;
148 }
149
150 } // namespace base
151