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_mem.h"
      6 
      7 #include <errno.h>
      8 #include <fcntl.h>
      9 
     10 #include <string>
     11 
     12 #include "nacl_io/mount.h"
     13 #include "nacl_io/mount_node.h"
     14 #include "nacl_io/mount_node_dir.h"
     15 #include "nacl_io/mount_node_mem.h"
     16 #include "nacl_io/osstat.h"
     17 #include "nacl_io/osunistd.h"
     18 #include "nacl_io/path.h"
     19 #include "sdk_util/auto_lock.h"
     20 #include "sdk_util/ref_object.h"
     21 
     22 namespace nacl_io {
     23 
     24 MountMem::MountMem() : root_(NULL) {}
     25 
     26 Error MountMem::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
     27   Error error = Mount::Init(dev, args, ppapi);
     28   if (error)
     29     return error;
     30 
     31   root_.reset(new MountNodeDir(this));
     32   error = root_->Init(S_IREAD | S_IWRITE);
     33   if (error) {
     34     root_.reset(NULL);
     35     return error;
     36   }
     37   return 0;
     38 }
     39 
     40 Error MountMem::FindNode(const Path& path,
     41                          int type,
     42                          ScopedMountNode* out_node) {
     43   out_node->reset(NULL);
     44   ScopedMountNode node = root_;
     45 
     46   // If there is no root there, we have an error.
     47   if (node == NULL)
     48     return ENOTDIR;
     49 
     50   // We are expecting an "absolute" path from this mount point.
     51   if (!path.IsAbsolute())
     52     return EINVAL;
     53 
     54   // Starting at the root, traverse the path parts.
     55   for (size_t index = 1; node && index < path.Size(); index++) {
     56     // If not a directory, then we have an error so return.
     57     if (!node->IsaDir())
     58       return ENOTDIR;
     59 
     60     // Find the child node
     61     Error error = node->FindChild(path.Part(index), &node);
     62     if (error)
     63       return error;
     64   }
     65 
     66   // If a directory is expected, but it's not a directory, then fail.
     67   if ((type & S_IFDIR) && !node->IsaDir())
     68     return ENOTDIR;
     69 
     70   // If a file is expected, but it's not a file, then fail.
     71   if ((type & S_IFREG) && node->IsaDir())
     72     return EISDIR;
     73 
     74   // We now have a valid object of the expected type, so return it.
     75   *out_node = node;
     76   return 0;
     77 }
     78 
     79 Error MountMem::Access(const Path& path, int a_mode) {
     80   ScopedMountNode node;
     81   Error error = FindNode(path, 0, &node);
     82 
     83   if (error)
     84     return error;
     85 
     86   int obj_mode = node->GetMode();
     87   if (((a_mode & R_OK) && !(obj_mode & S_IREAD)) ||
     88       ((a_mode & W_OK) && !(obj_mode & S_IWRITE)) ||
     89       ((a_mode & X_OK) && !(obj_mode & S_IEXEC))) {
     90     return EACCES;
     91   }
     92 
     93   return 0;
     94 }
     95 
     96 Error MountMem::Open(const Path& path, int mode, ScopedMountNode* out_node) {
     97   out_node->reset(NULL);
     98   ScopedMountNode node;
     99 
    100   Error error = FindNode(path, 0, &node);
    101   if (error) {
    102     // If the node does not exist and we can't create it, fail
    103     if ((mode & O_CREAT) == 0)
    104       return ENOENT;
    105 
    106     // Now first find the parent directory to see if we can add it
    107     ScopedMountNode parent;
    108     error = FindNode(path.Parent(), S_IFDIR, &parent);
    109     if (error)
    110       return error;
    111 
    112     node.reset(new MountNodeMem(this));
    113     error = node->Init(OpenModeToPermission(mode));
    114     if (error)
    115       return error;
    116 
    117     error = parent->AddChild(path.Basename(), node);
    118     if (error)
    119       return error;
    120 
    121     *out_node = node;
    122     return 0;
    123   }
    124 
    125   // Directories can only be opened read-only.
    126   if (node->IsaDir() && (mode & 3) != O_RDONLY)
    127     return EISDIR;
    128 
    129   // If we were expected to create it exclusively, fail
    130   if (mode & O_EXCL)
    131     return EEXIST;
    132 
    133   // Verify we got the requested permissions.
    134   int req_mode = OpenModeToPermission(mode);
    135   int obj_mode = node->GetMode() & OpenModeToPermission(O_RDWR);
    136   if ((obj_mode & req_mode) != req_mode)
    137     return EACCES;
    138 
    139   *out_node = node;
    140   return 0;
    141 }
    142 
    143 Error MountMem::Mkdir(const Path& path, int mode) {
    144   // We expect a Mount "absolute" path
    145   if (!path.IsAbsolute())
    146     return ENOENT;
    147 
    148   // The root of the mount is already created by the mount
    149   if (path.Size() == 1)
    150     return EEXIST;
    151 
    152   ScopedMountNode parent;
    153   int error = FindNode(path.Parent(), S_IFDIR, &parent);
    154   if (error)
    155     return error;
    156 
    157   ScopedMountNode node;
    158   error = parent->FindChild(path.Basename(), &node);
    159   if (!error)
    160     return EEXIST;
    161 
    162   if (error != ENOENT)
    163     return error;
    164 
    165   // Allocate a node, with a RefCount of 1.  If added to the parent
    166   // it will get ref counted again.  In either case, release the
    167   // recount we have on exit.
    168   node.reset(new MountNodeDir(this));
    169   error = node->Init(S_IREAD | S_IWRITE);
    170   if (error)
    171     return error;
    172 
    173   return parent->AddChild(path.Basename(), node);
    174 }
    175 
    176 Error MountMem::Unlink(const Path& path) {
    177   return RemoveInternal(path, REMOVE_FILE);
    178 }
    179 
    180 Error MountMem::Rmdir(const Path& path) {
    181   return RemoveInternal(path, REMOVE_DIR);
    182 }
    183 
    184 Error MountMem::Remove(const Path& path) {
    185   return RemoveInternal(path, REMOVE_ALL);
    186 }
    187 
    188 Error MountMem::RemoveInternal(const Path& path, int remove_type) {
    189   bool dir_only = remove_type == REMOVE_DIR;
    190   bool file_only = remove_type == REMOVE_FILE;
    191   bool remove_dir = (remove_type & REMOVE_DIR) != 0;
    192 
    193   if (dir_only) {
    194     // We expect a Mount "absolute" path
    195     if (!path.IsAbsolute())
    196       return ENOENT;
    197 
    198     // The root of the mount is already created by the mount
    199     if (path.Size() == 1)
    200       return EEXIST;
    201   }
    202 
    203   ScopedMountNode parent;
    204   int error = FindNode(path.Parent(), S_IFDIR, &parent);
    205   if (error)
    206     return error;
    207 
    208   // Verify we find a child which is a directory.
    209   ScopedMountNode child;
    210   error = parent->FindChild(path.Basename(), &child);
    211   if (error)
    212     return error;
    213 
    214   if (dir_only && !child->IsaDir())
    215     return ENOTDIR;
    216 
    217   if (file_only && child->IsaDir())
    218     return EISDIR;
    219 
    220   if (remove_dir && child->ChildCount() > 0)
    221     return ENOTEMPTY;
    222 
    223   return parent->RemoveChild(path.Basename());
    224 }
    225 
    226 }  // namespace nacl_io
    227 
    228