diff options
author | binji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-28 22:02:44 +0000 |
---|---|---|
committer | binji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-28 22:02:44 +0000 |
commit | 9ca9e4dbcbe984997fdb19156c4cc1d52366ee21 (patch) | |
tree | e4c6cba494034d036037e102f828b9cd507dca7d /native_client_sdk | |
parent | ed9b489a4ee13131703723e244e1b2dda7c4e0fc (diff) | |
download | chromium_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')
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); +} |