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