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"
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"
24 MemFs::MemFs() : root_(NULL) {
27 Error MemFs::Init(const FsInitArgs& args) {
28 Error error = Filesystem::Init(args);
32 root_.reset(new DirNode(this));
33 error = root_->Init(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.
49 // We are expecting an "absolute" path from this mount point.
50 if (!path.IsAbsolute())
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.
59 // Find the child node
60 Error error = node->FindChild(path.Part(index), &node);
65 // If a directory is expected, but it's not a directory, then fail.
66 if ((type & S_IFDIR) && !node->IsaDir())
69 // If a file is expected, but it's not a file, then fail.
70 if ((type & S_IFREG) && node->IsaDir())
73 // We now have a valid object of the expected type, so return it.
78 Error MemFs::OpenWithMode(const Path& path, int open_flags, mode_t mode,
79 ScopedNode* out_node) {
80 out_node->reset(NULL);
83 Error error = FindNode(path, 0, &node);
85 // If the node does not exist and we can't create it, fail
86 if ((open_flags & O_CREAT) == 0)
89 // Now first find the parent directory to see if we can add it
91 error = FindNode(path.Parent(), S_IFDIR, &parent);
95 node.reset(new MemFsNode(this));
96 error = node->Init(open_flags);
101 error = parent->AddChild(path.Basename(), node);
106 // Opening an existing file.
108 // Directories can only be opened read-only.
109 if (node->IsaDir() && (open_flags & 3) != O_RDONLY)
112 // If we were expected to create it exclusively, fail
113 if (open_flags & O_EXCL)
116 if (open_flags & O_TRUNC)
124 Error MemFs::Mkdir(const Path& path, int mode) {
125 // We expect a Filesystem "absolute" path
126 if (!path.IsAbsolute())
129 // The root of the filesystem is already created by the filesystem
130 if (path.Size() == 1)
134 int error = FindNode(path.Parent(), S_IFDIR, &parent);
139 error = parent->FindChild(path.Basename(), &node);
146 // Allocate a node, with a RefCount of 1. If added to the parent
147 // it will get ref counted again. In either case, release the
148 // recount we have on exit.
149 node.reset(new DirNode(this));
150 error = node->Init(0);
154 return parent->AddChild(path.Basename(), node);
157 Error MemFs::Unlink(const Path& path) {
158 return RemoveInternal(path, REMOVE_FILE);
161 Error MemFs::Rmdir(const Path& path) {
162 return RemoveInternal(path, REMOVE_DIR);
165 Error MemFs::Remove(const Path& path) {
166 return RemoveInternal(path, REMOVE_ALL);
169 Error MemFs::Rename(const Path& src_path, const Path& target_path) {
171 ScopedNode src_parent;
172 ScopedNode target_node;
173 ScopedNode target_parent;
174 int error = FindNode(src_path, 0, &src_node);
178 // The source must exist
179 error = FindNode(src_path.Parent(), S_IFDIR, &src_parent);
183 // The parent of the target must exist
184 error = FindNode(target_path.Parent(), 0, &target_parent);
188 std::string target_name = target_path.Basename();
190 // The target itself need not exist but if it does there are
191 // certain restrictions
192 error = FindNode(target_path, 0, &target_node);
193 bool replacing_target = error == 0;
194 if (replacing_target) {
195 if (target_node->IsaDir()) {
196 // If the target is a direcotry it must be empty
197 if (target_node->ChildCount()) {
201 if (src_node->IsaDir()) {
202 // Replacing an existing directory.
203 RemoveInternal(target_path, REMOVE_ALL);
205 // Renaming into an existing directory.
206 target_name = src_path.Basename();
207 target_parent = target_node;
210 if (src_node->IsaDir())
211 // Can't replace a file with a direcotory
214 // Replacing an existing file.
215 target_parent->RemoveChild(target_path.Basename());
219 // Perform that actual rename. Simply re-parent the original source node
220 // onto its new parent node.
221 error = src_parent->RemoveChild(src_path.Basename());
225 error = target_parent->AddChild(target_name, src_node);
227 // Re-parent the old target_node if we failed to add the new one.
228 if (replacing_target)
229 target_parent->AddChild(target_path.Basename(), target_node);
230 // Re-parent the src_node
231 target_parent->AddChild(target_path.Basename(), src_node);
238 Error MemFs::RemoveInternal(const Path& path, int remove_type) {
239 bool dir_only = remove_type == REMOVE_DIR;
240 bool file_only = remove_type == REMOVE_FILE;
241 bool remove_dir = (remove_type & REMOVE_DIR) != 0;
244 // We expect a Filesystem "absolute" path
245 if (!path.IsAbsolute())
248 // The root of the filesystem is already created by the filesystem
249 if (path.Size() == 1)
254 int error = FindNode(path.Parent(), S_IFDIR, &parent);
258 // Verify we find a child which is a directory.
260 error = parent->FindChild(path.Basename(), &child);
264 if (dir_only && !child->IsaDir())
267 if (file_only && child->IsaDir())
270 if (remove_dir && child->ChildCount() > 0)
273 return parent->RemoveChild(path.Basename());
276 } // namespace nacl_io