15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// found in the LICENSE file.
4ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#ifndef __STDC_LIMIT_MACROS
66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#define __STDC_LIMIT_MACROS
76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#endif
86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "nacl_io/memfs/mem_fs_node.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include <assert.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include <algorithm>
16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "nacl_io/kernel_handle.h"
186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "nacl_io/osinttypes.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "nacl_io/osstat.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "sdk_util/auto_lock.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace nacl_io {
23ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
24424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)namespace {
25424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
26424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// The maximum size to reserve in addition to the requested size. Resize() will
27424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// allocate twice as much as requested, up to this value.
28424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)const size_t kMaxResizeIncrement = 16 * 1024 * 1024;
29424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
30424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}  // namespace
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)MemFsNode::MemFsNode(Filesystem* filesystem)
336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  : Node(filesystem),
346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    data_(NULL),
356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    data_capacity_(0) {
368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  SetType(S_IFREG);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)MemFsNode::~MemFsNode() {
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  free(data_);
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error MemFsNode::Read(const HandleAttr& attr,
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      void* buf,
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      size_t count,
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      int* out_bytes) {
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  *out_bytes = 0;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  AUTO_LOCK(node_lock_);
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (count == 0)
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return 0;
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  size_t size = stat_.st_size;
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (attr.offs + count > size) {
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    count = size - attr.offs;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  memcpy(buf, data_ + attr.offs, count);
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  *out_bytes = static_cast<int>(count);
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return 0;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error MemFsNode::Write(const HandleAttr& attr,
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       const void* buf,
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       size_t count,
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                       int* out_bytes) {
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  *out_bytes = 0;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (count == 0)
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return 0;
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  AUTO_LOCK(node_lock_);
746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  off_t new_size = attr.offs + count;
756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (new_size > stat_.st_size) {
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    Error error = Resize(new_size);
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (error) {
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      LOG_ERROR("memfs: resize (%" PRIoff ") failed: %s", new_size,
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          strerror(error));
806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return error;
816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  memcpy(data_ + attr.offs, buf, count);
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  *out_bytes = static_cast<int>(count);
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return 0;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Error MemFsNode::FTruncate(off_t new_size) {
90424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  AUTO_LOCK(node_lock_);
916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return Resize(new_size);
92424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)Error MemFsNode::Resize(off_t new_length) {
956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (new_length < 0)
966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return EINVAL;
976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  size_t new_size = static_cast<size_t>(new_length);
986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t new_capacity = data_capacity_;
1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (new_size > data_capacity_) {
101424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // While the node size is small, grow exponentially. When it starts to get
102424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // larger, grow linearly.
1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    size_t extra = std::min(new_size, kMaxResizeIncrement);
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    new_capacity = new_size + extra;
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else if (new_length < stat_.st_size) {
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Shrinking capacity
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    new_capacity = new_size;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (new_capacity != data_capacity_) {
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    data_ = (char*)realloc(data_, new_capacity);
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (new_capacity != 0) {
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      assert(data_ != NULL);
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (data_ == NULL)
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return ENOMEM;
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    data_capacity_ = new_capacity;
1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (new_length > stat_.st_size)
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    memset(data_ + stat_.st_size, 0, new_length - stat_.st_size);
1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  stat_.st_size = new_length;
1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  return 0;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciError MemFsNode::Fchmod(mode_t mode) {
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AUTO_LOCK(node_lock_);
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SetMode(mode);
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return 0;
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
132ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}  // namespace nacl_io
133