Home | History | Annotate | Download | only in nacl_io
      1 // Copyright (c) 2012 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.
      4 
      5 #include "nacl_io/mount_node_mem.h"
      6 
      7 #include <errno.h>
      8 #include <string.h>
      9 
     10 #include "nacl_io/osstat.h"
     11 #include "sdk_util/auto_lock.h"
     12 
     13 namespace nacl_io {
     14 
     15 #define BLOCK_SIZE (1 << 16)
     16 #define BLOCK_MASK (BLOCK_SIZE - 1)
     17 
     18 MountNodeMem::MountNodeMem(Mount* mount)
     19     : MountNode(mount), data_(NULL), capacity_(0) {
     20   stat_.st_mode |= S_IFREG;
     21 }
     22 
     23 MountNodeMem::~MountNodeMem() { free(data_); }
     24 
     25 Error MountNodeMem::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
     26   *out_bytes = 0;
     27 
     28   AUTO_LOCK(node_lock_);
     29   if (count == 0)
     30     return 0;
     31 
     32   size_t size = stat_.st_size;
     33 
     34   if (offs + count > size) {
     35     count = size - offs;
     36   }
     37 
     38   memcpy(buf, &data_[offs], count);
     39   *out_bytes = static_cast<int>(count);
     40   return 0;
     41 }
     42 
     43 Error MountNodeMem::Write(size_t offs,
     44                           const void* buf,
     45                           size_t count,
     46                           int* out_bytes) {
     47   *out_bytes = 0;
     48   AUTO_LOCK(node_lock_);
     49 
     50   if (count == 0)
     51     return 0;
     52 
     53   if (count + offs > stat_.st_size) {
     54     Error error = FTruncate(count + offs);
     55     if (error)
     56       return error;
     57 
     58     count = stat_.st_size - offs;
     59   }
     60 
     61   memcpy(&data_[offs], buf, count);
     62   *out_bytes = static_cast<int>(count);
     63   return 0;
     64 }
     65 
     66 Error MountNodeMem::FTruncate(off_t new_size) {
     67   size_t need = (new_size + BLOCK_MASK) & ~BLOCK_MASK;
     68   size_t old_size = stat_.st_size;
     69 
     70   // If the current capacity is correct, just adjust and return
     71   if (need == capacity_) {
     72     stat_.st_size = static_cast<off_t>(new_size);
     73     return 0;
     74   }
     75 
     76   // Attempt to realloc the block
     77   char* newdata = static_cast<char*>(realloc(data_, need));
     78   if (newdata != NULL) {
     79     // Zero out new space.
     80     if (new_size > old_size)
     81       memset(newdata + old_size, 0, need - old_size);
     82 
     83     data_ = newdata;
     84     capacity_ = need;
     85     stat_.st_size = static_cast<off_t>(new_size);
     86     return 0;
     87   }
     88 
     89   // If we failed, then adjust size according to what we keep
     90   if (new_size > capacity_)
     91     new_size = capacity_;
     92 
     93   // Update the size and return the new size
     94   stat_.st_size = static_cast<off_t>(new_size);
     95   return EIO;
     96 }
     97 
     98 }  // namespace nacl_io
     99 
    100