blob: 4910cd552da4749a5951c07e9a5d097e27cc4e6d [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <inttypes.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fbl/algorithm.h>
#include <fbl/alloc_checker.h>
#include <fbl/atomic.h>
#include <fbl/ref_ptr.h>
#include <fbl/unique_ptr.h>
#include <fdio/vfs.h>
#include <fs/vfs.h>
#include <memfs/vnode.h>
#include <zircon/device/vfs.h>
#include "dnode.h"
namespace memfs {
namespace {
bool WindowMatchesVMO(zx_handle_t vmo, zx_off_t offset, zx_off_t length) {
if (offset != 0)
return false;
uint64_t size;
if (zx_vmo_get_size(vmo, &size) < 0)
return false;
return size == length;
}
} // namespace
VnodeVmo::VnodeVmo(Vfs* vfs, zx_handle_t vmo, zx_off_t offset, zx_off_t length)
: VnodeMemfs(vfs), vmo_(vmo), offset_(offset), length_(length), have_local_clone_(false) {}
VnodeVmo::~VnodeVmo() {
if (have_local_clone_) {
zx_handle_close(vmo_);
}
}
zx_status_t VnodeVmo::ValidateFlags(uint32_t flags) {
if (flags & ZX_FS_FLAG_DIRECTORY) {
return ZX_ERR_NOT_DIR;
}
if (flags & ZX_FS_RIGHT_WRITABLE) {
return ZX_ERR_ACCESS_DENIED;
}
return ZX_OK;
}
zx_status_t VnodeVmo::Serve(fs::Vfs* vfs, zx::channel channel, uint32_t flags) {
return ZX_OK;
}
zx_status_t VnodeVmo::GetHandles(uint32_t flags, zx_handle_t* hnd, uint32_t* type,
zxrio_object_info_t* extra) {
zx_off_t* off = &extra->vmofile.offset;
zx_off_t* len = &extra->vmofile.length;
zx_handle_t vmo;
zx_status_t status;
if (!have_local_clone_ && !WindowMatchesVMO(vmo_, offset_, length_)) {
status = zx_vmo_clone(vmo_, ZX_VMO_CLONE_COPY_ON_WRITE, offset_, length_, &vmo_);
if (status < 0)
return status;
offset_ = 0;
have_local_clone_ = true;
}
status = zx_handle_duplicate(
vmo_,
ZX_RIGHT_READ | ZX_RIGHT_EXECUTE | ZX_RIGHT_MAP |
ZX_RIGHTS_BASIC | ZX_RIGHT_GET_PROPERTY,
&vmo);
if (status < 0)
return status;
*off = offset_;
*len = length_;
*hnd = vmo;
*type = FDIO_PROTOCOL_VMOFILE;
return ZX_OK;
}
zx_status_t VnodeVmo::Read(void* data, size_t len, size_t off, size_t* out_actual) {
if (off > length_) {
*out_actual = 0;
return ZX_OK;
}
size_t rlen = length_ - off;
if (len > rlen)
len = rlen;
return zx_vmo_read_old(vmo_, data, offset_ + off, len, out_actual);
}
zx_status_t VnodeVmo::Getattr(vnattr_t* attr) {
memset(attr, 0, sizeof(vnattr_t));
attr->inode = ino_;
attr->mode = V_TYPE_FILE | V_IRUSR;
attr->size = length_;
attr->blksize = kMemfsBlksize;
attr->blkcount = fbl::round_up(attr->size, kMemfsBlksize) / VNATTR_BLKSIZE;
attr->nlink = link_count_;
attr->create_time = create_time_;
attr->modify_time = modify_time_;
return ZX_OK;
}
} // namespace memfs