1// Copyright 2017 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 <inttypes.h> 6#include <fcntl.h> 7#include <limits.h> 8#include <stdlib.h> 9#include <string.h> 10#include <sys/stat.h> 11 12#include <fbl/algorithm.h> 13#include <fbl/alloc_checker.h> 14#include <fbl/atomic.h> 15#include <fbl/ref_ptr.h> 16#include <fbl/unique_ptr.h> 17#include <lib/fdio/vfs.h> 18#include <fs/vfs.h> 19#include <lib/memfs/cpp/vnode.h> 20#include <zircon/device/vfs.h> 21 22#include "dnode.h" 23 24namespace memfs { 25namespace { 26 27bool WindowMatchesVMO(zx_handle_t vmo, zx_off_t offset, zx_off_t length) { 28 if (offset != 0) 29 return false; 30 uint64_t size; 31 if (zx_vmo_get_size(vmo, &size) < 0) 32 return false; 33 return size == length; 34} 35 36} // namespace 37 38VnodeVmo::VnodeVmo(Vfs* vfs, zx_handle_t vmo, zx_off_t offset, zx_off_t length) 39 : VnodeMemfs(vfs), vmo_(vmo), offset_(offset), length_(length), have_local_clone_(false) {} 40 41VnodeVmo::~VnodeVmo() { 42 if (have_local_clone_) { 43 zx_handle_close(vmo_); 44 } 45} 46 47zx_status_t VnodeVmo::ValidateFlags(uint32_t flags) { 48 if (flags & ZX_FS_FLAG_DIRECTORY) { 49 return ZX_ERR_NOT_DIR; 50 } 51 if (flags & ZX_FS_RIGHT_WRITABLE) { 52 return ZX_ERR_ACCESS_DENIED; 53 } 54 return ZX_OK; 55} 56 57zx_status_t VnodeVmo::Serve(fs::Vfs* vfs, zx::channel channel, uint32_t flags) { 58 return ZX_OK; 59} 60 61zx_status_t VnodeVmo::GetHandles(uint32_t flags, zx_handle_t* hnd, uint32_t* type, 62 zxrio_node_info_t* extra) { 63 zx_off_t* off = &extra->vmofile.offset; 64 zx_off_t* len = &extra->vmofile.length; 65 zx_status_t status; 66 if (!have_local_clone_ && !WindowMatchesVMO(vmo_, offset_, length_)) { 67 status = zx_vmo_clone(vmo_, ZX_VMO_CLONE_COPY_ON_WRITE, offset_, length_, &vmo_); 68 if (status < 0) 69 return status; 70 offset_ = 0; 71 have_local_clone_ = true; 72 } 73 74 zx_info_handle_basic_t info; 75 status = zx_object_get_info(vmo_, ZX_INFO_HANDLE_BASIC, 76 &info, sizeof(info), NULL, NULL); 77 if (status != ZX_OK) 78 return status; 79 80 // Drop write rights. 81 zx_handle_t vmo; 82 status = zx_handle_duplicate( 83 vmo_, 84 ZX_RIGHT_READ | ZX_RIGHT_MAP | 85 ZX_RIGHTS_BASIC | ZX_RIGHT_GET_PROPERTY | 86 (info.rights & ZX_RIGHT_EXECUTE), // Preserve exec if present. 87 &vmo); 88 if (status < 0) 89 return status; 90 91 *off = offset_; 92 *len = length_; 93 *hnd = vmo; 94 *type = fuchsia_io_NodeInfoTag_vmofile; 95 return ZX_OK; 96} 97 98zx_status_t VnodeVmo::Read(void* data, size_t len, size_t off, size_t* out_actual) { 99 if (off > length_) { 100 *out_actual = 0; 101 return ZX_OK; 102 } 103 size_t rlen = length_ - off; 104 if (len > rlen) { 105 len = rlen; 106 } 107 zx_status_t status = zx_vmo_read(vmo_, data, offset_ + off, len); 108 if (status == ZX_OK) { 109 *out_actual = len; 110 } 111 return status; 112} 113 114zx_status_t VnodeVmo::Getattr(vnattr_t* attr) { 115 memset(attr, 0, sizeof(vnattr_t)); 116 attr->inode = ino_; 117 attr->mode = V_TYPE_FILE | V_IRUSR; 118 attr->size = length_; 119 attr->blksize = kMemfsBlksize; 120 attr->blkcount = fbl::round_up(attr->size, kMemfsBlksize) / VNATTR_BLKSIZE; 121 attr->nlink = link_count_; 122 attr->create_time = create_time_; 123 attr->modify_time = modify_time_; 124 return ZX_OK; 125} 126 127} // namespace memfs 128