Mojo C++ bindings: better log message for serialization warnings.
[chromium-blink-merge.git] / native_client_sdk / src / libraries / nacl_io / memfs / mem_fs.cc
blobd29602d92ff9d023e219a9ef27790391f90efecf
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 #include "nacl_io/memfs/mem_fs.h"
7 #include <errno.h>
8 #include <fcntl.h>
10 #include <string>
12 #include "nacl_io/dir_node.h"
13 #include "nacl_io/filesystem.h"
14 #include "nacl_io/memfs/mem_fs_node.h"
15 #include "nacl_io/node.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"
22 namespace nacl_io {
24 MemFs::MemFs() : root_(NULL) {
27 Error MemFs::Init(const FsInitArgs& args) {
28 Error error = Filesystem::Init(args);
29 if (error)
30 return error;
32 root_.reset(new DirNode(this));
33 error = root_->Init(0);
34 if (error) {
35 root_.reset(NULL);
36 return error;
38 return 0;
41 Error MemFs::FindNode(const Path& path, int type, ScopedNode* out_node) {
42 out_node->reset(NULL);
43 ScopedNode node = root_;
45 // If there is no root there, we have an error.
46 if (node == NULL)
47 return ENOTDIR;
49 // We are expecting an "absolute" path from this mount point.
50 if (!path.IsAbsolute())
51 return EINVAL;
53 // Starting at the root, traverse the path parts.
54 for (size_t index = 1; node && index < path.Size(); index++) {
55 // If not a directory, then we have an error so return.
56 if (!node->IsaDir())
57 return ENOTDIR;
59 // Find the child node
60 Error error = node->FindChild(path.Part(index), &node);
61 if (error)
62 return error;
65 // If a directory is expected, but it's not a directory, then fail.
66 if ((type & S_IFDIR) && !node->IsaDir())
67 return ENOTDIR;
69 // If a file is expected, but it's not a file, then fail.
70 if ((type & S_IFREG) && node->IsaDir())
71 return EISDIR;
73 // We now have a valid object of the expected type, so return it.
74 *out_node = node;
75 return 0;
78 Error MemFs::Access(const Path& path, int a_mode) {
79 ScopedNode node;
80 Error error = FindNode(path, 0, &node);
82 if (error)
83 return error;
85 int obj_mode = node->GetMode();
86 if (((a_mode & R_OK) && !(obj_mode & S_IREAD)) ||
87 ((a_mode & W_OK) && !(obj_mode & S_IWRITE)) ||
88 ((a_mode & X_OK) && !(obj_mode & S_IEXEC))) {
89 return EACCES;
92 return 0;
95 Error MemFs::Open(const Path& path, int open_flags, ScopedNode* out_node) {
96 out_node->reset(NULL);
97 ScopedNode node;
99 Error error = FindNode(path, 0, &node);
100 if (error) {
101 // If the node does not exist and we can't create it, fail
102 if ((open_flags & O_CREAT) == 0)
103 return ENOENT;
105 // Now first find the parent directory to see if we can add it
106 ScopedNode parent;
107 error = FindNode(path.Parent(), S_IFDIR, &parent);
108 if (error)
109 return error;
111 node.reset(new MemFsNode(this));
112 error = node->Init(open_flags);
113 if (error)
114 return error;
116 error = parent->AddChild(path.Basename(), node);
117 if (error)
118 return error;
120 } else {
121 // Opening an existing file.
123 // Directories can only be opened read-only.
124 if (node->IsaDir() && (open_flags & 3) != O_RDONLY)
125 return EISDIR;
127 // If we were expected to create it exclusively, fail
128 if (open_flags & O_EXCL)
129 return EEXIST;
131 if (open_flags & O_TRUNC)
132 static_cast<MemFsNode*>(node.get())->Resize(0);
135 *out_node = node;
136 return 0;
139 Error MemFs::Mkdir(const Path& path, int mode) {
140 // We expect a Filesystem "absolute" path
141 if (!path.IsAbsolute())
142 return ENOENT;
144 // The root of the filesystem is already created by the filesystem
145 if (path.Size() == 1)
146 return EEXIST;
148 ScopedNode parent;
149 int error = FindNode(path.Parent(), S_IFDIR, &parent);
150 if (error)
151 return error;
153 ScopedNode node;
154 error = parent->FindChild(path.Basename(), &node);
155 if (!error)
156 return EEXIST;
158 if (error != ENOENT)
159 return error;
161 // Allocate a node, with a RefCount of 1. If added to the parent
162 // it will get ref counted again. In either case, release the
163 // recount we have on exit.
164 node.reset(new DirNode(this));
165 error = node->Init(0);
166 if (error)
167 return error;
169 return parent->AddChild(path.Basename(), node);
172 Error MemFs::Unlink(const Path& path) {
173 return RemoveInternal(path, REMOVE_FILE);
176 Error MemFs::Rmdir(const Path& path) {
177 return RemoveInternal(path, REMOVE_DIR);
180 Error MemFs::Remove(const Path& path) {
181 return RemoveInternal(path, REMOVE_ALL);
184 Error MemFs::Rename(const Path& src_path, const Path& target_path) {
185 ScopedNode src_node;
186 ScopedNode src_parent;
187 ScopedNode target_node;
188 ScopedNode target_parent;
189 int error = FindNode(src_path, 0, &src_node);
190 if (error)
191 return error;
193 // The source must exist
194 error = FindNode(src_path.Parent(), S_IFDIR, &src_parent);
195 if (error)
196 return error;
198 // The parent of the target must exist
199 error = FindNode(target_path.Parent(), 0, &target_parent);
200 if (error)
201 return error;
203 std::string target_name = target_path.Basename();
205 // The target itself need not exist but if it does there are
206 // certain restrictions
207 error = FindNode(target_path, 0, &target_node);
208 bool replacing_target = error == 0;
209 if (replacing_target) {
210 if (target_node->IsaDir()) {
211 // If the target is a direcotry it must be empty
212 if (target_node->ChildCount()) {
213 return ENOTEMPTY;
216 if (src_node->IsaDir()) {
217 // Replacing an existing directory.
218 RemoveInternal(target_path, REMOVE_ALL);
219 } else {
220 // Renaming into an existing directory.
221 target_name = src_path.Basename();
222 target_parent = target_node;
224 } else {
225 if (src_node->IsaDir())
226 // Can't replace a file with a direcotory
227 return EISDIR;
229 // Replacing an existing file.
230 target_parent->RemoveChild(target_path.Basename());
234 // Perform that actual rename. Simply re-parent the original source node
235 // onto its new parent node.
236 error = src_parent->RemoveChild(src_path.Basename());
237 if (error)
238 return error;
240 error = target_parent->AddChild(target_name, src_node);
241 if (error) {
242 // Re-parent the old target_node if we failed to add the new one.
243 if (replacing_target)
244 target_parent->AddChild(target_path.Basename(), target_node);
245 // Re-parent the src_node
246 target_parent->AddChild(target_path.Basename(), src_node);
247 return error;
250 return 0;
253 Error MemFs::RemoveInternal(const Path& path, int remove_type) {
254 bool dir_only = remove_type == REMOVE_DIR;
255 bool file_only = remove_type == REMOVE_FILE;
256 bool remove_dir = (remove_type & REMOVE_DIR) != 0;
258 if (dir_only) {
259 // We expect a Filesystem "absolute" path
260 if (!path.IsAbsolute())
261 return ENOENT;
263 // The root of the filesystem is already created by the filesystem
264 if (path.Size() == 1)
265 return EEXIST;
268 ScopedNode parent;
269 int error = FindNode(path.Parent(), S_IFDIR, &parent);
270 if (error)
271 return error;
273 // Verify we find a child which is a directory.
274 ScopedNode child;
275 error = parent->FindChild(path.Basename(), &child);
276 if (error)
277 return error;
279 if (dir_only && !child->IsaDir())
280 return ENOTDIR;
282 if (file_only && child->IsaDir())
283 return EISDIR;
285 if (remove_dir && child->ChildCount() > 0)
286 return ENOTEMPTY;
288 return parent->RemoveChild(path.Basename());
291 } // namespace nacl_io