summaryrefslogtreecommitdiffstats
path: root/native_client_sdk
diff options
context:
space:
mode:
authorbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-10 21:16:10 +0000
committerbinji@chromium.org <binji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-10 21:16:10 +0000
commit17511f9115d393261971726fc8a2663b5c29c348 (patch)
treecfcb8037e51cc9a7d7e742cba9a13d5e57808cdc /native_client_sdk
parent0e863bbdb3f9af2d6912f3ec9f8f86e2f05668bf (diff)
downloadchromium_src-17511f9115d393261971726fc8a2663b5c29c348.zip
chromium_src-17511f9115d393261971726fc8a2663b5c29c348.tar.gz
chromium_src-17511f9115d393261971726fc8a2663b5c29c348.tar.bz2
[NaCl SDK] nacl_io: big refactor to return error value (errno).
This is done to prevent forgetting to set it. It also isolates the responsibility of setting errno to kernel_proxy. BUG=244171 R=noelallen@chromium.org Review URL: https://codereview.chromium.org/16232016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@205308 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/build_tools/sdk_files.list3
-rw-r--r--native_client_sdk/src/libraries/nacl_io/error.h17
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_handle.cc63
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_handle.h9
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.cc55
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_object.h15
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc411
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.h5
-rw-r--r--native_client_sdk/src/libraries/nacl_io/library.dsc3
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount.cc27
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount.h53
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_dev.cc352
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_dev.h23
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc136
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_html5fs.h18
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_http.cc769
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_http.h20
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_mem.cc252
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_mem.h18
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.cc133
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.h54
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_dir.cc105
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_dir.h17
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc236
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h24
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_http.cc523
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_http.h70
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_mem.cc72
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_mem.h9
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc165
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_passthrough.h14
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/example.dsc1
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc71
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc86
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc4
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc38
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc98
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc117
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_test.cc123
39 files changed, 2330 insertions, 1879 deletions
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list
index 5fc3614..67eafd0 100644
--- a/native_client_sdk/src/build_tools/sdk_files.list
+++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -232,6 +232,7 @@ include/json/reader.h
include/json/value.h
include/json/writer.h
include/KHR/khrplatform.h
+include/nacl_io/error.h
include/nacl_io/inode_pool.h
include/nacl_io/kernel_handle.h
include/nacl_io/kernel_intercept.h
@@ -247,6 +248,7 @@ include/nacl_io/mount_mem.h
include/nacl_io/mount_node_dir.h
include/nacl_io/mount_node.h
include/nacl_io/mount_node_html5fs.h
+include/nacl_io/mount_node_http.h
include/nacl_io/mount_node_mem.h
include/nacl_io/mount_passthrough.h
include/nacl_io/nacl_io.h
@@ -667,6 +669,7 @@ src/nacl_io/mount_mem.cc
src/nacl_io/mount_node.cc
src/nacl_io/mount_node_dir.cc
src/nacl_io/mount_node_html5fs.cc
+src/nacl_io/mount_node_http.cc
src/nacl_io/mount_node_mem.cc
src/nacl_io/mount_passthrough.cc
src/nacl_io/nacl_io.cc
diff --git a/native_client_sdk/src/libraries/nacl_io/error.h b/native_client_sdk/src/libraries/nacl_io/error.h
new file mode 100644
index 0000000..8f7510e
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/error.h
@@ -0,0 +1,17 @@
+/* Copyright (c) 2013 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_IO_ERROR_H_
+#define LIBRARIES_NACL_IO_ERROR_H_
+
+struct Error {
+ // TODO(binji): Add debugging constructor w/ __FILE__, __LINE__.
+ // crbug.com/247816
+ Error(int error) : error(error) {}
+ operator int() const { return error; }
+
+ int error;
+};
+
+#endif // LIBRARIES_NACL_IO_ERROR_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc b/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
index dcf42fb..a943894 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
@@ -17,40 +17,57 @@
#include "nacl_io/mount_node.h"
// It is only legal to construct a handle while the kernel lock is held.
-KernelHandle::KernelHandle(Mount* mnt, MountNode* node, int mode)
- : mount_(mnt),
- node_(node),
- mode_(mode),
- offs_(0) {
- if (mode & O_APPEND) offs_ = node->GetSize();
+KernelHandle::KernelHandle(Mount* mnt, MountNode* node)
+ : mount_(mnt), node_(node), offs_(0) {}
+
+Error KernelHandle::Init(int open_mode) {
+ if (open_mode & O_APPEND) {
+ size_t node_size;
+ Error error = node_->GetSize(&offs_);
+ if (error)
+ return error;
+ }
+
+ return 0;
}
-off_t KernelHandle::Seek(off_t offset, int whence) {
+Error KernelHandle::Seek(off_t offset, int whence, off_t* out_offset) {
+ // By default, don't move the offset.
+ *out_offset = offset;
+
size_t base;
- size_t node_size = node_->GetSize();
+ size_t node_size;
+ Error error = node_->GetSize(&node_size);
+ if (error)
+ return error;
switch (whence) {
- default: return -1;
- case SEEK_SET: base = 0; break;
- case SEEK_CUR: base = offs_; break;
- case SEEK_END: base = node_size; break;
+ default:
+ return -1;
+ case SEEK_SET:
+ base = 0;
+ break;
+ case SEEK_CUR:
+ base = offs_;
+ break;
+ case SEEK_END:
+ base = node_size;
+ break;
}
- if (base + offset < 0) {
- errno = EINVAL;
- return -1;
- }
+ if (base + offset < 0)
+ return EINVAL;
- offs_ = base + offset;
+ off_t new_offset = base + offset;
// Seeking past the end of the file will zero out the space between the old
// end and the new end.
- if (offs_ > node_size) {
- if (node_->FTruncate(offs_) < 0) {
- errno = EINVAL;
- return -1;
- }
+ if (new_offset > node_size) {
+ error = node_->FTruncate(new_offset);
+ if (error)
+ return EINVAL;
}
- return offs_;
+ *out_offset = offs_ = new_offset;
+ return 0;
}
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_handle.h b/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
index 4695be3..ab7b7cd 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
@@ -7,6 +7,7 @@
#include <pthread.h>
+#include "nacl_io/error.h"
#include "nacl_io/ostypes.h"
#include "sdk_util/macros.h"
#include "sdk_util/ref_object.h"
@@ -19,13 +20,15 @@ class MountNode;
// KernelHandle can only be referenced when the KernelProxy lock is held.
class KernelHandle : public RefObject {
public:
- KernelHandle(Mount* mnt, MountNode* node, int oflags);
+ // Assumes |mnt| and |node| are non-NULL.
+ KernelHandle(Mount* mnt, MountNode* node);
- off_t Seek(off_t offset, int whence);
+ Error Init(int open_flags);
+ // Assumes |out_offset| is non-NULL.
+ Error Seek(off_t offset, int whence, off_t* out_offset);
Mount* mount_;
MountNode* node_;
- int mode_;
size_t offs_;
private:
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
index 4841864..6be3c97 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.cc
@@ -31,8 +31,12 @@ KernelObject::~KernelObject() {
// Uses longest prefix to find the mount for the give path, then
// acquires the mount and returns it with a relative path.
-Mount* KernelObject::AcquireMountAndPath(const std::string& relpath,
- Path* out_path) {
+Error KernelObject::AcquireMountAndPath(const std::string& relpath,
+ Mount** out_mount,
+ Path* out_path) {
+ *out_mount = NULL;
+ *out_path = Path();
+
Path abs_path;
{
AutoLock lock(&process_lock_);
@@ -42,7 +46,6 @@ Mount* KernelObject::AcquireMountAndPath(const std::string& relpath,
AutoLock lock(&kernel_lock_);
Mount* mount = NULL;
-
// Find longest prefix
size_t max = abs_path.Size();
for (size_t len = 0; len < abs_path.Size(); len++) {
@@ -55,14 +58,13 @@ Mount* KernelObject::AcquireMountAndPath(const std::string& relpath,
}
}
- if (NULL == mount) {
- errno = ENOTDIR;
- return NULL;
- }
+ if (NULL == mount)
+ return ENOTDIR;
// Acquire the mount while we hold the proxy lock
mount->Acquire();
- return mount;
+ *out_mount = mount;
+ return 0;
}
void KernelObject::ReleaseMount(Mount* mnt) {
@@ -70,43 +72,38 @@ void KernelObject::ReleaseMount(Mount* mnt) {
mnt->Release();
}
-KernelHandle* KernelObject::AcquireHandle(int fd) {
+Error KernelObject::AcquireHandle(int fd, KernelHandle** out_handle) {
+ *out_handle = NULL;
+
AutoLock lock(&process_lock_);
- if (fd < 0 || fd >= static_cast<int>(handle_map_.size())) {
- errno = EBADF;
- return NULL;
- }
+ if (fd < 0 || fd >= static_cast<int>(handle_map_.size()))
+ return EBADF;
KernelHandle* handle = handle_map_[fd];
- if (NULL == handle) {
- errno = EBADF;
- return NULL;
- }
+ if (NULL == handle)
+ return EBADF;
// Ref count while holding parent mutex
handle->Acquire();
lock.Unlock();
- if (handle->node_) handle->mount_->AcquireNode(handle->node_);
+ if (handle->node_)
+ handle->mount_->AcquireNode(handle->node_);
- return handle;
+ *out_handle = handle;
+ return 0;
}
void KernelObject::ReleaseHandle(KernelHandle* handle) {
// The handle must already be held before taking the
// kernel lock.
- if (handle->node_) handle->mount_->ReleaseNode(handle->node_);
+ if (handle->node_)
+ handle->mount_->ReleaseNode(handle->node_);
AutoLock lock(&process_lock_);
handle->Release();
}
-// Helper function to properly sort FD order in the heap, forcing
-// lower numbered FD to be available first.
-static bool FdOrder(int i, int j) {
- return i > j;
-}
-
int KernelObject::AllocateFD(KernelHandle* handle) {
AutoLock lock(&process_lock_);
int id;
@@ -119,7 +116,8 @@ int KernelObject::AllocateFD(KernelHandle* handle) {
// If we can recycle and FD, use that first
if (free_fds_.size()) {
id = free_fds_.front();
- std::pop_heap(free_fds_.begin(), free_fds_.end(), FdOrder);
+ // Force lower numbered FD to be available first.
+ std::pop_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>());
free_fds_.pop_back();
handle_map_[id] = handle;
} else {
@@ -166,7 +164,8 @@ void KernelObject::FreeFD(int fd) {
handle_map_[fd] = NULL;
free_fds_.push_back(fd);
- std::push_heap(free_fds_.begin(), free_fds_.end(), FdOrder);
+ // Force lower numbered FD to be available first.
+ std::push_heap(free_fds_.begin(), free_fds_.end(), std::greater<int>());
}
Path KernelObject::GetAbsPathLocked(const std::string& path) {
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_object.h b/native_client_sdk/src/libraries/nacl_io/kernel_object.h
index 97b197f..eb4c8ac 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_object.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_object.h
@@ -11,6 +11,7 @@
#include <string>
#include <vector>
+#include "nacl_io/error.h"
#include "nacl_io/path.h"
class KernelHandle;
@@ -28,17 +29,25 @@ class KernelObject {
KernelObject();
virtual ~KernelObject();
- // Find the mount for the given path, and acquires it
- Mount* AcquireMountAndPath(const std::string& relpath, Path *pobj);
+ // Find the mount for the given path, and acquires it.
+ // Assumes |out_mount| and |out_path| are non-NULL.
+ Error AcquireMountAndPath(const std::string& relpath,
+ Mount** out_mount,
+ Path* out_path);
+ // Assumes |mnt| is non-NULL.
void ReleaseMount(Mount* mnt);
// Convert from FD to KernelHandle, and acquire the handle.
- KernelHandle* AcquireHandle(int fd);
+ // Assumes |out_handle| is non-NULL.
+ Error AcquireHandle(int fd, KernelHandle** out_handle);
+ // Assumes |handle| is non-NULL.
void ReleaseHandle(KernelHandle* handle);
// Allocate a new fd and assign the handle to it, while
// ref counting the handle and associated mount.
+ // Assumes |handle| is non-NULL;
int AllocateFD(KernelHandle* handle);
+ // Assumes |handle| is non-NULL;
void FreeAndReassignFD(int fd, KernelHandle* handle);
void FreeFD(int fd);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
index b0c449f..2f49395 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -36,16 +36,9 @@
#define USR_ID 1002
#define GRP_ID 1003
+KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL) {}
-
-KernelProxy::KernelProxy()
- : dev_(0),
- ppapi_(NULL) {
-}
-
-KernelProxy::~KernelProxy() {
- delete ppapi_;
-}
+KernelProxy::~KernelProxy() { delete ppapi_; }
void KernelProxy::Init(PepperInterface* ppapi) {
ppapi_ = ppapi;
@@ -58,11 +51,12 @@ void KernelProxy::Init(PepperInterface* ppapi) {
factories_["httpfs"] = MountHttp::Create<MountHttp>;
factories_["passthroughfs"] = MountPassthrough::Create<MountPassthrough>;
- // Create passthrough mount at root
- StringMap_t smap;
- mounts_["/"] = MountPassthrough::Create<MountPassthrough>(
- dev_++, smap, ppapi_);
- mounts_["/dev"] = MountDev::Create<MountDev>(dev_++, smap, ppapi_);
+ int result;
+ result = mount("", "/", "passthroughfs", 0, NULL);
+ assert(result == 0);
+
+ result = mount("", "/dev", "dev", 0, NULL);
+ assert(result == 0);
// Open the first three in order to get STDIN, STDOUT, STDERR
open("/dev/stdin", O_RDONLY);
@@ -70,19 +64,32 @@ void KernelProxy::Init(PepperInterface* ppapi) {
open("/dev/stderr", O_WRONLY);
}
-int KernelProxy::open(const char *path, int oflags) {
+int KernelProxy::open(const char* path, int oflags) {
Path rel;
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
+ Mount* mnt;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- MountNode* node = mnt->Open(rel, oflags);
- if (node == NULL) {
+ MountNode* node = NULL;
+ error = mnt->Open(rel, oflags, &node);
+ if (error) {
+ errno = error;
+ ReleaseMount(mnt);
+ return -1;
+ }
+
+ KernelHandle* handle = new KernelHandle(mnt, node);
+ error = handle->Init(oflags);
+ if (error) {
+ errno = error;
ReleaseMount(mnt);
return -1;
}
- KernelHandle* handle = new KernelHandle(mnt, node, oflags);
int fd = AllocateFD(handle);
mnt->AcquireNode(node);
@@ -93,9 +100,12 @@ int KernelProxy::open(const char *path, int oflags) {
}
int KernelProxy::close(int fd) {
- KernelHandle* handle = AcquireHandle(fd);
-
- if (NULL == handle) return -1;
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
Mount* mount = handle->mount_;
// Acquire the mount to ensure FreeFD doesn't prematurely destroy it.
@@ -115,8 +125,12 @@ int KernelProxy::close(int fd) {
}
int KernelProxy::dup(int oldfd) {
- KernelHandle* handle = AcquireHandle(oldfd);
- if (NULL == handle) return -1;
+ KernelHandle* handle;
+ Error error = AcquireHandle(oldfd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
int newfd = AllocateFD(handle);
ReleaseHandle(handle);
@@ -126,17 +140,21 @@ int KernelProxy::dup(int oldfd) {
int KernelProxy::dup2(int oldfd, int newfd) {
// If it's the same file handle, just return
- if (oldfd == newfd) return newfd;
+ if (oldfd == newfd)
+ return newfd;
- KernelHandle* old_handle = AcquireHandle(oldfd);
- if (NULL == old_handle) return -1;
+ KernelHandle* old_handle;
+ Error error = AcquireHandle(oldfd, &old_handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
FreeAndReassignFD(newfd, old_handle);
ReleaseHandle(old_handle);
return newfd;
}
-
char* KernelProxy::getcwd(char* buf, size_t size) {
AutoLock lock(&process_lock_);
if (size <= 0) {
@@ -171,42 +189,64 @@ char* KernelProxy::getwd(char* buf) {
return getcwd(buf, MAXPATHLEN);
}
-int KernelProxy::chmod(const char *path, mode_t mode) {
+int KernelProxy::chmod(const char* path, mode_t mode) {
int fd = KernelProxy::open(path, O_RDWR);
- if (-1 == fd) return -1;
+ if (-1 == fd)
+ return -1;
- int ret = fchmod(fd, mode);
+ int result = fchmod(fd, mode);
close(fd);
- return ret;
+ return result;
}
-int KernelProxy::mkdir(const char *path, mode_t mode) {
+int KernelProxy::mkdir(const char* path, mode_t mode) {
+ Mount* mnt;
Path rel;
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ int result = 0;
+ error = mnt->Mkdir(rel, mode);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
- int val = mnt->Mkdir(rel, mode);
ReleaseMount(mnt);
- return val;
+ return result;
}
-int KernelProxy::rmdir(const char *path) {
+int KernelProxy::rmdir(const char* path) {
+ Mount* mnt;
Path rel;
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ int result = 0;
+ error = mnt->Rmdir(rel);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
- int val = mnt->Rmdir(rel);
ReleaseMount(mnt);
- return val;
+ return result;
}
-int KernelProxy::stat(const char *path, struct stat *buf) {
+int KernelProxy::stat(const char* path, struct stat* buf) {
int fd = open(path, O_RDONLY);
- if (-1 == fd) return -1;
+ if (-1 == fd)
+ return -1;
- int ret = fstat(fd, buf);
+ int result = fstat(fd, buf);
close(fd);
- return ret;
+ return result;
}
int KernelProxy::chdir(const char* path) {
@@ -215,19 +255,21 @@ int KernelProxy::chdir(const char* path) {
return -1;
bool is_dir = (statbuf.st_mode & S_IFDIR) != 0;
- if (is_dir) {
- AutoLock lock(&process_lock_);
- cwd_ = GetAbsPathLocked(path).Join();
- return 0;
+ if (!is_dir) {
+ errno = ENOTDIR;
+ return -1;
}
- errno = ENOTDIR;
- return -1;
+ AutoLock lock(&process_lock_);
+ cwd_ = GetAbsPathLocked(path).Join();
+ return 0;
}
-int KernelProxy::mount(const char *source, const char *target,
- const char *filesystemtype, unsigned long mountflags,
- const void *data) {
+int KernelProxy::mount(const char* source,
+ const char* target,
+ const char* filesystemtype,
+ unsigned long mountflags,
+ const void* data) {
// See if it's already mounted
std::string abs_targ;
@@ -255,8 +297,8 @@ int KernelProxy::mount(const char *source, const char *target,
smap["TARGET"] = abs_targ;
if (data) {
- char* str = strdup(static_cast<const char *>(data));
- char* ptr = strtok(str,",");
+ char* str = strdup(static_cast<const char*>(data));
+ char* ptr = strtok(str, ",");
char* val;
while (ptr != NULL) {
val = strchr(ptr, '=');
@@ -271,16 +313,18 @@ int KernelProxy::mount(const char *source, const char *target,
free(str);
}
- Mount* mnt = factory->second(dev_++, smap, ppapi_);
- if (mnt) {
- mounts_[abs_targ] = mnt;
- return 0;
+ Mount* mnt = NULL;
+ Error error = factory->second(dev_++, smap, ppapi_, &mnt);
+ if (error) {
+ errno = error;
+ return -1;
}
- errno = EINVAL;
- return -1;
+
+ mounts_[abs_targ] = mnt;
+ return 0;
}
-int KernelProxy::umount(const char *path) {
+int KernelProxy::umount(const char* path) {
Path abs_path;
// Scope this lock to prevent holding both process and kernel locks
@@ -307,125 +351,204 @@ int KernelProxy::umount(const char *path) {
return 0;
}
-ssize_t KernelProxy::read(int fd, void *buf, size_t nbytes) {
- KernelHandle* handle = AcquireHandle(fd);
-
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
+ssize_t KernelProxy::read(int fd, void* buf, size_t nbytes) {
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
AutoLock lock(&handle->lock_);
- ssize_t cnt = handle->node_->Read(handle->offs_, buf, nbytes);
- if (cnt > 0) handle->offs_ += cnt;
+ int cnt = 0;
+ error = handle->node_->Read(handle->offs_, buf, nbytes, &cnt);
+ if (error)
+ errno = error;
+
+ if (cnt > 0)
+ handle->offs_ += cnt;
ReleaseHandle(handle);
return cnt;
}
-ssize_t KernelProxy::write(int fd, const void *buf, size_t nbytes) {
- KernelHandle* handle = AcquireHandle(fd);
-
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
+ssize_t KernelProxy::write(int fd, const void* buf, size_t nbytes) {
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
AutoLock lock(&handle->lock_);
- ssize_t cnt = handle->node_->Write(handle->offs_, buf, nbytes);
- if (cnt > 0) handle->offs_ += cnt;
+ int cnt = 0;
+ error = handle->node_->Write(handle->offs_, buf, nbytes, &cnt);
+ if (error)
+ errno = error;
+
+ if (cnt > 0)
+ handle->offs_ += cnt;
ReleaseHandle(handle);
return cnt;
}
int KernelProxy::fstat(int fd, struct stat* buf) {
- KernelHandle* handle = AcquireHandle(fd);
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
+ int result = 0;
+ error = handle->node_->GetStat(buf);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
- int ret = handle->node_->GetStat(buf);
ReleaseHandle(handle);
- return ret;
+ return result;
}
int KernelProxy::getdents(int fd, void* buf, unsigned int count) {
- KernelHandle* handle = AcquireHandle(fd);
-
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
AutoLock lock(&handle->lock_);
- int cnt = handle->node_->GetDents(handle->offs_,
- static_cast<dirent *>(buf), count);
+ int cnt = 0;
+ error = handle->node_
+ ->GetDents(handle->offs_, static_cast<dirent*>(buf), count, &cnt);
+ if (error)
+ errno = error;
- if (cnt > 0) handle->offs_ += cnt;
+ if (cnt > 0)
+ handle->offs_ += cnt;
ReleaseHandle(handle);
return cnt;
}
int KernelProxy::ftruncate(int fd, off_t length) {
- KernelHandle* handle = AcquireHandle(fd);
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
- int ret = handle->node_->FTruncate(length);
+ int result = 0;
+ error = handle->node_->FTruncate(length);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
ReleaseHandle(handle);
- return ret;
+ return result;
}
int KernelProxy::fsync(int fd) {
- KernelHandle* handle = AcquireHandle(fd);
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
- int ret = handle->node_->FSync();
+ int result = 0;
+ error = handle->node_->FSync();
+ if (error) {
+ errno = error;
+ result = -1;
+ }
ReleaseHandle(handle);
- return ret;
+ return result;
}
int KernelProxy::isatty(int fd) {
- KernelHandle* handle = AcquireHandle(fd);
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
- int ret = handle->node_->IsaTTY();
+ int result = 0;
+ error = handle->node_->IsaTTY();
+ if (error) {
+ errno = error;
+ result = -1;
+ }
ReleaseHandle(handle);
- return ret;
+ return result;
}
off_t KernelProxy::lseek(int fd, off_t offset, int whence) {
- KernelHandle* handle = AcquireHandle(fd);
-
- // check if fd is valid and handle exists
- if (NULL == handle) return -1;
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
+ return -1;
+ }
AutoLock lock(&handle->lock_);
- int ret = handle->Seek(offset, whence);
+ off_t new_offset;
+ error = handle->Seek(offset, whence, &new_offset);
+ if (error) {
+ errno = error;
+ new_offset = -1;
+ }
ReleaseHandle(handle);
- return ret;
+ return new_offset;
}
int KernelProxy::unlink(const char* path) {
+ Mount* mnt;
Path rel;
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ int result = 0;
+ error = mnt->Unlink(rel);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
- int val = mnt->Unlink(rel);
ReleaseMount(mnt);
- return val;
+ return result;
}
int KernelProxy::remove(const char* path) {
+ Mount* mnt;
Path rel;
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ int result = 0;
+ error = mnt->Remove(rel);
+ if (error) {
+ errno = error;
+ result = -1;
+ }
- int val = mnt->Remove(rel);
ReleaseMount(mnt);
- return val;
+ return result;
}
// TODO(noelallen): Needs implementation.
@@ -449,22 +572,29 @@ int KernelProxy::symlink(const char* oldpath, const char* newpath) {
return -1;
}
-void* KernelProxy::mmap(void* addr, size_t length, int prot, int flags, int fd,
+void* KernelProxy::mmap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ int fd,
size_t offset) {
// We shouldn't be getting anonymous mmaps here.
assert((flags & MAP_ANONYMOUS) == 0);
assert(fd != -1);
- KernelHandle* handle = AcquireHandle(fd);
-
- if (NULL == handle)
+ KernelHandle* handle;
+ Error error = AcquireHandle(fd, &handle);
+ if (error) {
+ errno = error;
return MAP_FAILED;
+ }
void* new_addr;
{
AutoLock lock(&handle->lock_);
- new_addr = handle->node_->MMap(addr, length, prot, flags, offset);
- if (new_addr == MAP_FAILED) {
+ error = handle->node_->MMap(addr, length, prot, flags, offset, &new_addr);
+ if (error) {
+ errno = error;
ReleaseHandle(handle);
return MAP_FAILED;
}
@@ -510,23 +640,34 @@ int KernelProxy::munmap(void* addr, size_t length) {
}
int KernelProxy::open_resource(const char* path) {
+ Mount* mnt;
Path rel;
+ Error error = AcquireMountAndPath(path, &mnt, &rel);
+ if (error) {
+ errno = error;
+ return -1;
+ }
- Mount* mnt = AcquireMountAndPath(path, &rel);
- if (mnt == NULL) return -1;
-
- MountNode* node = mnt->OpenResource(rel);
- if (node == NULL) {
- node = mnt->Open(rel, O_RDONLY);
- if (node == NULL) {
+ MountNode* node = NULL;
+ error = mnt->OpenResource(rel, &node);
+ if (error) {
+ // OpenResource failed, try Open().
+ error = mnt->Open(rel, O_RDONLY, &node);
+ if (error) {
+ errno = error;
ReleaseMount(mnt);
return -1;
}
}
- // OpenResource failed, try Open().
+ KernelHandle* handle = new KernelHandle(mnt, node);
+ error = handle->Init(O_RDONLY);
+ if (error) {
+ errno = error;
+ ReleaseMount(mnt);
+ return -1;
+ }
- KernelHandle* handle = new KernelHandle(mnt, node, O_RDONLY);
int fd = AllocateFD(handle);
mnt->AcquireNode(node);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
index 6c7b6b3..e8c251a 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
@@ -24,9 +24,12 @@ class PepperInterface;
// KernelProxy provide one-to-one mapping for libc kernel calls. Calls to the
// proxy will result in IO access to the provided Mount and MountNode objects.
+//
+// NOTE: The KernelProxy is the only class that should be setting errno. All
+// other classes should return Error (as defined by nacl_io/error.h).
class KernelProxy : protected KernelObject {
public:
- typedef Mount* (*MountFactory_t)(int, StringMap_t&, PepperInterface*);
+ typedef Error (*MountFactory_t)(int, StringMap_t&, PepperInterface*, Mount**);
typedef std::map<std::string, std::string> StringMap_t;
typedef std::map<std::string, MountFactory_t> MountFactoryMap_t;
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index 612af7d..81d621c 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -24,6 +24,7 @@
"mount_node.cc",
"mount_node_dir.cc",
"mount_node_html5fs.cc",
+ "mount_node_http.cc",
"mount_node_mem.cc",
"mount_passthrough.cc",
"nacl_io.cc",
@@ -36,6 +37,7 @@
'HEADERS': [
{
'FILES': [
+ "error.h",
"inode_pool.h",
"kernel_handle.h",
"kernel_intercept.h",
@@ -51,6 +53,7 @@
"mount_node_dir.h",
"mount_node.h",
"mount_node_html5fs.h",
+ "mount_node_http.h",
"mount_node_mem.h",
"mount_passthrough.h",
"nacl_io.h",
diff --git a/native_client_sdk/src/libraries/nacl_io/mount.cc b/native_client_sdk/src/libraries/nacl_io/mount.cc
index f099aa8..76fe3a7 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount.cc
@@ -20,16 +20,14 @@
#include <windows.h>
#endif
-Mount::Mount()
- : dev_(0) {
-}
+Mount::Mount() : dev_(0) {}
Mount::~Mount() {}
-bool Mount::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+Error Mount::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
dev_ = dev;
ppapi_ = ppapi;
- return true;
+ return 0;
}
void Mount::Destroy() {}
@@ -44,23 +42,30 @@ void Mount::ReleaseNode(MountNode* node) {
node->Release();
}
+Error Mount::OpenResource(const Path& path, MountNode** out_node) {
+ *out_node = NULL;
+ return EINVAL;
+}
+
int Mount::OpenModeToPermission(int mode) {
int out;
switch (mode & 3) {
- case O_RDONLY: out = S_IREAD;
- case O_WRONLY: out = S_IWRITE;
- case O_RDWR: out = S_IREAD | S_IWRITE;
+ case O_RDONLY:
+ out = S_IREAD;
+ case O_WRONLY:
+ out = S_IWRITE;
+ case O_RDWR:
+ out = S_IREAD | S_IWRITE;
}
return out;
}
-
void Mount::OnNodeCreated(MountNode* node) {
node->stat_.st_ino = inode_pool_.Acquire();
node->stat_.st_dev = dev_;
}
void Mount::OnNodeDestroyed(MountNode* node) {
- if (node->stat_.st_ino) inode_pool_.Release(node->stat_.st_ino);
+ if (node->stat_.st_ino)
+ inode_pool_.Release(node->stat_.st_ino);
}
-
diff --git a/native_client_sdk/src/libraries/nacl_io/mount.h b/native_client_sdk/src/libraries/nacl_io/mount.h
index abfe68f..ddf1fd5 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount.h
@@ -8,6 +8,7 @@
#include <map>
#include <string>
+#include "nacl_io/error.h"
#include "nacl_io/inode_pool.h"
#include "nacl_io/mount_node.h"
#include "nacl_io/path.h"
@@ -19,7 +20,8 @@ class PepperInterface;
typedef std::map<std::string, std::string> StringMap_t;
-
+// NOTE: The KernelProxy is the only class that should be setting errno. All
+// other classes should return Error (as defined by nacl_io/error.h).
class Mount : public RefObject {
protected:
// The protected functions are only used internally and will not
@@ -30,38 +32,49 @@ class Mount : public RefObject {
// Init must be called by the factory before the mount is used.
// This function must assign a root node, or replace FindNode.
// |ppapi| can be NULL. If so, this mount cannot make any pepper calls.
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
public:
template <class M>
- static Mount* Create(int dev, StringMap_t& args, PepperInterface* ppapi);
+ // Assumes that |out_mount| is non-NULL.
+ static Error Create(int dev,
+ StringMap_t& args,
+ PepperInterface* ppapi,
+ Mount** out_mount);
PepperInterface* ppapi() { return ppapi_; }
- // All paths are expected to containing a leading "/"
+ // Assumes that |node| is non-NULL.
void AcquireNode(MountNode* node);
+ // Assumes that |node| is non-NULL.
void ReleaseNode(MountNode* node);
+ // All paths in functions below are expected to containing a leading "/".
+
// Open a node at |path| with the specified open flags. The resulting
// MountNode is created with a ref count of 1.
- virtual MountNode *Open(const Path& path, int o_flags) = 0;
+ // Assumes that |out_node| is non-NULL.
+ virtual Error Open(const Path& path, int o_flags, MountNode** out_node) = 0;
// OpenResource is only used to read files from the NaCl NMF file. No mount
// except MountPassthrough should implement it.
- virtual MountNode *OpenResource(const Path& path) { return NULL; }
+ // Assumes that |out_node| is non-NULL.
+ virtual Error OpenResource(const Path& path, MountNode** out_node);
// Unlink, Mkdir, Rmdir will affect the both the RefCount
// and the nlink number in the stat object.
- virtual int Unlink(const Path& path) = 0;
- virtual int Mkdir(const Path& path, int permissions) = 0;
- virtual int Rmdir(const Path& path) = 0;
- virtual int Remove(const Path& path) = 0;
+ virtual Error Unlink(const Path& path) = 0;
+ virtual Error Mkdir(const Path& path, int permissions) = 0;
+ virtual Error Rmdir(const Path& path) = 0;
+ virtual Error Remove(const Path& path) = 0;
// Convert from R,W,R/W open flags to STAT permission flags
static int OpenModeToPermission(int mode);
- void OnNodeCreated(MountNode* node) ;
+ // Assumes that |node| is non-NULL.
+ void OnNodeCreated(MountNode* node);
+ // Assumes that |node| is non-NULL.
void OnNodeDestroyed(MountNode* node);
protected:
@@ -81,16 +94,22 @@ class Mount : public RefObject {
DISALLOW_COPY_AND_ASSIGN(Mount);
};
-
-template <class M>
/*static*/
-Mount* Mount::Create(int dev, StringMap_t& args, PepperInterface* ppapi) {
+template <class M>
+Error Mount::Create(int dev,
+ StringMap_t& args,
+ PepperInterface* ppapi,
+ Mount** out_mount) {
Mount* mnt = new M();
- if (mnt->Init(dev, args, ppapi) == false) {
+ Error error = mnt->Init(dev, args, ppapi);
+ if (error) {
delete mnt;
- return NULL;
+ *out_mount = NULL;
+ return error;
}
- return mnt;
+
+ *out_mount = mnt;
+ return 0;
}
#endif // LIBRARIES_NACL_IO_MOUNT_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_dev.cc b/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
index 9190a92..11893ea 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_dev.cc
@@ -17,28 +17,23 @@
#include "sdk_util/auto_lock.h"
#if defined(__native_client__)
-# include <irt.h>
+#include <irt.h>
#elif defined(WIN32)
-# include <stdlib.h>
+#include <stdlib.h>
#endif
-
namespace {
-void ReleaseAndNullNode(MountNode** node) {
- if (*node)
- (*node)->Release();
- *node = NULL;
-}
-
-
class RealNode : public MountNode {
public:
RealNode(Mount* mount, int fd);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
- virtual int GetStat(struct stat* stat);
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
+ virtual Error GetStat(struct stat* stat);
protected:
int fd_;
@@ -48,43 +43,56 @@ class NullNode : public MountNode {
public:
explicit NullNode(Mount* mount);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
};
class ConsoleNode : public NullNode {
public:
ConsoleNode(Mount* mount, PP_LogLevel level);
- virtual int Write(size_t offs, const void* buf, size_t count);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
-private:
+ private:
PP_LogLevel level_;
};
-
class TtyNode : public NullNode {
public:
explicit TtyNode(Mount* mount);
- virtual int Write(size_t offs, const void* buf, size_t count);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
};
-
class ZeroNode : public MountNode {
public:
explicit ZeroNode(Mount* mount);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
};
class UrandomNode : public MountNode {
public:
explicit UrandomNode(Mount* mount);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
private:
#if defined(__native_client__)
@@ -93,132 +101,141 @@ class UrandomNode : public MountNode {
#endif
};
-RealNode::RealNode(Mount* mount, int fd)
- : MountNode(mount),
- fd_(fd) {
+RealNode::RealNode(Mount* mount, int fd) : MountNode(mount), fd_(fd) {
stat_.st_mode = S_IFCHR;
}
-int RealNode::Read(size_t offs, void* buf, size_t count) {
+Error RealNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
+
size_t readcnt;
int err = _real_read(fd_, buf, count, &readcnt);
- if (err) {
- errno = err;
- return -1;
- }
- return static_cast<int>(readcnt);
+ if (err)
+ return err;
+
+ *out_bytes = static_cast<int>(readcnt);
+ return 0;
}
-int RealNode::Write(size_t offs, const void* buf, size_t count) {
+Error RealNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
size_t writecnt;
int err = _real_write(fd_, buf, count, &writecnt);
- if (err) {
- errno = err;
- return -1;
- }
- return static_cast<int>(writecnt);
-}
+ if (err)
+ return err;
-int RealNode::GetStat(struct stat* stat) {
- int err = _real_fstat(fd_, stat);
- if (err) {
- errno = err;
- return -1;
- }
+ *out_bytes = static_cast<int>(writecnt);
return 0;
}
-NullNode::NullNode(Mount* mount)
- : MountNode(mount) {
- stat_.st_mode = S_IFCHR;
-}
+Error RealNode::GetStat(struct stat* stat) { return _real_fstat(fd_, stat); }
-int NullNode::Read(size_t offs, void* buf, size_t count) {
+NullNode::NullNode(Mount* mount) : MountNode(mount) { stat_.st_mode = S_IFCHR; }
+
+Error NullNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
return 0;
}
-int NullNode::Write(size_t offs, const void* buf, size_t count) {
- return count;
+Error NullNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = count;
+ return 0;
}
ConsoleNode::ConsoleNode(Mount* mount, PP_LogLevel level)
- : NullNode(mount),
- level_(level) {
+ : NullNode(mount), level_(level) {
stat_.st_mode = S_IFCHR;
}
-int ConsoleNode::Write(size_t offs, const void* buf, size_t count) {
+Error ConsoleNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
ConsoleInterface* con_intr = mount_->ppapi()->GetConsoleInterface();
VarInterface* var_intr = mount_->ppapi()->GetVarInterface();
- if (var_intr && con_intr) {
- const char* data = static_cast<const char *>(buf);
- uint32_t len = static_cast<uint32_t>(count);
- struct PP_Var val = var_intr->VarFromUtf8(data, len);
- con_intr->Log(mount_->ppapi()->GetInstance(), level_, val);
- return count;
- }
+ if (!(var_intr && con_intr))
+ return ENOSYS;
+
+ const char* data = static_cast<const char*>(buf);
+ uint32_t len = static_cast<uint32_t>(count);
+ struct PP_Var val = var_intr->VarFromUtf8(data, len);
+ con_intr->Log(mount_->ppapi()->GetInstance(), level_, val);
+
+ *out_bytes = count;
return 0;
}
+TtyNode::TtyNode(Mount* mount) : NullNode(mount) {}
-TtyNode::TtyNode(Mount* mount)
- : NullNode(mount) {
-}
+Error TtyNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
-int TtyNode::Write(size_t offs, const void* buf, size_t count) {
MessagingInterface* msg_intr = mount_->ppapi()->GetMessagingInterface();
VarInterface* var_intr = mount_->ppapi()->GetVarInterface();
- if (var_intr && msg_intr) {
- const char* data = static_cast<const char *>(buf);
- uint32_t len = static_cast<uint32_t>(count);
- struct PP_Var val = var_intr->VarFromUtf8(data, len);
- msg_intr->PostMessage(mount_->ppapi()->GetInstance(), val);
- return count;
- }
- return 0;
-}
+ if (!(var_intr && msg_intr))
+ return ENOSYS;
+ const char* data = static_cast<const char*>(buf);
+ uint32_t len = static_cast<uint32_t>(count);
+ struct PP_Var val = var_intr->VarFromUtf8(data, len);
+ msg_intr->PostMessage(mount_->ppapi()->GetInstance(), val);
-ZeroNode::ZeroNode(Mount* mount)
- : MountNode(mount) {
- stat_.st_mode = S_IFCHR;
+ *out_bytes = count;
+ return 0;
}
-int ZeroNode::Read(size_t offs, void* buf, size_t count) {
+ZeroNode::ZeroNode(Mount* mount) : MountNode(mount) { stat_.st_mode = S_IFCHR; }
+
+Error ZeroNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
memset(buf, 0, count);
- return count;
+ *out_bytes = count;
+ return 0;
}
-int ZeroNode::Write(size_t offs, const void* buf, size_t count) {
- return count;
+Error ZeroNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = count;
+ return 0;
}
-UrandomNode::UrandomNode(Mount* mount)
- : MountNode(mount) {
+UrandomNode::UrandomNode(Mount* mount) : MountNode(mount) {
stat_.st_mode = S_IFCHR;
#if defined(__native_client__)
- size_t result = nacl_interface_query(NACL_IRT_RANDOM_v0_1, &random_interface_,
- sizeof(random_interface_));
+ 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) {
+Error UrandomNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
+
#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;
- }
+ if (!interface_ok_)
+ return EBADF;
- return count;
- }
+ size_t nread;
+ int error = (*random_interface_.get_random_bytes)(buf, count, &nread);
+ if (error)
+ return error;
- errno = EBADF;
+ *out_bytes = count;
return 0;
#elif defined(WIN32)
char* out = static_cast<char*>(buf);
@@ -227,8 +244,8 @@ int UrandomNode::Read(size_t offs, void* buf, size_t count) {
unsigned int random_int;
errno_t err = rand_s(&random_int);
if (err) {
- errno = err;
- return count - bytes_left;
+ *out_bytes = count - bytes_left;
+ return err;
}
int bytes_to_copy = std::min(bytes_left, sizeof(random_int));
@@ -237,107 +254,84 @@ int UrandomNode::Read(size_t offs, void* buf, size_t count) {
bytes_left -= bytes_to_copy;
}
- return count;
+ *out_bytes = count;
+ return 0;
#endif
}
-int UrandomNode::Write(size_t offs, const void* buf, size_t count) {
- return count;
+Error UrandomNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = count;
+ return 0;
}
-
-
} // namespace
-MountNode *MountDev::Open(const Path& path, int mode) {
+Error MountDev::Open(const Path& path, int mode, MountNode** out_node) {
+ *out_node = NULL;
+
AutoLock lock(&lock_);
// Don't allow creating any files.
if (mode & O_CREAT)
- return NULL;
+ return EINVAL;
- MountNode* node = root_->FindChild(path.Join());
- if (node)
- node->Acquire();
- return node;
-}
+ MountNode* node = NULL;
+ int error = root_->FindChild(path.Join(), &node);
+ if (error)
+ return error;
-int MountDev::Unlink(const Path& path) {
- errno = EINVAL;
- return -1;
+ node->Acquire();
+ *out_node = node;
+ return 0;
}
-int MountDev::Mkdir(const Path& path, int permissions) {
- errno = EINVAL;
- return -1;
-}
+Error MountDev::Unlink(const Path& path) { return EINVAL; }
-int MountDev::Rmdir(const Path& path) {
- errno = EINVAL;
- return -1;
-}
+Error MountDev::Mkdir(const Path& path, int permissions) { return EINVAL; }
-int MountDev::Remove(const Path& path) {
- errno = EINVAL;
- return -1;
-}
+Error MountDev::Rmdir(const Path& path) { return EINVAL; }
-MountDev::MountDev()
- : null_node_(NULL),
- zero_node_(NULL),
- random_node_(NULL),
- console0_node_(NULL),
- console1_node_(NULL),
- console2_node_(NULL),
- console3_node_(NULL),
- tty_node_(NULL) {
-}
+Error MountDev::Remove(const Path& path) { return EINVAL; }
-bool MountDev::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
- if (!Mount::Init(dev, args, ppapi))
- return false;
+MountDev::MountDev() {}
+
+#define INITIALIZE_DEV_NODE(path, klass) \
+ error = root_->AddChild(path, new klass(this)); \
+ if (error) \
+ return error;
+
+#define INITIALIZE_DEV_NODE_1(path, klass, arg) \
+ error = root_->AddChild(path, new klass(this, arg)); \
+ if (error) \
+ return error;
+
+Error MountDev::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+ Error error = Mount::Init(dev, args, ppapi);
+ if (error)
+ return error;
root_ = new MountNodeDir(this);
- null_node_ = new NullNode(this);
- root_->AddChild("/null", null_node_);
- zero_node_ = new ZeroNode(this);
- root_->AddChild("/zero", zero_node_);
- random_node_ = new UrandomNode(this);
- root_->AddChild("/urandom", random_node_);
-
- console0_node_ = new ConsoleNode(this, PP_LOGLEVEL_TIP);
- root_->AddChild("/console0", console0_node_);
- console1_node_ = new ConsoleNode(this, PP_LOGLEVEL_LOG);
- root_->AddChild("/console1", console1_node_);
- console2_node_ = new ConsoleNode(this, PP_LOGLEVEL_WARNING);
- root_->AddChild("/console2", console2_node_);
- console3_node_ = new ConsoleNode(this, PP_LOGLEVEL_ERROR);
- root_->AddChild("/console3", console3_node_);
-
- tty_node_ = new TtyNode(this);
- root_->AddChild("/tty", tty_node_);
-
- stdin_node_ = new RealNode(this, 0);
- root_->AddChild("/stdin", stdin_node_);
- stdout_node_ = new RealNode(this, 1);
- root_->AddChild("/stdout", stdout_node_);
- stderr_node_ = new RealNode(this, 2);
- root_->AddChild("/stderr", stderr_node_);
-
- return true;
+
+ INITIALIZE_DEV_NODE("/null", NullNode);
+ INITIALIZE_DEV_NODE("/zero", ZeroNode);
+ INITIALIZE_DEV_NODE("/urandom", UrandomNode);
+ INITIALIZE_DEV_NODE_1("/console0", ConsoleNode, PP_LOGLEVEL_TIP);
+ INITIALIZE_DEV_NODE_1("/console1", ConsoleNode, PP_LOGLEVEL_LOG);
+ INITIALIZE_DEV_NODE_1("/console2", ConsoleNode, PP_LOGLEVEL_WARNING);
+ INITIALIZE_DEV_NODE_1("/console3", ConsoleNode, PP_LOGLEVEL_ERROR);
+ INITIALIZE_DEV_NODE("/tty", TtyNode);
+ INITIALIZE_DEV_NODE_1("/stdin", RealNode, 0);
+ INITIALIZE_DEV_NODE_1("/stdout", RealNode, 1);
+ INITIALIZE_DEV_NODE_1("/stderr", RealNode, 2);
+
+ return 0;
}
void MountDev::Destroy() {
- ReleaseAndNullNode(&stdin_node_);
- ReleaseAndNullNode(&stdout_node_);
- ReleaseAndNullNode(&stderr_node_);
- ReleaseAndNullNode(&tty_node_);
- ReleaseAndNullNode(&console3_node_);
- ReleaseAndNullNode(&console2_node_);
- ReleaseAndNullNode(&console1_node_);
- ReleaseAndNullNode(&console0_node_);
- ReleaseAndNullNode(&random_node_);
- ReleaseAndNullNode(&zero_node_);
- ReleaseAndNullNode(&null_node_);
- ReleaseAndNullNode(&root_);
+ if (root_)
+ root_->Release();
+ root_ = NULL;
}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_dev.h b/native_client_sdk/src/libraries/nacl_io/mount_dev.h
index ff3d99c1..7ad7daa 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_dev.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_dev.h
@@ -11,32 +11,21 @@ class MountNode;
class MountDev : public Mount {
public:
- virtual MountNode *Open(const Path& path, int mode);
+ virtual Error Open(const Path& path, int mode, MountNode** out_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);
+ virtual Error Unlink(const Path& path);
+ virtual Error Mkdir(const Path& path, int permissions);
+ virtual Error Rmdir(const Path& path);
+ virtual Error Remove(const Path& path);
protected:
MountDev();
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
private:
MountNode* root_;
- MountNode* null_node_;
- MountNode* zero_node_;
- MountNode* random_node_;
- MountNode* console0_node_;
- MountNode* console1_node_;
- MountNode* console2_node_;
- MountNode* console3_node_;
- MountNode* tty_node_;
- MountNode* stderr_node_;
- MountNode* stdin_node_;
- MountNode* stdout_node_;
friend class Mount;
};
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
index c49acae..0008284 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
@@ -24,96 +24,85 @@ int64_t strtoull(const char* nptr, char** endptr, int base) {
} // namespace
-MountNode *MountHtml5Fs::Open(const Path& path, int mode) {
- if (BlockUntilFilesystemOpen() != PP_OK) {
- errno = ENODEV;
- return NULL;
- }
+Error MountHtml5Fs::Open(const Path& path, int mode, MountNode** out_node) {
+ *out_node = NULL;
+
+ Error error = BlockUntilFilesystemOpen();
+ if (error)
+ return error;
- PP_Resource fileref = ppapi()->GetFileRefInterface()->Create(
- filesystem_resource_, path.Join().c_str());
+ PP_Resource fileref = ppapi()->GetFileRefInterface()
+ ->Create(filesystem_resource_, path.Join().c_str());
if (!fileref)
- return NULL;
+ return ENOSYS;
MountNodeHtml5Fs* node = new MountNodeHtml5Fs(this, fileref);
- if (!node->Init(mode)) {
+ error = node->Init(mode);
+ if (error) {
node->Release();
- return NULL;
+ return error;
}
- return node;
+ *out_node = node;
+ return 0;
}
-int MountHtml5Fs::Unlink(const Path& path) {
- return Remove(path);
-}
+Error MountHtml5Fs::Unlink(const Path& path) { return Remove(path); }
-int MountHtml5Fs::Mkdir(const Path& path, int permissions) {
- if (BlockUntilFilesystemOpen() != PP_OK) {
- errno = ENODEV;
- return -1;
- }
+Error MountHtml5Fs::Mkdir(const Path& path, int permissions) {
+ Error error = BlockUntilFilesystemOpen();
+ if (error)
+ return error;
ScopedResource fileref_resource(
- ppapi(), ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
- path.Join().c_str()));
- if (!fileref_resource.pp_resource()) {
- errno = EINVAL;
- return -1;
- }
+ ppapi(),
+ ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
+ path.Join().c_str()));
+ if (!fileref_resource.pp_resource())
+ return EIO;
int32_t result = ppapi()->GetFileRefInterface()->MakeDirectory(
fileref_resource.pp_resource(), PP_FALSE, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
return 0;
}
-int MountHtml5Fs::Rmdir(const Path& path) {
- return Remove(path);
-}
+Error MountHtml5Fs::Rmdir(const Path& path) { return Remove(path); }
-int MountHtml5Fs::Remove(const Path& path) {
- if (BlockUntilFilesystemOpen() != PP_OK) {
- errno = ENODEV;
- return -1;
- }
+Error MountHtml5Fs::Remove(const Path& path) {
+ Error error = BlockUntilFilesystemOpen();
+ if (error)
+ return error;
ScopedResource fileref_resource(
- ppapi(), ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
- path.Join().c_str()));
- if (!fileref_resource.pp_resource()) {
- errno = EINVAL;
- return -1;
- }
+ ppapi(),
+ ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
+ path.Join().c_str()));
+ if (!fileref_resource.pp_resource())
+ return ENOSYS;
- int32_t result = ppapi()->GetFileRefInterface()->Delete(
- fileref_resource.pp_resource(),
- PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+ int32_t result = ppapi()->GetFileRefInterface()
+ ->Delete(fileref_resource.pp_resource(), PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
return 0;
}
-
MountHtml5Fs::MountHtml5Fs()
: filesystem_resource_(0),
filesystem_open_has_result_(false),
- filesystem_open_result_(PP_OK) {
-}
+ filesystem_open_error_(0) {}
-bool MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
- if (!Mount::Init(dev, args, ppapi))
- return false;
+Error MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+ Error error = Mount::Init(dev, args, ppapi);
+ if (error)
+ return error;
if (!ppapi)
- return false;
+ return ENOSYS;
pthread_cond_init(&filesystem_open_cond_, NULL);
@@ -121,7 +110,7 @@ bool MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
PP_FileSystemType filesystem_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
int64_t expected_size = 0;
for (StringMap_t::iterator iter = args.begin(), end = args.end(); iter != end;
- ++iter) {
+ ++iter) {
if (iter->first == "type") {
if (iter->second == "PERSISTENT") {
filesystem_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
@@ -134,33 +123,32 @@ bool MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
}
// Initialize filesystem.
- filesystem_resource_ = ppapi->GetFileSystemInterface()->Create(
- ppapi_->GetInstance(), filesystem_type);
-
+ filesystem_resource_ = ppapi->GetFileSystemInterface()
+ ->Create(ppapi_->GetInstance(), filesystem_type);
if (filesystem_resource_ == 0)
- return false;
+ return ENOSYS;
// We can't block the main thread, so make an asynchronous call if on main
// thread. If we are off-main-thread, then don't make an asynchronous call;
// otherwise we require a message loop.
bool main_thread = ppapi->IsMainThread();
- PP_CompletionCallback cc = main_thread ?
- PP_MakeCompletionCallback(&MountHtml5Fs::FilesystemOpenCallbackThunk,
- this) :
- PP_BlockUntilComplete();
+ PP_CompletionCallback cc =
+ main_thread ? PP_MakeCompletionCallback(
+ &MountHtml5Fs::FilesystemOpenCallbackThunk, this)
+ : PP_BlockUntilComplete();
- int32_t result = ppapi->GetFileSystemInterface()->Open(
- filesystem_resource_, expected_size, cc);
+ int32_t result = ppapi->GetFileSystemInterface()
+ ->Open(filesystem_resource_, expected_size, cc);
if (!main_thread) {
filesystem_open_has_result_ = true;
- filesystem_open_result_ = result;
+ filesystem_open_error_ = PPErrorToErrno(result);
- return filesystem_open_result_ == PP_OK;
+ return filesystem_open_error_;
} else {
// We have to assume the call to Open will succeed; there is no better
// result to return here.
- return true;
+ return 0;
}
}
@@ -169,12 +157,12 @@ void MountHtml5Fs::Destroy() {
pthread_cond_destroy(&filesystem_open_cond_);
}
-int32_t MountHtml5Fs::BlockUntilFilesystemOpen() {
+Error MountHtml5Fs::BlockUntilFilesystemOpen() {
AutoLock lock(&lock_);
while (!filesystem_open_has_result_) {
pthread_cond_wait(&filesystem_open_cond_, &lock_);
}
- return filesystem_open_result_;
+ return filesystem_open_error_;
}
// static
@@ -187,6 +175,6 @@ void MountHtml5Fs::FilesystemOpenCallbackThunk(void* user_data,
void MountHtml5Fs::FilesystemOpenCallback(int32_t result) {
AutoLock lock(&lock_);
filesystem_open_has_result_ = true;
- filesystem_open_result_ = result;
+ filesystem_open_error_ = PPErrorToErrno(result);
pthread_cond_signal(&filesystem_open_cond_);
}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h
index a6633be..e872dae 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.h
@@ -11,23 +11,23 @@
class MountNode;
-class MountHtml5Fs: public Mount {
+class MountHtml5Fs : public Mount {
public:
- virtual MountNode *Open(const Path& path, int mode);
- 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);
+ virtual Error Open(const Path& path, int mode, MountNode** out_node);
+ virtual Error Unlink(const Path& path);
+ virtual Error Mkdir(const Path& path, int permissions);
+ virtual Error Rmdir(const Path& path);
+ virtual Error Remove(const Path& path);
PP_Resource filesystem_resource() { return filesystem_resource_; }
protected:
MountHtml5Fs();
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
- int32_t BlockUntilFilesystemOpen();
+ Error BlockUntilFilesystemOpen();
private:
static void FilesystemOpenCallbackThunk(void* user_data, int32_t result);
@@ -35,7 +35,7 @@ class MountHtml5Fs: public Mount {
PP_Resource filesystem_resource_;
bool filesystem_open_has_result_; // protected by lock_.
- int32_t filesystem_open_result_; // protected by lock_.
+ Error filesystem_open_error_; // protected by lock_.
pthread_cond_t filesystem_open_cond_;
friend class Mount;
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_http.cc b/native_client_sdk/src/libraries/nacl_io/mount_http.cc
index 9e6155f..7b4316e 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_http.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_http.cc
@@ -4,30 +4,30 @@
*/
#include "nacl_io/mount_http.h"
+
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
-#include <ppapi/c/pp_errors.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
+
#include <vector>
+
+#include <ppapi/c/pp_errors.h>
+
#include "nacl_io/mount_node_dir.h"
+#include "nacl_io/mount_node_http.h"
#include "nacl_io/osinttypes.h"
#include "sdk_util/auto_lock.h"
-#if defined(WIN32)
-#define snprintf _snprintf
-#endif
-
-
namespace {
-typedef std::vector<char *> StringList_t;
-size_t SplitString(char *str, const char *delim, StringList_t* list) {
- char *item = strtok(str, delim);
+typedef std::vector<char*> StringList_t;
+size_t SplitString(char* str, const char* delim, StringList_t* list) {
+ char* item = strtok(str, delim);
list->clear();
while (item) {
@@ -38,13 +38,7 @@ size_t SplitString(char *str, const char *delim, StringList_t* list) {
return list->size();
}
-
-// If we're attempting to read a partial request, but the server returns a full
-// request, we need to read all of the data up to the start of our partial
-// request into a dummy buffer. This is the maximum size of that buffer.
-const size_t MAX_READ_BUFFER_SIZE = 64 * 1024;
-const int32_t STATUSCODE_OK = 200;
-const int32_t STATUSCODE_PARTIAL_CONTENT = 206;
+} // namespace
std::string NormalizeHeaderKey(const std::string& s) {
// Capitalize the first letter and any letter following a hyphen:
@@ -60,557 +54,64 @@ std::string NormalizeHeaderKey(const std::string& s) {
return result;
}
-StringMap_t ParseHeaders(const char* headers, int32_t headers_length) {
- enum State {
- FINDING_KEY,
- SKIPPING_WHITESPACE,
- FINDING_VALUE,
- };
-
- StringMap_t result;
- std::string key;
- std::string value;
-
- State state = FINDING_KEY;
- const char* start = headers;
- for (int i = 0; i < headers_length; ++i) {
- switch (state) {
- case FINDING_KEY:
- if (headers[i] == ':') {
- // Found key.
- key.assign(start, &headers[i] - start);
- key = NormalizeHeaderKey(key);
- state = SKIPPING_WHITESPACE;
- }
- break;
-
- case SKIPPING_WHITESPACE:
- if (headers[i] == ' ') {
- // Found whitespace, keep going...
- break;
- }
-
- // Found a non-whitespace, mark this as the start of the value.
- start = &headers[i];
- state = FINDING_VALUE;
- // Fallthrough to start processing value without incrementing i.
-
- case FINDING_VALUE:
- if (headers[i] == '\n') {
- // Found value.
- value.assign(start, &headers[i] - start);
- result[key] = value;
- start = &headers[i + 1];
- state = FINDING_KEY;
- }
- break;
- }
- }
-
- return result;
-}
-
-bool ParseContentLength(const StringMap_t& headers, size_t* content_length) {
- StringMap_t::const_iterator iter = headers.find("Content-Length");
- if (iter == headers.end())
- return false;
-
- *content_length = strtoul(iter->second.c_str(), NULL, 10);
- return true;
-}
-
-bool ParseContentRange(const StringMap_t& headers, size_t* read_start,
- size_t* read_end, size_t* entity_length) {
- StringMap_t::const_iterator iter = headers.find("Content-Range");
- if (iter == headers.end())
- return false;
-
- // The key should look like "bytes ##-##/##" or "bytes ##-##/*". The last
- // value is the entity length, which can potentially be * (i.e. unknown).
- int read_start_int;
- int read_end_int;
- int entity_length_int;
- int result = sscanf(iter->second.c_str(), "bytes %"SCNuS"-%"SCNuS"/%"SCNuS,
- &read_start_int, &read_end_int, &entity_length_int);
-
- // The Content-Range header specifies an inclusive range: e.g. the first ten
- // bytes is "bytes 0-9/*". Convert it to a half-open range by incrementing
- // read_end.
- if (result == 2) {
- *read_start = read_start_int;
- *read_end = read_end_int + 1;
- *entity_length = 0;
- return true;
- } else if (result == 3) {
- *read_start = read_start_int;
- *read_end = read_end_int + 1;
- *entity_length = entity_length_int;
- return true;
- }
-
- return false;
-}
-
-} // namespace
-
-
-class MountNodeHttp : public MountNode {
- public:
- virtual int FSync();
- virtual int GetDents(size_t offs, struct dirent* pdir, size_t count);
- virtual int GetStat(struct stat* stat);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int FTruncate(off_t size);
- virtual int Write(size_t offs, const void* buf, size_t count);
- virtual size_t GetSize();
-
- void SetCachedSize(off_t size);
-
- protected:
- MountNodeHttp(Mount* mount, const std::string& url, bool cache_content);
-
- private:
- bool OpenUrl(const char* method,
- StringMap_t* request_headers,
- PP_Resource* out_loader,
- PP_Resource* out_request,
- PP_Resource* out_response,
- int32_t* out_statuscode,
- StringMap_t* out_response_headers);
-
- int DownloadToCache();
- int ReadPartialFromCache(size_t offs, void* buf, size_t count);
- int DownloadPartial(size_t offs, void* buf, size_t count);
- int DownloadToBuffer(PP_Resource loader, void* buf, size_t count);
-
- std::string url_;
- std::vector<char> buffer_;
-
- bool cache_content_;
- bool has_cached_size_;
- std::vector<char> cached_data_;
-
- friend class MountHttp;
-};
-
-void MountNodeHttp::SetCachedSize(off_t size) {
- has_cached_size_ = true;
- stat_.st_size = size;
-}
-
-int MountNodeHttp::FSync() {
- errno = ENOSYS;
- return -1;
-}
-
-int MountNodeHttp::GetDents(size_t offs, struct dirent* pdir, size_t count) {
- errno = ENOSYS;
- return -1;
-}
-
-int MountNodeHttp::GetStat(struct stat* stat) {
- AutoLock lock(&lock_);
-
- // Assume we need to 'HEAD' if we do not know the size, otherwise, assume
- // that the information is constant. We can add a timeout if needed.
- MountHttp* mount = static_cast<MountHttp*>(mount_);
- if (stat_.st_size == 0 || !mount->cache_stat_) {
- StringMap_t headers;
- PP_Resource loader;
- PP_Resource request;
- PP_Resource response;
- int32_t statuscode;
- StringMap_t response_headers;
- if (!OpenUrl("HEAD", &headers, &loader, &request, &response, &statuscode,
- &response_headers)) {
- // errno is already set by OpenUrl.
- return -1;
- }
-
- ScopedResource scoped_loader(mount_->ppapi(), loader);
- ScopedResource scoped_request(mount_->ppapi(), request);
- ScopedResource scoped_response(mount_->ppapi(), response);
-
-
- size_t entity_length;
- if (ParseContentLength(response_headers, &entity_length)) {
- SetCachedSize(static_cast<off_t>(entity_length));
- } else if (cache_content_ && !has_cached_size_) {
- DownloadToCache();
- } else {
- // Don't use SetCachedSize here -- it is actually unknown.
- stat_.st_size = 0;
- }
-
- stat_.st_atime = 0; // TODO(binji): Use "Last-Modified".
- stat_.st_mtime = 0;
- stat_.st_ctime = 0;
- }
-
- // Fill the stat structure if provided
- if (stat) {
- memcpy(stat, &stat_, sizeof(stat_));
- }
- return 0;
-}
-
-int MountNodeHttp::Read(size_t offs, void* buf, size_t count) {
- AutoLock lock(&lock_);
- if (cache_content_) {
- if (cached_data_.empty()) {
- if (DownloadToCache() < 0)
- return -1;
- }
-
- return ReadPartialFromCache(offs, buf, count);
- }
-
- return DownloadPartial(offs, buf, count);
-}
-
-int MountNodeHttp::FTruncate(off_t size) {
- errno = ENOSYS;
- return -1;
-}
-
-int MountNodeHttp::Write(size_t offs, const void* buf, size_t count) {
- // TODO(binji): support POST?
- errno = ENOSYS;
- return -1;
-}
-
-size_t MountNodeHttp::GetSize() {
- // TODO(binji): This value should be cached properly; i.e. obey the caching
- // headers returned by the server.
- AutoLock lock(&lock_);
- if (!has_cached_size_) {
- // Even if DownloadToCache fails, the best result we can return is what
- // was written to stat_.st_size.
- if (cache_content_)
- DownloadToCache();
- }
-
- return stat_.st_size;
-}
-
-MountNodeHttp::MountNodeHttp(Mount* mount, const std::string& url,
- bool cache_content)
- : MountNode(mount),
- url_(url),
- cache_content_(cache_content),
- has_cached_size_(false) {
-}
-
-bool MountNodeHttp::OpenUrl(const char* method,
- StringMap_t* request_headers,
- PP_Resource* out_loader,
- PP_Resource* out_request,
- PP_Resource* out_response,
- int32_t* out_statuscode,
- StringMap_t* out_response_headers) {
- // Assume lock_ is already held.
-
- PepperInterface* ppapi = mount_->ppapi();
-
- MountHttp* mount_http = static_cast<MountHttp*>(mount_);
- ScopedResource request(ppapi,
- mount_http->MakeUrlRequestInfo(url_, method,
- request_headers));
- if (!request.pp_resource()) {
- errno = EINVAL;
- return false;
- }
-
- URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface();
- URLResponseInfoInterface* response_interface =
- ppapi->GetURLResponseInfoInterface();
- VarInterface* var_interface = ppapi->GetVarInterface();
-
- ScopedResource loader(ppapi, loader_interface->Create(ppapi->GetInstance()));
- if (!loader.pp_resource()) {
- errno = EINVAL;
- return false;
- }
-
- int32_t result = loader_interface->Open(
- loader.pp_resource(), request.pp_resource(), PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return false;
- }
-
- ScopedResource response(
- ppapi,
- loader_interface->GetResponseInfo(loader.pp_resource()));
- if (!response.pp_resource()) {
- errno = EINVAL;
- return false;
- }
-
- // Get response statuscode.
- PP_Var statuscode = response_interface->GetProperty(
- response.pp_resource(),
- PP_URLRESPONSEPROPERTY_STATUSCODE);
-
- if (statuscode.type != PP_VARTYPE_INT32) {
- errno = EINVAL;
- return false;
- }
-
- *out_statuscode = statuscode.value.as_int;
-
- // Only accept OK or Partial Content.
- if (*out_statuscode != STATUSCODE_OK &&
- *out_statuscode != STATUSCODE_PARTIAL_CONTENT) {
- errno = EINVAL;
- return false;
- }
-
- // Get response headers.
- PP_Var response_headers_var = response_interface->GetProperty(
- response.pp_resource(),
- PP_URLRESPONSEPROPERTY_HEADERS);
-
- uint32_t response_headers_length;
- const char* response_headers_str = var_interface->VarToUtf8(
- response_headers_var,
- &response_headers_length);
-
- *out_loader = loader.Release();
- *out_request = request.Release();
- *out_response = response.Release();
- *out_response_headers = ParseHeaders(response_headers_str,
- response_headers_length);
-
- return true;
-}
-
-int MountNodeHttp::DownloadToCache() {
- StringMap_t headers;
- PP_Resource loader;
- PP_Resource request;
- PP_Resource response;
- int32_t statuscode;
- StringMap_t response_headers;
- if (!OpenUrl("GET", &headers, &loader, &request, &response, &statuscode,
- &response_headers)) {
- // errno is already set by OpenUrl.
- return -1;
- }
-
- PepperInterface* ppapi = mount_->ppapi();
- ScopedResource scoped_loader(ppapi, loader);
- ScopedResource scoped_request(ppapi, request);
- ScopedResource scoped_response(ppapi, response);
-
- size_t content_length = 0;
- if (ParseContentLength(response_headers, &content_length)) {
- cached_data_.resize(content_length);
- int real_size = DownloadToBuffer(loader, cached_data_.data(),
- content_length);
- if (real_size < 0)
- return -1;
-
- SetCachedSize(real_size);
- cached_data_.resize(real_size);
- return real_size;
- }
-
- // We don't know how big the file is. Read in chunks.
- cached_data_.resize(MAX_READ_BUFFER_SIZE);
- size_t total_bytes_read = 0;
- size_t bytes_to_read = MAX_READ_BUFFER_SIZE;
- while (true) {
- char* buf = cached_data_.data() + total_bytes_read;
- int bytes_read = DownloadToBuffer(loader, buf, bytes_to_read);
- if (bytes_read < 0)
- return -1;
-
- total_bytes_read += bytes_read;
-
- if (bytes_read < bytes_to_read) {
- SetCachedSize(total_bytes_read);
- cached_data_.resize(total_bytes_read);
- return total_bytes_read;
- }
-
- cached_data_.resize(total_bytes_read + bytes_to_read);
- }
-}
-
-int MountNodeHttp::ReadPartialFromCache(size_t offs, void* buf, size_t count) {
- if (offs > cached_data_.size()) {
- errno = EINVAL;
- return -1;
- }
-
- count = std::min(count, cached_data_.size() - offs);
- memcpy(buf, &cached_data_.data()[offs], count);
- return count;
-}
-
-int MountNodeHttp::DownloadPartial(size_t offs, void* buf, size_t count) {
- StringMap_t headers;
-
- char buffer[100];
- // Range request is inclusive: 0-99 returns 100 bytes.
- snprintf(&buffer[0], sizeof(buffer), "bytes=%"PRIuS"-%"PRIuS,
- offs, offs + count - 1);
- headers["Range"] = buffer;
-
- PP_Resource loader;
- PP_Resource request;
- PP_Resource response;
- int32_t statuscode;
- StringMap_t response_headers;
- if (!OpenUrl("GET", &headers, &loader, &request, &response, &statuscode,
- &response_headers)) {
- // errno is already set by OpenUrl.
- return -1;
- }
-
- PepperInterface* ppapi = mount_->ppapi();
- ScopedResource scoped_loader(ppapi, loader);
- ScopedResource scoped_request(ppapi, request);
- ScopedResource scoped_response(ppapi, response);
-
- size_t read_start = 0;
- if (statuscode == STATUSCODE_OK) {
- // No partial result, read everything starting from the part we care about.
- size_t content_length;
- if (ParseContentLength(response_headers, &content_length)) {
- if (offs >= content_length) {
- errno = EINVAL;
- return 0;
- }
+Error MountHttp::Open(const Path& path, int mode, MountNode** out_node) {
+ *out_node = NULL;
- // Clamp count, if trying to read past the end of the file.
- if (offs + count > content_length) {
- count = content_length - offs;
- }
- }
- } else if (statuscode == STATUSCODE_PARTIAL_CONTENT) {
- // Determine from the headers where we are reading.
- size_t read_end;
- size_t entity_length;
- if (ParseContentRange(response_headers, &read_start, &read_end,
- &entity_length)) {
- if (read_start > offs || read_start > read_end) {
- // If this error occurs, the server is returning bogus values.
- errno = EINVAL;
- return -1;
- }
+ assert(url_root_.empty() || url_root_[url_root_.length() - 1] == '/');
- // Clamp count, if trying to read past the end of the file.
- count = std::min(read_end - read_start, count);
- } else {
- // Partial Content without Content-Range. Assume that the server gave us
- // exactly what we asked for. This can happen even when the server
- // returns 200 -- the cache may return 206 in this case, but not modify
- // the headers.
- read_start = offs;
- }
+ NodeMap_t::iterator iter = node_cache_.find(path.Join());
+ if (iter != node_cache_.end()) {
+ *out_node = iter->second;
+ return 0;
}
- if (read_start < offs) {
- // We aren't yet at the location where we want to start reading. Read into
- // our dummy buffer until then.
- size_t bytes_to_read = offs - read_start;
- if (buffer_.size() < bytes_to_read)
- buffer_.resize(std::min(bytes_to_read, MAX_READ_BUFFER_SIZE));
-
- while (bytes_to_read > 0) {
- int32_t bytes_read = DownloadToBuffer(loader, buffer_.data(),
- buffer_.size());
- if (bytes_read < 0)
- return -1;
+ // If we can't find the node in the cache, create it
+ std::string url = url_root_ + (path.IsAbsolute() ? path.Range(1, path.Size())
+ : path.Join());
- bytes_to_read -= bytes_read;
- }
+ MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_);
+ Error error = node->Init(mode);
+ if (error) {
+ node->Release();
+ return error;
}
- return DownloadToBuffer(loader, buf, count);
-}
-
-int MountNodeHttp::DownloadToBuffer(PP_Resource loader, void* buf,
- size_t count) {
- PepperInterface* ppapi = mount_->ppapi();
- URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface();
-
- char* out_buffer = static_cast<char*>(buf);
- size_t bytes_to_read = count;
- while (bytes_to_read > 0) {
- int32_t bytes_read = loader_interface->ReadResponseBody(
- loader, out_buffer, bytes_to_read, PP_BlockUntilComplete());
-
- if (bytes_read == 0) {
- // This is not an error -- it may just be that we were trying to read
- // more data than exists.
- return count - bytes_to_read;
- }
-
- if (bytes_read < 0) {
- errno = PPErrorToErrno(bytes_read);
- return -1;
- }
-
- assert(bytes_read <= bytes_to_read);
- bytes_to_read -= bytes_read;
- out_buffer += bytes_read;
+ error = node->GetStat(NULL);
+ if (error) {
+ node->Release();
+ return error;
}
- return count;
-}
-
-MountNode *MountHttp::Open(const Path& path, int mode) {
- assert(url_root_.empty() || url_root_[url_root_.length() - 1] == '/');
-
- NodeMap_t::iterator iter = node_cache_.find(path.Join());
- if (iter != node_cache_.end()) {
- return iter->second;
+ MountNodeDir* parent;
+ error = FindOrCreateDir(path.Parent(), &parent);
+ if (error) {
+ node->Release();
+ return error;
}
- // If we can't find the node in the cache, create it
- std::string url = url_root_ + (path.IsAbsolute() ?
- path.Range(1, path.Size()) :
- path.Join());
-
- MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_);
- if (!node->Init(mode) || (0 != node->GetStat(NULL))) {
+ error = parent->AddChild(path.Basename(), node);
+ if (error) {
node->Release();
- return NULL;
+ return error;
}
- MountNodeDir* parent = FindOrCreateDir(path.Parent());
node_cache_[path.Join()] = node;
- parent->AddChild(path.Basename(), node);
- return node;
-}
-int MountHttp::Unlink(const Path& path) {
- errno = ENOSYS;
- return -1;
+ *out_node = node;
+ return 0;
}
-int MountHttp::Mkdir(const Path& path, int permissions) {
- errno = ENOSYS;
- return -1;
-}
+Error MountHttp::Unlink(const Path& path) { return ENOSYS; }
-int MountHttp::Rmdir(const Path& path) {
- errno = ENOSYS;
- return -1;
-}
+Error MountHttp::Mkdir(const Path& path, int permissions) { return ENOSYS; }
-int MountHttp::Remove(const Path& path) {
- errno = ENOSYS;
- return -1;
-}
+Error MountHttp::Rmdir(const Path& path) { return ENOSYS; }
+
+Error MountHttp::Remove(const Path& path) { return ENOSYS; }
-PP_Resource MountHttp::MakeUrlRequestInfo(
- const std::string& url,
- const char* method,
- StringMap_t* additional_headers) {
+PP_Resource MountHttp::MakeUrlRequestInfo(const std::string& url,
+ const char* method,
+ StringMap_t* additional_headers) {
URLRequestInfoInterface* interface = ppapi_->GetURLRequestInfoInterface();
VarInterface* var_interface = ppapi_->GetVarInterface();
@@ -618,21 +119,23 @@ PP_Resource MountHttp::MakeUrlRequestInfo(
if (!request_info)
return 0;
- interface->SetProperty(
- request_info, PP_URLREQUESTPROPERTY_URL,
- var_interface->VarFromUtf8(url.c_str(), url.length()));
- interface->SetProperty(request_info, PP_URLREQUESTPROPERTY_METHOD,
+ interface->SetProperty(request_info,
+ PP_URLREQUESTPROPERTY_URL,
+ var_interface->VarFromUtf8(url.c_str(), url.length()));
+ interface->SetProperty(request_info,
+ PP_URLREQUESTPROPERTY_METHOD,
var_interface->VarFromUtf8(method, strlen(method)));
interface->SetProperty(request_info,
PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS,
PP_MakeBool(allow_cors_ ? PP_TRUE : PP_FALSE));
- interface->SetProperty(request_info, PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS,
+ interface->SetProperty(request_info,
+ PP_URLREQUESTPROPERTY_ALLOWCREDENTIALS,
PP_MakeBool(allow_credentials_ ? PP_TRUE : PP_FALSE));
// Merge the mount headers with the request headers. If the field is already
// set it |additional_headers|, don't use the one from headers_.
for (StringMap_t::iterator iter = headers_.begin(); iter != headers_.end();
- ++iter) {
+ ++iter) {
const std::string& key = NormalizeHeaderKey(iter->first);
if (additional_headers->find(key) == additional_headers->end()) {
additional_headers->insert(std::make_pair(key, iter->second));
@@ -642,12 +145,14 @@ PP_Resource MountHttp::MakeUrlRequestInfo(
// Join the headers into one string.
std::string headers;
for (StringMap_t::iterator iter = additional_headers->begin();
- iter != additional_headers->end(); ++iter) {
+ iter != additional_headers->end();
+ ++iter) {
headers += iter->first + ": " + iter->second + '\n';
}
interface->SetProperty(
- request_info, PP_URLREQUESTPROPERTY_HEADERS,
+ request_info,
+ PP_URLREQUESTPROPERTY_HEADERS,
var_interface->VarFromUtf8(headers.c_str(), headers.length()));
return request_info;
@@ -657,12 +162,12 @@ MountHttp::MountHttp()
: allow_cors_(false),
allow_credentials_(false),
cache_stat_(true),
- cache_content_(true) {
-}
+ cache_content_(true) {}
-bool MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
- if (!Mount::Init(dev, args, ppapi))
- return false;
+Error MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+ Error error = Mount::Init(dev, args, ppapi);
+ if (error)
+ return error;
// Parse mount args.
for (StringMap_t::iterator iter = args.begin(); iter != args.end(); ++iter) {
@@ -674,11 +179,18 @@ bool MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
url_root_ += '/';
}
} else if (iter->first == "manifest") {
- char *text = LoadManifest(iter->second);
- if (text != NULL) {
- ParseManifest(text);
+ char* text;
+ error = LoadManifest(iter->second, &text);
+ if (error)
+ return error;
+
+ error = ParseManifest(text);
+ if (error) {
delete[] text;
+ return error;
}
+
+ delete[] text;
} else if (iter->first == "allow_cross_origin_requests") {
allow_cors_ = iter->second == "true";
} else if (iter->first == "allow_credentials") {
@@ -693,34 +205,53 @@ bool MountHttp::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
}
}
- return true;
+ return 0;
}
-void MountHttp::Destroy() {
-}
+void MountHttp::Destroy() {}
+
+Error MountHttp::FindOrCreateDir(const Path& path, MountNodeDir** out_node) {
+ *out_node = NULL;
-MountNodeDir* MountHttp::FindOrCreateDir(const Path& path) {
std::string strpath = path.Join();
NodeMap_t::iterator iter = node_cache_.find(strpath);
if (iter != node_cache_.end()) {
- return static_cast<MountNodeDir*>(iter->second);
+ *out_node = static_cast<MountNodeDir*>(iter->second);
+ return 0;
}
- // If the node does not exist, create it, and add it to the node cache
+ // If the node does not exist, create it.
MountNodeDir* node = new MountNodeDir(this);
- node->Init(S_IREAD);
- node_cache_[strpath] = node;
+ Error error = node->Init(S_IREAD);
+ if (error) {
+ node->Release();
+ return error;
+ }
// If not the root node, find the parent node and add it to the parent
if (!path.Top()) {
- MountNodeDir* parent = FindOrCreateDir(path.Parent());
- parent->AddChild(path.Basename(), node);
+ MountNodeDir* parent;
+ error = FindOrCreateDir(path.Parent(), &parent);
+ if (error) {
+ node->Release();
+ return error;
+ }
+
+ error = parent->AddChild(path.Basename(), node);
+ if (error) {
+ node->Release();
+ return error;
+ }
}
- return node;
+ // Add it to the node cache.
+ node_cache_[strpath] = node;
+
+ *out_node = node;
+ return 0;
}
-bool MountHttp::ParseManifest(char *text) {
+Error MountHttp::ParseManifest(char* text) {
StringList_t lines;
SplitString(text, "\n", &lines);
@@ -741,62 +272,102 @@ bool MountHttp::ParseManifest(char *text) {
// Ignore EXEC bit
int mode = S_IFREG;
switch (modestr[0]) {
- case '-': mode = S_IFREG; break;
- case 'c': mode = S_IFCHR; break;
+ case '-':
+ mode = S_IFREG;
+ break;
+ case 'c':
+ mode = S_IFCHR;
+ break;
default:
fprintf(stderr, "Unable to parse type %s for %s.\n", modestr, name);
- return false;
+ return EINVAL;
}
switch (modestr[1]) {
- case '-': break;
- case 'r': mode |= S_IREAD; break;
+ case '-':
+ break;
+ case 'r':
+ mode |= S_IREAD;
+ break;
default:
fprintf(stderr, "Unable to parse read %s for %s.\n", modestr, name);
- return false;
+ return EINVAL;
}
switch (modestr[2]) {
- case '-': break;
- case 'w': mode |= S_IWRITE; break;
+ case '-':
+ break;
+ case 'w':
+ mode |= S_IWRITE;
+ break;
default:
fprintf(stderr, "Unable to parse write %s for %s.\n", modestr, name);
- return false;
+ return EINVAL;
}
Path path(name);
- std::string url = url_root_ + (path.IsAbsolute() ?
- path.Range(1, path.Size()) :
- path.Join());
+ std::string url =
+ url_root_ +
+ (path.IsAbsolute() ? path.Range(1, path.Size()) : path.Join());
MountNodeHttp* node = new MountNodeHttp(this, url, cache_content_);
- node->Init(mode);
+ Error error = node->Init(mode);
+ if (error) {
+ node->Release();
+ return error;
+ }
+
node->SetCachedSize(atoi(lenstr));
- MountNodeDir* dir_node = FindOrCreateDir(path.Parent());
- dir_node->AddChild(path.Basename(), node);
+ MountNodeDir* dir_node;
+ error = FindOrCreateDir(path.Parent(), &dir_node);
+ if (error) {
+ node->Release();
+ return error;
+ }
+
+ error = dir_node->AddChild(path.Basename(), node);
+ if (error) {
+ node->Release();
+ return error;
+ }
std::string pname = path.Join();
node_cache_[pname] = node;
}
}
- return true;
+ return 0;
}
-char *MountHttp::LoadManifest(const std::string& manifest_name) {
+Error MountHttp::LoadManifest(const std::string& manifest_name,
+ char** out_manifest) {
Path manifest_path(manifest_name);
- MountNode* manifest_node = Open(manifest_path, O_RDONLY);
+ MountNode* manifest_node = NULL;
+ *out_manifest = NULL;
- if (manifest_node) {
- char *text = new char[manifest_node->GetSize() + 1];
- off_t len = manifest_node->Read(0, text, manifest_node->GetSize());
+ int error = Open(manifest_path, O_RDONLY, &manifest_node);
+ if (error)
+ return error;
+
+ size_t size;
+ error = manifest_node->GetSize(&size);
+ if (error) {
manifest_node->Release();
+ return error;
+ }
- text[len] = 0;
- return text;
+ char* text = new char[size + 1];
+ int len;
+ error = manifest_node->Read(0, text, size, &len);
+ if (error) {
+ manifest_node->Release();
+ return error;
}
- fprintf(stderr, "Could not open manifest: %s\n", manifest_name.c_str());
- return NULL;
+ manifest_node->Release();
+ text[len] = 0;
+
+ *out_manifest = text;
+ return 0;
}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_http.h b/native_client_sdk/src/libraries/nacl_io/mount_http.h
index 3a842a04..e10f1af 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_http.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_http.h
@@ -15,15 +15,17 @@ class MountNodeDir;
class MountNodeHttp;
class MountHttpMock;
+std::string NormalizeHeaderKey(const std::string& s);
+
class MountHttp : public Mount {
public:
typedef std::map<std::string, MountNode*> NodeMap_t;
- virtual MountNode *Open(const Path& path, int mode);
- 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);
+ virtual Error Open(const Path& path, int mode, MountNode** out_node);
+ virtual Error Unlink(const Path& path);
+ virtual Error Mkdir(const Path& path, int permissions);
+ virtual Error Rmdir(const Path& path);
+ virtual Error Remove(const Path& path);
PP_Resource MakeUrlRequestInfo(const std::string& url,
const char* method,
@@ -32,11 +34,11 @@ class MountHttp : public Mount {
protected:
MountHttp();
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
- MountNodeDir* FindOrCreateDir(const Path& path);
- char *LoadManifest(const std::string& path);
- bool ParseManifest(char *text);
+ Error FindOrCreateDir(const Path& path, MountNodeDir** out_node);
+ Error LoadManifest(const std::string& path, char** out_manifest);
+ Error ParseManifest(char *text);
private:
std::string url_root_;
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_mem.cc b/native_client_sdk/src/libraries/nacl_io/mount_mem.cc
index 541f58c..356600b 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_mem.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_mem.cc
@@ -17,19 +17,21 @@
#include "sdk_util/auto_lock.h"
#include "sdk_util/ref_object.h"
-// TODO(noelallen) : Grab/Redefine these in the kernel object once available.
-#define USR_ID 1002
-#define GRP_ID 1003
+MountMem::MountMem() : root_(NULL), max_ino_(0) {}
-MountMem::MountMem()
- : root_(NULL),
- max_ino_(0) {
-}
+Error MountMem::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+ Error error = Mount::Init(dev, args, ppapi);
+ if (error)
+ return error;
+
+ root_ = new MountNodeDir(this);
+ error = root_->Init(S_IREAD | S_IWRITE);
+ if (error) {
+ root_->Release();
+ return error;
+ }
-bool MountMem::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
- Mount::Init(dev, args, ppapi);
- root_ = AllocatePath(S_IREAD | S_IWRITE);
- return (bool) (root_ != NULL);
+ return 0;
}
void MountMem::Destroy() {
@@ -38,173 +40,156 @@ void MountMem::Destroy() {
root_ = NULL;
}
-MountNode* MountMem::AllocatePath(int mode) {
- MountNode *ptr = new MountNodeDir(this);
- if (!ptr->Init(mode)) {
- ptr->Release();
- return NULL;
- }
- return ptr;
-}
-
-MountNode* MountMem::AllocateData(int mode) {
- MountNode* ptr = new MountNodeMem(this);
- if (!ptr->Init(mode)) {
- ptr->Release();
- return NULL;
- }
- return ptr;
-}
-
-MountNode* MountMem::FindNode(const Path& path, int type) {
+Error MountMem::FindNode(const Path& path, int type, MountNode** out_node) {
MountNode* node = root_;
// If there is no root there, we have an error.
- if (node == NULL) {
- errno = ENOTDIR;
- return NULL;
- }
+ if (node == NULL)
+ return ENOTDIR;
// We are expecting an "absolute" path from this mount point.
- if (!path.IsAbsolute()) {
- errno = EINVAL;
- return NULL;
- }
+ if (!path.IsAbsolute())
+ return EINVAL;
// Starting at the root, traverse the path parts.
for (size_t index = 1; node && index < path.Size(); index++) {
// If not a directory, then we have an error so return.
- if (!node->IsaDir()) {
- errno = ENOTDIR;
- return NULL;
- }
+ if (!node->IsaDir())
+ return ENOTDIR;
// Find the child node
- node = node->FindChild(path.Part(index));
+ Error error = node->FindChild(path.Part(index), &node);
+ if (error)
+ return error;
}
- // node should be root, a found child, or a failed 'FindChild'
- // which already has the correct errno set.
- if (NULL == node) return NULL;
-
// If a directory is expected, but it's not a directory, then fail.
- if ((type & S_IFDIR) && !node->IsaDir()) {
- errno = ENOTDIR;
- return NULL;
- }
+ if ((type & S_IFDIR) && !node->IsaDir())
+ return ENOTDIR;
// If a file is expected, but it's not a file, then fail.
- if ((type & S_IFREG) && node->IsaDir()) {
- errno = EISDIR;
- return NULL;
- }
+ if ((type & S_IFREG) && node->IsaDir())
+ return EISDIR;
// We now have a valid object of the expected type, so return it.
- return node;
+ *out_node = node;
+ return 0;
}
-MountNode* MountMem::Open(const Path& path, int mode) {
+Error MountMem::Open(const Path& path, int mode, MountNode** out_node) {
AutoLock lock(&lock_);
- MountNode* node = FindNode(path);
+ MountNode* node = NULL;
+ *out_node = NULL;
- if (NULL == node) {
- // Now first find the parent directory to see if we can add it
- MountNode* parent = FindNode(path.Parent(), S_IFDIR);
- if (NULL == parent) return NULL;
+ Error error = FindNode(path, 0, &node);
+ if (error) {
// If the node does not exist and we can't create it, fail
- if ((mode & O_CREAT) == 0) return NULL;
+ if ((mode & O_CREAT) == 0)
+ return ENOENT;
- // Otherwise, create it with a single reference
- mode = OpenModeToPermission(mode);
- node = AllocateData(mode);
- if (NULL == node) return NULL;
+ // Now first find the parent directory to see if we can add it
+ MountNode* parent = NULL;
+ error = FindNode(path.Parent(), S_IFDIR, &parent);
+ if (error)
+ return error;
+
+ // Create it with a single reference
+ node = new MountNodeMem(this);
+ error = node->Init(OpenModeToPermission(mode));
+ if (error) {
+ node->Release();
+ return error;
+ }
- if (parent->AddChild(path.Basename(), node) == -1) {
+ error = parent->AddChild(path.Basename(), node);
+ if (error) {
// Or if it fails, release it
node->Release();
- return NULL;
+ return error;
}
- return node;
+
+ *out_node = node;
+ return 0;
}
+ // Directories can only be opened read-only.
+ if (node->IsaDir() && (mode & 3) != O_RDONLY)
+ return EISDIR;
+
// If we were expected to create it exclusively, fail
- if (mode & O_EXCL) {
- errno = EEXIST;
- return NULL;
- }
+ if (mode & O_EXCL)
+ return EEXIST;
// Verify we got the requested permissions.
int req_mode = OpenModeToPermission(mode);
int obj_mode = node->GetMode() & OpenModeToPermission(O_RDWR);
- if ((obj_mode & req_mode) != req_mode) {
- errno = EACCES;
- return NULL;
- }
+ if ((obj_mode & req_mode) != req_mode)
+ return EACCES;
// We opened it, so ref count it before passing it back.
node->Acquire();
- return node;
+ *out_node = node;
+ return 0;
}
-int MountMem::Mkdir(const Path& path, int mode) {
+Error MountMem::Mkdir(const Path& path, int mode) {
AutoLock lock(&lock_);
// We expect a Mount "absolute" path
- if (!path.IsAbsolute()) {
- errno = ENOENT;
- return -1;
- }
+ if (!path.IsAbsolute())
+ return ENOENT;
// The root of the mount is already created by the mount
- if (path.Size() == 1) {
- errno = EEXIST;
- return -1;
- }
-
- MountNode* parent = FindNode(path.Parent(), S_IFDIR);
- MountNode* node;
+ if (path.Size() == 1)
+ return EEXIST;
- // If we failed to find the parent, the error code is already set.
- if (NULL == parent) return -1;
+ MountNode* parent = NULL;
+ int error = FindNode(path.Parent(), S_IFDIR, &parent);
+ if (error)
+ return error;
- node = parent->FindChild(path.Basename());
- if (NULL != node) {
- errno = EEXIST;
- return -1;
- }
+ MountNode* node = NULL;
+ error = parent->FindChild(path.Basename(), &node);
+ if (!error)
+ return EEXIST;
- // Otherwise, create a new node and attempt to add it
- mode = OpenModeToPermission(mode);
+ if (error != ENOENT)
+ return error;
// Allocate a node, with a RefCount of 1. If added to the parent
// it will get ref counted again. In either case, release the
// recount we have on exit.
- node = AllocatePath(S_IREAD | S_IWRITE);
- if (NULL == node) return -1;
+ node = new MountNodeDir(this);
+ error = node->Init(S_IREAD | S_IWRITE);
+ if (error) {
+ node->Release();
+ return error;
+ }
- if (parent->AddChild(path.Basename(), node) == -1) {
+ error = parent->AddChild(path.Basename(), node);
+ if (error) {
node->Release();
- return -1;
+ return error;
}
node->Release();
return 0;
}
-int MountMem::Unlink(const Path& path) {
+Error MountMem::Unlink(const Path& path) {
return RemoveInternal(path, REMOVE_FILE);
}
-int MountMem::Rmdir(const Path& path) {
+Error MountMem::Rmdir(const Path& path) {
return RemoveInternal(path, REMOVE_DIR);
}
-int MountMem::Remove(const Path& path) {
+Error MountMem::Remove(const Path& path) {
return RemoveInternal(path, REMOVE_ALL);
}
-int MountMem::RemoveInternal(const Path& path, int remove_type) {
+Error MountMem::RemoveInternal(const Path& path, int remove_type) {
AutoLock lock(&lock_);
bool dir_only = remove_type == REMOVE_DIR;
bool file_only = remove_type == REMOVE_FILE;
@@ -212,40 +197,33 @@ int MountMem::RemoveInternal(const Path& path, int remove_type) {
if (dir_only) {
// We expect a Mount "absolute" path
- if (!path.IsAbsolute()) {
- errno = ENOENT;
- return -1;
- }
+ if (!path.IsAbsolute())
+ return ENOENT;
// The root of the mount is already created by the mount
- if (path.Size() == 1) {
- errno = EEXIST;
- return -1;
- }
+ if (path.Size() == 1)
+ return EEXIST;
}
- MountNode* parent = FindNode(path.Parent(), S_IFDIR);
-
- // If we failed to find the parent, the error code is already set.
- if (NULL == parent) return -1;
+ MountNode* parent = NULL;
+ int error = FindNode(path.Parent(), S_IFDIR, &parent);
+ if (error)
+ return error;
// Verify we find a child which is a directory.
- MountNode* child = parent->FindChild(path.Basename());
- if (NULL == child) {
- errno = ENOENT;
- return -1;
- }
- if (dir_only && !child->IsaDir()) {
- errno = ENOTDIR;
- return -1;
- }
- if (file_only && child->IsaDir()) {
- errno = EISDIR;
- return -1;
- }
- if (remove_dir && child->ChildCount() > 0) {
- errno = ENOTEMPTY;
- return -1;
- }
+ MountNode* child = NULL;
+ error = parent->FindChild(path.Basename(), &child);
+ if (error)
+ return error;
+
+ if (dir_only && !child->IsaDir())
+ return ENOTDIR;
+
+ if (file_only && child->IsaDir())
+ return EISDIR;
+
+ if (remove_dir && child->ChildCount() > 0)
+ return ENOTEMPTY;
+
return parent->RemoveChild(path.Basename());
}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_mem.h b/native_client_sdk/src/libraries/nacl_io/mount_mem.h
index dc75e81..930e9c7 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_mem.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_mem.h
@@ -14,35 +14,33 @@ class MountMem : public Mount {
protected:
MountMem();
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
// The protected functions are only used internally and will not
// acquire or release the mount's lock themselves. The caller is
// required to use correct locking as needed.
- MountNode *AllocateData(int mode);
- MountNode *AllocatePath(int mode);
// Allocate or free an INODE number.
int AllocateINO();
void FreeINO(int ino);
// Find a Node specified node optionally failing if type does not match.
- virtual MountNode* FindNode(const Path& path, int type = 0);
+ virtual Error FindNode(const Path& path, int type, MountNode** out_node);
public:
- virtual MountNode *Open(const Path& path, int mode);
- virtual int Unlink(const Path& path);
- virtual int Mkdir(const Path& path, int perm);
- virtual int Rmdir(const Path& path);
- virtual int Remove(const Path& path);
+ virtual Error Open(const Path& path, int mode, MountNode** out_node);
+ virtual Error Unlink(const Path& path);
+ virtual Error Mkdir(const Path& path, int perm);
+ virtual Error Rmdir(const Path& path);
+ virtual Error Remove(const Path& path);
private:
static const int REMOVE_DIR = 1;
static const int REMOVE_FILE = 2;
static const int REMOVE_ALL = REMOVE_DIR | REMOVE_FILE;
- int RemoveInternal(const Path& path, int remove_type);
+ Error RemoveInternal(const Path& path, int remove_type);
MountNode* root_;
size_t max_ino_;
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node.cc b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
index 97dc799..34de7a8 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
@@ -18,8 +18,7 @@
static const int USR_ID = 1001;
static const int GRP_ID = 1002;
-MountNode::MountNode(Mount* mount)
- : mount_(mount) {
+MountNode::MountNode(Mount* mount) : mount_(mount) {
memset(&stat_, 0, sizeof(stat_));
stat_.st_gid = GRP_ID;
stat_.st_uid = USR_ID;
@@ -32,12 +31,11 @@ MountNode::MountNode(Mount* mount)
stat_.st_ino = 1;
}
-MountNode::~MountNode() {
-}
+MountNode::~MountNode() {}
-bool MountNode::Init(int perm) {
+Error MountNode::Init(int perm) {
stat_.st_mode |= perm;
- return true;
+ return 0;
}
void MountNode::Destroy() {
@@ -46,119 +44,110 @@ void MountNode::Destroy() {
}
}
-int MountNode::FSync() {
- return 0;
-}
+Error MountNode::FSync() { return 0; }
-int MountNode::FTruncate(off_t length) {
- errno = EINVAL;
- return -1;
+Error MountNode::FTruncate(off_t length) {
+ return EINVAL;
}
-int MountNode::GetDents(size_t offs, struct dirent* pdir, size_t count) {
- errno = ENOTDIR;
- return -1;
+Error MountNode::GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+ return ENOTDIR;
}
-int MountNode::GetStat(struct stat* pstat) {
+Error MountNode::GetStat(struct stat* pstat) {
AutoLock lock(&lock_);
memcpy(pstat, &stat_, sizeof(stat_));
return 0;
}
-int MountNode::Ioctl(int request, char* arg) {
- errno = EINVAL;
- return -1;
+Error MountNode::Ioctl(int request, char* arg) {
+ return EINVAL;
}
-int MountNode::Read(size_t offs, void* buf, size_t count) {
- errno = EINVAL;
- return -1;
+Error MountNode::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
+ return EINVAL;
}
-int MountNode::Write(size_t offs, const void* buf, size_t count) {
- errno = EINVAL;
- return -1;
+Error MountNode::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+ return EINVAL;
}
-void* MountNode::MMap(void* addr, size_t length, int prot, int flags,
- size_t offset) {
+Error MountNode::MMap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ size_t offset,
+ void** out_addr) {
+ *out_addr = NULL;
+
// Never allow mmap'ing PROT_EXEC. The passthrough node supports this, but we
// don't. Fortunately, glibc will fallback if this fails, so dlopen will
// continue to work.
- if (prot & PROT_EXEC) {
- errno = EPERM;
- return MAP_FAILED;
- }
+ if (prot & PROT_EXEC)
+ return EPERM;
// This default mmap support is just enough to make dlopen work.
// This implementation just reads from the mount into the mmap'd memory area.
void* new_addr = addr;
- int err = _real_mmap(&new_addr, length, prot | PROT_WRITE, flags |
- MAP_ANONYMOUS, -1, 0);
+ int mmap_error = _real_mmap(
+ &new_addr, length, prot | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
if (new_addr == MAP_FAILED) {
_real_munmap(new_addr, length);
- errno = err;
- return MAP_FAILED;
+ return mmap_error;
}
- ssize_t cnt = Read(offset, new_addr, length);
- if (cnt == -1) {
+ int bytes_read;
+ Error read_error = Read(offset, new_addr, length, &bytes_read);
+ if (read_error) {
_real_munmap(new_addr, length);
- errno = ENOSYS;
- return MAP_FAILED;
+ return read_error;
}
- return new_addr;
-}
-
-int MountNode::GetLinks() {
- return stat_.st_nlink;
+ *out_addr = new_addr;
+ return 0;
}
-int MountNode::GetMode() {
- return stat_.st_mode & ~S_IFMT;
-}
+int MountNode::GetLinks() { return stat_.st_nlink; }
-size_t MountNode::GetSize() {
- return stat_.st_size;
-}
+int MountNode::GetMode() { return stat_.st_mode & ~S_IFMT; }
-int MountNode::GetType() {
- return stat_.st_mode & S_IFMT;
+Error MountNode::GetSize(size_t* out_size) {
+ *out_size = stat_.st_size;
+ return 0;
}
-bool MountNode::IsaDir() {
- return (stat_.st_mode & S_IFDIR) != 0;
-}
+int MountNode::GetType() { return stat_.st_mode & S_IFMT; }
-bool MountNode::IsaFile() {
- return (stat_.st_mode & S_IFREG) != 0;
-}
+bool MountNode::IsaDir() { return (stat_.st_mode & S_IFDIR) != 0; }
-bool MountNode::IsaTTY() {
- return (stat_.st_mode & S_IFCHR) != 0;
-}
+bool MountNode::IsaFile() { return (stat_.st_mode & S_IFREG) != 0; }
+bool MountNode::IsaTTY() { return (stat_.st_mode & S_IFCHR) != 0; }
-int MountNode:: AddChild(const std::string& name, MountNode* node) {
- errno = ENOTDIR;
- return -1;
+Error MountNode::AddChild(const std::string& name, MountNode* node) {
+ return ENOTDIR;
}
-int MountNode::RemoveChild(const std::string& name) {
- errno = ENOTDIR;
- return -1;
+Error MountNode::RemoveChild(const std::string& name) {
+ return ENOTDIR;
}
-MountNode* MountNode::FindChild(const std::string& name) {
- errno = ENOTDIR;
- return NULL;
+Error MountNode::FindChild(const std::string& name, MountNode** out_node) {
+ *out_node = NULL;
+ return ENOTDIR;
}
int MountNode::ChildCount() {
- errno = ENOTDIR;
- return -1;
+ return 0;
}
void MountNode::Link() {
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node.h b/native_client_sdk/src/libraries/nacl_io/mount_node.h
index 6837548..0acce66 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.h
@@ -7,6 +7,7 @@
#include <string>
+#include "nacl_io/error.h"
#include "nacl_io/osstat.h"
#include "sdk_util/ref_object.h"
@@ -14,6 +15,8 @@ struct dirent;
struct stat;
class Mount;
+// NOTE: The KernelProxy is the only class that should be setting errno. All
+// other classes should return Error (as defined by nacl_io/error.h).
class MountNode : public RefObject {
protected:
explicit MountNode(Mount* mount);
@@ -21,27 +24,46 @@ class MountNode : public RefObject {
protected:
// Initialize with node specific flags, in this case stat permissions.
- virtual bool Init(int flags);
+ virtual Error Init(int flags);
virtual void Destroy();
public:
// Normal OS operations on a node (file), can be called by the kernel
// directly so it must lock and unlock appropriately. These functions
// must not be called by the mount.
- virtual int FSync();
- virtual int FTruncate(off_t length);
- virtual int GetDents(size_t offs, struct dirent* pdir, size_t count);
- virtual int GetStat(struct stat* stat);
- virtual int Ioctl(int request, char* arg);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
- virtual void* MMap(void* addr, size_t length, int prot, int flags,
- size_t offset);
+ virtual Error FSync();
+ // It is expected that the derived MountNode will fill with 0 when growing
+ // the file.
+ virtual Error FTruncate(off_t length);
+ // Assume that |out_bytes| is non-NULL.
+ virtual Error GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes);
+ // Assume that |stat| is non-NULL.
+ virtual Error GetStat(struct stat* stat);
+ // Assume that |arg| is non-NULL.
+ virtual Error Ioctl(int request, char* arg);
+ // Assume that |buf| and |out_bytes| are non-NULL.
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+ // Assume that |buf| and |out_bytes| are non-NULL.
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
+ // Assume that |addr| and |out_addr| are non-NULL.
+ virtual Error MMap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ size_t offset,
+ void** out_addr);
virtual int GetLinks();
virtual int GetMode();
virtual int GetType();
- virtual size_t GetSize();
+ // Assume that |out_size| is non-NULL.
+ virtual Error GetSize(size_t *out_size);
virtual bool IsaDir();
virtual bool IsaFile();
virtual bool IsaTTY();
@@ -51,18 +73,20 @@ class MountNode : public RefObject {
// must be held while these calls are made.
// Adds or removes a directory entry updating the link numbers and refcount
- virtual int AddChild(const std::string& name, MountNode *node);
- virtual int RemoveChild(const std::string& name);
+ // Assumes that |node| is non-NULL.
+ virtual Error AddChild(const std::string& name, MountNode* node);
+ virtual Error RemoveChild(const std::string& name);
// Find a child and return it without updating the refcount
- virtual MountNode* FindChild(const std::string& name);
+ // Assumes that |out_node| is non-NULL.
+ virtual Error FindChild(const std::string& name, MountNode** out_node);
virtual int ChildCount();
// Update the link count
virtual void Link();
virtual void Unlink();
-protected:
+ protected:
struct stat stat_;
Mount* mount_;
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_dir.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_dir.cc
index aa4b019..6f7feab 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_dir.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_dir.cc
@@ -12,75 +12,79 @@
#include "sdk_util/auto_lock.h"
#include "sdk_util/macros.h"
-MountNodeDir::MountNodeDir(Mount* mount)
- : MountNode(mount),
- cache_(NULL) {
+MountNodeDir::MountNodeDir(Mount* mount) : MountNode(mount), cache_(NULL) {
stat_.st_mode |= S_IFDIR;
}
MountNodeDir::~MountNodeDir() {
+ for (MountNodeMap_t::iterator it = map_.begin(); it != map_.end(); ++it) {
+ it->second->Unlink();
+ }
free(cache_);
}
-int MountNodeDir::Read(size_t offs, void *buf, size_t count) {
- errno = EISDIR;
- return -1;
+Error MountNodeDir::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
+ return EISDIR;
}
-int MountNodeDir::FTruncate(off_t size) {
- errno = EISDIR;
- return -1;
-}
+Error MountNodeDir::FTruncate(off_t size) { return EISDIR; }
-int MountNodeDir::Write(size_t offs, void *buf, size_t count) {
- errno = EISDIR;
- return -1;
+Error MountNodeDir::Write(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+ return EISDIR;
}
-int MountNodeDir::GetDents(size_t offs, struct dirent* pdir, size_t size) {
+Error MountNodeDir::GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t size,
+ int* out_bytes) {
+ *out_bytes = 0;
+
AutoLock lock(&lock_);
// If the buffer pointer is invalid, fail
- if (NULL == pdir) {
- errno = EINVAL;
- return -1;
- }
+ if (NULL == pdir)
+ return EINVAL;
// If the buffer is too small, fail
- if (size < sizeof(struct dirent)) {
- errno = EINVAL;
- return -1;
- }
+ if (size < sizeof(struct dirent))
+ return EINVAL;
// Force size to a multiple of dirent
size -= size % sizeof(struct dirent);
size_t max = map_.size() * sizeof(struct dirent);
- if (cache_ == NULL) BuildCache();
+ if (cache_ == NULL)
+ BuildCache();
- if (offs >= max) return 0;
- if (offs + size >= max) size = max - offs;
+ if (offs >= max) {
+ // OK, trying to read past the end.
+ return 0;
+ }
- memcpy(pdir, ((char *) cache_) + offs, size);
- return size;
+ if (offs + size >= max)
+ size = max - offs;
+
+ memcpy(pdir, ((char*)cache_) + offs, size);
+ *out_bytes = size;
+ return 0;
}
-int MountNodeDir::AddChild(const std::string& name, MountNode* node) {
+Error MountNodeDir::AddChild(const std::string& name, MountNode* node) {
AutoLock lock(&lock_);
- if (name.empty()) {
- errno = ENOENT;
- return -1;
- }
- if (name.length() >= MEMBER_SIZE(struct dirent, d_name)) {
- errno = ENAMETOOLONG;
- return -1;
- }
+ if (name.empty())
+ return ENOENT;
+
+ if (name.length() >= MEMBER_SIZE(struct dirent, d_name))
+ return ENAMETOOLONG;
MountNodeMap_t::iterator it = map_.find(name);
- if (it != map_.end()) {
- errno = EEXIST;
- return -1;
- }
+ if (it != map_.end())
+ return EEXIST;
node->Link();
map_[name] = node;
@@ -88,7 +92,7 @@ int MountNodeDir::AddChild(const std::string& name, MountNode* node) {
return 0;
}
-int MountNodeDir::RemoveChild(const std::string& name) {
+Error MountNodeDir::RemoveChild(const std::string& name) {
AutoLock lock(&lock_);
MountNodeMap_t::iterator it = map_.find(name);
if (it != map_.end()) {
@@ -97,18 +101,19 @@ int MountNodeDir::RemoveChild(const std::string& name) {
ClearCache();
return 0;
}
- errno = ENOENT;
- return -1;
+ return ENOENT;
}
-MountNode* MountNodeDir::FindChild(const std::string& name) {
+Error MountNodeDir::FindChild(const std::string& name, MountNode** out_node) {
+ *out_node = NULL;
+
AutoLock lock(&lock_);
MountNodeMap_t::iterator it = map_.find(name);
- if (it != map_.end()) {
- return it->second;
- }
- errno = ENOENT;
- return NULL;
+ if (it == map_.end())
+ return ENOENT;
+
+ *out_node = it->second;
+ return 0;
}
int MountNodeDir::ChildCount() {
@@ -123,7 +128,7 @@ void MountNodeDir::ClearCache() {
void MountNodeDir::BuildCache() {
if (map_.size()) {
- cache_ = (struct dirent *) malloc(sizeof(struct dirent) * map_.size());
+ cache_ = (struct dirent*)malloc(sizeof(struct dirent) * map_.size());
MountNodeMap_t::iterator it = map_.begin();
for (size_t index = 0; it != map_.end(); it++, index++) {
MountNode* node = it->second;
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_dir.h b/native_client_sdk/src/libraries/nacl_io/mount_node_dir.h
index b6af58d..a2ab67e 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_dir.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_dir.h
@@ -25,15 +25,18 @@ class MountNodeDir : public MountNode {
public:
typedef std::map<std::string, MountNode*> MountNodeMap_t;
- virtual int FTruncate(off_t size);
- virtual int GetDents(size_t offs, struct dirent* pdir, size_t count);
- virtual int Read(size_t offs, void *buf, size_t count);
- virtual int Write(size_t offs, void *buf, size_t count);
+ virtual Error FTruncate(off_t size);
+ virtual Error GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes);
+ virtual Error Read(size_t offs, void *buf, size_t count, int* out_bytes);
+ virtual Error Write(size_t offs, void *buf, size_t count, int* out_bytes);
// Adds a finds or adds a directory entry as an INO, updating the refcount
- virtual int AddChild(const std::string& name, MountNode *node);
- virtual int RemoveChild(const std::string& name);
- virtual MountNode* FindChild(const std::string& name);
+ virtual Error AddChild(const std::string& name, MountNode *node);
+ virtual Error RemoveChild(const std::string& name);
+ virtual Error FindChild(const std::string& name, MountNode** out_node);
virtual int ChildCount();
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc
index 63c6ab8..8be2a4f 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc
@@ -55,66 +55,61 @@ int32_t ModeToOpenFlags(int mode) {
break;
}
- if (mode & O_CREAT) open_flags |= PP_FILEOPENFLAG_CREATE;
- if (mode & O_TRUNC) open_flags |= PP_FILEOPENFLAG_TRUNCATE;
- if (mode & O_EXCL) open_flags |= PP_FILEOPENFLAG_EXCLUSIVE;
+ if (mode & O_CREAT)
+ open_flags |= PP_FILEOPENFLAG_CREATE;
+ if (mode & O_TRUNC)
+ open_flags |= PP_FILEOPENFLAG_TRUNCATE;
+ if (mode & O_EXCL)
+ open_flags |= PP_FILEOPENFLAG_EXCLUSIVE;
return open_flags;
}
} // namespace
-int MountNodeHtml5Fs::FSync() {
+Error MountNodeHtml5Fs::FSync() {
// Cannot call Flush on a directory; simply do nothing.
if (IsDirectory())
return 0;
- int32_t result = mount_->ppapi()->GetFileIoInterface()->Flush(
- fileio_resource_, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
-
+ int32_t result = mount_->ppapi()->GetFileIoInterface()
+ ->Flush(fileio_resource_, PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
return 0;
}
-int MountNodeHtml5Fs::GetDents(size_t offs, struct dirent* pdir, size_t size) {
+Error MountNodeHtml5Fs::GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t size,
+ int* out_bytes) {
+ *out_bytes = 0;
+
// If the buffer pointer is invalid, fail
- if (NULL == pdir) {
- errno = EINVAL;
- return -1;
- }
+ if (NULL == pdir)
+ return EINVAL;
// If the buffer is too small, fail
- if (size < sizeof(struct dirent)) {
- errno = EINVAL;
- return -1;
- }
+ if (size < sizeof(struct dirent))
+ return EINVAL;
// If this is not a directory, fail
- if (!IsDirectory()) {
- errno = ENOTDIR;
- return -1;
- }
+ if (!IsDirectory())
+ return ENOTDIR;
- OutputBuffer output_buf = { NULL, 0 };
- PP_ArrayOutput output = { &GetOutputBuffer, &output_buf };
- int32_t result =
- mount_->ppapi()->GetFileRefInterface()->ReadDirectoryEntries(
- fileref_resource_, output, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+ OutputBuffer output_buf = {NULL, 0};
+ PP_ArrayOutput output = {&GetOutputBuffer, &output_buf};
+ int32_t result = mount_->ppapi()->GetFileRefInterface()->ReadDirectoryEntries(
+ fileref_resource_, output, PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
std::vector<struct dirent> dirents;
- PP_DirectoryEntry* entries =
- static_cast<PP_DirectoryEntry*>(output_buf.data);
+ PP_DirectoryEntry* entries = static_cast<PP_DirectoryEntry*>(output_buf.data);
for (int i = 0; i < output_buf.element_count; ++i) {
- PP_Var file_name_var = mount_->ppapi()->GetFileRefInterface()->GetName(
- entries[i].file_ref);
+ PP_Var file_name_var =
+ mount_->ppapi()->GetFileRefInterface()->GetName(entries[i].file_ref);
// Release the file reference.
mount_->ppapi()->ReleaseResource(entries[i].file_ref);
@@ -123,14 +118,14 @@ int MountNodeHtml5Fs::GetDents(size_t offs, struct dirent* pdir, size_t size) {
continue;
uint32_t file_name_length;
- const char* file_name = mount_->ppapi()->GetVarInterface()->VarToUtf8(
- file_name_var, &file_name_length);
+ const char* file_name = mount_->ppapi()->GetVarInterface()
+ ->VarToUtf8(file_name_var, &file_name_length);
if (!file_name)
continue;
file_name_length = std::min(
static_cast<size_t>(file_name_length),
- sizeof(static_cast<struct dirent*>(0)->d_name) - 1); // -1 for NULL.
+ sizeof(static_cast<struct dirent*>(0)->d_name) - 1); // -1 for NULL.
dirents.push_back(dirent());
struct dirent& direntry = dirents.back();
@@ -148,33 +143,40 @@ int MountNodeHtml5Fs::GetDents(size_t offs, struct dirent* pdir, size_t size) {
size -= size % sizeof(struct dirent);
size_t max = dirents.size() * sizeof(struct dirent);
- if (offs >= max) return 0;
- if (offs + size >= max) size = max - offs;
+ if (offs >= max)
+ return 0;
+
+ if (offs + size >= max)
+ size = max - offs;
memcpy(pdir, reinterpret_cast<char*>(dirents.data()) + offs, size);
- return size;
+ *out_bytes = size;
+ return 0;
}
-int MountNodeHtml5Fs::GetStat(struct stat* stat) {
+Error MountNodeHtml5Fs::GetStat(struct stat* stat) {
AutoLock lock(&lock_);
PP_FileInfo info;
int32_t result = mount_->ppapi()->GetFileRefInterface()->Query(
fileref_resource_, &info, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
// Fill in known info here.
memcpy(stat, &stat_, sizeof(stat_));
// Fill in the additional info from ppapi.
switch (info.type) {
- case PP_FILETYPE_REGULAR: stat->st_mode |= S_IFREG; break;
- case PP_FILETYPE_DIRECTORY: stat->st_mode |= S_IFDIR; break;
+ case PP_FILETYPE_REGULAR:
+ stat->st_mode |= S_IFREG;
+ break;
+ case PP_FILETYPE_DIRECTORY:
+ stat->st_mode |= S_IFDIR;
+ break;
case PP_FILETYPE_OTHER:
- default: break;
+ default:
+ break;
}
stat->st_size = static_cast<off_t>(info.size);
stat->st_atime = info.last_access_time;
@@ -184,80 +186,85 @@ int MountNodeHtml5Fs::GetStat(struct stat* stat) {
return 0;
}
-int MountNodeHtml5Fs::Read(size_t offs, void* buf, size_t count) {
- if (IsDirectory()) {
- errno = EISDIR;
- return -1;
- }
+Error MountNodeHtml5Fs::Read(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
- int32_t result = mount_->ppapi()->GetFileIoInterface()->Read(
- fileio_resource_, offs, static_cast<char*>(buf),
- static_cast<int32_t>(count),
- PP_BlockUntilComplete());
- if (result < 0) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+ if (IsDirectory())
+ return EISDIR;
- return result;
+ int32_t result =
+ mount_->ppapi()->GetFileIoInterface()->Read(fileio_resource_,
+ offs,
+ static_cast<char*>(buf),
+ static_cast<int32_t>(count),
+ PP_BlockUntilComplete());
+ if (result < 0)
+ return PPErrorToErrno(result);
+
+ *out_bytes = result;
+ return 0;
}
-int MountNodeHtml5Fs::FTruncate(off_t size) {
- if (IsDirectory()) {
- errno = EISDIR;
- return -1;
- }
-
- int32_t result = mount_->ppapi()->GetFileIoInterface()->SetLength(
- fileio_resource_, size, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+Error MountNodeHtml5Fs::FTruncate(off_t size) {
+ if (IsDirectory())
+ return EISDIR;
+ int32_t result = mount_->ppapi()->GetFileIoInterface()
+ ->SetLength(fileio_resource_, size, PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
return 0;
}
-int MountNodeHtml5Fs::Write(size_t offs, const void* buf, size_t count) {
- if (IsDirectory()) {
- errno = EISDIR;
- return -1;
- }
-
- int32_t result = mount_->ppapi()->GetFileIoInterface()->Write(
- fileio_resource_, offs, static_cast<const char*>(buf),
- static_cast<int32_t>(count), PP_BlockUntilComplete());
- if (result < 0) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+Error MountNodeHtml5Fs::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
- return result;
+ if (IsDirectory())
+ return EISDIR;
+
+ int32_t result = mount_->ppapi()->GetFileIoInterface()
+ ->Write(fileio_resource_,
+ offs,
+ static_cast<const char*>(buf),
+ static_cast<int32_t>(count),
+ PP_BlockUntilComplete());
+ if (result < 0)
+ return PPErrorToErrno(result);
+
+ *out_bytes = result;
+ return 0;
}
-size_t MountNodeHtml5Fs::GetSize() {
+Error MountNodeHtml5Fs::GetSize(size_t* out_size) {
+ *out_size = 0;
+
AutoLock lock(&lock_);
PP_FileInfo info;
- int32_t result = mount_->ppapi()->GetFileRefInterface()->Query(
- fileref_resource_, &info, PP_BlockUntilComplete());
- if (result != PP_OK) {
- errno = PPErrorToErrno(result);
- return -1;
- }
+ int32_t result = mount_->ppapi()->GetFileIoInterface()
+ ->Query(fileio_resource_, &info, PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
- return static_cast<size_t>(info.size);
+ *out_size = static_cast<size_t>(info.size);
+ return 0;
}
MountNodeHtml5Fs::MountNodeHtml5Fs(Mount* mount, PP_Resource fileref_resource)
: MountNode(mount),
fileref_resource_(fileref_resource),
- fileio_resource_(0) {
-}
+ fileio_resource_(0) {}
-bool MountNodeHtml5Fs::Init(int perm) {
- if (!MountNode::Init(Mount::OpenModeToPermission(perm)))
- return false;
+Error MountNodeHtml5Fs::Init(int perm) {
+ Error error = MountNode::Init(Mount::OpenModeToPermission(perm));
+ if (error)
+ return error;
// First query the FileRef to see if it is a file or directory.
PP_FileInfo file_info;
@@ -265,20 +272,21 @@ bool MountNodeHtml5Fs::Init(int perm) {
PP_BlockUntilComplete());
// If this is a directory, do not get a FileIO.
if (file_info.type == PP_FILETYPE_DIRECTORY)
- return true;
+ return 0;
- fileio_resource_= mount_->ppapi()->GetFileIoInterface()->Create(
- mount_->ppapi()->GetInstance());
+ fileio_resource_ = mount_->ppapi()->GetFileIoInterface()
+ ->Create(mount_->ppapi()->GetInstance());
if (!fileio_resource_)
- return false;
+ return ENOSYS;
- int32_t open_result = mount_->ppapi()->GetFileIoInterface()->Open(
- fileio_resource_, fileref_resource_, ModeToOpenFlags(perm),
- PP_BlockUntilComplete());
+ int32_t open_result =
+ mount_->ppapi()->GetFileIoInterface()->Open(fileio_resource_,
+ fileref_resource_,
+ ModeToOpenFlags(perm),
+ PP_BlockUntilComplete());
if (open_result != PP_OK)
- return false;
-
- return true;
+ return PPErrorToErrno(open_result);
+ return 0;
}
void MountNodeHtml5Fs::Destroy() {
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h
index e472208..832d3d4 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h
@@ -15,20 +15,26 @@ class MountNodeHtml5Fs : public MountNode {
// Normal OS operations on a node (file), can be called by the kernel
// directly so it must lock and unlock appropriately. These functions
// must not be called by the mount.
- virtual int FSync();
- virtual int GetDents(size_t offs, struct dirent* pdir, size_t count);
- virtual int GetStat(struct stat* stat);
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int FTruncate(off_t size);
- virtual int Write(size_t offs, const void* buf, size_t count);
-
- virtual size_t GetSize();
+ virtual Error FSync();
+ virtual Error GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes);
+ virtual Error GetStat(struct stat* stat);
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+ virtual Error FTruncate(off_t size);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
+
+ virtual Error GetSize(size_t *out_size);
protected:
MountNodeHtml5Fs(Mount* mount, PP_Resource fileref);
// Init with standard open flags
- virtual bool Init(int o_mode);
+ virtual Error Init(int o_mode);
virtual void Destroy();
private:
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_http.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_http.cc
new file mode 100644
index 0000000..5005ff4
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_http.cc
@@ -0,0 +1,523 @@
+/* Copyright (c) 2013 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.
+ */
+
+#include "nacl_io/mount_node_http.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <ppapi/c/pp_errors.h>
+
+#include "nacl_io/mount_http.h"
+#include "nacl_io/osinttypes.h"
+
+#if defined(WIN32)
+#define snprintf _snprintf
+#endif
+
+namespace {
+
+// If we're attempting to read a partial request, but the server returns a full
+// request, we need to read all of the data up to the start of our partial
+// request into a dummy buffer. This is the maximum size of that buffer.
+const size_t MAX_READ_BUFFER_SIZE = 64 * 1024;
+const int32_t STATUSCODE_OK = 200;
+const int32_t STATUSCODE_PARTIAL_CONTENT = 206;
+
+StringMap_t ParseHeaders(const char* headers, int32_t headers_length) {
+ enum State {
+ FINDING_KEY,
+ SKIPPING_WHITESPACE,
+ FINDING_VALUE,
+ };
+
+ StringMap_t result;
+ std::string key;
+ std::string value;
+
+ State state = FINDING_KEY;
+ const char* start = headers;
+ for (int i = 0; i < headers_length; ++i) {
+ switch (state) {
+ case FINDING_KEY:
+ if (headers[i] == ':') {
+ // Found key.
+ key.assign(start, &headers[i] - start);
+ key = NormalizeHeaderKey(key);
+ state = SKIPPING_WHITESPACE;
+ }
+ break;
+
+ case SKIPPING_WHITESPACE:
+ if (headers[i] == ' ') {
+ // Found whitespace, keep going...
+ break;
+ }
+
+ // Found a non-whitespace, mark this as the start of the value.
+ start = &headers[i];
+ state = FINDING_VALUE;
+ // Fallthrough to start processing value without incrementing i.
+
+ case FINDING_VALUE:
+ if (headers[i] == '\n') {
+ // Found value.
+ value.assign(start, &headers[i] - start);
+ result[key] = value;
+ start = &headers[i + 1];
+ state = FINDING_KEY;
+ }
+ break;
+ }
+ }
+
+ return result;
+}
+
+bool ParseContentLength(const StringMap_t& headers, size_t* content_length) {
+ StringMap_t::const_iterator iter = headers.find("Content-Length");
+ if (iter == headers.end())
+ return false;
+
+ *content_length = strtoul(iter->second.c_str(), NULL, 10);
+ return true;
+}
+
+bool ParseContentRange(const StringMap_t& headers,
+ size_t* read_start,
+ size_t* read_end,
+ size_t* entity_length) {
+ StringMap_t::const_iterator iter = headers.find("Content-Range");
+ if (iter == headers.end())
+ return false;
+
+ // The key should look like "bytes ##-##/##" or "bytes ##-##/*". The last
+ // value is the entity length, which can potentially be * (i.e. unknown).
+ int read_start_int;
+ int read_end_int;
+ int entity_length_int;
+ int result = sscanf(iter->second.c_str(),
+ "bytes %" SCNuS "-%" SCNuS "/%" SCNuS,
+ &read_start_int,
+ &read_end_int,
+ &entity_length_int);
+
+ // The Content-Range header specifies an inclusive range: e.g. the first ten
+ // bytes is "bytes 0-9/*". Convert it to a half-open range by incrementing
+ // read_end.
+ if (result == 2) {
+ *read_start = read_start_int;
+ *read_end = read_end_int + 1;
+ *entity_length = 0;
+ return true;
+ } else if (result == 3) {
+ *read_start = read_start_int;
+ *read_end = read_end_int + 1;
+ *entity_length = entity_length_int;
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace
+
+void MountNodeHttp::SetCachedSize(off_t size) {
+ has_cached_size_ = true;
+ stat_.st_size = size;
+}
+
+Error MountNodeHttp::FSync() { return ENOSYS; }
+
+Error MountNodeHttp::GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+ return ENOSYS;
+}
+
+Error MountNodeHttp::GetStat(struct stat* stat) {
+ AutoLock lock(&lock_);
+
+ // Assume we need to 'HEAD' if we do not know the size, otherwise, assume
+ // that the information is constant. We can add a timeout if needed.
+ MountHttp* mount = static_cast<MountHttp*>(mount_);
+ if (stat_.st_size == 0 || !mount->cache_stat_) {
+ StringMap_t headers;
+ PP_Resource loader;
+ PP_Resource request;
+ PP_Resource response;
+ int32_t statuscode;
+ StringMap_t response_headers;
+ Error error = OpenUrl("HEAD",
+ &headers,
+ &loader,
+ &request,
+ &response,
+ &statuscode,
+ &response_headers);
+ if (error)
+ return error;
+
+ ScopedResource scoped_loader(mount_->ppapi(), loader);
+ ScopedResource scoped_request(mount_->ppapi(), request);
+ ScopedResource scoped_response(mount_->ppapi(), response);
+
+ size_t entity_length;
+ if (ParseContentLength(response_headers, &entity_length)) {
+ SetCachedSize(static_cast<off_t>(entity_length));
+ } else if (cache_content_ && !has_cached_size_) {
+ error = DownloadToCache();
+ // TODO(binji): this error should not be dropped, but it requires a bit
+ // of a refactor of the tests. See crbug.com/245431
+ // if (error)
+ // return error;
+ } else {
+ // Don't use SetCachedSize here -- it is actually unknown.
+ stat_.st_size = 0;
+ }
+
+ stat_.st_atime = 0; // TODO(binji): Use "Last-Modified".
+ stat_.st_mtime = 0;
+ stat_.st_ctime = 0;
+ }
+
+ // Fill the stat structure if provided
+ if (stat)
+ memcpy(stat, &stat_, sizeof(stat_));
+
+ return 0;
+}
+
+Error MountNodeHttp::Read(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ AutoLock lock(&lock_);
+ if (cache_content_) {
+ if (cached_data_.empty()) {
+ Error error = DownloadToCache();
+ if (error)
+ return error;
+ }
+
+ return ReadPartialFromCache(offs, buf, count, out_bytes);
+ }
+
+ return DownloadPartial(offs, buf, count, out_bytes);
+}
+
+Error MountNodeHttp::FTruncate(off_t size) { return ENOSYS; }
+
+Error MountNodeHttp::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ // TODO(binji): support POST?
+ *out_bytes = 0;
+ return ENOSYS;
+}
+
+Error MountNodeHttp::GetSize(size_t* out_size) {
+ *out_size = 0;
+
+ // TODO(binji): This value should be cached properly; i.e. obey the caching
+ // headers returned by the server.
+ AutoLock lock(&lock_);
+ if (!has_cached_size_) {
+ // Even if DownloadToCache fails, the best result we can return is what
+ // was written to stat_.st_size.
+ if (cache_content_) {
+ Error error = DownloadToCache();
+ if (error)
+ return error;
+ }
+ }
+
+ *out_size = stat_.st_size;
+ return 0;
+}
+
+MountNodeHttp::MountNodeHttp(Mount* mount,
+ const std::string& url,
+ bool cache_content)
+ : MountNode(mount),
+ url_(url),
+ cache_content_(cache_content),
+ has_cached_size_(false) {}
+
+Error MountNodeHttp::OpenUrl(const char* method,
+ StringMap_t* request_headers,
+ PP_Resource* out_loader,
+ PP_Resource* out_request,
+ PP_Resource* out_response,
+ int32_t* out_statuscode,
+ StringMap_t* out_response_headers) {
+ // Assume lock_ is already held.
+ PepperInterface* ppapi = mount_->ppapi();
+
+ MountHttp* mount_http = static_cast<MountHttp*>(mount_);
+ ScopedResource request(
+ ppapi, mount_http->MakeUrlRequestInfo(url_, method, request_headers));
+ if (!request.pp_resource())
+ return EINVAL;
+
+ URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface();
+ URLResponseInfoInterface* response_interface =
+ ppapi->GetURLResponseInfoInterface();
+ VarInterface* var_interface = ppapi->GetVarInterface();
+
+ ScopedResource loader(ppapi, loader_interface->Create(ppapi->GetInstance()));
+ if (!loader.pp_resource())
+ return EINVAL;
+
+ int32_t result = loader_interface->Open(
+ loader.pp_resource(), request.pp_resource(), PP_BlockUntilComplete());
+ if (result != PP_OK)
+ return PPErrorToErrno(result);
+
+ ScopedResource response(
+ ppapi, loader_interface->GetResponseInfo(loader.pp_resource()));
+ if (!response.pp_resource())
+ return EINVAL;
+
+ // Get response statuscode.
+ PP_Var statuscode = response_interface->GetProperty(
+ response.pp_resource(), PP_URLRESPONSEPROPERTY_STATUSCODE);
+
+ if (statuscode.type != PP_VARTYPE_INT32)
+ return EINVAL;
+
+ *out_statuscode = statuscode.value.as_int;
+
+ // Only accept OK or Partial Content.
+ if (*out_statuscode != STATUSCODE_OK &&
+ *out_statuscode != STATUSCODE_PARTIAL_CONTENT) {
+ return EINVAL;
+ }
+
+ // Get response headers.
+ PP_Var response_headers_var = response_interface->GetProperty(
+ response.pp_resource(), PP_URLRESPONSEPROPERTY_HEADERS);
+
+ uint32_t response_headers_length;
+ const char* response_headers_str =
+ var_interface->VarToUtf8(response_headers_var, &response_headers_length);
+
+ *out_loader = loader.Release();
+ *out_request = request.Release();
+ *out_response = response.Release();
+ *out_response_headers =
+ ParseHeaders(response_headers_str, response_headers_length);
+
+ return 0;
+}
+
+Error MountNodeHttp::DownloadToCache() {
+ StringMap_t headers;
+ PP_Resource loader;
+ PP_Resource request;
+ PP_Resource response;
+ int32_t statuscode;
+ StringMap_t response_headers;
+ Error error = OpenUrl("GET",
+ &headers,
+ &loader,
+ &request,
+ &response,
+ &statuscode,
+ &response_headers);
+ if (error)
+ return error;
+
+ PepperInterface* ppapi = mount_->ppapi();
+ ScopedResource scoped_loader(ppapi, loader);
+ ScopedResource scoped_request(ppapi, request);
+ ScopedResource scoped_response(ppapi, response);
+
+ size_t content_length = 0;
+ if (ParseContentLength(response_headers, &content_length)) {
+ cached_data_.resize(content_length);
+ int real_size;
+ error = DownloadToBuffer(
+ loader, cached_data_.data(), content_length, &real_size);
+ if (error)
+ return error;
+
+ SetCachedSize(real_size);
+ cached_data_.resize(real_size);
+ return 0;
+ }
+
+ // We don't know how big the file is. Read in chunks.
+ cached_data_.resize(MAX_READ_BUFFER_SIZE);
+ size_t total_bytes_read = 0;
+ size_t bytes_to_read = MAX_READ_BUFFER_SIZE;
+ while (true) {
+ char* buf = cached_data_.data() + total_bytes_read;
+ int bytes_read;
+ error = DownloadToBuffer(loader, buf, bytes_to_read, &bytes_read);
+ if (error)
+ return error;
+
+ total_bytes_read += bytes_read;
+
+ if (bytes_read < bytes_to_read) {
+ SetCachedSize(total_bytes_read);
+ cached_data_.resize(total_bytes_read);
+ return 0;
+ }
+
+ cached_data_.resize(total_bytes_read + bytes_to_read);
+ }
+}
+
+Error MountNodeHttp::ReadPartialFromCache(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ if (offs > cached_data_.size())
+ return EINVAL;
+
+ count = std::min(count, cached_data_.size() - offs);
+ memcpy(buf, &cached_data_.data()[offs], count);
+
+ *out_bytes = count;
+ return 0;
+}
+
+Error MountNodeHttp::DownloadPartial(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ StringMap_t headers;
+
+ char buffer[100];
+ // Range request is inclusive: 0-99 returns 100 bytes.
+ snprintf(&buffer[0],
+ sizeof(buffer),
+ "bytes=%" PRIuS "-%" PRIuS,
+ offs,
+ offs + count - 1);
+ headers["Range"] = buffer;
+
+ PP_Resource loader;
+ PP_Resource request;
+ PP_Resource response;
+ int32_t statuscode;
+ StringMap_t response_headers;
+ Error error = OpenUrl("GET",
+ &headers,
+ &loader,
+ &request,
+ &response,
+ &statuscode,
+ &response_headers);
+ if (error)
+ return error;
+
+ PepperInterface* ppapi = mount_->ppapi();
+ ScopedResource scoped_loader(ppapi, loader);
+ ScopedResource scoped_request(ppapi, request);
+ ScopedResource scoped_response(ppapi, response);
+
+ size_t read_start = 0;
+ if (statuscode == STATUSCODE_OK) {
+ // No partial result, read everything starting from the part we care about.
+ size_t content_length;
+ if (ParseContentLength(response_headers, &content_length)) {
+ if (offs >= content_length)
+ return EINVAL;
+
+ // Clamp count, if trying to read past the end of the file.
+ if (offs + count > content_length) {
+ count = content_length - offs;
+ }
+ }
+ } else if (statuscode == STATUSCODE_PARTIAL_CONTENT) {
+ // Determine from the headers where we are reading.
+ size_t read_end;
+ size_t entity_length;
+ if (ParseContentRange(
+ response_headers, &read_start, &read_end, &entity_length)) {
+ if (read_start > offs || read_start > read_end) {
+ // If this error occurs, the server is returning bogus values.
+ return EINVAL;
+ }
+
+ // Clamp count, if trying to read past the end of the file.
+ count = std::min(read_end - read_start, count);
+ } else {
+ // Partial Content without Content-Range. Assume that the server gave us
+ // exactly what we asked for. This can happen even when the server
+ // returns 200 -- the cache may return 206 in this case, but not modify
+ // the headers.
+ read_start = offs;
+ }
+ }
+
+ if (read_start < offs) {
+ // We aren't yet at the location where we want to start reading. Read into
+ // our dummy buffer until then.
+ size_t bytes_to_read = offs - read_start;
+ if (buffer_.size() < bytes_to_read)
+ buffer_.resize(std::min(bytes_to_read, MAX_READ_BUFFER_SIZE));
+
+ while (bytes_to_read > 0) {
+ int32_t bytes_read;
+ Error error =
+ DownloadToBuffer(loader, buffer_.data(), buffer_.size(), &bytes_read);
+ if (error)
+ return error;
+
+ bytes_to_read -= bytes_read;
+ }
+ }
+
+ return DownloadToBuffer(loader, buf, count, out_bytes);
+}
+
+Error MountNodeHttp::DownloadToBuffer(PP_Resource loader,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ PepperInterface* ppapi = mount_->ppapi();
+ URLLoaderInterface* loader_interface = ppapi->GetURLLoaderInterface();
+
+ char* out_buffer = static_cast<char*>(buf);
+ size_t bytes_to_read = count;
+ while (bytes_to_read > 0) {
+ int32_t bytes_read = loader_interface->ReadResponseBody(
+ loader, out_buffer, bytes_to_read, PP_BlockUntilComplete());
+
+ if (bytes_read == 0) {
+ // This is not an error -- it may just be that we were trying to read
+ // more data than exists.
+ *out_bytes = count - bytes_to_read;
+ return 0;
+ }
+
+ if (bytes_read < 0)
+ return PPErrorToErrno(bytes_read);
+
+ assert(bytes_read <= bytes_to_read);
+ bytes_to_read -= bytes_read;
+ out_buffer += bytes_read;
+ }
+
+ *out_bytes = count;
+ return 0;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_http.h b/native_client_sdk/src/libraries/nacl_io/mount_node_http.h
new file mode 100644
index 0000000..6b17468
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_http.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2013 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_IO_MOUNT_NODE_HTTP_H_
+#define LIBRARIES_NACL_IO_MOUNT_NODE_HTTP_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "nacl_io/error.h"
+#include "nacl_io/mount_node.h"
+#include "nacl_io/pepper_interface.h"
+
+typedef std::map<std::string, std::string> StringMap_t;
+
+class MountNodeHttp : public MountNode {
+ public:
+ virtual Error FSync();
+ virtual Error GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t count,
+ int* out_bytes);
+ virtual Error GetStat(struct stat* stat);
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+ virtual Error FTruncate(off_t size);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
+ virtual Error GetSize(size_t* out_size);
+
+ void SetCachedSize(off_t size);
+
+ protected:
+ MountNodeHttp(Mount* mount, const std::string& url, bool cache_content);
+
+ private:
+ Error OpenUrl(const char* method,
+ StringMap_t* request_headers,
+ PP_Resource* out_loader,
+ PP_Resource* out_request,
+ PP_Resource* out_response,
+ int32_t* out_statuscode,
+ StringMap_t* out_response_headers);
+
+ Error DownloadToCache();
+ Error ReadPartialFromCache(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes);
+ Error DownloadPartial(size_t offs, void* buf, size_t count, int* out_bytes);
+ Error DownloadToBuffer(PP_Resource loader,
+ void* buf,
+ size_t count,
+ int* out_bytes);
+
+ std::string url_;
+ std::vector<char> buffer_;
+
+ bool cache_content_;
+ bool has_cached_size_;
+ std::vector<char> cached_data_;
+
+ friend class MountHttp;
+};
+
+#endif // LIBRARIES_NACL_IO_MOUNT_NODE_HTTP_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_mem.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_mem.cc
index 13f0d21..d324079 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_mem.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_mem.cc
@@ -13,69 +13,83 @@
#define BLOCK_SIZE (1 << 16)
#define BLOCK_MASK (BLOCK_SIZE - 1)
-MountNodeMem::MountNodeMem(Mount *mount)
- : MountNode(mount),
- data_(NULL),
- capacity_(0) {
+MountNodeMem::MountNodeMem(Mount* mount)
+ : MountNode(mount), data_(NULL), capacity_(0) {
stat_.st_mode |= S_IFREG;
}
-MountNodeMem::~MountNodeMem() {
- free(data_);
-}
+MountNodeMem::~MountNodeMem() { free(data_); }
+
+Error MountNodeMem::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
-int MountNodeMem::Read(size_t offs, void *buf, size_t count) {
AutoLock lock(&lock_);
- if (count == 0) return 0;
- if (offs + count > GetSize()) {
- count = GetSize() - offs;
+ if (count == 0)
+ return 0;
+
+ size_t size = stat_.st_size;
+
+ if (offs + count > size) {
+ count = size - offs;
}
memcpy(buf, &data_[offs], count);
- return static_cast<int>(count);
+ *out_bytes = static_cast<int>(count);
+ return 0;
}
-int MountNodeMem::Write(size_t offs, const void *buf, size_t count) {
+Error MountNodeMem::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
AutoLock lock(&lock_);
- if (count == 0) return 0;
+ if (count == 0)
+ return 0;
+
+ if (count + offs > stat_.st_size) {
+ Error error = FTruncate(count + offs);
+ if (error)
+ return error;
- if (count + offs > GetSize()) {
- FTruncate(count + offs);
- count = GetSize() - offs;
+ count = stat_.st_size - offs;
}
memcpy(&data_[offs], buf, count);
- return static_cast<int>(count);
+ *out_bytes = static_cast<int>(count);
+ return 0;
}
-int MountNodeMem::FTruncate(off_t size) {
- size_t need = (size + BLOCK_MASK) & ~BLOCK_MASK;
+Error MountNodeMem::FTruncate(off_t new_size) {
+ size_t need = (new_size + BLOCK_MASK) & ~BLOCK_MASK;
+ size_t old_size = stat_.st_size;
// If the current capacity is correct, just adjust and return
if (need == capacity_) {
- stat_.st_size = static_cast<off_t>(size);
+ stat_.st_size = static_cast<off_t>(new_size);
return 0;
}
// Attempt to realloc the block
- char *newdata = static_cast<char *>(realloc(data_, need));
+ char* newdata = static_cast<char*>(realloc(data_, need));
if (newdata != NULL) {
// Zero out new space.
- if (size > GetSize())
- memset(newdata + GetSize(), 0, size - GetSize());
+ if (new_size > old_size)
+ memset(newdata + old_size, 0, new_size - old_size);
data_ = newdata;
capacity_ = need;
- stat_.st_size = static_cast<off_t>(size);
+ stat_.st_size = static_cast<off_t>(new_size);
return 0;
}
// If we failed, then adjust size according to what we keep
- if (size > capacity_) size = capacity_;
+ if (new_size > capacity_)
+ new_size = capacity_;
// Update the size and return the new size
- stat_.st_size = static_cast<off_t>(size);
- errno = EIO;
- return -1;
+ stat_.st_size = static_cast<off_t>(new_size);
+ return EIO;
}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_mem.h b/native_client_sdk/src/libraries/nacl_io/mount_node_mem.h
index 07acfe1..6457014 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_mem.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_mem.h
@@ -16,9 +16,12 @@ class MountNodeMem : public MountNode {
public:
// Normal read/write operations on a file
- virtual int Read(size_t offs, void* buf, size_t count);
- virtual int Write(size_t offs, const void* buf, size_t count);
- virtual int FTruncate(off_t size);
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes);
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes);
+ virtual Error FTruncate(off_t size);
private:
char* data_;
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
index 82660d6..268cbea 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.cc
@@ -9,14 +9,10 @@
class MountNodePassthrough : public MountNode {
public:
explicit MountNodePassthrough(Mount* mount, int real_fd)
- : MountNode(mount),
- real_fd_(real_fd) {
- }
+ : MountNode(mount), real_fd_(real_fd) {}
protected:
- virtual bool Init(int flags) {
- return true;
- }
+ virtual Error Init(int flags) { return 0; }
virtual void Destroy() {
if (real_fd_)
@@ -26,77 +22,74 @@ class MountNodePassthrough : public MountNode {
public:
// Normal read/write operations on a file
- virtual int Read(size_t offs, void* buf, size_t count) {
+ virtual Error Read(size_t offs, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
+
off_t new_offset;
int err = _real_lseek(real_fd_, offs, 0, &new_offset);
- if (err) {
- errno = err;
- return -1;
- }
+ if (err)
+ return err;
size_t nread;
err = _real_read(real_fd_, buf, count, &nread);
- if (err) {
- errno = err;
- return -1;
- }
+ if (err)
+ return err;
- return static_cast<int>(nread);
+ *out_bytes = static_cast<int>(nread);
+ return 0;
}
- virtual int Write(size_t offs, const void* buf, size_t count) {
+ virtual Error Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
off_t new_offset;
int err = _real_lseek(real_fd_, offs, 0, &new_offset);
- if (err) {
- errno = err;
- return -1;
- }
+ if (err)
+ return err;
size_t nwrote;
err = _real_write(real_fd_, buf, count, &nwrote);
- if (err) {
- errno = err;
- return -1;
- }
+ if (err)
+ return err;
- return static_cast<int>(nwrote);
+ *out_bytes = static_cast<int>(nwrote);
+ return 0;
}
- virtual int FTruncate(off_t size) {
+ virtual Error FTruncate(off_t size) {
// TODO(binji): what to do here?
- return -1;
+ return ENOSYS;
}
- virtual int GetDents(size_t offs, struct dirent* pdir, size_t count) {
+ virtual Error GetDents(size_t offs, struct dirent* pdir, size_t count) {
size_t nread;
int err = _real_getdents(real_fd_, pdir, count, &nread);
- if (err) {
- errno = err;
- return -1;
- }
-
+ if (err)
+ return err;
return nread;
}
- virtual int GetStat(struct stat* stat) {
+ virtual Error GetStat(struct stat* stat) {
int err = _real_fstat(real_fd_, stat);
- if (err) {
- errno = err;
- return -1;
- }
-
+ if (err)
+ return err;
return 0;
}
- void* MMap(void* addr, size_t length, int prot, int flags, size_t offset) {
- void* new_addr = addr;
- int err = _real_mmap(&new_addr, length, prot, flags, real_fd_, offset);
- if (err) {
- errno = err;
- return (void*)-1;
- }
-
- return new_addr;
+ Error MMap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ size_t offset,
+ void** out_addr) {
+ *out_addr = addr;
+ int err = _real_mmap(out_addr, length, prot, flags, real_fd_, offset);
+ if (err)
+ return err;
+ return 0;
}
private:
@@ -105,70 +98,56 @@ class MountNodePassthrough : public MountNode {
int real_fd_;
};
-MountPassthrough::MountPassthrough() {
-}
+MountPassthrough::MountPassthrough() {}
-bool MountPassthrough::Init(int dev, StringMap_t& args,
- PepperInterface* ppapi) {
- Mount::Init(dev, args, ppapi);
- return true;
+Error MountPassthrough::Init(int dev,
+ StringMap_t& args,
+ PepperInterface* ppapi) {
+ return Mount::Init(dev, args, ppapi);
}
-void MountPassthrough::Destroy() {
-}
+void MountPassthrough::Destroy() {}
+
+Error MountPassthrough::Open(const Path& path, int mode, MountNode** out_node) {
+ *out_node = NULL;
-MountNode *MountPassthrough::Open(const Path& path, int mode) {
int real_fd;
- int err = _real_open(path.Join().c_str(), mode, 0666, &real_fd);
- if (err) {
- errno = err;
- return NULL;
- }
+ int error = _real_open(path.Join().c_str(), mode, 0666, &real_fd);
+ if (error)
+ return error;
MountNodePassthrough* node = new MountNodePassthrough(this, real_fd);
- return node;
+ *out_node = node;
+ return 0;
}
-MountNode *MountPassthrough::OpenResource(const Path& path) {
+Error MountPassthrough::OpenResource(const Path& path, MountNode** out_node) {
+ *out_node = NULL;
+
int real_fd;
- int err = _real_open_resource(path.Join().c_str(), &real_fd);
- if (err) {
- errno = err;
- return NULL;
- }
+ int error = _real_open_resource(path.Join().c_str(), &real_fd);
+ if (error)
+ return error;
MountNodePassthrough* node = new MountNodePassthrough(this, real_fd);
- return node;
+ *out_node = node;
+ return 0;
}
-int MountPassthrough::Unlink(const Path& path) {
+Error MountPassthrough::Unlink(const Path& path) {
// Not implemented by NaCl.
- errno = ENOSYS;
- return -1;
+ return ENOSYS;
}
-int MountPassthrough::Mkdir(const Path& path, int perm) {
- int err = _real_mkdir(path.Join().c_str(), perm);
- if (err) {
- errno = err;
- return -1;
- }
-
- return 0;
+Error MountPassthrough::Mkdir(const Path& path, int perm) {
+ return _real_mkdir(path.Join().c_str(), perm);
}
-int MountPassthrough::Rmdir(const Path& path) {
- int err = _real_rmdir(path.Join().c_str());
- if (err) {
- errno = err;
- return -1;
- }
-
- return 0;
+Error MountPassthrough::Rmdir(const Path& path) {
+ return _real_rmdir(path.Join().c_str());
}
-int MountPassthrough::Remove(const Path& path) {
+Error MountPassthrough::Remove(const Path& path) {
// Not implemented by NaCl.
- errno = ENOSYS;
- return -1;
+ return ENOSYS;
}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
index 00a0eec..b143abf 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_passthrough.h
@@ -11,16 +11,16 @@ class MountPassthrough : public Mount {
protected:
MountPassthrough();
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi);
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi);
virtual void Destroy();
public:
- virtual MountNode *Open(const Path& path, int mode);
- virtual MountNode *OpenResource(const Path& path);
- virtual int Unlink(const Path& path);
- virtual int Mkdir(const Path& path, int perm);
- virtual int Rmdir(const Path& path);
- virtual int Remove(const Path& path);
+ virtual Error Open(const Path& path, int mode, MountNode** out_node);
+ virtual Error OpenResource(const Path& path, MountNode** out_node);
+ virtual Error Unlink(const Path& path);
+ virtual Error Mkdir(const Path& path, int perm);
+ virtual Error Rmdir(const Path& path);
+ virtual Error Remove(const Path& path);
private:
friend class Mount;
diff --git a/native_client_sdk/src/libraries/nacl_io_test/example.dsc b/native_client_sdk/src/libraries/nacl_io_test/example.dsc
index a47ed63..df934a5 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/example.dsc
+++ b/native_client_sdk/src/libraries/nacl_io_test/example.dsc
@@ -1,5 +1,4 @@
{
- # TODO(binji): pnacl doesn't build right now because gtest doesn't build yet.
'TOOLS': ['newlib', 'glibc', 'pnacl', 'win'],
# Need to add ../../examples for common.js
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc
index 268c6f5..9e6f483 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc
@@ -23,22 +23,21 @@ namespace {
class MountRefMock : public Mount {
public:
MountRefMock(int* mount_count, int* handle_count)
- : mount_count(mount_count),
- handle_count(handle_count) {
+ : mount_count(mount_count), handle_count(handle_count) {
(*mount_count)++;
}
- ~MountRefMock() {
- (*mount_count)--;
- }
+ ~MountRefMock() { (*mount_count)--; }
public:
- MountNode* Open(const Path& path, int mode) { return NULL; }
- int Close(MountNode* node) { return 0; }
- int Unlink(const Path& path) { return 0; }
- int Mkdir(const Path& path, int permissions) { return 0; }
- int Rmdir(const Path& path) { return 0; }
- int Remove(const Path& path) { return 0; }
+ Error Open(const Path& path, int mode, MountNode** out_node) {
+ *out_node = NULL;
+ return ENOSYS;
+ }
+ Error Unlink(const Path& path) { return 0; }
+ Error Mkdir(const Path& path, int permissions) { return 0; }
+ Error Rmdir(const Path& path) { return 0; }
+ Error Remove(const Path& path) { return 0; }
public:
int* mount_count;
@@ -47,8 +46,8 @@ class MountRefMock : public Mount {
class KernelHandleRefMock : public KernelHandle {
public:
- KernelHandleRefMock(Mount* mnt, MountNode* node, int flags)
- : KernelHandle(mnt, node, flags) {
+ KernelHandleRefMock(Mount* mnt, MountNode* node)
+ : KernelHandle(mnt, node) {
MountRefMock* mock_mount = static_cast<MountRefMock*>(mnt);
(*mock_mount->handle_count)++;
}
@@ -61,9 +60,7 @@ class KernelHandleRefMock : public KernelHandle {
class KernelObjectTest : public ::testing::Test {
public:
- KernelObjectTest()
- : mount_count(0),
- handle_count(0) {
+ KernelObjectTest() : mount_count(0), handle_count(0) {
proxy = new KernelObject;
mnt = new MountRefMock(&mount_count, &handle_count);
}
@@ -81,10 +78,10 @@ class KernelObjectTest : public ::testing::Test {
} // namespace
-
TEST_F(KernelObjectTest, Referencing) {
- KernelHandle* handle = new KernelHandleRefMock(mnt, NULL, 0);
- KernelHandle* handle2 = new KernelHandleRefMock(mnt, NULL, 0);
+ KernelHandle* handle = new KernelHandleRefMock(mnt, NULL);
+ KernelHandle* handle2 = new KernelHandleRefMock(mnt, NULL);
+ KernelHandle* result_handle = NULL;
// Objects should have one ref when we start
EXPECT_EQ(1, mnt->RefCount());
@@ -111,14 +108,16 @@ TEST_F(KernelObjectTest, Referencing) {
EXPECT_EQ(2, fd3);
// We should find the handle by either fd
- EXPECT_EQ(handle, proxy->AcquireHandle(fd1));
- EXPECT_EQ(handle, proxy->AcquireHandle(fd2));
+ EXPECT_EQ(0, proxy->AcquireHandle(fd1, &result_handle));
+ EXPECT_EQ(handle, result_handle);
+ EXPECT_EQ(0, proxy->AcquireHandle(fd2, &result_handle));
+ EXPECT_EQ(handle, result_handle);
// A non existent fd should fail
- EXPECT_EQ(NULL, proxy->AcquireHandle(-1));
- EXPECT_EQ(EBADF, errno);
- EXPECT_EQ(NULL, proxy->AcquireHandle(100));
- EXPECT_EQ(EBADF, errno);
+ EXPECT_EQ(EBADF, proxy->AcquireHandle(-1, &result_handle));
+ EXPECT_EQ(NULL, result_handle);
+ EXPECT_EQ(EBADF, proxy->AcquireHandle(100, &result_handle));
+ EXPECT_EQ(NULL, result_handle);
// Acquiring the handle, should have ref'd it
EXPECT_EQ(4, mnt->RefCount());
@@ -155,27 +154,35 @@ TEST_F(KernelObjectTest, Referencing) {
}
TEST_F(KernelObjectTest, FreeAndReassignFD) {
+ KernelHandle* result_handle = NULL;
+
EXPECT_EQ(0, handle_count);
- KernelHandle* handle = new KernelHandleRefMock(mnt, NULL, 0);
+ KernelHandle* handle = new KernelHandleRefMock(mnt, NULL);
EXPECT_EQ(1, handle_count);
EXPECT_EQ(1, handle->RefCount());
// Assign to a non-existent FD
proxy->FreeAndReassignFD(2, handle);
- EXPECT_EQ((KernelHandle*)NULL, proxy->AcquireHandle(0));
- EXPECT_EQ((KernelHandle*)NULL, proxy->AcquireHandle(1));
- EXPECT_EQ(handle, proxy->AcquireHandle(2));
+ EXPECT_EQ(EBADF, proxy->AcquireHandle(0, &result_handle));
+ EXPECT_EQ(NULL, result_handle);
+ EXPECT_EQ(EBADF, proxy->AcquireHandle(1, &result_handle));
+ EXPECT_EQ(NULL, result_handle);
+ EXPECT_EQ(0, proxy->AcquireHandle(2, &result_handle));
+ EXPECT_EQ(handle, result_handle);
proxy->ReleaseHandle(handle);
EXPECT_EQ(1, handle_count);
EXPECT_EQ(2, handle->RefCount());
proxy->FreeAndReassignFD(0, handle);
- EXPECT_EQ(handle, proxy->AcquireHandle(0));
- EXPECT_EQ((KernelHandle*)NULL, proxy->AcquireHandle(1));
- EXPECT_EQ(handle, proxy->AcquireHandle(2));
+ EXPECT_EQ(0, proxy->AcquireHandle(0, &result_handle));
+ EXPECT_EQ(handle, result_handle);
+ EXPECT_EQ(EBADF, proxy->AcquireHandle(1, &result_handle));
+ EXPECT_EQ(NULL, result_handle);
+ EXPECT_EQ(0, proxy->AcquireHandle(2, &result_handle));
+ EXPECT_EQ(handle, result_handle);
proxy->ReleaseHandle(handle);
proxy->ReleaseHandle(handle);
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
index d681653..40f4ef7 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
@@ -21,11 +21,9 @@
#include "gtest/gtest.h"
-
class KernelProxyTest : public ::testing::Test {
public:
- KernelProxyTest()
- : kp_(new KernelProxy) {
+ KernelProxyTest() : kp_(new KernelProxy) {
ki_init(kp_);
// Unmount the passthrough FS and mount a memfs.
EXPECT_EQ(0, kp_->umount("/"));
@@ -41,7 +39,6 @@ class KernelProxyTest : public ::testing::Test {
KernelProxy* kp_;
};
-
TEST_F(KernelProxyTest, WorkingDirectory) {
char text[1024];
@@ -50,7 +47,7 @@ TEST_F(KernelProxyTest, WorkingDirectory) {
EXPECT_STREQ("/", text);
char* alloc = ki_getwd(NULL);
- EXPECT_EQ((char *) NULL, alloc);
+ EXPECT_EQ((char*)NULL, alloc);
EXPECT_EQ(EFAULT, errno);
text[0] = 0;
@@ -113,7 +110,8 @@ TEST_F(KernelProxyTest, MemMountIO) {
EXPECT_NE(-1, fd3);
len = ki_read(fd3, text, sizeof(text));
- if (len > -0) text[len] = 0;
+ if (len > 0)
+ text[len] = 0;
EXPECT_EQ(5, len);
EXPECT_STREQ("HELLO", text);
EXPECT_EQ(0, ki_close(fd1));
@@ -124,7 +122,8 @@ TEST_F(KernelProxyTest, MemMountIO) {
EXPECT_EQ(5, ki_write(fd1, "WORLD", 5));
len = ki_read(fd3, text, sizeof(text));
- if (len >= 0) text[len] = 0;
+ if (len >= 0)
+ text[len] = 0;
EXPECT_EQ(5, len);
EXPECT_STREQ("WORLD", text);
@@ -132,7 +131,8 @@ TEST_F(KernelProxyTest, MemMountIO) {
fd2 = ki_open("/foo/bar", O_RDONLY);
EXPECT_NE(-1, fd2);
len = ki_read(fd2, text, sizeof(text));
- if (len > 0) text[len] = 0;
+ if (len > 0)
+ text[len] = 0;
EXPECT_EQ(10, len);
EXPECT_STREQ("HELLOWORLD", text);
}
@@ -197,17 +197,17 @@ TEST_F(KernelProxyTest, MemMountDup) {
// fd, new_fd, dup_fd -> "/bar"
}
-
StringMap_t g_StringMap;
class MountMockInit : public MountMem {
public:
- virtual bool Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
+ virtual Error Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
g_StringMap = args;
if (args.find("false") != args.end())
- return false;
- return true;
- };
+ return EINVAL;
+ return 0;
+ }
+ ;
};
class KernelProxyMountMock : public KernelProxy {
@@ -219,10 +219,7 @@ class KernelProxyMountMock : public KernelProxy {
class KernelProxyMountTest : public ::testing::Test {
public:
- KernelProxyMountTest()
- : kp_(new KernelProxyMountMock) {
- ki_init(kp_);
- }
+ KernelProxyMountTest() : kp_(new KernelProxyMountMock) { ki_init(kp_); }
~KernelProxyMountTest() {
ki_uninit();
@@ -245,28 +242,38 @@ TEST_F(KernelProxyMountTest, MountInit) {
EXPECT_EQ("y", g_StringMap["x"]);
}
-
namespace {
int g_MMapCount = 0;
class MountNodeMockMMap : public MountNode {
public:
- MountNodeMockMMap(Mount* mount)
- : MountNode(mount),
- node_mmap_count_(0) {
- Init(0);
+ MountNodeMockMMap(Mount* mount) : MountNode(mount), node_mmap_count_(0) {
+ EXPECT_EQ(0, Init(0));
}
- virtual void* MMap(void* addr, size_t length, int prot, int flags,
- size_t offset) {
+ virtual Error MMap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ size_t offset,
+ void** out_addr) {
node_mmap_count_++;
switch (g_MMapCount++) {
- case 0: return reinterpret_cast<void*>(0x1000);
- case 1: return reinterpret_cast<void*>(0x2000);
- case 2: return reinterpret_cast<void*>(0x3000);
- default: return MAP_FAILED;
+ case 0:
+ *out_addr = reinterpret_cast<void*>(0x1000);
+ break;
+ case 1:
+ *out_addr = reinterpret_cast<void*>(0x2000);
+ break;
+ case 2:
+ *out_addr = reinterpret_cast<void*>(0x3000);
+ break;
+ default:
+ return EPERM;
}
+
+ return 0;
}
private:
@@ -275,16 +282,20 @@ class MountNodeMockMMap : public MountNode {
class MountMockMMap : public Mount {
public:
- virtual MountNode* Open(const Path& path, int mode) {
+ virtual Error Open(const Path& path, int mode, MountNode** out_node) {
MountNodeMockMMap* node = new MountNodeMockMMap(this);
- return node;
+ *out_node = node;
+ return 0;
}
- virtual MountNode* OpenResource(const Path& path) { return NULL; }
- virtual int Unlink(const Path& path) { return -1; }
- virtual int Mkdir(const Path& path, int permissions) { return -1; }
- virtual int Rmdir(const Path& path) { return -1; }
- virtual int Remove(const Path& path) { return -1; }
+ virtual Error OpenResource(const Path& path, MountNode** out_node) {
+ *out_node = NULL;
+ return ENOSYS;
+ }
+ virtual Error Unlink(const Path& path) { return ENOSYS; }
+ virtual Error Mkdir(const Path& path, int permissions) { return ENOSYS; }
+ virtual Error Rmdir(const Path& path) { return ENOSYS; }
+ virtual Error Remove(const Path& path) { return ENOSYS; }
};
class KernelProxyMockMMap : public KernelProxy {
@@ -296,10 +307,7 @@ class KernelProxyMockMMap : public KernelProxy {
class KernelProxyMMapTest : public ::testing::Test {
public:
- KernelProxyMMapTest()
- : kp_(new KernelProxyMockMMap) {
- ki_init(kp_);
- }
+ KernelProxyMMapTest() : kp_(new KernelProxyMockMMap) { ki_init(kp_); }
~KernelProxyMMapTest() {
ki_uninit();
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
index f6f010c..34d8472 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
@@ -81,6 +81,10 @@ class KernelWrapTest : public ::testing::Test {
.WillOnce(Return(0))
.WillOnce(Return(1))
.WillOnce(Return(2));
+ // And will call mount / and /dev.
+ EXPECT_CALL(mock, mount(_, _, _, _, _))
+ .WillOnce(Return(0))
+ .WillOnce(Return(0));
ki_init(&mock);
}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc
index 0ca210b..e92a20a 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc
@@ -166,7 +166,7 @@ void MountHtml5FsNodeTest::InitFilesystem() {
}
void MountHtml5FsNodeTest::InitNode() {
- node_ = mnt_->Open(Path(path_), O_CREAT | O_RDWR);
+ ASSERT_EQ(0, mnt_->Open(Path(path_), O_CREAT | O_RDWR, &node_));
ASSERT_NE((MountNode*)NULL, node_);
}
@@ -378,7 +378,8 @@ TEST_F(MountHtml5FsNodeSyncTest, Write) {
EXPECT_CALL(*fileio_, Write(fileio_resource_, offset, &buffer[0], count, _))
.WillOnce(Return(count));
- int result = node_->Write(offset, &buffer, count);
+ int result = 0;
+ EXPECT_EQ(0, node_->Write(offset, &buffer, count, &result));
EXPECT_EQ(count, result);
}
@@ -390,7 +391,8 @@ TEST_F(MountHtml5FsNodeSyncTest, Read) {
EXPECT_CALL(*fileio_, Read(fileio_resource_, offset, &buffer[0], count, _))
.WillOnce(Return(count));
- int result = node_->Read(offset, &buffer, count);
+ int result = 0;
+ EXPECT_EQ(0, node_->Read(offset, &buffer, count, &result));
EXPECT_EQ(count, result);
}
@@ -437,9 +439,10 @@ TEST_F(MountHtml5FsNodeSyncTest, GetDents) {
memset(&dirents[0], 0, sizeof(dirents));
// Should fail for regular files.
- int result = node_->GetDents(0, &dirents[0], sizeof(dirent) * 2);
- ASSERT_EQ(-1, result);
- ASSERT_EQ(ENOTDIR, errno);
+ int result_bytes = 0;
+ EXPECT_EQ(ENOTDIR, node_->GetDents(0, &dirents[0], sizeof(dirent) * 2,
+ &result_bytes));
+ ASSERT_EQ(0, result_bytes);
}
TEST_F(MountHtml5FsNodeSyncDirTest, OpenAndClose) {
@@ -451,9 +454,9 @@ TEST_F(MountHtml5FsNodeSyncDirTest, Write) {
const char buffer[30] = {0};
// Should fail for directories.
- int result = node_->Write(offset, &buffer, count);
- ASSERT_EQ(-1, result);
- EXPECT_EQ(EISDIR, errno);
+ int result_bytes = 0;
+ EXPECT_EQ(EISDIR, node_->Write(offset, &buffer, count, &result_bytes));
+ ASSERT_EQ(0, result_bytes);
}
TEST_F(MountHtml5FsNodeSyncDirTest, Read) {
@@ -462,9 +465,9 @@ TEST_F(MountHtml5FsNodeSyncDirTest, Read) {
char buffer[30] = {0};
// Should fail for directories.
- int result = node_->Read(offset, &buffer, count);
- ASSERT_EQ(-1, result);
- EXPECT_EQ(EISDIR, errno);
+ int result_bytes = 0;
+ EXPECT_EQ(EISDIR, node_->Read(offset, &buffer, count, &result_bytes));
+ ASSERT_EQ(0, result_bytes);
}
TEST_F(MountHtml5FsNodeSyncDirTest, GetStat) {
@@ -498,9 +501,7 @@ TEST_F(MountHtml5FsNodeSyncDirTest, GetStat) {
TEST_F(MountHtml5FsNodeSyncDirTest, FTruncate) {
const int size = 123;
// Should fail for directories.
- int result = node_->FTruncate(size);
- ASSERT_EQ(-1, result);
- EXPECT_EQ(EISDIR, errno);
+ EXPECT_EQ(EISDIR, node_->FTruncate(size));
}
TEST_F(MountHtml5FsNodeSyncDirTest, GetDents) {
@@ -542,9 +543,12 @@ TEST_F(MountHtml5FsNodeSyncDirTest, GetDents) {
memset(&dirents[0], 0, sizeof(dirents));
// +2 to test a size that is not a multiple of sizeof(dirent).
// Expect it to round down.
- int result = node_->GetDents(0, &dirents[0], sizeof(dirent) * 2 + 2);
+ int result_bytes = 0;
+ EXPECT_EQ(
+ 0,
+ node_->GetDents(0, &dirents[0], sizeof(dirent) * 2 + 2, &result_bytes));
- ASSERT_EQ(sizeof(dirent) * 2, result);
+ ASSERT_EQ(sizeof(dirent) * 2, result_bytes);
EXPECT_LT(0, dirents[0].d_ino); // 0 is an invalid inode number.
EXPECT_EQ(sizeof(dirent), dirents[0].d_off);
EXPECT_EQ(sizeof(dirent), dirents[0].d_reclen);
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc
index 350874d..ced8d06 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc
@@ -29,7 +29,7 @@ using ::testing::StrEq;
class MountHttpMock : public MountHttp {
public:
MountHttpMock(StringMap_t map, PepperInterfaceMock* ppapi) {
- EXPECT_TRUE(Init(1, map, ppapi));
+ EXPECT_EQ(0, Init(1, map, ppapi));
}
~MountHttpMock() {
@@ -71,25 +71,34 @@ TEST_F(MountHttpTest, MountEmpty) {
TEST_F(MountHttpTest, ParseManifest) {
StringMap_t args;
+ size_t result_size = 0;
+
mnt_ = new MountHttpMock(args, &ppapi_);
char manifest[] = "-r-- 123 /mydir/foo\n-rw- 234 /thatdir/bar\n";
- EXPECT_TRUE(mnt_->ParseManifest(manifest));
+ EXPECT_EQ(0, mnt_->ParseManifest(manifest));
- MountNodeDir* root = mnt_->FindOrCreateDir(Path("/"));
+ MountNodeDir* root = NULL;
+ EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/"), &root));
+ ASSERT_NE((MountNode*)NULL, root);
EXPECT_EQ(2, root->ChildCount());
- MountNodeDir* dir = mnt_->FindOrCreateDir(Path("/mydir"));
+ MountNodeDir* dir = NULL;
+ EXPECT_EQ(0, mnt_->FindOrCreateDir(Path("/mydir"), &dir));
+ ASSERT_NE((MountNode*)NULL, dir);
EXPECT_EQ(1, dir->ChildCount());
MountNode* node = mnt_->GetMap()["/mydir/foo"];
- EXPECT_TRUE(node);
- EXPECT_EQ(123, node->GetSize());
+ EXPECT_NE((MountNode*)NULL, node);
+ EXPECT_EQ(0, node->GetSize(&result_size));
+ EXPECT_EQ(123, result_size);
// Since these files are cached thanks to the manifest, we can open them
// without accessing the PPAPI URL API.
- MountNode* foo = mnt_->Open(Path("/mydir/foo"), O_RDONLY);
- MountNode* bar = mnt_->Open(Path("/thatdir/bar"), O_RDWR);
+ MountNode* foo = NULL;
+ EXPECT_EQ(0, mnt_->Open(Path("/mydir/foo"), O_RDONLY, &foo));
+ MountNode* bar = NULL;
+ EXPECT_EQ(0, mnt_->Open(Path("/thatdir/bar"), O_RDWR, &bar));
struct stat sfoo;
struct stat sbar;
@@ -248,7 +257,7 @@ void MountHttpNodeTest::SetResponseBody(const char* body) {
}
void MountHttpNodeTest::OpenNode() {
- node_ = mnt_->Open(Path(path_), O_RDONLY);
+ ASSERT_EQ(0, mnt_->Open(Path(path_), O_RDONLY, &node_));
ASSERT_NE((MountNode*)NULL, node_);
}
@@ -266,7 +275,9 @@ void MountHttpNodeTest::TearDown() {
delete mnt_;
}
-TEST_F(MountHttpNodeTest, OpenAndClose) {
+TEST_F(MountHttpNodeTest, OpenAndCloseNoCache) {
+ StringMap_t smap;
+ smap["cache_content"] = "false";
SetMountArgs(StringMap_t());
ExpectOpen("HEAD");
ExpectHeaders("");
@@ -275,6 +286,9 @@ TEST_F(MountHttpNodeTest, OpenAndClose) {
}
TEST_F(MountHttpNodeTest, ReadCached) {
+ size_t result_size = 0;
+ int result_bytes = 0;
+
SetMountArgs(StringMap_t());
ExpectOpen("HEAD");
ExpectHeaders("");
@@ -282,7 +296,8 @@ TEST_F(MountHttpNodeTest, ReadCached) {
OpenNode();
ResetMocks();
- EXPECT_EQ(42, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(42, result_size);
char buf[10];
memset(&buf[0], 0, sizeof(buf));
@@ -291,20 +306,24 @@ TEST_F(MountHttpNodeTest, ReadCached) {
ExpectHeaders("");
SetResponse(200, "Content-Length: 42\n");
SetResponseBody("Here is some response text. And some more.");
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("Here is s", &buf[0]);
ResetMocks();
// Further reads should be cached.
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("Here is s", &buf[0]);
- node_->Read(10, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("me respon", &buf[0]);
- EXPECT_EQ(42, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(42, result_size);
}
TEST_F(MountHttpNodeTest, ReadCachedNoContentLength) {
+ size_t result_size = 0;
+ int result_bytes = 0;
+
SetMountArgs(StringMap_t());
ExpectOpen("HEAD");
ExpectHeaders("");
@@ -319,25 +338,30 @@ TEST_F(MountHttpNodeTest, ReadCachedNoContentLength) {
// GetSize will Read() because it didn't get the content length from the HEAD
// request.
- EXPECT_EQ(42, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(42, result_size);
char buf[10];
memset(&buf[0], 0, sizeof(buf));
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("Here is s", &buf[0]);
ResetMocks();
// Further reads should be cached.
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("Here is s", &buf[0]);
- node_->Read(10, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
EXPECT_STREQ("me respon", &buf[0]);
- EXPECT_EQ(42, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(42, result_size);
}
TEST_F(MountHttpNodeTest, ReadCachedUnderrun) {
+ size_t result_size = 0;
+ int result_bytes = 0;
+
SetMountArgs(StringMap_t());
ExpectOpen("HEAD");
ExpectHeaders("");
@@ -345,7 +369,8 @@ TEST_F(MountHttpNodeTest, ReadCachedUnderrun) {
OpenNode();
ResetMocks();
- EXPECT_EQ(100, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(100, result_size);
char buf[10];
memset(&buf[0], 0, sizeof(buf));
@@ -354,14 +379,19 @@ TEST_F(MountHttpNodeTest, ReadCachedUnderrun) {
ExpectHeaders("");
SetResponse(200, "Content-Length: 100\n");
SetResponseBody("abcdefghijklmnopqrstuvwxyz");
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
+ EXPECT_EQ(sizeof(buf) - 1, result_bytes);
EXPECT_STREQ("abcdefghi", &buf[0]);
ResetMocks();
- EXPECT_EQ(26, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(26, result_size);
}
TEST_F(MountHttpNodeTest, ReadCachedOverrun) {
+ size_t result_size = 0;
+ int result_bytes = 0;
+
SetMountArgs(StringMap_t());
ExpectOpen("HEAD");
ExpectHeaders("");
@@ -369,7 +399,8 @@ TEST_F(MountHttpNodeTest, ReadCachedOverrun) {
OpenNode();
ResetMocks();
- EXPECT_EQ(15, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(15, result_size);
char buf[10];
memset(&buf[0], 0, sizeof(buf));
@@ -378,14 +409,18 @@ TEST_F(MountHttpNodeTest, ReadCachedOverrun) {
ExpectHeaders("");
SetResponse(200, "Content-Length: 15\n");
SetResponseBody("01234567890123456789");
- node_->Read(10, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
+ EXPECT_EQ(5, result_bytes);
EXPECT_STREQ("01234", &buf[0]);
ResetMocks();
- EXPECT_EQ(15, node_->GetSize());
+ EXPECT_EQ(0, node_->GetSize(&result_size));
+ EXPECT_EQ(15, result_size);
}
TEST_F(MountHttpNodeTest, ReadPartial) {
+ int result_bytes = 0;
+
StringMap_t args;
args["cache_content"] = "false";
SetMountArgs(args);
@@ -402,7 +437,8 @@ TEST_F(MountHttpNodeTest, ReadPartial) {
ExpectHeaders("Range: bytes=0-8\n");
SetResponse(206, "Content-Length: 9\nContent-Range: bytes=0-8\n");
SetResponseBody("012345678");
- node_->Read(0, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(0, buf, sizeof(buf) - 1, &result_bytes));
+ EXPECT_EQ(sizeof(buf) - 1, result_bytes);
EXPECT_STREQ("012345678", &buf[0]);
ResetMocks();
@@ -411,11 +447,14 @@ TEST_F(MountHttpNodeTest, ReadPartial) {
ExpectHeaders("Range: bytes=10-18\n");
SetResponse(206, "Content-Length: 9\nContent-Range: bytes=10-18\n");
SetResponseBody("abcdefghi");
- node_->Read(10, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
+ EXPECT_EQ(sizeof(buf) - 1, result_bytes);
EXPECT_STREQ("abcdefghi", &buf[0]);
}
TEST_F(MountHttpNodeTest, ReadPartialNoServerSupport) {
+ int result_bytes = 0;
+
StringMap_t args;
args["cache_content"] = "false";
SetMountArgs(args);
@@ -432,6 +471,7 @@ TEST_F(MountHttpNodeTest, ReadPartialNoServerSupport) {
ExpectHeaders("Range: bytes=10-18\n");
SetResponse(200, "Content-Length: 20\n");
SetResponseBody("0123456789abcdefghij");
- node_->Read(10, buf, sizeof(buf) - 1);
+ EXPECT_EQ(0, node_->Read(10, buf, sizeof(buf) - 1, &result_bytes));
+ EXPECT_EQ(sizeof(buf) - 1, result_bytes);
EXPECT_STREQ("abcdefghi", &buf[0]);
}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc
index 2de13cd..bc6fa65 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc
@@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
+#include "nacl_io/error.h"
#include "nacl_io/kernel_proxy.h"
#include "nacl_io/mount_node.h"
#include "nacl_io/mount_node_dir.h"
@@ -14,31 +15,25 @@
#include "gtest/gtest.h"
-#define NULL_NODE ((MountNode *) NULL)
+#define NULL_NODE ((MountNode*) NULL)
static int s_AllocNum = 0;
class MockMemory : public MountNodeMem {
public:
- MockMemory() : MountNodeMem(NULL) {
- s_AllocNum++;
- }
+ MockMemory() : MountNodeMem(NULL) { s_AllocNum++; }
- ~MockMemory() {
- s_AllocNum--;
- }
+ ~MockMemory() { s_AllocNum--; }
- bool Init(int mode) {
- return MountNodeMem::Init(mode);
- }
- int AddChild(const std::string& name, MountNode *node) {
+ Error Init(int mode) { return MountNodeMem::Init(mode); }
+ Error AddChild(const std::string& name, MountNode* node) {
return MountNodeMem::AddChild(name, node);
}
- int RemoveChild(const std::string& name) {
+ Error RemoveChild(const std::string& name) {
return MountNodeMem::RemoveChild(name);
}
- MountNode* FindChild(const std::string& name) {
- return MountNodeMem::FindChild(name);
+ Error FindChild(const std::string& name, MountNode** out_node) {
+ return MountNodeMem::FindChild(name, out_node);
}
void Link() { MountNodeMem::Link(); }
void Unlink() { MountNodeMem::Unlink(); }
@@ -49,25 +44,19 @@ class MockMemory : public MountNodeMem {
class MockDir : public MountNodeDir {
public:
- MockDir() : MountNodeDir(NULL) {
- s_AllocNum++;
- }
+ MockDir() : MountNodeDir(NULL) { s_AllocNum++; }
- ~MockDir() {
- s_AllocNum--;
- }
+ ~MockDir() { s_AllocNum--; }
- bool Init(int mode) {
- return MountNodeDir::Init(mode);
- }
- int AddChild(const std::string& name, MountNode *node) {
+ Error Init(int mode) { return MountNodeDir::Init(mode); }
+ Error AddChild(const std::string& name, MountNode* node) {
return MountNodeDir::AddChild(name, node);
}
- int RemoveChild(const std::string& name) {
+ Error RemoveChild(const std::string& name) {
return MountNodeDir::RemoveChild(name);
}
- MountNode* FindChild(const std::string& name) {
- return MountNodeDir::FindChild(name);
+ Error FindChild(const std::string& name, MountNode** out_node) {
+ return MountNodeDir::FindChild(name, out_node);
}
void Link() { MountNodeDir::Link(); }
void Unlink() { MountNodeDir::Unlink(); }
@@ -77,9 +66,12 @@ class MockDir : public MountNodeDir {
};
TEST(MountNodeTest, File) {
- MockMemory *file = new MockMemory;
+ MockMemory* file = new MockMemory;
+ MountNode* result_node = NULL;
+ size_t result_size = 0;
+ int result_bytes = 0;
- EXPECT_TRUE(file->Init(S_IREAD | S_IWRITE));
+ EXPECT_EQ(0, file->Init(S_IREAD | S_IWRITE));
// Test properties
EXPECT_EQ(0, file->GetLinks());
@@ -97,12 +89,18 @@ TEST(MountNodeTest, File) {
buf1[a] = a;
memset(buf2, 0, sizeof(buf2));
- EXPECT_EQ(0, file->GetSize());
- EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2)));
- EXPECT_EQ(0, file->GetSize());
- EXPECT_EQ(sizeof(buf1), file->Write(0, buf1, sizeof(buf1)));
- EXPECT_EQ(sizeof(buf1), file->GetSize());
- EXPECT_EQ(sizeof(buf1), file->Read(0, buf2, sizeof(buf2)));
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(0, result_size);
+ EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2), &result_bytes));
+ EXPECT_EQ(0, result_bytes);
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(0, result_size);
+ EXPECT_EQ(0, file->Write(0, buf1, sizeof(buf1), &result_bytes));
+ EXPECT_EQ(sizeof(buf1), result_bytes);
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(sizeof(buf1), result_size);
+ EXPECT_EQ(0, file->Read(0, buf2, sizeof(buf2), &result_bytes));
+ EXPECT_EQ(sizeof(buf1), result_bytes);
EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(buf1)));
struct stat s;
@@ -112,20 +110,21 @@ TEST(MountNodeTest, File) {
// Directory operations should fail
struct dirent d;
- EXPECT_EQ(-1, file->GetDents(0, &d, sizeof(d)));
- EXPECT_EQ(errno, ENOTDIR);
- EXPECT_EQ(-1, file->AddChild("", file));
- EXPECT_EQ(errno, ENOTDIR);
- EXPECT_EQ(-1, file->RemoveChild(""));
- EXPECT_EQ(errno, ENOTDIR);
- EXPECT_EQ(NULL_NODE, file->FindChild(""));
- EXPECT_EQ(errno, ENOTDIR);
+ EXPECT_EQ(ENOTDIR, file->GetDents(0, &d, sizeof(d), &result_bytes));
+ EXPECT_EQ(ENOTDIR, file->AddChild("", file));
+ EXPECT_EQ(ENOTDIR, file->RemoveChild(""));
+ EXPECT_EQ(ENOTDIR, file->FindChild("", &result_node));
+ EXPECT_EQ(NULL_NODE, result_node);
delete file;
}
TEST(MountNodeTest, Directory) {
- MockDir *root = new MockDir();
+ MockDir* root = new MockDir();
+ MountNode* result_node = NULL;
+ size_t result_size = 0;
+ int result_bytes = 0;
+
root->Init(S_IREAD | S_IWRITE);
// Test properties
@@ -139,15 +138,14 @@ TEST(MountNodeTest, Directory) {
// IO operations should fail
char buf1[1024];
- EXPECT_EQ(0, root->GetSize());
- EXPECT_EQ(-1, root->Read(0, buf1, sizeof(buf1)));
- EXPECT_EQ(errno, EISDIR);
- EXPECT_EQ(-1, root->Write(0, buf1, sizeof(buf1)));
- EXPECT_EQ(errno, EISDIR);
+ EXPECT_EQ(0, root->GetSize(&result_size));
+ EXPECT_EQ(0, result_size);
+ EXPECT_EQ(EISDIR, root->Read(0, buf1, sizeof(buf1), &result_bytes));
+ EXPECT_EQ(EISDIR, root->Write(0, buf1, sizeof(buf1), &result_bytes));
// Test directory operations
MockMemory* file = new MockMemory;
- EXPECT_TRUE(file->Init(S_IREAD | S_IWRITE));
+ EXPECT_EQ(0, file->Init(S_IREAD | S_IWRITE));
EXPECT_EQ(1, root->RefCount());
EXPECT_EQ(1, file->RefCount());
@@ -157,25 +155,28 @@ TEST(MountNodeTest, Directory) {
// Test that the directory is there
struct dirent d;
- EXPECT_EQ(sizeof(d), root->GetDents(0, &d, sizeof(d)));
+ EXPECT_EQ(0, root->GetDents(0, &d, sizeof(d), &result_bytes));
+ EXPECT_EQ(sizeof(d), result_bytes);
EXPECT_LT(0, d.d_ino); // 0 is an invalid inode number.
EXPECT_EQ(sizeof(d), d.d_off);
EXPECT_EQ(sizeof(d), d.d_reclen);
EXPECT_EQ(0, strcmp("F1", d.d_name));
- EXPECT_EQ(0, root->GetDents(sizeof(d), &d, sizeof(d)));
+ EXPECT_EQ(0, root->GetDents(sizeof(d), &d, sizeof(d), &result_bytes));
+ EXPECT_EQ(0, result_bytes);
EXPECT_EQ(0, root->AddChild("F2", file));
EXPECT_EQ(2, file->GetLinks());
EXPECT_EQ(3, file->RefCount());
- EXPECT_EQ(-1, root->AddChild("F1", file));
- EXPECT_EQ(EEXIST, errno);
+ EXPECT_EQ(EEXIST, root->AddChild("F1", file));
EXPECT_EQ(2, file->GetLinks());
EXPECT_EQ(2, s_AllocNum);
- EXPECT_NE(NULL_NODE, root->FindChild("F1"));
- EXPECT_NE(NULL_NODE, root->FindChild("F2"));
- EXPECT_EQ(NULL_NODE, root->FindChild("F3"));
- EXPECT_EQ(errno, ENOENT);
+ EXPECT_EQ(0, root->FindChild("F1", &result_node));
+ EXPECT_NE(NULL_NODE, result_node);
+ EXPECT_EQ(0, root->FindChild("F2", &result_node));
+ EXPECT_NE(NULL_NODE, result_node);
+ EXPECT_EQ(ENOENT, root->FindChild("F3", &result_node));
+ EXPECT_EQ(NULL_NODE, result_node);
EXPECT_EQ(2, s_AllocNum);
EXPECT_EQ(0, root->RemoveChild("F1"));
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc b/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc
index 1604cca..245d13d 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc
@@ -22,12 +22,10 @@ class MountMemMock : public MountMem {
public:
MountMemMock() {
StringMap_t map;
- Init(1, map, NULL);
- };
-
- int num_nodes() {
- return (int) inode_pool_.size();
+ EXPECT_EQ(0, Init(1, map, NULL));
}
+
+ int num_nodes() { return (int) inode_pool_.size(); }
};
class MountDevMock : public MountDev {
@@ -36,20 +34,20 @@ class MountDevMock : public MountDev {
StringMap_t map;
Init(1, map, NULL);
}
- int num_nodes() {
- return (int) inode_pool_.size();
- }
+ int num_nodes() { return (int) inode_pool_.size(); }
};
} // namespace
-
-#define NULL_NODE ((MountNode *) NULL)
+#define NULL_NODE ((MountNode*) NULL)
TEST(MountTest, Sanity) {
MountMemMock* mnt = new MountMemMock();
MountNode* file;
MountNode* root;
+ MountNode* result_node;
+ size_t result_size = 0;
+ int result_bytes = 0;
char buf1[1024];
@@ -57,43 +55,54 @@ TEST(MountTest, Sanity) {
EXPECT_EQ(1, mnt->num_nodes());
// Fail to open non existent file
- EXPECT_EQ(NULL_NODE, mnt->Open(Path("/foo"), O_RDWR));
- EXPECT_EQ(errno, ENOENT);
+ EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &result_node));
+ EXPECT_EQ(NULL, result_node);
// Create a file
- file = mnt->Open(Path("/foo"), O_RDWR | O_CREAT);
+ EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &file));
EXPECT_NE(NULL_NODE, file);
- if (file == NULL) return;
+ if (file == NULL)
+ return;
EXPECT_EQ(2, file->RefCount());
EXPECT_EQ(2, mnt->num_nodes());
+ // Open the root directory for write should fail.
+ EXPECT_EQ(EISDIR, mnt->Open(Path("/"), O_RDWR, &root));
+
// Open the root directory
- root = mnt->Open(Path("/"), O_RDWR);
+ EXPECT_EQ(0, mnt->Open(Path("/"), O_RDONLY, &root));
EXPECT_NE(NULL_NODE, root);
if (NULL != root) {
struct dirent dirs[2];
- int len = root->GetDents(0, dirs, sizeof(dirs));
+ int len;
+ EXPECT_EQ(0, root->GetDents(0, dirs, sizeof(dirs), &len));
EXPECT_EQ(sizeof(struct dirent), len);
}
// Fail to re-create the same file
- EXPECT_EQ(NULL_NODE, mnt->Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL));
- EXPECT_EQ(errno, EEXIST);
+ EXPECT_EQ(EEXIST,
+ mnt->Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node));
+ EXPECT_EQ(NULL_NODE, result_node);
EXPECT_EQ(2, mnt->num_nodes());
// Fail to create a directory with the same name
- EXPECT_EQ(-1, mnt->Mkdir(Path("/foo"), O_RDWR));
- EXPECT_EQ(errno, EEXIST);
+ EXPECT_EQ(EEXIST, mnt->Mkdir(Path("/foo"), O_RDWR));
// Attempt to READ/WRITE
- EXPECT_EQ(0, file->GetSize());
- EXPECT_EQ(sizeof(buf1), file->Write(0, buf1, sizeof(buf1)));
- EXPECT_EQ(sizeof(buf1), file->GetSize());
- EXPECT_EQ(sizeof(buf1), file->Read(0, buf1, sizeof(buf1)));
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(0, result_size);
+ EXPECT_EQ(0, file->Write(0, buf1, sizeof(buf1), &result_bytes));
+ EXPECT_EQ(sizeof(buf1), result_bytes);
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(sizeof(buf1), result_size);
+ EXPECT_EQ(0, file->Read(0, buf1, sizeof(buf1), &result_bytes));
+ EXPECT_EQ(sizeof(buf1), result_bytes);
// Attempt to open the same file
- EXPECT_EQ(file, mnt->Open(Path("/foo"), O_RDWR | O_CREAT));
- EXPECT_EQ(sizeof(buf1), file->GetSize());
+ EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &result_node));
+ EXPECT_EQ(file, result_node);
+ EXPECT_EQ(0, file->GetSize(&result_size));
+ EXPECT_EQ(sizeof(buf1), result_size);
EXPECT_EQ(3, file->RefCount());
EXPECT_EQ(2, mnt->num_nodes());
@@ -102,9 +111,8 @@ TEST(MountTest, Sanity) {
EXPECT_EQ(2, mnt->num_nodes());
EXPECT_EQ(0, mnt->Unlink(Path("/foo")));
EXPECT_EQ(2, mnt->num_nodes());
- EXPECT_EQ(-1, mnt->Unlink(Path("/foo")));
+ EXPECT_EQ(ENOENT, mnt->Unlink(Path("/foo")));
EXPECT_EQ(2, mnt->num_nodes());
- EXPECT_EQ(errno, ENOENT);
mnt->ReleaseNode(file);
EXPECT_EQ(1, mnt->num_nodes());
@@ -112,13 +120,13 @@ TEST(MountTest, Sanity) {
EXPECT_EQ(0, mnt->Mkdir(Path("/foo"), O_RDWR));
// Create a file (exclusively)
- file = mnt->Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL);
+ EXPECT_EQ(0, mnt->Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file));
EXPECT_NE(NULL_NODE, file);
- if (NULL == file) return;
+ if (NULL == file)
+ return;
// Attempt to delete the directory
- EXPECT_EQ(-1, mnt->Rmdir(Path("/foo")));
- EXPECT_EQ(errno, ENOTEMPTY);
+ EXPECT_EQ(ENOTEMPTY, mnt->Rmdir(Path("/foo")));
// Unlink the file, then delete the directory
EXPECT_EQ(0, mnt->Unlink(Path("/foo/bar")));
@@ -128,60 +136,71 @@ TEST(MountTest, Sanity) {
EXPECT_EQ(1, mnt->num_nodes());
// Verify the directory is gone
- file = mnt->Open(Path("/foo"), O_RDWR);
+ EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &file));
EXPECT_EQ(NULL_NODE, file);
- EXPECT_EQ(errno, ENOENT);
}
TEST(MountTest, MemMountRemove) {
MountMemMock* mnt = new MountMemMock();
MountNode* file;
+ MountNode* result_node;
EXPECT_EQ(0, mnt->Mkdir(Path("/dir"), O_RDWR));
- file = mnt->Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL);
+ EXPECT_EQ(0, mnt->Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
EXPECT_NE(NULL_NODE, file);
mnt->ReleaseNode(file);
EXPECT_EQ(0, mnt->Remove(Path("/dir")));
EXPECT_EQ(0, mnt->Remove(Path("/file")));
- EXPECT_EQ(NULL_NODE, mnt->Open(Path("/dir/foo"), O_CREAT | O_RDWR));
- EXPECT_EQ(ENOENT, errno);
- EXPECT_EQ(NULL_NODE, mnt->Open(Path("/file"), O_RDONLY));
- EXPECT_EQ(ENOENT, errno);
+ EXPECT_EQ(ENOENT,
+ mnt->Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
+ EXPECT_EQ(NULL_NODE, result_node);
+ EXPECT_EQ(ENOENT, mnt->Open(Path("/file"), O_RDONLY, &result_node));
+ EXPECT_EQ(NULL_NODE, result_node);
}
TEST(MountTest, DevNull) {
MountDevMock* mnt = new MountDevMock();
- MountNode* dev_null = mnt->Open(Path("/null"), O_RDWR);
+ MountNode* dev_null = NULL;
+ int result_bytes = 0;
+
+ ASSERT_EQ(0, mnt->Open(Path("/null"), O_RDWR, &dev_null));
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)));
+ EXPECT_EQ(0, dev_null->Write(0, &msg[0], strlen(msg), &result_bytes));
+ EXPECT_EQ(strlen(msg), result_bytes);
// 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, dev_null->Read(0, &buffer[0], kBufferLength, &result_bytes));
+ EXPECT_EQ(0, result_bytes);
mnt->ReleaseNode(dev_null);
}
TEST(MountTest, DevZero) {
MountDevMock* mnt = new MountDevMock();
- MountNode* dev_zero = mnt->Open(Path("/zero"), O_RDWR);
+ MountNode* dev_zero = NULL;
+ int result_bytes = 0;
+
+ ASSERT_EQ(0, mnt->Open(Path("/zero"), O_RDWR, &dev_zero));
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)));
+ EXPECT_EQ(0, dev_zero->Write(0, &msg[0], strlen(msg), &result_bytes));
+ EXPECT_EQ(strlen(msg), result_bytes);
// 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));
+ EXPECT_EQ(0, dev_zero->Read(0, &buffer[0], kBufferLength, &result_bytes));
+ EXPECT_EQ(kBufferLength, result_bytes);
char zero_buffer[kBufferLength];
memset(&zero_buffer[0], 0, kBufferLength);
@@ -191,12 +210,16 @@ TEST(MountTest, DevZero) {
TEST(MountTest, DevUrandom) {
MountDevMock* mnt = new MountDevMock();
- MountNode* dev_urandom = mnt->Open(Path("/urandom"), O_RDWR);
+ MountNode* dev_urandom = NULL;
+ int result_bytes = 0;
+
+ ASSERT_EQ(0, mnt->Open(Path("/urandom"), O_RDWR, &dev_urandom));
ASSERT_NE(NULL_NODE, dev_urandom);
- // Writing to /dev/zero should write everything.
+ // Writing to /dev/urandom should write everything.
const char msg[] = "Dummy test message.";
- EXPECT_EQ(strlen(msg), dev_urandom->Write(0, &msg[0], strlen(msg)));
+ EXPECT_EQ(0, dev_urandom->Write(0, &msg[0], strlen(msg), &result_bytes));
+ EXPECT_EQ(strlen(msg), result_bytes);
// Reading from /dev/urandom should read random bytes.
const int kSampleBatches = 1000;
@@ -207,7 +230,9 @@ TEST(MountTest, DevUrandom) {
unsigned char buffer[kSampleBatchSize];
for (int batch = 0; batch < kSampleBatches; ++batch) {
- int bytes_read = dev_urandom->Read(0, &buffer[0], kSampleBatchSize);
+ int bytes_read = 0;
+ EXPECT_EQ(0,
+ dev_urandom->Read(0, &buffer[0], kSampleBatchSize, &bytes_read));
EXPECT_EQ(kSampleBatchSize, bytes_read);
for (int i = 0; i < bytes_read; ++i) {