summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-28 22:02:44 +0000
committerbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-28 22:02:44 +0000
commit9ca9e4dbcbe984997fdb19156c4cc1d52366ee21 (patch)
treee4c6cba494034d036037e102f828b9cd507dca7d /native_client_sdk
parented9b489a4ee13131703723e244e1b2dda7c4e0fc (diff)
downloadchromium_src-9ca9e4dbcbe984997fdb19156c4cc1d52366ee21.zip
chromium_src-9ca9e4dbcbe984997fdb19156c4cc1d52366ee21.tar.gz
chromium_src-9ca9e4dbcbe984997fdb19156c4cc1d52366ee21.tar.bz2
[NaCl SDK] Add /dev mount to nacl-mounts.
Currently supports the following files: /dev/zero /dev/null /dev/urandom BUG=none R=noelallen@chromium.org NOTRY=true Review URL: https://chromiumcodereview.appspot.com/11418071 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170065 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rwxr-xr-xnative_client_sdk/src/build_tools/build_examples.py5
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.cc6
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/library.dsc2
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount.h9
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_dev.cc200
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_dev.h39
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_node.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_mounts_test/mount_test.cc105
9 files changed, 347 insertions, 22 deletions
diff --git a/native_client_sdk/src/build_tools/build_examples.py b/native_client_sdk/src/build_tools/build_examples.py
index ae5bb73..f358e20 100755
--- a/native_client_sdk/src/build_tools/build_examples.py
+++ b/native_client_sdk/src/build_tools/build_examples.py
@@ -27,6 +27,9 @@ def main(args):
parser.add_option('-t', '--toolchain',
help='Build using toolchain. Can be passed more than once.',
action='append')
+ parser.add_option('--gyp',
+ help='Use gyp to build examples/libraries/Makefiles.',
+ action='store_true')
options, args = parser.parse_args(args[1:])
@@ -43,6 +46,8 @@ def main(args):
pepperdir = os.path.join(build_sdk.OUT_DIR, 'pepper_' + pepper_ver)
platform = getos.GetPlatform()
+ build_sdk.options = options
+
build_sdk.BuildStepCopyExamples(pepperdir, toolchains, options.experimental,
options.clobber_examples)
# False = don't clean after building the libraries directory.
diff --git a/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.cc
index 5d6fe08..9c94f94 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts/kernel_proxy.cc
@@ -12,11 +12,10 @@
#include "nacl_mounts/kernel_handle.h"
#include "nacl_mounts/mount.h"
+#include "nacl_mounts/mount_dev.h"
#include "nacl_mounts/mount_mem.h"
#include "nacl_mounts/mount_node.h"
#include "nacl_mounts/osstat.h"
-// TODO(binji): implement MountURL
-//#include "nacl_mounts/mount_url.h"
#include "nacl_mounts/path.h"
#include "utils/auto_lock.h"
#include "utils/ref_object.h"
@@ -38,8 +37,7 @@ void KernelProxy::Init() {
dev_ = 1;
factories_["memfs"] = MountMem::Create<MountMem>;
- // TODO(binji): implement MountURL
- //factories_["urlfs"] = MountURL::Create;
+ factories_["dev"] = MountDev::Create<MountDev>;
// Create memory mount at root
StringMap_t smap;
diff --git a/native_client_sdk/src/libraries/nacl_mounts/library.dsc b/native_client_sdk/src/libraries/nacl_mounts/library.dsc
index e82c4b9..8b1d1e4 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_mounts/library.dsc
@@ -18,6 +18,7 @@
"kernel_proxy.cc",
"kernel_wrap.cc",
"mount.cc",
+ "mount_dev.cc",
"mount_mem.cc",
"mount_node.cc",
"mount_node_dir.cc",
@@ -35,6 +36,7 @@
"kernel_proxy.h",
"kernel_wrap.h",
"mount.h",
+ "mount_dev.h",
"mount_mem.h",
"mount_node.h",
"mount_node_dir.h",
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount.h b/native_client_sdk/src/libraries/nacl_mounts/mount.h
index 44d79fe..0e3296a 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount.h
@@ -14,19 +14,10 @@
#include "utils/ref_object.h"
class MountNode;
-class MountManager;
typedef std::map<std::string, std::string> StringMap_t;
-// Mount serves as the base mounting class that will be used by
-// the mount manager (class MountManager). The mount manager
-// relies heavily on the GetNode method as a way of directing
-// system calls that take a path as an argument. The methods
-// of this class are pure virtual. BaseMount class contains
-// stub implementations for these methods. Feel free to use
-// BaseMount if your mount does not implement all of these
-// operations.
class Mount : public RefObject {
protected:
// The protected functions are only used internally and will not
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_dev.cc b/native_client_sdk/src/libraries/nacl_mounts/mount_dev.cc
new file mode 100644
index 0000000..97100f0
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_dev.cc
@@ -0,0 +1,200 @@
+/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#if defined(WIN32)
+#define _CRT_RAND_S
+#endif
+
+#include "nacl_mounts/mount_dev.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include "nacl_mounts/mount_node.h"
+#include "nacl_mounts/mount_node_dir.h"
+#include "utils/auto_lock.h"
+
+#if defined(__native_client__)
+# include <irt.h>
+#elif defined(WIN32)
+# include <stdlib.h>
+#endif
+
+namespace {
+
+void ReleaseAndNullNode(MountNode** node) {
+ if (*node)
+ (*node)->Release();
+ *node = NULL;
+}
+
+class NullNode : public MountNode {
+ public:
+ NullNode(Mount* mount, int ino, int dev);
+
+ virtual int Read(size_t offs, void* buf, size_t count);
+ virtual int Write(size_t offs, const void* buf, size_t count);
+};
+
+class ZeroNode : public MountNode {
+ public:
+ ZeroNode(Mount* mount, int ino, int dev);
+
+ virtual int Read(size_t offs, void* buf, size_t count);
+ virtual int Write(size_t offs, const void* buf, size_t count);
+};
+
+class UrandomNode : public MountNode {
+ public:
+ UrandomNode(Mount* mount, int ino, int dev);
+
+ virtual int Read(size_t offs, void* buf, size_t count);
+ virtual int Write(size_t offs, const void* buf, size_t count);
+
+ private:
+#if defined(__native_client__)
+ nacl_irt_random random_interface_;
+ bool interface_ok_;
+#endif
+};
+
+NullNode::NullNode(Mount* mount, int ino, int dev)
+ : MountNode(mount, ino, dev) {
+}
+
+int NullNode::Read(size_t offs, void* buf, size_t count) {
+ return 0;
+}
+
+int NullNode::Write(size_t offs, const void* buf, size_t count) {
+ return count;
+}
+
+ZeroNode::ZeroNode(Mount* mount, int ino, int dev)
+ : MountNode(mount, ino, dev) {
+}
+
+int ZeroNode::Read(size_t offs, void* buf, size_t count) {
+ memset(buf, 0, count);
+ return count;
+}
+
+int ZeroNode::Write(size_t offs, const void* buf, size_t count) {
+ return count;
+}
+
+UrandomNode::UrandomNode(Mount* mount, int ino, int dev)
+ : MountNode(mount, ino, dev) {
+#if defined(__native_client__)
+ size_t result = nacl_interface_query(NACL_IRT_RANDOM_v0_1, &random_interface_,
+ sizeof(random_interface_));
+ interface_ok_ = result != 0;
+#endif
+}
+
+int UrandomNode::Read(size_t offs, void* buf, size_t count) {
+#if defined(__native_client__)
+ if (interface_ok_) {
+ size_t nread;
+ int result = (*random_interface_.get_random_bytes)(buf, count, &nread);
+ if (result != 0) {
+ errno = result;
+ return 0;
+ }
+
+ return count;
+ }
+
+ errno = EBADF;
+ return 0;
+#elif defined(WIN32)
+ char* out = static_cast<char*>(buf);
+ size_t bytes_left = count;
+ while (bytes_left) {
+ unsigned int random_int;
+ errno_t err = rand_s(&random_int);
+ if (err) {
+ errno = err;
+ return count - bytes_left;
+ }
+
+ int bytes_to_copy = std::min(bytes_left, sizeof(random_int));
+ memcpy(out, &random_int, bytes_to_copy);
+ out += bytes_to_copy;
+ bytes_left -= bytes_to_copy;
+ }
+
+ return count;
+#endif
+}
+
+int UrandomNode::Write(size_t offs, const void* buf, size_t count) {
+ return count;
+}
+
+} // namespace
+
+MountNode *MountDev::Open(const Path& path, int mode) {
+ AutoLock lock(&lock_);
+
+ // Don't allow creating any files.
+ if (mode & O_CREAT)
+ return NULL;
+
+ MountNode* node = root_->FindChild(path.Join());
+ if (node)
+ node->Acquire();
+ return node;
+}
+
+int MountDev::Close(MountNode* node) {
+ AutoLock lock(&lock_);
+ node->Close();
+ node->Release();
+ return 0;
+}
+
+int MountDev::Unlink(const Path& path) {
+ errno = EINVAL;
+ return -1;
+}
+
+int MountDev::Mkdir(const Path& path, int permissions) {
+ errno = EINVAL;
+ return -1;
+}
+
+int MountDev::Rmdir(const Path& path) {
+ errno = EINVAL;
+ return -1;
+}
+
+int MountDev::Remove(const Path& path) {
+ errno = EINVAL;
+ return -1;
+}
+
+MountDev::MountDev()
+ : null_node_(NULL),
+ zero_node_(NULL),
+ random_node_(NULL) {
+}
+
+bool MountDev::Init(int dev, StringMap_t& args) {
+ dev_ = dev;
+ root_ = new MountNodeDir(this, 1, dev_);
+ null_node_ = new NullNode(this, 2, dev_);
+ root_->AddChild("/null", null_node_);
+ zero_node_ = new ZeroNode(this, 3, dev_);
+ root_->AddChild("/zero", zero_node_);
+ random_node_ = new UrandomNode(this, 4, dev_);
+ root_->AddChild("/urandom", random_node_);
+ return true;
+}
+
+void MountDev::Destroy() {
+ ReleaseAndNullNode(&random_node_);
+ ReleaseAndNullNode(&zero_node_);
+ ReleaseAndNullNode(&null_node_);
+ ReleaseAndNullNode(&root_);
+}
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_dev.h b/native_client_sdk/src/libraries/nacl_mounts/mount_dev.h
new file mode 100644
index 0000000..9e92199
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_dev.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef LIBRARIES_NACL_MOUNTS_MOUNT_DEV_H_
+#define LIBRARIES_NACL_MOUNTS_MOUNT_DEV_H_
+
+#include "nacl_mounts/mount.h"
+
+class MountNode;
+
+class MountDev : public Mount {
+ public:
+ // Open and Close will affect the RefCount on the node, so
+ // there must be a call to close for each call to open.
+ virtual MountNode *Open(const Path& path, int mode);
+ virtual int Close(MountNode* node);
+
+ virtual int Unlink(const Path& path);
+ virtual int Mkdir(const Path& path, int permissions);
+ virtual int Rmdir(const Path& path);
+ virtual int Remove(const Path& path);
+
+ protected:
+ MountDev();
+
+ virtual bool Init(int dev, StringMap_t& args);
+ virtual void Destroy();
+
+ private:
+ MountNode* root_;
+ MountNode* null_node_;
+ MountNode* zero_node_;
+ MountNode* random_node_;
+
+ friend class Mount;
+};
+
+#endif // LIBRARIES_NACL_MOUNTS_MOUNT_DEV_H_
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_node.h b/native_client_sdk/src/libraries/nacl_mounts/mount_node.h
index f14957a..46bf0e2 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_node.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_node.h
@@ -64,8 +64,8 @@ protected:
struct stat stat_;
Mount* mount_;
- friend class MountHFS;
friend class MountMem;
+ friend class MountDev;
friend class MountNodeDir;
};
diff --git a/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.h b/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.h
index 1d182ef6e..b7ec1c7 100644
--- a/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.h
+++ b/native_client_sdk/src/libraries/nacl_mounts/mount_node_dir.h
@@ -41,6 +41,7 @@ private:
struct dirent* cache_;
MountNodeMap_t map_;
+ friend class MountDev;
friend class MountMem;
};
diff --git a/native_client_sdk/src/libraries/nacl_mounts_test/mount_test.cc b/native_client_sdk/src/libraries/nacl_mounts_test/mount_test.cc
index abd0e30..fc8cafa 100644
--- a/native_client_sdk/src/libraries/nacl_mounts_test/mount_test.cc
+++ b/native_client_sdk/src/libraries/nacl_mounts_test/mount_test.cc
@@ -5,26 +5,29 @@
#include <errno.h>
#include <fcntl.h>
+#include <string>
#include <sys/stat.h>
-#include <string>
#include "nacl_mounts/mount.h"
+#include "nacl_mounts/mount_dev.h"
#include "nacl_mounts/mount_mem.h"
#include "nacl_mounts/osdirent.h"
#include "gtest/gtest.h"
-class MountMock : public MountMem {
+namespace {
+
+class MountMemMock : public MountMem {
public:
- MountMock()
- : MountMem(),
- nodes_(0) {
+ MountMemMock()
+ : MountMem(),
+ nodes_(0) {
StringMap_t map;
Init(1, map);
};
- MountNode *AllocateData(int mode) {
+ MountNode* AllocateData(int mode) {
nodes_++;
return MountMem::AllocateData(mode);
}
@@ -38,10 +41,21 @@ class MountMock : public MountMem {
int nodes_;
};
+class MountDevMock : public MountDev {
+ public:
+ MountDevMock() : MountDev() {
+ StringMap_t map;
+ Init(1, map);
+ }
+};
+
+} // namespace
+
+
#define NULL_NODE ((MountNode *) NULL)
TEST(MountTest, Sanity) {
- MountMock* mnt = new MountMock();
+ MountMemMock* mnt = new MountMemMock();
MountNode* file;
MountNode* root;
@@ -127,7 +141,7 @@ TEST(MountTest, Sanity) {
}
TEST(MountTest, MemMountRemove) {
- MountMock* mnt = new MountMock();
+ MountMemMock* mnt = new MountMemMock();
MountNode* file;
EXPECT_EQ(0, mnt->Mkdir(Path("/dir"), O_RDWR));
@@ -143,3 +157,78 @@ TEST(MountTest, MemMountRemove) {
EXPECT_EQ(NULL_NODE, mnt->Open(Path("/file"), O_RDONLY));
EXPECT_EQ(ENOENT, errno);
}
+
+TEST(MountTest, DevNull) {
+ MountDevMock* mnt = new MountDevMock();
+ MountNode* dev_null = mnt->Open(Path("/null"), O_RDWR);
+ ASSERT_NE(NULL_NODE, dev_null);
+
+ // Writing to /dev/null should write everything.
+ const char msg[] = "Dummy test message.";
+ EXPECT_EQ(strlen(msg), dev_null->Write(0, &msg[0], strlen(msg)));
+
+ // Reading from /dev/null should read nothing.
+ const int kBufferLength = 100;
+ char buffer[kBufferLength];
+ EXPECT_EQ(0, dev_null->Read(0, &buffer[0], kBufferLength));
+ EXPECT_EQ(0, mnt->Close(dev_null));
+}
+
+TEST(MountTest, DevZero) {
+ MountDevMock* mnt = new MountDevMock();
+ MountNode* dev_zero = mnt->Open(Path("/zero"), O_RDWR);
+ ASSERT_NE(NULL_NODE, dev_zero);
+
+ // Writing to /dev/zero should write everything.
+ const char msg[] = "Dummy test message.";
+ EXPECT_EQ(strlen(msg), dev_zero->Write(0, &msg[0], strlen(msg)));
+
+ // Reading from /dev/zero should read all zeroes.
+ const int kBufferLength = 100;
+ char buffer[kBufferLength];
+ // First fill with all 1s.
+ memset(&buffer[0], 0x1, kBufferLength);
+ EXPECT_EQ(kBufferLength, dev_zero->Read(0, &buffer[0], kBufferLength));
+
+ char zero_buffer[kBufferLength];
+ memset(&zero_buffer[0], 0, kBufferLength);
+ EXPECT_EQ(0, memcmp(&buffer[0], &zero_buffer[0], kBufferLength));
+ EXPECT_EQ(0, mnt->Close(dev_zero));
+}
+
+TEST(MountTest, DevUrandom) {
+ MountDevMock* mnt = new MountDevMock();
+ MountNode* dev_urandom = mnt->Open(Path("/urandom"), O_RDWR);
+ ASSERT_NE(NULL_NODE, dev_urandom);
+
+ // Writing to /dev/zero should write everything.
+ const char msg[] = "Dummy test message.";
+ EXPECT_EQ(strlen(msg), dev_urandom->Write(0, &msg[0], strlen(msg)));
+
+ // Reading from /dev/urandom should read random bytes.
+ const int kSampleBatches = 1000;
+ const int kSampleBatchSize = 1000;
+ const int kTotalSamples = kSampleBatches * kSampleBatchSize;
+
+ int byte_count[256] = {0};
+
+ unsigned char buffer[kSampleBatchSize];
+ for (int batch = 0; batch < kSampleBatches; ++batch) {
+ int bytes_read = dev_urandom->Read(0, &buffer[0], kSampleBatchSize);
+ EXPECT_EQ(kSampleBatchSize, bytes_read);
+
+ for (int i = 0; i < bytes_read; ++i) {
+ byte_count[buffer[i]]++;
+ }
+ }
+
+ double expected_count = kTotalSamples / 256.;
+ double chi_squared = 0;
+ for (int i = 0; i < 256; ++i) {
+ double difference = byte_count[i] - expected_count;
+ chi_squared += difference * difference / expected_count;
+ }
+
+ // Approximate chi-squared value for p-value 0.05, 255 degrees-of-freedom.
+ EXPECT_LE(chi_squared, 293.24);
+}