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::Access(const Path
& path
, int a_mode
) {
80 Error error
= FindNode(path
, 0, &node
);
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
))) {
95 Error
MemFs::Open(const Path
& path
, int open_flags
, ScopedNode
* out_node
) {
96 out_node
->reset(NULL
);
99 Error error
= FindNode(path
, 0, &node
);
101 // If the node does not exist and we can't create it, fail
102 if ((open_flags
& O_CREAT
) == 0)
105 // Now first find the parent directory to see if we can add it
107 error
= FindNode(path
.Parent(), S_IFDIR
, &parent
);
111 node
.reset(new MemFsNode(this));
112 error
= node
->Init(open_flags
);
116 error
= parent
->AddChild(path
.Basename(), node
);
121 // Opening an existing file.
123 // Directories can only be opened read-only.
124 if (node
->IsaDir() && (open_flags
& 3) != O_RDONLY
)
127 // If we were expected to create it exclusively, fail
128 if (open_flags
& O_EXCL
)
131 if (open_flags
& O_TRUNC
)
132 static_cast<MemFsNode
*>(node
.get())->Resize(0);
139 Error
MemFs::Mkdir(const Path
& path
, int mode
) {
140 // We expect a Filesystem "absolute" path
141 if (!path
.IsAbsolute())
144 // The root of the filesystem is already created by the filesystem
145 if (path
.Size() == 1)
149 int error
= FindNode(path
.Parent(), S_IFDIR
, &parent
);
154 error
= parent
->FindChild(path
.Basename(), &node
);
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);
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
) {
186 ScopedNode src_parent
;
187 ScopedNode target_node
;
188 ScopedNode target_parent
;
189 int error
= FindNode(src_path
, 0, &src_node
);
193 // The source must exist
194 error
= FindNode(src_path
.Parent(), S_IFDIR
, &src_parent
);
198 // The parent of the target must exist
199 error
= FindNode(target_path
.Parent(), 0, &target_parent
);
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()) {
216 if (src_node
->IsaDir()) {
217 // Replacing an existing directory.
218 RemoveInternal(target_path
, REMOVE_ALL
);
220 // Renaming into an existing directory.
221 target_name
= src_path
.Basename();
222 target_parent
= target_node
;
225 if (src_node
->IsaDir())
226 // Can't replace a file with a direcotory
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());
240 error
= target_parent
->AddChild(target_name
, src_node
);
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
);
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;
259 // We expect a Filesystem "absolute" path
260 if (!path
.IsAbsolute())
263 // The root of the filesystem is already created by the filesystem
264 if (path
.Size() == 1)
269 int error
= FindNode(path
.Parent(), S_IFDIR
, &parent
);
273 // Verify we find a child which is a directory.
275 error
= parent
->FindChild(path
.Basename(), &child
);
279 if (dir_only
&& !child
->IsaDir())
282 if (file_only
&& child
->IsaDir())
285 if (remove_dir
&& child
->ChildCount() > 0)
288 return parent
->RemoveChild(path
.Basename());
291 } // namespace nacl_io