Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / memfs / mem_fs_node.cc
blob5a8c929bf14d5835c46025e7f5cc04075ff63759
1 // Copyright 2013 The Chromium 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.
5 #ifndef __STDC_LIMIT_MACROS
6 #define __STDC_LIMIT_MACROS
7 #endif
9 #include "nacl_io/memfs/mem_fs_node.h"
11 #include <assert.h>
12 #include <errno.h>
13 #include <string.h>
15 #include <algorithm>
17 #include "nacl_io/kernel_handle.h"
18 #include "nacl_io/osinttypes.h"
19 #include "nacl_io/osstat.h"
20 #include "nacl_io/ostime.h"
21 #include "sdk_util/auto_lock.h"
23 namespace nacl_io {
25 namespace {
27 // The maximum size to reserve in addition to the requested size. Resize() will
28 // allocate twice as much as requested, up to this value.
29 const size_t kMaxResizeIncrement = 16 * 1024 * 1024;
31 } // namespace
33 MemFsNode::MemFsNode(Filesystem* filesystem)
34 : Node(filesystem),
35 data_(NULL),
36 data_capacity_(0) {
37 SetType(S_IFREG);
38 UpdateTime(UPDATE_ATIME | UPDATE_MTIME | UPDATE_CTIME);
41 MemFsNode::~MemFsNode() {
42 free(data_);
45 Error MemFsNode::Read(const HandleAttr& attr,
46 void* buf,
47 size_t count,
48 int* out_bytes) {
49 *out_bytes = 0;
51 AUTO_LOCK(node_lock_);
52 if (count == 0)
53 return 0;
55 size_t size = stat_.st_size;
57 if (attr.offs + count > size) {
58 count = size - attr.offs;
61 if (count > 0) {
62 UpdateTime(UPDATE_ATIME);
65 memcpy(buf, data_ + attr.offs, count);
66 *out_bytes = static_cast<int>(count);
67 return 0;
70 Error MemFsNode::Write(const HandleAttr& attr,
71 const void* buf,
72 size_t count,
73 int* out_bytes) {
74 *out_bytes = 0;
76 if (count == 0)
77 return 0;
79 AUTO_LOCK(node_lock_);
80 off_t new_size = attr.offs + count;
81 if (new_size > stat_.st_size) {
82 Error error = Resize(new_size);
83 if (error) {
84 LOG_ERROR("memfs: resize (%" PRIoff ") failed: %s", new_size,
85 strerror(error));
86 return error;
90 if (count > 0) {
91 UpdateTime(UPDATE_MTIME | UPDATE_CTIME);
94 memcpy(data_ + attr.offs, buf, count);
95 *out_bytes = static_cast<int>(count);
96 return 0;
99 Error MemFsNode::FTruncate(off_t new_size) {
100 AUTO_LOCK(node_lock_);
101 Error error = Resize(new_size);
102 if (error == 0) {
103 UpdateTime(UPDATE_MTIME | UPDATE_CTIME);
105 return error;
108 Error MemFsNode::Resize(off_t new_length) {
109 if (new_length < 0)
110 return EINVAL;
111 size_t new_size = static_cast<size_t>(new_length);
113 size_t new_capacity = data_capacity_;
114 if (new_size > data_capacity_) {
115 // While the node size is small, grow exponentially. When it starts to get
116 // larger, grow linearly.
117 size_t extra = std::min(new_size, kMaxResizeIncrement);
118 new_capacity = new_size + extra;
119 } else if (new_length < stat_.st_size) {
120 // Shrinking capacity
121 new_capacity = new_size;
124 if (new_capacity != data_capacity_) {
125 data_ = (char*)realloc(data_, new_capacity);
126 if (new_capacity != 0) {
127 assert(data_ != NULL);
128 if (data_ == NULL)
129 return ENOMEM;
131 data_capacity_ = new_capacity;
134 if (new_length > stat_.st_size)
135 memset(data_ + stat_.st_size, 0, new_length - stat_.st_size);
136 stat_.st_size = new_length;
137 return 0;
140 Error MemFsNode::Futimens(const struct timespec times[2]) {
141 AUTO_LOCK(node_lock_);
142 stat_.st_atime = times[0].tv_sec;
143 stat_.st_atimensec = times[0].tv_nsec;
144 stat_.st_mtime = times[1].tv_sec;
145 stat_.st_mtimensec = times[1].tv_nsec;
146 return 0;
149 Error MemFsNode::Fchmod(mode_t mode) {
150 AUTO_LOCK(node_lock_);
151 SetMode(mode);
152 UpdateTime(UPDATE_CTIME);
153 return 0;
156 } // namespace nacl_io