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