1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
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 <fuchsia/io/c/fidl.h>
6 #include <lib/zxio/inception.h>
7 #include <lib/zxio/null.h>
8 #include <lib/zxio/ops.h>
9 #include <string.h>
10 #include <sys/stat.h>
11 #include <zircon/syscalls.h>
12
zxio_vmofile_release(zxio_t * io,zx_handle_t * out_handle)13 static zx_status_t zxio_vmofile_release(zxio_t* io, zx_handle_t* out_handle) {
14 zxio_vmofile_t* file = reinterpret_cast<zxio_vmofile_t*>(io);
15
16 mtx_lock(&file->lock);
17 uint64_t seek = file->ptr - file->off;
18 zx_handle_t control = file->control;
19 zx_handle_t vmo = file->vmo;
20 mtx_unlock(&file->lock);
21
22 zx_status_t io_status, status;
23 if ((io_status = fuchsia_io_FileSeek(control, seek, fuchsia_io_SeekOrigin_START,
24 &status, &seek)) != ZX_OK) {
25 return io_status;
26 }
27 if (status != ZX_OK) {
28 return status;
29 }
30
31 mtx_lock(&file->lock);
32 file->vmo = ZX_HANDLE_INVALID;
33 file->control = ZX_HANDLE_INVALID;
34 mtx_unlock(&file->lock);
35
36 zx_handle_close(vmo);
37 *out_handle = control;
38 return ZX_OK;
39 }
40
zxio_vmofile_close(zxio_t * io)41 static zx_status_t zxio_vmofile_close(zxio_t* io) {
42 zxio_vmofile_t* file = reinterpret_cast<zxio_vmofile_t*>(io);
43 zx_handle_t control = file->control;
44 if (control != ZX_HANDLE_INVALID) {
45 file->control = ZX_HANDLE_INVALID;
46 zx_handle_close(control);
47 }
48 zx_handle_t vmo = file->vmo;
49 file->vmo = ZX_HANDLE_INVALID;
50 zx_handle_close(vmo);
51 return ZX_OK;
52 }
53
zxio_vmofile_clone_async(zxio_t * io,uint32_t flags,zx_handle_t request)54 static zx_status_t zxio_vmofile_clone_async(zxio_t* io, uint32_t flags,
55 zx_handle_t request) {
56 zxio_vmofile_t* file = reinterpret_cast<zxio_vmofile_t*>(io);
57 return fuchsia_io_NodeClone(file->control, flags, request);
58 }
59
zxio_vmofile_attr_get(zxio_t * io,zxio_node_attr_t * out_attr)60 static zx_status_t zxio_vmofile_attr_get(zxio_t* io, zxio_node_attr_t* out_attr) {
61 zxio_vmofile_t* file = reinterpret_cast<zxio_vmofile_t*>(io);
62 memset(out_attr, 0, sizeof(*out_attr));
63 out_attr->mode = S_IFREG | S_IRUSR;
64 out_attr->content_size = file->end - file->off;
65 return ZX_OK;
66 }
67
zxio_vmofile_read(zxio_t * io,void * buffer,size_t capacity,size_t * out_actual)68 static zx_status_t zxio_vmofile_read(zxio_t* io, void* buffer, size_t capacity,
69 size_t* out_actual) {
70 zxio_vmofile_t* file = reinterpret_cast<zxio_vmofile_t*>(io);
71
72 mtx_lock(&file->lock);
73 if (capacity > (file->end - file->ptr)) {
74 capacity = file->end - file->ptr;
75 }
76 zx_off_t offset = file->ptr;
77 file->ptr += capacity;
78 mtx_unlock(&file->lock);
79
80 zx_status_t status = zx_vmo_read(file->vmo, buffer, offset, capacity);
81 if (status == ZX_OK) {
82 *out_actual = capacity;
83 }
84 return status;
85 }
86
zxio_vmofile_read_at(zxio_t * io,size_t offset,void * buffer,size_t capacity,size_t * out_actual)87 static zx_status_t zxio_vmofile_read_at(zxio_t* io, size_t offset, void* buffer,
88 size_t capacity, size_t* out_actual) {
89 zxio_vmofile_t* file = reinterpret_cast<zxio_vmofile_t*>(io);
90
91 // Make sure we're within the file's bounds.
92 if (offset > file->end - file->off) {
93 return ZX_ERR_INVALID_ARGS;
94 }
95
96 // Adjust to vmo offset.
97 offset += file->off;
98
99 // Clip length to file bounds.
100 if (capacity > file->end - offset) {
101 capacity = file->end - offset;
102 }
103
104 zx_status_t status = zx_vmo_read(file->vmo, buffer, offset, capacity);
105 if (status == ZX_OK) {
106 *out_actual = capacity;
107 }
108 return status;
109 }
110
zxio_vmofile_seek(zxio_t * io,size_t offset,zxio_seek_origin_t start,size_t * out_offset)111 static zx_status_t zxio_vmofile_seek(zxio_t* io, size_t offset,
112 zxio_seek_origin_t start,
113 size_t* out_offset) {
114 zxio_vmofile_t* file = reinterpret_cast<zxio_vmofile_t*>(io);
115
116 mtx_lock(&file->lock);
117 zx_off_t at = 0u;
118 switch (start) {
119 case fuchsia_io_SeekOrigin_START:
120 at = offset;
121 break;
122 case fuchsia_io_SeekOrigin_CURRENT:
123 at = (file->ptr - file->off) + offset;
124 break;
125 case fuchsia_io_SeekOrigin_END:
126 at = (file->end - file->off) + offset;
127 break;
128 default:
129 mtx_unlock(&file->lock);
130 return ZX_ERR_INVALID_ARGS;
131 }
132 if (at > file->end - file->off) {
133 at = ZX_ERR_OUT_OF_RANGE;
134 } else {
135 file->ptr = file->off + at;
136 }
137 mtx_unlock(&file->lock);
138
139 *out_offset = at;
140 return ZX_OK;
141 }
142
__anonab39c0760102() 143 static constexpr zxio_ops_t zxio_vmofile_ops = []() {
144 zxio_ops_t ops = zxio_default_ops;
145 ops.release = zxio_vmofile_release;
146 ops.close = zxio_vmofile_close;
147 ops.clone_async = zxio_vmofile_clone_async;
148 ops.attr_get = zxio_vmofile_attr_get;
149 ops.read = zxio_vmofile_read;
150 ops.read_at = zxio_vmofile_read_at;
151 ops.seek = zxio_vmofile_seek;
152 return ops;
153 }();
154
zxio_vmofile_init(zxio_storage_t * storage,zx_handle_t control,zx_handle_t vmo,zx_off_t offset,zx_off_t length,zx_off_t seek)155 zx_status_t zxio_vmofile_init(zxio_storage_t* storage, zx_handle_t control,
156 zx_handle_t vmo, zx_off_t offset, zx_off_t length,
157 zx_off_t seek) {
158 zxio_vmofile_t* file = reinterpret_cast<zxio_vmofile_t*>(storage);
159 zxio_init(&file->io, &zxio_vmofile_ops);
160 if (seek > length)
161 seek = length;
162 file->control = control;
163 file->vmo = vmo;
164 file->off = offset;
165 file->end = offset + length;
166 file->ptr = offset + seek;
167 mtx_init(&file->lock, mtx_plain);
168 return ZX_OK;
169 }
170