summaryrefslogtreecommitdiff
path: root/native_client_sdk
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-08-23 16:39:15 +0100
committerTorne (Richard Coles) <torne@google.com>2013-08-23 16:39:15 +0100
commit3551c9c881056c480085172ff9840cab31610854 (patch)
tree23660320f5f4c279966609cf9da7491b96d10ca8 /native_client_sdk
parent4e9d9adbbb6cf287125ca44a0823791a570472f5 (diff)
downloadchromium_org-3551c9c881056c480085172ff9840cab31610854.tar.gz
Merge from Chromium at DEPS revision r219274
This commit was generated by merge_to_master.py. Change-Id: Ibb7f41396cadf4071e89153e1913c986d126f65d
Diffstat (limited to 'native_client_sdk')
-rw-r--r--native_client_sdk/src/build_tools/json/naclsdk_manifest2.json30
-rw-r--r--native_client_sdk/src/build_tools/sdk_files.list1035
-rw-r--r--native_client_sdk/src/build_tools/test.js6
-rwxr-xr-xnative_client_sdk/src/build_tools/test_projects.py42
-rwxr-xr-xnative_client_sdk/src/build_tools/test_sdk.py1
-rwxr-xr-xnative_client_sdk/src/build_tools/tests/verify_filelist_test.py13
-rwxr-xr-xnative_client_sdk/src/build_tools/verify_filelist.py8
-rw-r--r--native_client_sdk/src/examples/common.js92
-rw-r--r--native_client_sdk/src/examples/demo/earth/earth.cc11
-rw-r--r--native_client_sdk/src/examples/demo/flock/flock.cc2
-rw-r--r--native_client_sdk/src/examples/demo/life/life.c39
-rw-r--r--native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc2
-rw-r--r--native_client_sdk/src/examples/demo/voronoi/voronoi.cc13
-rw-r--r--native_client_sdk/src/examples/tutorial/load_progress/example.js7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/dbgprint.c36
-rw-r--r--native_client_sdk/src/libraries/nacl_io/dbgprint.h16
-rw-r--r--native_client_sdk/src/libraries/nacl_io/event_listener.cc8
-rw-r--r--native_client_sdk/src/libraries/nacl_io/include/sys/ioctl.h26
-rw-r--r--native_client_sdk/src/libraries/nacl_io/include/sys/termios.h14
-rw-r--r--native_client_sdk/src/libraries/nacl_io/ioctl.h31
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_handle.cc7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_handle.h7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc29
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_intercept.h4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc252
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_proxy.h11
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap.h6
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc39
-rw-r--r--native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc51
-rw-r--r--native_client_sdk/src/libraries/nacl_io/library.dsc34
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.cc2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node.h5
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_char.h4
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.cc53
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_html5fs.h8
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc263
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_socket.h105
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc146
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h52
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc140
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_tty.h26
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_udp.cc188
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_node_udp.h64
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_socket.cc28
-rw-r--r--native_client_sdk/src/libraries/nacl_io/mount_socket.h37
-rw-r--r--native_client_sdk/src/libraries/nacl_io/nacl_io.h2
-rw-r--r--native_client_sdk/src/libraries/nacl_io/ossignal.h17
-rw-r--r--native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h52
-rw-r--r--native_client_sdk/src/libraries/nacl_io/pepper/define_empty_macros.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/pepper/undef_macros.h1
-rw-r--r--native_client_sdk/src/libraries/nacl_io/pepper_interface.cc19
-rw-r--r--native_client_sdk/src/libraries/nacl_io/pepper_interface.h48
-rw-r--r--native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.cc46
-rw-r--r--native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.h82
-rw-r--r--native_client_sdk/src/libraries/nacl_io/pepper_interface_dummy.h43
-rw-r--r--native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc51
-rw-r--r--native_client_sdk/src/libraries/nacl_io/real_pepper_interface.h7
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/cfgetispeed.c10
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/cfgetospeed.c10
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/cfsetispeed.c11
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/cfsetospeed.c11
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/cfsetspeed.c12
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/ioctl.c10
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/kill.c10
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/signal.c10
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/sigset.c10
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/tcdrain.c (renamed from native_client_sdk/src/libraries/nacl_io/syscalls/getdents.c)9
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/tcflow.c13
-rw-r--r--native_client_sdk/src/libraries/nacl_io/syscalls/tcsendbreak.c13
-rw-r--r--native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc629
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc10
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h9
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc144
-rw-r--r--native_client_sdk/src/libraries/ppapi_simple/ps_instance.h64
-rw-r--r--native_client_sdk/src/libraries/sdk_util/auto_lock.h2
-rw-r--r--native_client_sdk/src/libraries/third_party/newlib-extras/sys/signal.h311
-rw-r--r--native_client_sdk/src/tests/nacl_io_socket_test/event_test.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/event_test.cc)4
-rw-r--r--native_client_sdk/src/tests/nacl_io_socket_test/example.dsc37
-rw-r--r--native_client_sdk/src/tests/nacl_io_socket_test/example.js126
-rw-r--r--native_client_sdk/src/tests/nacl_io_socket_test/index.html (renamed from native_client_sdk/src/libraries/nacl_io_test/index.html)0
-rw-r--r--native_client_sdk/src/tests/nacl_io_socket_test/main.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/main.cc)0
-rw-r--r--native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc191
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/event_test.cc481
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/example.dsc (renamed from native_client_sdk/src/libraries/nacl_io_test/example.dsc)13
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/example.js92
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/fake_core_interface.cc15
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/fake_core_interface.h28
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.cc707
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.h200
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.cc116
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.h99
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/fake_var_interface.cc93
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/fake_var_interface.h41
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/index.html28
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc)37
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/kernel_proxy_mock.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.cc)0
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/kernel_proxy_mock.h (renamed from native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h)10
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc)56
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc)28
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/main.cc70
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mock_util.h (renamed from native_client_sdk/src/libraries/nacl_io_test/mock_util.h)3
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_dev_mock.h24
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_html5fs_test.cc448
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_http_test.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc)31
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_mock.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/mount_mock.cc)0
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_mock.h (renamed from native_client_sdk/src/libraries/nacl_io_test/mount_mock.h)0
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_node_mock.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.cc)0
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_node_mock.h (renamed from native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.h)0
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc)127
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc249
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/mount_test.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/mount_test.cc)205
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/path_test.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/path_test.cc)5
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/pepper_interface_mock.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.cc)0
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/pepper_interface_mock.h (renamed from native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.h)5
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/signal_test.cc28
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/socket_test.cc (renamed from native_client_sdk/src/libraries/nacl_io_test/socket_test.cc)26
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/syscalls_test.cc119
-rw-r--r--native_client_sdk/src/tests/nacl_io_test/test.js18
-rw-r--r--native_client_sdk/src/tests/sdk_util_test/example.dsc29
-rw-r--r--native_client_sdk/src/tests/sdk_util_test/example.js (renamed from native_client_sdk/src/libraries/nacl_io_test/example.js)2
-rw-r--r--native_client_sdk/src/tests/sdk_util_test/index.html28
-rw-r--r--native_client_sdk/src/tests/sdk_util_test/main.cc66
-rw-r--r--native_client_sdk/src/tools/common.mk4
124 files changed, 6301 insertions, 2255 deletions
diff --git a/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json b/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
index 9d415c9a02..c002b98cc5 100644
--- a/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
+++ b/native_client_sdk/src/build_tools/json/naclsdk_manifest2.json
@@ -35,16 +35,6 @@
},
{
"archives": [],
- "description": "Chrome 24 bundle, revision xxxxx",
- "name": "pepper_24",
- "recommended": "no",
- "repath": "pepper_24",
- "revision": 0,
- "stability": "post_stable",
- "version": 24
- },
- {
- "archives": [],
"description": "Chrome 25 bundle, revision xxxxx",
"name": "pepper_25",
"recommended": "no",
@@ -67,20 +57,20 @@
"archives": [],
"description": "Chrome 27 bundle, revision xxxxx",
"name": "pepper_27",
- "recommended": "yes",
+ "recommended": "no",
"repath": "pepper_27",
"revision": 0,
- "stability": "stable",
+ "stability": "post_stable",
"version": 27
},
{
"archives": [],
"description": "Chrome 28 bundle, revision xxxxx",
"name": "pepper_28",
- "recommended": "no",
+ "recommended": "yes",
"repath": "pepper_28",
"revision": 0,
- "stability": "beta",
+ "stability": "stable",
"version": 28
},
{
@@ -90,11 +80,21 @@
"recommended": "no",
"repath": "pepper_29",
"revision": 0,
- "stability": "dev",
+ "stability": "beta",
"version": 29
},
{
"archives": [],
+ "description": "Chrome 30 bundle, revision xxxxx",
+ "name": "pepper_30",
+ "recommended": "no",
+ "repath": "pepper_30",
+ "revision": 0,
+ "stability": "dev",
+ "version": 30
+ },
+ {
+ "archives": [],
"description": "Chrome Canary",
"name": "pepper_canary",
"recommended": "no",
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list
index a210f4ab48..96fb7f49ff 100644
--- a/native_client_sdk/src/build_tools/sdk_files.list
+++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -1,622 +1,85 @@
AUTHORS
COPYING
-examples/api/audio/audio.cc
-examples/api/audio/background.js
-examples/api/audio/common.js
-examples/api/audio/example.js
-examples/api/audio/icon128.png
-examples/api/audio/index.html
-[win]examples/api/audio/make.bat
-examples/api/audio/Makefile
-examples/api/audio/manifest.json
-examples/api/core/background.js
-examples/api/core/common.js
-examples/api/core/core.cc
-examples/api/core/example.js
-examples/api/core/icon128.png
-examples/api/core/index.html
-[win]examples/api/core/make.bat
-examples/api/core/Makefile
-examples/api/core/manifest.json
-examples/api/file_io/background.js
-examples/api/file_io/common.js
-examples/api/file_io/example.js
-examples/api/file_io/file_io.cc
-examples/api/file_io/icon128.png
-examples/api/file_io/index.html
-[win]examples/api/file_io/make.bat
-examples/api/file_io/Makefile
-examples/api/file_io/manifest.json
-examples/api/gamepad/background.js
-examples/api/gamepad/common.js
-examples/api/gamepad/gamepad.cc
-examples/api/gamepad/icon128.png
-examples/api/gamepad/index.html
-[win]examples/api/gamepad/make.bat
-examples/api/gamepad/Makefile
-examples/api/gamepad/manifest.json
-examples/api/graphics_3d/background.js
-examples/api/graphics_3d/common.js
-examples/api/graphics_3d/fragment_shader_es2.frag
-examples/api/graphics_3d/graphics_3d.cc
-examples/api/graphics_3d/hello.raw
-examples/api/graphics_3d/icon128.png
-examples/api/graphics_3d/index.html
-[win]examples/api/graphics_3d/make.bat
-examples/api/graphics_3d/Makefile
-examples/api/graphics_3d/manifest.json
-examples/api/graphics_3d/matrix.cc
-examples/api/graphics_3d/matrix.h
-examples/api/graphics_3d/vertex_shader_es2.vert
-examples/api/input_event/background.js
-examples/api/input_event/common.js
-examples/api/input_event/custom_events.cc
-examples/api/input_event/custom_events.h
-examples/api/input_event/example.js
-examples/api/input_event/icon128.png
-examples/api/input_event/index.html
-examples/api/input_event/input_event.cc
-[win]examples/api/input_event/make.bat
-examples/api/input_event/Makefile
-examples/api/input_event/manifest.json
-examples/api/input_event/shared_queue.h
+examples/api/audio/*
+examples/api/core/*
+examples/api/file_io/*
+examples/api/gamepad/*
+examples/api/graphics_3d/*
+examples/api/input_event/*
[win]examples/api/make.bat
examples/api/Makefile
-examples/api/mouse_lock/background.js
-examples/api/mouse_lock/common.js
-examples/api/mouse_lock/icon128.png
-examples/api/mouse_lock/index.html
-[win]examples/api/mouse_lock/make.bat
-examples/api/mouse_lock/Makefile
-examples/api/mouse_lock/manifest.json
-examples/api/mouse_lock/mouse_lock.cc
-examples/api/mouse_lock/mouse_lock.h
-examples/api/socket/background.js
-examples/api/socket/common.js
-examples/api/socket/example.js
-examples/api/socket/icon128.png
-examples/api/socket/index.html
-[win]examples/api/socket/make.bat
-examples/api/socket/Makefile
-examples/api/socket/manifest.json
-examples/api/socket/socket.cc
-examples/api/url_loader/background.js
-examples/api/url_loader/common.js
-examples/api/url_loader/example.js
-examples/api/url_loader/icon128.png
-examples/api/url_loader/index.html
-[win]examples/api/url_loader/make.bat
-examples/api/url_loader/Makefile
-examples/api/url_loader/manifest.json
-examples/api/url_loader/url_loader.cc
-examples/api/url_loader/url_loader_handler.cc
-examples/api/url_loader/url_loader_handler.h
-examples/api/url_loader/url_loader_success.html
-examples/api/var_array_buffer/background.js
-examples/api/var_array_buffer/common.js
-examples/api/var_array_buffer/example.js
-examples/api/var_array_buffer/icon128.png
-examples/api/var_array_buffer/index.html
-[win]examples/api/var_array_buffer/make.bat
-examples/api/var_array_buffer/Makefile
-examples/api/var_array_buffer/manifest.json
-examples/api/var_array_buffer/var_array_buffer.cc
-examples/api/websocket/background.js
-examples/api/websocket/common.js
-examples/api/websocket/example.js
-examples/api/websocket/icon128.png
-examples/api/websocket/index.html
-[win]examples/api/websocket/make.bat
-examples/api/websocket/Makefile
-examples/api/websocket/manifest.json
-examples/api/websocket/websocket.cc
+examples/api/mouse_lock/*
+examples/api/socket/*
+examples/api/url_loader/*
+examples/api/var_array_buffer/*
+examples/api/websocket/*
examples/button_close.png
examples/button_close_hover.png
-examples/demo/drive/background.js
-examples/demo/drive/common.js
-examples/demo/drive/drive.cc
-examples/demo/drive/example.js
-examples/demo/drive/icon128.png
-examples/demo/drive/index.html
-[win]examples/demo/drive/make.bat
-examples/demo/drive/Makefile
-examples/demo/drive/manifest.json
-examples/demo/earth/background.js
-examples/demo/earth/common.js
-examples/demo/earth/earth.cc
-examples/demo/earth/earth.jpg
-examples/demo/earth/earthnight.jpg
-examples/demo/earth/example.js
-examples/demo/earth/icon128.png
-examples/demo/earth/index.html
-[win]examples/demo/earth/make.bat
-examples/demo/earth/Makefile
-examples/demo/earth/manifest.json
-examples/demo/flock/background.js
-examples/demo/flock/common.js
-examples/demo/flock/flock.cc
-examples/demo/flock/goose.cc
-examples/demo/flock/goose.h
-examples/demo/flock/icon128.png
-examples/demo/flock/images/flock_green.raw
-examples/demo/flock/index.html
-[win]examples/demo/flock/make.bat
-examples/demo/flock/Makefile
-examples/demo/flock/manifest.json
-examples/demo/flock/sprite.cc
-examples/demo/flock/sprite.h
-examples/demo/flock/vector2.h
-examples/demo/life/background.js
-examples/demo/life/common.js
-examples/demo/life/icon128.png
-examples/demo/life/index.html
-examples/demo/life/life.c
-[win]examples/demo/life/make.bat
-examples/demo/life/Makefile
-examples/demo/life/manifest.json
+examples/demo/drive/*
+examples/demo/earth/*
+examples/demo/flock/*
+examples/demo/life/*
[win]examples/demo/make.bat
examples/demo/Makefile
-examples/demo/nacl_io/background.js
-examples/demo/nacl_io/common.js
-examples/demo/nacl_io/example.js
-examples/demo/nacl_io/handlers.c
-examples/demo/nacl_io/handlers.h
-examples/demo/nacl_io/icon128.png
-examples/demo/nacl_io/index.html
-[win]examples/demo/nacl_io/make.bat
-examples/demo/nacl_io/Makefile
-examples/demo/nacl_io/manifest.json
-examples/demo/nacl_io/nacl_io_demo.c
-examples/demo/nacl_io/nacl_io_demo.h
-examples/demo/nacl_io/queue.c
-examples/demo/nacl_io/queue.h
-examples/demo/pi_generator/background.js
-examples/demo/pi_generator/common.js
-examples/demo/pi_generator/example.js
-examples/demo/pi_generator/icon128.png
-examples/demo/pi_generator/index.html
-[win]examples/demo/pi_generator/make.bat
-examples/demo/pi_generator/Makefile
-examples/demo/pi_generator/manifest.json
-examples/demo/pi_generator/pi_generator.cc
-examples/demo/voronoi/background.js
-examples/demo/voronoi/common.js
-examples/demo/voronoi/example.js
-examples/demo/voronoi/icon128.png
-examples/demo/voronoi/index.html
-[win]examples/demo/voronoi/make.bat
-examples/demo/voronoi/Makefile
-examples/demo/voronoi/manifest.json
-examples/demo/voronoi/voronoi.cc
+examples/demo/nacl_io/*
+examples/demo/pi_generator/*
+examples/demo/voronoi/*
examples/favicon.ico
-examples/getting_started/hello_world/background.js
-examples/getting_started/hello_world/common.js
-examples/getting_started/hello_world/example.js
-examples/getting_started/hello_world/hello_world.c
-examples/getting_started/hello_world/icon128.png
-examples/getting_started/hello_world/index.html
-[win]examples/getting_started/hello_world/make.bat
-examples/getting_started/hello_world/Makefile
-examples/getting_started/hello_world/manifest.json
+examples/getting_started/hello_world/*
[win]examples/getting_started/make.bat
examples/getting_started/Makefile
-examples/getting_started/simple_hello_world/background.js
-examples/getting_started/simple_hello_world/common.js
-examples/getting_started/simple_hello_world/example.js
-examples/getting_started/simple_hello_world/hello_world.c
-examples/getting_started/simple_hello_world/icon128.png
-examples/getting_started/simple_hello_world/index.html
-[win]examples/getting_started/simple_hello_world/make.bat
-examples/getting_started/simple_hello_world/Makefile
-examples/getting_started/simple_hello_world/manifest.json
+examples/getting_started/simple_hello_world/*
examples/httpd.cmd
examples/index.css
examples/index.html
examples/index.js
[win]examples/make.bat
examples/Makefile
-examples/tutorial/debugging/background.js
-examples/tutorial/debugging/common.js
-examples/tutorial/debugging/debugging.c
-examples/tutorial/debugging/example.js
-examples/tutorial/debugging/icon128.png
-examples/tutorial/debugging/index.html
-[win]examples/tutorial/debugging/make.bat
-examples/tutorial/debugging/Makefile
-examples/tutorial/debugging/manifest.json
-examples/tutorial/dlopen/background.js
-examples/tutorial/dlopen/common.js
-examples/tutorial/dlopen/dlopen.cc
-examples/tutorial/dlopen/eightball.cc
-examples/tutorial/dlopen/eightball.h
-examples/tutorial/dlopen/example.js
-examples/tutorial/dlopen/icon128.png
-examples/tutorial/dlopen/index.html
-[win]examples/tutorial/dlopen/make.bat
-examples/tutorial/dlopen/Makefile
-examples/tutorial/dlopen/manifest.json
-examples/tutorial/dlopen/reverse.cc
-examples/tutorial/dlopen/reverse.h
-examples/tutorial/load_progress/background.js
-examples/tutorial/load_progress/common.js
-examples/tutorial/load_progress/example.js
-examples/tutorial/load_progress/icon128.png
-examples/tutorial/load_progress/index.html
-examples/tutorial/load_progress/load_progress.cc
-[win]examples/tutorial/load_progress/make.bat
-examples/tutorial/load_progress/Makefile
-examples/tutorial/load_progress/manifest.json
+examples/tutorial/debugging/*
+examples/tutorial/dlopen/*
+examples/tutorial/load_progress/*
[win]examples/tutorial/make.bat
examples/tutorial/Makefile
-examples/tutorial/testing/background.js
-examples/tutorial/testing/common.js
-examples/tutorial/testing/example.js
-examples/tutorial/testing/icon128.png
-examples/tutorial/testing/index.html
-[win]examples/tutorial/testing/make.bat
-examples/tutorial/testing/Makefile
-examples/tutorial/testing/manifest.json
-examples/tutorial/testing/testing.cc
-include/error_handling/error_handling.h
-include/error_handling/string_stream.h
-include/GLES2/gl2.h
-include/GLES2/gl2ext.h
-include/GLES2/gl2platform.h
-include/gmock/gmock-actions.h
-include/gmock/gmock-cardinalities.h
-include/gmock/gmock-generated-actions.h
-include/gmock/gmock-generated-actions.h.pump
-include/gmock/gmock-generated-function-mockers.h
-include/gmock/gmock-generated-function-mockers.h.pump
-include/gmock/gmock-generated-matchers.h
-include/gmock/gmock-generated-matchers.h.pump
-include/gmock/gmock-generated-nice-strict.h
-include/gmock/gmock-generated-nice-strict.h.pump
-include/gmock/gmock-matchers.h
-include/gmock/gmock-more-actions.h
-include/gmock/gmock-spec-builders.h
-include/gmock/gmock.h
-include/gmock/internal/gmock-generated-internal-utils.h
-include/gmock/internal/gmock-generated-internal-utils.h.pump
-include/gmock/internal/gmock-internal-utils.h
-include/gmock/internal/gmock-port.h
-include/gtest/gtest-death-test.h
-include/gtest/gtest-message.h
-include/gtest/gtest-param-test.h
-include/gtest/gtest-printers.h
-include/gtest/gtest-spi.h
-include/gtest/gtest-test-part.h
-include/gtest/gtest-typed-test.h
-include/gtest/gtest.h
-include/gtest/gtest_pred_impl.h
-include/gtest/gtest_prod.h
-include/gtest/internal/gtest-death-test-internal.h
-include/gtest/internal/gtest-filepath.h
-include/gtest/internal/gtest-internal.h
-include/gtest/internal/gtest-linked_ptr.h
-include/gtest/internal/gtest-param-util-generated.h
-include/gtest/internal/gtest-param-util.h
-include/gtest/internal/gtest-port.h
-include/gtest/internal/gtest-string.h
-include/gtest/internal/gtest-tuple.h
-include/gtest/internal/gtest-type-util.h
-include/gtest/internal/src/gtest-internal-inl.h
-include/json/assertions.h
-include/json/autolink.h
-include/json/config.h
-include/json/features.h
-include/json/forwards.h
-include/json/json.h
-include/json/reader.h
-include/json/value.h
-include/json/writer.h
-include/KHR/khrplatform.h
-include/nacl_io/error.h
-include/nacl_io/event_emitter.h
-include/nacl_io/event_listener.h
-include/nacl_io/host_resolver.h
-include/nacl_io/inode_pool.h
-include/nacl_io/ioctl.h
-include/nacl_io/kernel_handle.h
-include/nacl_io/kernel_intercept.h
-include/nacl_io/kernel_object.h
-include/nacl_io/kernel_proxy.h
-include/nacl_io/kernel_wrap.h
-include/nacl_io/kernel_wrap_real.h
-include/nacl_io/mount.h
-include/nacl_io/mount_dev.h
-include/nacl_io/mount_factory.h
-include/nacl_io/mount_html5fs.h
-include/nacl_io/mount_http.h
-include/nacl_io/mount_mem.h
-include/nacl_io/mount_node.h
-include/nacl_io/mount_node_char.h
-include/nacl_io/mount_node_dir.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_node_tty.h
-include/nacl_io/mount_passthrough.h
-include/nacl_io/nacl_io.h
-include/nacl_io/osdirent.h
-include/nacl_io/osinttypes.h
-include/nacl_io/osmman.h
-include/nacl_io/ossocket.h
-include/nacl_io/osstat.h
-include/nacl_io/ostermios.h
-include/nacl_io/ostime.h
-include/nacl_io/ostypes.h
-include/nacl_io/osunistd.h
-include/nacl_io/osutime.h
-include/nacl_io/path.h
-include/nacl_io/pepper/all_interfaces.h
-include/nacl_io/pepper/define_empty_macros.h
-include/nacl_io/pepper/undef_macros.h
-include/nacl_io/pepper_interface.h
-include/nacl_io/real_pepper_interface.h
-include/nacl_io/typed_mount_factory.h
-include/newlib/arpa/inet.h
-include/newlib/netdb.h
-include/newlib/netinet/in.h
-include/newlib/netinet/tcp.h
-include/newlib/netinet6/in6.h
-include/newlib/poll.h
-include/newlib/sys/mount.h
-include/newlib/sys/select.h
-include/newlib/sys/socket.h
-include/newlib/sys/termios.h
-include/newlib/sys/utsname.h
-include/pnacl/arpa/inet.h
-include/pnacl/netdb.h
-include/pnacl/netinet/in.h
-include/pnacl/netinet/tcp.h
-include/pnacl/netinet6/in6.h
-include/pnacl/poll.h
-include/pnacl/sys/mount.h
-include/pnacl/sys/select.h
-include/pnacl/sys/socket.h
-include/pnacl/sys/termios.h
-include/pnacl/sys/utsname.h
-include/ppapi/c/dev/deprecated_bool.h
-include/ppapi/c/dev/pp_cursor_type_dev.h
-include/ppapi/c/dev/pp_print_settings_dev.h
-include/ppapi/c/dev/pp_video_capture_dev.h
-include/ppapi/c/dev/pp_video_dev.h
-include/ppapi/c/dev/ppb_audio_input_dev.h
-include/ppapi/c/dev/ppb_buffer_dev.h
-include/ppapi/c/dev/ppb_char_set_dev.h
-include/ppapi/c/dev/ppb_crypto_dev.h
-include/ppapi/c/dev/ppb_cursor_control_dev.h
-include/ppapi/c/dev/ppb_device_ref_dev.h
-include/ppapi/c/dev/ppb_file_chooser_dev.h
-include/ppapi/c/dev/ppb_find_dev.h
-include/ppapi/c/dev/ppb_font_dev.h
-include/ppapi/c/dev/ppb_gles_chromium_texture_mapping_dev.h
-include/ppapi/c/dev/ppb_graphics_2d_dev.h
-include/ppapi/c/dev/ppb_ime_input_event_dev.h
-include/ppapi/c/dev/ppb_keyboard_input_event_dev.h
-include/ppapi/c/dev/ppb_memory_dev.h
-include/ppapi/c/dev/ppb_opengles2ext_dev.h
-include/ppapi/c/dev/ppb_printing_dev.h
-include/ppapi/c/dev/ppb_resource_array_dev.h
-include/ppapi/c/dev/ppb_scrollbar_dev.h
-include/ppapi/c/dev/ppb_testing_dev.h
-include/ppapi/c/dev/ppb_text_input_dev.h
-include/ppapi/c/dev/ppb_trace_event_dev.h
-include/ppapi/c/dev/ppb_truetype_font_dev.h
-include/ppapi/c/dev/ppb_url_util_dev.h
-include/ppapi/c/dev/ppb_var_deprecated.h
-include/ppapi/c/dev/ppb_video_capture_dev.h
-include/ppapi/c/dev/ppb_video_decoder_dev.h
-include/ppapi/c/dev/ppb_view_dev.h
-include/ppapi/c/dev/ppb_widget_dev.h
-include/ppapi/c/dev/ppb_zoom_dev.h
-include/ppapi/c/dev/ppp_class_deprecated.h
-include/ppapi/c/dev/ppp_find_dev.h
-include/ppapi/c/dev/ppp_network_state_dev.h
-include/ppapi/c/dev/ppp_printing_dev.h
-include/ppapi/c/dev/ppp_scrollbar_dev.h
-include/ppapi/c/dev/ppp_selection_dev.h
-include/ppapi/c/dev/ppp_text_input_dev.h
-include/ppapi/c/dev/ppp_video_capture_dev.h
-include/ppapi/c/dev/ppp_video_decoder_dev.h
-include/ppapi/c/dev/ppp_widget_dev.h
-include/ppapi/c/dev/ppp_zoom_dev.h
-include/ppapi/c/extensions/dev/ppb_ext_alarms_dev.h
-include/ppapi/c/extensions/dev/ppb_ext_events_dev.h
-include/ppapi/c/extensions/dev/ppb_ext_socket_dev.h
-include/ppapi/c/pp_array_output.h
-include/ppapi/c/pp_bool.h
-include/ppapi/c/pp_completion_callback.h
-include/ppapi/c/pp_directory_entry.h
-include/ppapi/c/pp_errors.h
-include/ppapi/c/pp_file_info.h
-include/ppapi/c/pp_graphics_3d.h
-include/ppapi/c/pp_input_event.h
-include/ppapi/c/pp_instance.h
-include/ppapi/c/pp_macros.h
-include/ppapi/c/pp_module.h
-include/ppapi/c/pp_point.h
-include/ppapi/c/pp_rect.h
-include/ppapi/c/pp_resource.h
-include/ppapi/c/pp_size.h
-include/ppapi/c/pp_stdint.h
-include/ppapi/c/pp_time.h
-include/ppapi/c/pp_touch_point.h
-include/ppapi/c/pp_var.h
-include/ppapi/c/ppb.h
-include/ppapi/c/ppb_audio.h
-include/ppapi/c/ppb_audio_config.h
-include/ppapi/c/ppb_console.h
-include/ppapi/c/ppb_core.h
-include/ppapi/c/ppb_file_io.h
-include/ppapi/c/ppb_file_ref.h
-include/ppapi/c/ppb_file_system.h
-include/ppapi/c/ppb_fullscreen.h
-include/ppapi/c/ppb_gamepad.h
-include/ppapi/c/ppb_graphics_2d.h
-include/ppapi/c/ppb_graphics_3d.h
-include/ppapi/c/ppb_host_resolver.h
-include/ppapi/c/ppb_image_data.h
-include/ppapi/c/ppb_input_event.h
-include/ppapi/c/ppb_instance.h
-include/ppapi/c/ppb_message_loop.h
-include/ppapi/c/ppb_messaging.h
-include/ppapi/c/ppb_mouse_cursor.h
-include/ppapi/c/ppb_mouse_lock.h
-include/ppapi/c/ppb_net_address.h
-include/ppapi/c/ppb_network_proxy.h
-include/ppapi/c/ppb_opengles2.h
-include/ppapi/c/ppb_tcp_socket.h
-include/ppapi/c/ppb_text_input_controller.h
-include/ppapi/c/ppb_udp_socket.h
-include/ppapi/c/ppb_url_loader.h
-include/ppapi/c/ppb_url_request_info.h
-include/ppapi/c/ppb_url_response_info.h
-include/ppapi/c/ppb_var.h
-include/ppapi/c/ppb_var_array.h
-include/ppapi/c/ppb_var_array_buffer.h
-include/ppapi/c/ppb_var_dictionary.h
-include/ppapi/c/ppb_view.h
-include/ppapi/c/ppb_websocket.h
-include/ppapi/c/ppp.h
-include/ppapi/c/ppp_graphics_3d.h
-include/ppapi/c/ppp_input_event.h
-include/ppapi/c/ppp_instance.h
-include/ppapi/c/ppp_messaging.h
-include/ppapi/c/ppp_mouse_lock.h
-include/ppapi/c/private/pp_file_handle.h
-include/ppapi/c/private/ppb_ext_crx_file_system_private.h
-include/ppapi/c/private/ppb_file_io_private.h
-include/ppapi/c/private/ppb_file_ref_private.h
-include/ppapi/c/private/ppb_host_resolver_private.h
-include/ppapi/c/private/ppb_net_address_private.h
-include/ppapi/c/private/ppb_tcp_server_socket_private.h
-include/ppapi/c/private/ppb_tcp_socket_private.h
-include/ppapi/c/private/ppb_udp_socket_private.h
-include/ppapi/c/private/ppb_x509_certificate_private.h
-include/ppapi/cpp/array_output.h
-include/ppapi/cpp/audio.h
-include/ppapi/cpp/audio_config.h
-include/ppapi/cpp/completion_callback.h
-include/ppapi/cpp/core.h
-include/ppapi/cpp/dev/audio_input_dev.h
-include/ppapi/cpp/dev/buffer_dev.h
-include/ppapi/cpp/dev/crypto_dev.h
-include/ppapi/cpp/dev/cursor_control_dev.h
-include/ppapi/cpp/dev/device_ref_dev.h
-include/ppapi/cpp/dev/file_chooser_dev.h
-include/ppapi/cpp/dev/find_dev.h
-include/ppapi/cpp/dev/font_dev.h
-include/ppapi/cpp/dev/graphics_2d_dev.h
-include/ppapi/cpp/dev/ime_input_event_dev.h
-include/ppapi/cpp/dev/memory_dev.h
-include/ppapi/cpp/dev/printing_dev.h
-include/ppapi/cpp/dev/resource_array_dev.h
-include/ppapi/cpp/dev/scriptable_object_deprecated.h
-include/ppapi/cpp/dev/scrollbar_dev.h
-include/ppapi/cpp/dev/selection_dev.h
-include/ppapi/cpp/dev/text_input_dev.h
-include/ppapi/cpp/dev/truetype_font_dev.h
-include/ppapi/cpp/dev/url_util_dev.h
-include/ppapi/cpp/dev/video_capture_client_dev.h
-include/ppapi/cpp/dev/video_capture_dev.h
-include/ppapi/cpp/dev/video_decoder_client_dev.h
-include/ppapi/cpp/dev/video_decoder_dev.h
-include/ppapi/cpp/dev/view_dev.h
-include/ppapi/cpp/dev/widget_client_dev.h
-include/ppapi/cpp/dev/widget_dev.h
-include/ppapi/cpp/dev/zoom_dev.h
-include/ppapi/cpp/directory_entry.h
-include/ppapi/cpp/extensions/dev/alarms_dev.h
-include/ppapi/cpp/extensions/dev/events_dev.h
-include/ppapi/cpp/extensions/dev/socket_dev.h
-include/ppapi/cpp/extensions/dict_field.h
-include/ppapi/cpp/extensions/event_base.h
-include/ppapi/cpp/extensions/ext_output_traits.h
-include/ppapi/cpp/extensions/from_var_converter.h
-include/ppapi/cpp/extensions/optional.h
-include/ppapi/cpp/extensions/to_var_converter.h
-include/ppapi/cpp/file_io.h
-include/ppapi/cpp/file_ref.h
-include/ppapi/cpp/file_system.h
-include/ppapi/cpp/fullscreen.h
-include/ppapi/cpp/graphics_2d.h
-include/ppapi/cpp/graphics_3d.h
-include/ppapi/cpp/graphics_3d_client.h
-include/ppapi/cpp/host_resolver.h
-include/ppapi/cpp/image_data.h
-include/ppapi/cpp/input_event.h
-include/ppapi/cpp/instance.h
-include/ppapi/cpp/instance_handle.h
-include/ppapi/cpp/logging.h
-include/ppapi/cpp/message_loop.h
-include/ppapi/cpp/module.h
-include/ppapi/cpp/module_embedder.h
-include/ppapi/cpp/module_impl.h
-include/ppapi/cpp/mouse_cursor.h
-include/ppapi/cpp/mouse_lock.h
-include/ppapi/cpp/net_address.h
-include/ppapi/cpp/network_proxy.h
-include/ppapi/cpp/output_traits.h
-include/ppapi/cpp/pass_ref.h
-include/ppapi/cpp/point.h
-include/ppapi/cpp/private/ext_crx_file_system_private.h
-include/ppapi/cpp/private/file_io_private.h
-include/ppapi/cpp/private/host_resolver_private.h
-include/ppapi/cpp/private/net_address_private.h
-include/ppapi/cpp/private/pass_file_handle.h
-include/ppapi/cpp/private/tcp_server_socket_private.h
-include/ppapi/cpp/private/tcp_socket_private.h
-include/ppapi/cpp/private/udp_socket_private.h
-include/ppapi/cpp/private/x509_certificate_private.h
-include/ppapi/cpp/rect.h
-include/ppapi/cpp/resource.h
-include/ppapi/cpp/size.h
-include/ppapi/cpp/tcp_socket.h
-include/ppapi/cpp/text_input_controller.h
-include/ppapi/cpp/touch_point.h
-include/ppapi/cpp/udp_socket.h
-include/ppapi/cpp/url_loader.h
-include/ppapi/cpp/url_request_info.h
-include/ppapi/cpp/url_response_info.h
-include/ppapi/cpp/var.h
-include/ppapi/cpp/var_array.h
-include/ppapi/cpp/var_array_buffer.h
-include/ppapi/cpp/var_dictionary.h
-include/ppapi/cpp/view.h
-include/ppapi/cpp/websocket.h
-include/ppapi/gles2/gl2ext_ppapi.h
-include/ppapi/lib/gl/gles2/gl2ext_ppapi.h
-include/ppapi/utility/completion_callback_factory.h
-include/ppapi/utility/completion_callback_factory_thread_traits.h
-include/ppapi/utility/graphics/paint_aggregator.h
-include/ppapi/utility/graphics/paint_manager.h
-include/ppapi/utility/threading/lock.h
-include/ppapi/utility/threading/simple_thread.h
-include/ppapi/utility/websocket/websocket_api.h
-include/ppapi_simple/ps.h
-include/ppapi_simple/ps_context_2d.h
-include/ppapi_simple/ps_event.h
-include/ppapi_simple/ps_instance.h
-include/ppapi_simple/ps_interface.h
-include/ppapi_simple/ps_main.h
-include/sdk_util/atomicops.h
-include/sdk_util/auto_lock.h
-include/sdk_util/macros.h
-include/sdk_util/ref_object.h
-include/sdk_util/scoped_ref.h
-include/sdk_util/simple_lock.h
-include/sdk_util/thread_pool.h
-include/sdk_util/thread_safe_queue.h
-[win]include/win/config.h
-[win]include/win/context.h
-[win]include/win/implement.h
-[win]include/win/need_errno.h
+examples/tutorial/testing/*
+include/error_handling/*
+include/GLES2/*
+include/gmock/*
+include/gmock/internal/*
+include/gtest/*
+include/gtest/internal/*
+include/gtest/internal/src/*
+include/json/*
+include/KHR/*
+include/nacl_io/*
+include/nacl_io/pepper/*
+include/newlib/*
+include/newlib/arpa/*
+include/newlib/netinet/*
+include/newlib/netinet6/*
+include/newlib/sys/*
+include/pnacl/*
+include/pnacl/arpa/*
+include/pnacl/netinet/*
+include/pnacl/netinet6/*
+include/pnacl/sys/*
+include/ppapi/c/*
+include/ppapi/c/dev/*
+include/ppapi/c/extensions/dev/*
+include/ppapi/c/private/*
+include/ppapi/cpp/*
+include/ppapi/cpp/dev/*
+include/ppapi/cpp/extensions/*
+include/ppapi/cpp/private/*
+include/ppapi/gles2/*
+include/ppapi/lib/gl/gles2/*
+include/ppapi/utility/*
+include/ppapi/utility/graphics/*
+include/ppapi/utility/threading/*
+include/ppapi/utility/websocket/*
+include/ppapi_simple/*
+include/sdk_util/*
+[win]include/win/*
include/win/poll.h
-[win]include/win/pthread.h
-[win]include/win/sched.h
-[win]include/win/semaphore.h
[linux]lib/${PLATFORM}_host/Debug/libgmock.a
[linux]lib/${PLATFORM}_host/Debug/libgtest.a
[linux]lib/${PLATFORM}_host/Debug/libjsoncpp.a
@@ -803,373 +266,23 @@ LICENSE
NOTICE
README
README.Makefiles
-src/error_handling/error_handling.c
-[win]src/error_handling/make.bat
-src/error_handling/Makefile
-src/error_handling/string_stream.c
-src/gmock/gmock-cardinalities.cc
-src/gmock/gmock-internal-utils.cc
-src/gmock/gmock-matchers.cc
-src/gmock/gmock-spec-builders.cc
-src/gmock/gmock.cc
-[win]src/gmock/make.bat
-src/gmock/Makefile
-src/gtest/gtest-death-test.cc
-src/gtest/gtest-filepath.cc
-src/gtest/gtest-port.cc
-src/gtest/gtest-printers.cc
-src/gtest/gtest-test-part.cc
-src/gtest/gtest-typed-test.cc
-src/gtest/gtest.cc
-src/gtest/gtest_main.cc
-[win]src/gtest/make.bat
-src/gtest/Makefile
-src/gtest/nacl_gtest_dummy_sys.cc
-src/jsoncpp/json_batchallocator.h
-src/jsoncpp/json_internalarray.inl
-src/jsoncpp/json_internalmap.inl
-src/jsoncpp/json_reader.cpp
-src/jsoncpp/json_tool.h
-src/jsoncpp/json_value.cpp
-src/jsoncpp/json_valueiterator.inl
-src/jsoncpp/json_writer.cpp
-src/jsoncpp/LICENSE
-[win]src/jsoncpp/make.bat
-src/jsoncpp/Makefile
-src/jsoncpp/README.chromium
+src/error_handling/*
+src/gmock/*
+src/gtest/*
+src/jsoncpp/*
[win]src/make.bat
src/Makefile
-src/nacl_io/event_emitter.cc
-src/nacl_io/event_listener.cc
-src/nacl_io/h_errno.cc
-src/nacl_io/host_resolver.cc
-src/nacl_io/kernel_handle.cc
-src/nacl_io/kernel_intercept.cc
-src/nacl_io/kernel_object.cc
-src/nacl_io/kernel_proxy.cc
-src/nacl_io/kernel_wrap_glibc.cc
-src/nacl_io/kernel_wrap_newlib.cc
-src/nacl_io/kernel_wrap_win.cc
-[win]src/nacl_io/make.bat
-src/nacl_io/Makefile
-src/nacl_io/mount.cc
-src/nacl_io/mount_dev.cc
-src/nacl_io/mount_html5fs.cc
-src/nacl_io/mount_http.cc
-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_node_tty.cc
-src/nacl_io/mount_passthrough.cc
-src/nacl_io/nacl_io.cc
-src/nacl_io/path.cc
-src/nacl_io/pepper_interface.cc
-src/nacl_io/real_pepper_interface.cc
-src/nacl_io/syscalls/accept.c
-src/nacl_io/syscalls/access.c
-src/nacl_io/syscalls/bind.c
-src/nacl_io/syscalls/chdir.c
-src/nacl_io/syscalls/chmod.c
-src/nacl_io/syscalls/chown.c
-src/nacl_io/syscalls/connect.c
-src/nacl_io/syscalls/fchown.c
-src/nacl_io/syscalls/fsync.c
-src/nacl_io/syscalls/ftruncate.c
-src/nacl_io/syscalls/getcwd.c
-src/nacl_io/syscalls/getdents.c
-src/nacl_io/syscalls/gethostbyname.c
-src/nacl_io/syscalls/getpeername.c
-src/nacl_io/syscalls/getsockname.c
-src/nacl_io/syscalls/getsockopt.c
-src/nacl_io/syscalls/getwd.c
-src/nacl_io/syscalls/herror.c
-src/nacl_io/syscalls/hstrerror.cc
-src/nacl_io/syscalls/htonl.c
-src/nacl_io/syscalls/htons.c
-src/nacl_io/syscalls/inet_ntoa.cc
-src/nacl_io/syscalls/inet_ntop.cc
-src/nacl_io/syscalls/ioctl.c
-src/nacl_io/syscalls/isatty.c
-src/nacl_io/syscalls/lchown.c
-src/nacl_io/syscalls/link.c
-src/nacl_io/syscalls/listen.c
-src/nacl_io/syscalls/mkdir.c
-src/nacl_io/syscalls/mount.c
-src/nacl_io/syscalls/ntohl.c
-src/nacl_io/syscalls/ntohs.c
-src/nacl_io/syscalls/poll.c
-src/nacl_io/syscalls/recv.c
-src/nacl_io/syscalls/recvfrom.c
-src/nacl_io/syscalls/recvmsg.c
-src/nacl_io/syscalls/remove.c
-src/nacl_io/syscalls/rmdir.c
-src/nacl_io/syscalls/select.c
-src/nacl_io/syscalls/send.c
-src/nacl_io/syscalls/sendmsg.c
-src/nacl_io/syscalls/sendto.c
-src/nacl_io/syscalls/setsockopt.c
-src/nacl_io/syscalls/shutdown.c
-src/nacl_io/syscalls/socket.c
-src/nacl_io/syscalls/socketpair.c
-src/nacl_io/syscalls/tcflush.c
-src/nacl_io/syscalls/tcgetattr.c
-src/nacl_io/syscalls/tcsetattr.c
-src/nacl_io/syscalls/umount.c
-src/nacl_io/syscalls/uname.c
-src/nacl_io/syscalls/unlink.c
-src/nacl_io/syscalls/utime.c
+src/nacl_io/*
+src/ppapi/*
[win]src/ppapi/make.bat
src/ppapi/Makefile
-src/ppapi/ppapi_externs.c
-src/ppapi_cpp/alarms_dev.cc
-src/ppapi_cpp/array_output.cc
-src/ppapi_cpp/audio.cc
-src/ppapi_cpp/audio_config.cc
-src/ppapi_cpp/audio_input_dev.cc
-src/ppapi_cpp/buffer_dev.cc
-src/ppapi_cpp/core.cc
-src/ppapi_cpp/crypto_dev.cc
-src/ppapi_cpp/cursor_control_dev.cc
-src/ppapi_cpp/device_ref_dev.cc
-src/ppapi_cpp/directory_entry.cc
-src/ppapi_cpp/event_base.cc
-src/ppapi_cpp/events_dev.cc
-src/ppapi_cpp/file_chooser_dev.cc
-src/ppapi_cpp/file_io.cc
-src/ppapi_cpp/file_ref.cc
-src/ppapi_cpp/file_system.cc
-src/ppapi_cpp/find_dev.cc
-src/ppapi_cpp/font_dev.cc
-src/ppapi_cpp/fullscreen.cc
-src/ppapi_cpp/graphics_2d.cc
-src/ppapi_cpp/graphics_2d_dev.cc
-src/ppapi_cpp/graphics_3d.cc
-src/ppapi_cpp/graphics_3d_client.cc
-src/ppapi_cpp/host_resolver.cc
-src/ppapi_cpp/image_data.cc
-src/ppapi_cpp/ime_input_event_dev.cc
-src/ppapi_cpp/input_event.cc
-src/ppapi_cpp/instance.cc
-src/ppapi_cpp/instance_handle.cc
-src/ppapi_cpp/lock.cc
-[win]src/ppapi_cpp/make.bat
-src/ppapi_cpp/Makefile
-src/ppapi_cpp/memory_dev.cc
-src/ppapi_cpp/message_loop.cc
-src/ppapi_cpp/module.cc
-src/ppapi_cpp/mouse_cursor.cc
-src/ppapi_cpp/mouse_lock.cc
-src/ppapi_cpp/net_address.cc
-src/ppapi_cpp/network_proxy.cc
-src/ppapi_cpp/paint_aggregator.cc
-src/ppapi_cpp/paint_manager.cc
-src/ppapi_cpp/ppp_entrypoints.cc
-src/ppapi_cpp/printing_dev.cc
-src/ppapi_cpp/rect.cc
-src/ppapi_cpp/resource.cc
-src/ppapi_cpp/resource_array_dev.cc
-src/ppapi_cpp/scriptable_object_deprecated.cc
-src/ppapi_cpp/scrollbar_dev.cc
-src/ppapi_cpp/selection_dev.cc
-src/ppapi_cpp/simple_thread.cc
-src/ppapi_cpp/socket_dev.cc
-src/ppapi_cpp/tcp_socket.cc
-src/ppapi_cpp/text_input_controller.cc
-src/ppapi_cpp/text_input_dev.cc
-src/ppapi_cpp/truetype_font_dev.cc
-src/ppapi_cpp/udp_socket.cc
-src/ppapi_cpp/url_loader.cc
-src/ppapi_cpp/url_request_info.cc
-src/ppapi_cpp/url_response_info.cc
-src/ppapi_cpp/url_util_dev.cc
-src/ppapi_cpp/var.cc
-src/ppapi_cpp/var_array.cc
-src/ppapi_cpp/var_array_buffer.cc
-src/ppapi_cpp/var_dictionary.cc
-src/ppapi_cpp/video_capture_client_dev.cc
-src/ppapi_cpp/video_capture_dev.cc
-src/ppapi_cpp/video_decoder_client_dev.cc
-src/ppapi_cpp/video_decoder_dev.cc
-src/ppapi_cpp/view.cc
-src/ppapi_cpp/view_dev.cc
-src/ppapi_cpp/websocket.cc
-src/ppapi_cpp/websocket_api.cc
-src/ppapi_cpp/widget_client_dev.cc
-src/ppapi_cpp/widget_dev.cc
-src/ppapi_cpp/zoom_dev.cc
-src/ppapi_cpp_private/ext_crx_file_system_private.cc
-src/ppapi_cpp_private/file_io_private.cc
-src/ppapi_cpp_private/host_resolver_private.cc
-[win]src/ppapi_cpp_private/make.bat
-src/ppapi_cpp_private/Makefile
-src/ppapi_cpp_private/net_address_private.cc
-src/ppapi_cpp_private/pass_file_handle.cc
-src/ppapi_cpp_private/tcp_server_socket_private.cc
-src/ppapi_cpp_private/tcp_socket_private.cc
-src/ppapi_cpp_private/udp_socket_private.cc
-src/ppapi_cpp_private/x509_certificate_private.cc
-src/ppapi_gles2/gl2ext_ppapi.c
-src/ppapi_gles2/gles2.c
-[win]src/ppapi_gles2/make.bat
-src/ppapi_gles2/Makefile
-[win]src/ppapi_simple/make.bat
-src/ppapi_simple/Makefile
-src/ppapi_simple/ps.cc
-src/ppapi_simple/ps_context_2d.cc
-src/ppapi_simple/ps_event.cc
-src/ppapi_simple/ps_instance.cc
-src/ppapi_simple/ps_interface.cc
-src/ppapi_simple/ps_main.cc
-[win]src/pthread/autostatic.c
-[win]src/pthread/cleanup.c
-[win]src/pthread/CONTRIBUTORS
-[win]src/pthread/COPYING
-[win]src/pthread/COPYING.LIB
-[win]src/pthread/create.c
-[win]src/pthread/errno.c
-[win]src/pthread/fork.c
-[win]src/pthread/global.c
-[win]src/pthread/MAINTAINERS
-[win]src/pthread/make.bat
-[win]src/pthread/Makefile
-[win]src/pthread/pthread_attr_destroy.c
-[win]src/pthread/pthread_attr_getdetachstate.c
-[win]src/pthread/pthread_attr_getinheritsched.c
-[win]src/pthread/pthread_attr_getschedparam.c
-[win]src/pthread/pthread_attr_getschedpolicy.c
-[win]src/pthread/pthread_attr_getscope.c
-[win]src/pthread/pthread_attr_getstackaddr.c
-[win]src/pthread/pthread_attr_getstacksize.c
-[win]src/pthread/pthread_attr_init.c
-[win]src/pthread/pthread_attr_setdetachstate.c
-[win]src/pthread/pthread_attr_setinheritsched.c
-[win]src/pthread/pthread_attr_setschedparam.c
-[win]src/pthread/pthread_attr_setschedpolicy.c
-[win]src/pthread/pthread_attr_setscope.c
-[win]src/pthread/pthread_attr_setstackaddr.c
-[win]src/pthread/pthread_attr_setstacksize.c
-[win]src/pthread/pthread_barrier_destroy.c
-[win]src/pthread/pthread_barrier_init.c
-[win]src/pthread/pthread_barrier_wait.c
-[win]src/pthread/pthread_barrierattr_destroy.c
-[win]src/pthread/pthread_barrierattr_getpshared.c
-[win]src/pthread/pthread_barrierattr_init.c
-[win]src/pthread/pthread_barrierattr_setpshared.c
-[win]src/pthread/pthread_cancel.c
-[win]src/pthread/pthread_cond_destroy.c
-[win]src/pthread/pthread_cond_init.c
-[win]src/pthread/pthread_cond_signal.c
-[win]src/pthread/pthread_cond_wait.c
-[win]src/pthread/pthread_condattr_destroy.c
-[win]src/pthread/pthread_condattr_getpshared.c
-[win]src/pthread/pthread_condattr_init.c
-[win]src/pthread/pthread_condattr_setpshared.c
-[win]src/pthread/pthread_delay_np.c
-[win]src/pthread/pthread_detach.c
-[win]src/pthread/pthread_equal.c
-[win]src/pthread/pthread_exit.c
-[win]src/pthread/pthread_getconcurrency.c
-[win]src/pthread/pthread_getschedparam.c
-[win]src/pthread/pthread_getspecific.c
-[win]src/pthread/pthread_getunique_np.c
-[win]src/pthread/pthread_getw32threadhandle_np.c
-[win]src/pthread/pthread_join.c
-[win]src/pthread/pthread_key_create.c
-[win]src/pthread/pthread_key_delete.c
-[win]src/pthread/pthread_kill.c
-[win]src/pthread/pthread_mutex_consistent.c
-[win]src/pthread/pthread_mutex_destroy.c
-[win]src/pthread/pthread_mutex_init.c
-[win]src/pthread/pthread_mutex_lock.c
-[win]src/pthread/pthread_mutex_timedlock.c
-[win]src/pthread/pthread_mutex_trylock.c
-[win]src/pthread/pthread_mutex_unlock.c
-[win]src/pthread/pthread_mutexattr_destroy.c
-[win]src/pthread/pthread_mutexattr_getkind_np.c
-[win]src/pthread/pthread_mutexattr_getpshared.c
-[win]src/pthread/pthread_mutexattr_getrobust.c
-[win]src/pthread/pthread_mutexattr_gettype.c
-[win]src/pthread/pthread_mutexattr_init.c
-[win]src/pthread/pthread_mutexattr_setkind_np.c
-[win]src/pthread/pthread_mutexattr_setpshared.c
-[win]src/pthread/pthread_mutexattr_setrobust.c
-[win]src/pthread/pthread_mutexattr_settype.c
-[win]src/pthread/pthread_num_processors_np.c
-[win]src/pthread/pthread_once.c
-[win]src/pthread/pthread_rwlock_destroy.c
-[win]src/pthread/pthread_rwlock_init.c
-[win]src/pthread/pthread_rwlock_rdlock.c
-[win]src/pthread/pthread_rwlock_timedrdlock.c
-[win]src/pthread/pthread_rwlock_timedwrlock.c
-[win]src/pthread/pthread_rwlock_tryrdlock.c
-[win]src/pthread/pthread_rwlock_trywrlock.c
-[win]src/pthread/pthread_rwlock_unlock.c
-[win]src/pthread/pthread_rwlock_wrlock.c
-[win]src/pthread/pthread_rwlockattr_destroy.c
-[win]src/pthread/pthread_rwlockattr_getpshared.c
-[win]src/pthread/pthread_rwlockattr_init.c
-[win]src/pthread/pthread_rwlockattr_setpshared.c
-[win]src/pthread/pthread_self.c
-[win]src/pthread/pthread_setcancelstate.c
-[win]src/pthread/pthread_setcanceltype.c
-[win]src/pthread/pthread_setconcurrency.c
-[win]src/pthread/pthread_setschedparam.c
-[win]src/pthread/pthread_setspecific.c
-[win]src/pthread/pthread_spin_destroy.c
-[win]src/pthread/pthread_spin_init.c
-[win]src/pthread/pthread_spin_lock.c
-[win]src/pthread/pthread_spin_trylock.c
-[win]src/pthread/pthread_spin_unlock.c
-[win]src/pthread/pthread_testcancel.c
-[win]src/pthread/pthread_timechange_handler_np.c
-[win]src/pthread/pthread_win32_attach_detach_np.c
-[win]src/pthread/ptw32_calloc.c
-[win]src/pthread/ptw32_callUserDestroyRoutines.c
-[win]src/pthread/ptw32_cond_check_need_init.c
-[win]src/pthread/ptw32_getprocessors.c
-[win]src/pthread/ptw32_is_attr.c
-[win]src/pthread/ptw32_MCS_lock.c
-[win]src/pthread/ptw32_mutex_check_need_init.c
-[win]src/pthread/ptw32_new.c
-[win]src/pthread/ptw32_processInitialize.c
-[win]src/pthread/ptw32_processTerminate.c
-[win]src/pthread/ptw32_relmillisecs.c
-[win]src/pthread/ptw32_reuse.c
-[win]src/pthread/ptw32_rwlock_cancelwrwait.c
-[win]src/pthread/ptw32_rwlock_check_need_init.c
-[win]src/pthread/ptw32_semwait.c
-[win]src/pthread/ptw32_spinlock_check_need_init.c
-[win]src/pthread/ptw32_threadDestroy.c
-[win]src/pthread/ptw32_threadStart.c
-[win]src/pthread/ptw32_throw.c
-[win]src/pthread/ptw32_timespec.c
-[win]src/pthread/ptw32_tkAssocCreate.c
-[win]src/pthread/ptw32_tkAssocDestroy.c
+src/ppapi_cpp/*
+src/ppapi_cpp_private/*
+src/ppapi_gles2/*
+src/ppapi_simple/*
+[win]src/pthread/*
[win]src/pthread/README
-[win]src/pthread/sched_get_priority_max.c
-[win]src/pthread/sched_get_priority_min.c
-[win]src/pthread/sched_getscheduler.c
-[win]src/pthread/sched_setscheduler.c
-[win]src/pthread/sched_yield.c
-[win]src/pthread/sem_close.c
-[win]src/pthread/sem_destroy.c
-[win]src/pthread/sem_getvalue.c
-[win]src/pthread/sem_init.c
-[win]src/pthread/sem_open.c
-[win]src/pthread/sem_post.c
-[win]src/pthread/sem_post_multiple.c
-[win]src/pthread/sem_timedwait.c
-[win]src/pthread/sem_trywait.c
-[win]src/pthread/sem_unlink.c
-[win]src/pthread/sem_wait.c
-[win]src/pthread/signal.c
-[win]src/pthread/w32_CancelableWait.c
-[win]src/sdk_util/make.bat
-src/sdk_util/Makefile
-src/sdk_util/thread_pool.cc
+src/sdk_util/*
toolchain/${PLATFORM}_arm_newlib/*
toolchain/${PLATFORM}_arm_newlib/arm-nacl/include/irt.h
toolchain/${PLATFORM}_arm_newlib/arm-nacl/include/irt_ppapi.h
diff --git a/native_client_sdk/src/build_tools/test.js b/native_client_sdk/src/build_tools/test.js
new file mode 100644
index 0000000000..d6ba6d862a
--- /dev/null
+++ b/native_client_sdk/src/build_tools/test.js
@@ -0,0 +1,6 @@
+// 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.
+
+// This is a dummy JavaScript file that will be loaded by browser_tester if no
+// example-specific test.js is found.
diff --git a/native_client_sdk/src/build_tools/test_projects.py b/native_client_sdk/src/build_tools/test_projects.py
index a74292304e..04fe73dfa3 100755
--- a/native_client_sdk/src/build_tools/test_projects.py
+++ b/native_client_sdk/src/build_tools/test_projects.py
@@ -13,7 +13,7 @@ import buildbot_common
import build_version
import parse_dsc
-from build_paths import OUT_DIR, SRC_DIR, SDK_SRC_DIR
+from build_paths import OUT_DIR, SRC_DIR, SDK_SRC_DIR, SCRIPT_DIR
sys.path.append(os.path.join(SDK_SRC_DIR, 'tools'))
import getos
@@ -61,9 +61,6 @@ DISABLED_TESTS = [
{'name': 'graphics_3d', 'platform': ('win', 'linux')},
]
-DEFAULT_RETRY_ON_FAILURE_TIMES = 3
-
-
def ValidateToolchains(toolchains):
invalid_toolchains = set(toolchains) - set(ALL_TOOLCHAINS)
if invalid_toolchains:
@@ -77,6 +74,12 @@ def GetServingDirForProject(desc):
return os.path.join(path, desc['NAME'])
+def GetRepoServingDirForProject(desc):
+ # This differs from GetServingDirForProject, because it returns the location
+ # within the Chrome repository of the project, not the "pepperdir".
+ return os.path.dirname(desc['FILEPATH'])
+
+
def GetExecutableDirForProject(desc, toolchain, config):
return os.path.join(GetServingDirForProject(desc), toolchain, config)
@@ -89,15 +92,17 @@ def GetBrowserTesterCommand(desc, toolchain, config):
'--timeout', '30.0', # seconds
# Prevent the infobar that shows up when requesting filesystem quota.
'--browser_flag', '--unlimited-storage',
- # Some samples need the use the socket API. Enabling this for all
- # tests should be harmless.
- '--browser_flag', '--allow-nacl-socket-api=localhost',
+ '--enable_sockets',
]
args.extend(['--serving_dir', GetServingDirForProject(desc)])
- exe_dir = GetExecutableDirForProject(desc, toolchain, config)
+ # Fall back on the example directory in the Chromium repo, to find test.js.
+ args.extend(['--serving_dir', GetRepoServingDirForProject(desc)])
+ # If it is not found there, fall back on the dummy one (in this directory.)
+ args.extend(['--serving_dir', SCRIPT_DIR])
if toolchain == platform:
+ exe_dir = GetExecutableDirForProject(desc, toolchain, config)
ppapi_plugin = os.path.join(exe_dir, desc['NAME'])
if platform == 'win':
ppapi_plugin += '.dll'
@@ -181,10 +186,17 @@ def GetTestName(desc, toolchain, config):
def IsTestDisabled(desc, toolchain, config):
def AsList(value):
- if type(value) in (list, tuple):
- return (value,)
+ if type(value) not in (list, tuple):
+ return [value]
return value
+ def TestMatchesDisabled(test_values, disabled_test):
+ for key in test_values:
+ if key in disabled_test:
+ if test_values[key] not in AsList(disabled_test[key]):
+ return False
+ return True
+
test_values = {
'name': desc['NAME'],
'toolchain': toolchain,
@@ -193,10 +205,8 @@ def IsTestDisabled(desc, toolchain, config):
}
for disabled_test in DISABLED_TESTS:
- for key in test_values:
- if key in disabled_test:
- if test_values[key] in AsList(disabled_test[key]):
- return True
+ if TestMatchesDisabled(test_values, disabled_test):
+ return True
return False
@@ -265,7 +275,7 @@ def GetProjectTree(include):
def main(args):
parser = optparse.OptionParser()
- parser.add_option('--config',
+ parser.add_option('-c', '--config',
help='Choose configuration to run (Debug or Release). Runs both '
'by default', action='append')
parser.add_option('-x', '--experimental',
@@ -281,7 +291,7 @@ def main(args):
action='append')
parser.add_option('--retry-times',
help='Number of types to retry on failure (Default: %default)',
- type='int', default=DEFAULT_RETRY_ON_FAILURE_TIMES)
+ type='int', default=1)
options, args = parser.parse_args(args[1:])
if args:
diff --git a/native_client_sdk/src/build_tools/test_sdk.py b/native_client_sdk/src/build_tools/test_sdk.py
index 6e7360b8a4..bd5a00b711 100755
--- a/native_client_sdk/src/build_tools/test_sdk.py
+++ b/native_client_sdk/src/build_tools/test_sdk.py
@@ -101,6 +101,7 @@ def StepRunBrowserTests(toolchains, experimental):
args = [
sys.executable,
os.path.join(SCRIPT_DIR, 'test_projects.py'),
+ '--retry-times=3',
]
if experimental:
diff --git a/native_client_sdk/src/build_tools/tests/verify_filelist_test.py b/native_client_sdk/src/build_tools/tests/verify_filelist_test.py
index a1da59150e..2e01da1c93 100755
--- a/native_client_sdk/src/build_tools/tests/verify_filelist_test.py
+++ b/native_client_sdk/src/build_tools/tests/verify_filelist_test.py
@@ -122,6 +122,19 @@ foo/missing
dirlist = ['foo/bar/baz\\foo']
Verify('linux', rules, dirlist)
+ def testNestedGlobs(self):
+ rules = """\
+foo/*
+foo/bar/*"""
+ dirlist = ['foo/file', 'foo/bar/file']
+ Verify('linux', rules, dirlist)
+
+ rules = """\
+foo/bar/*
+foo/*"""
+ dirlist = ['foo/file', 'foo/bar/file']
+ Verify('linux', rules, dirlist)
+
if __name__ == '__main__':
unittest.main()
diff --git a/native_client_sdk/src/build_tools/verify_filelist.py b/native_client_sdk/src/build_tools/verify_filelist.py
index 95526bf70e..e6ccbb08af 100755
--- a/native_client_sdk/src/build_tools/verify_filelist.py
+++ b/native_client_sdk/src/build_tools/verify_filelist.py
@@ -90,6 +90,14 @@ class Rules(object):
# Remove the *
pattern = pattern[:-1]
self.glob_prefixes.append(pattern)
+ # Sort by longest prefix first; otherwise the rules:
+ #
+ # foo/*
+ # foo/bar/*
+ #
+ # Won't work properly. A file "foo/bar/baz" will match the first rule,
+ # not the second.
+ self.glob_prefixes.sort(cmp=lambda x, y: cmp(len(y), len(x)))
else:
self.exact_filenames.add(pattern)
diff --git a/native_client_sdk/src/examples/common.js b/native_client_sdk/src/examples/common.js
index 51adb54157..79687d55e4 100644
--- a/native_client_sdk/src/examples/common.js
+++ b/native_client_sdk/src/examples/common.js
@@ -64,6 +64,56 @@ var common = (function() {
}
/**
+ * Inject a script into the DOM, and call a callback when it is loaded.
+ *
+ * @param {string} url The url of the script to load.
+ * @param {Function} onload The callback to call when the script is loaded.
+ * @param {Function} onerror The callback to call if the script fails to load.
+ */
+ function injectScript(url, onload, onerror) {
+ var scriptEl = document.createElement('script');
+ scriptEl.type = 'text/javascript';
+ scriptEl.src = url;
+ scriptEl.onload = onload;
+ if (onerror) {
+ scriptEl.addEventListener('error', onerror, false);
+ }
+ document.head.appendChild(scriptEl);
+ }
+
+ /**
+ * Run all tests for this example.
+ *
+ * @param {bool} waitForModule True if the tests should wait for the module
+ * to load. This is not necessary for trusted plugins (i.e. host plugins).
+ * @param {Object} moduleEl The module DOM element.
+ */
+ function runTests(waitForModule, moduleEl) {
+ console.log('runTests()');
+ common.tester = new Tester();
+
+ // All NaCl SDK examples are OK if the example exits cleanly; (i.e. the
+ // NaCl module returns 0 or calls exit(0)).
+ //
+ // Without this exception, the browser_tester thinks that the module
+ // has crashed.
+ common.tester.exitCleanlyIsOK();
+
+ common.tester.addAsyncTest('loaded', function(test) {
+ test.pass();
+ });
+
+ if (typeof window.addTests !== 'undefined') {
+ window.addTests();
+ }
+
+ if (waitForModule) {
+ common.tester.waitFor(moduleEl);
+ }
+ common.tester.run();
+ }
+
+ /**
* Create the Native Client <embed> element as a child of the DOM element
* named "listener".
*
@@ -86,7 +136,7 @@ var common = (function() {
// Add any optional arguments
if (attrs) {
for (var key in attrs) {
- moduleEl.setAttribute(key, attrs[key])
+ moduleEl.setAttribute(key, attrs[key]);
}
}
@@ -113,34 +163,16 @@ var common = (function() {
// This is code that is only used to test the SDK.
if (isTest) {
- var scriptEl = document.createElement('script');
- scriptEl.type = 'text/javascript';
- scriptEl.src = 'nacltest.js';
- document.head.appendChild(scriptEl);
-
- scriptEl.onload = function() {
- common.tester = new Tester();
-
- // All NaCl SDK examples are OK if the example exits cleanly; (i.e. the
- // NaCl module returns 0 or calls exit(0)).
- //
- // Without this exception, the browser_tester thinks that the module
- // has crashed.
- common.tester.exitCleanlyIsOK();
-
- common.tester.addAsyncTest('loaded', function(test) {
- test.pass();
+ var loadNaClTest = function() {
+ injectScript('nacltest.js', function() {
+ var waitForModule = !isHost;
+ runTests(waitForModule, moduleEl);
});
-
- if (typeof window.addTests !== 'undefined') {
- window.addTests();
- }
-
- if (!isHost) {
- common.tester.waitFor(moduleEl);
- }
- common.tester.run();
};
+
+ // Try to load test.js for the example. Whether or not it exists, load
+ // nacltest.js.
+ injectScript('test.js', loadNaClTest, loadNaClTest);
}
}
@@ -171,9 +203,9 @@ var common = (function() {
*/
function handleCrash(event) {
if (common.naclModule.exitStatus == -1) {
- updateStatus('CRASHED')
+ updateStatus('CRASHED');
} else {
- updateStatus('EXITED [' + common.naclModule.exitStatus + ']')
+ updateStatus('EXITED [' + common.naclModule.exitStatus + ']');
}
if (typeof window.handleCrash !== 'undefined') {
window.handleCrash(common.naclModule.lastError);
@@ -276,7 +308,7 @@ var common = (function() {
return;
}
- logMessage('Unhandled message: ' + message_event.data)
+ logMessage('Unhandled message: ' + message_event.data);
}
/**
diff --git a/native_client_sdk/src/examples/demo/earth/earth.cc b/native_client_sdk/src/examples/demo/earth/earth.cc
index 2a1c95810c..559cc79754 100644
--- a/native_client_sdk/src/examples/demo/earth/earth.cc
+++ b/native_client_sdk/src/examples/demo/earth/earth.cc
@@ -60,7 +60,7 @@ inline double getseconds() {
return 0.0;
}
-// RGBA helper functions.
+// RGBA helper functions, used for extracting color from RGBA source image.
inline float ExtractR(uint32_t c) {
return static_cast<float>(c & 0xFF) * kOneOver255;
}
@@ -73,7 +73,8 @@ inline float ExtractB(uint32_t c) {
return static_cast<float>((c & 0xFF0000) >> 16) * kOneOver255;
}
-inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
+// BGRA helper function, for constructing a pixel for a BGRA buffer.
+inline uint32_t MakeBGRA(uint32_t b, uint32_t g, uint32_t r, uint32_t a) {
return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
}
@@ -353,7 +354,7 @@ Planet::Planet() : base_tex_(NULL), night_tex_(NULL), num_threads_(0),
// By default, render from the dispatch thread.
workers_ = new ThreadPool(num_threads_);
PSEventSetFilter(PSE_ALL);
- ps_context_ = PSContext2DAllocate();
+ ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
}
Planet::~Planet() {
@@ -382,7 +383,7 @@ inline uint32_t* Planet::wGetAddr(int x, int y) {
void Planet::wRenderPixelSpan(int x0, int x1, int y) {
if (!base_tex_ || !night_tex_)
return;
- const int kColorBlack = MakeRGBA(0, 0, 0, 0xFF);
+ const int kColorBlack = MakeBGRA(0, 0, 0, 0xFF);
float width = ps_context_->width;
float height = ps_context_->height;
float min_dim = width < height ? width : height;
@@ -495,7 +496,7 @@ void Planet::wRenderPixelSpan(int x0, int x1, int y) {
unsigned int ig = Clamp255(pg * tg + ng * ipg);
unsigned int ib = Clamp255(pb * tb + nb * ipb);
- unsigned int color = MakeRGBA(ir, ig, ib, 0xFF);
+ unsigned int color = MakeBGRA(ib, ig, ir, 0xFF);
*pixels = color;
++pixels;
diff --git a/native_client_sdk/src/examples/demo/flock/flock.cc b/native_client_sdk/src/examples/demo/flock/flock.cc
index 94707a03e9..9e1a639f8e 100644
--- a/native_client_sdk/src/examples/demo/flock/flock.cc
+++ b/native_client_sdk/src/examples/demo/flock/flock.cc
@@ -116,7 +116,7 @@ int example_main(int argc, char *argv[]) {
g_goose_sprite = new Sprite(buffer, pp::Size(fmt.width, fmt.height), 0);
- PSContext2D_t* ctx = PSContext2DAllocate();
+ PSContext2D_t* ctx = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
ResetFlock(ctx, 50);
while (1) {
PSEvent* event;
diff --git a/native_client_sdk/src/examples/demo/life/life.c b/native_client_sdk/src/examples/demo/life/life.c
index ef107be52a..06b020d850 100644
--- a/native_client_sdk/src/examples/demo/life/life.c
+++ b/native_client_sdk/src/examples/demo/life/life.c
@@ -42,7 +42,8 @@ struct {
const unsigned int kInitialRandSeed = 0xC0DE533D;
-#define MakeRGBA(r, g, b, a) \
+/* BGRA helper macro, for constructing a pixel for a BGRA buffer. */
+#define MakeBGRA(b, g, r, a) \
(((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
@@ -53,24 +54,24 @@ const unsigned int kInitialRandSeed = 0xC0DE533D;
* a binary alive or dead.
*/
const uint32_t kNeighborColors[] = {
- MakeRGBA(0x00, 0x00, 0x00, 0xff),
- MakeRGBA(0x00, 0x40, 0x00, 0xff),
- MakeRGBA(0x00, 0x60, 0x00, 0xff),
- MakeRGBA(0x00, 0x80, 0x00, 0xff),
- MakeRGBA(0x00, 0xA0, 0x00, 0xff),
- MakeRGBA(0x00, 0xC0, 0x00, 0xff),
- MakeRGBA(0x00, 0xE0, 0x00, 0xff),
- MakeRGBA(0x00, 0x00, 0x00, 0xff),
- MakeRGBA(0x00, 0x40, 0x00, 0xff),
- MakeRGBA(0x00, 0x60, 0x00, 0xff),
- MakeRGBA(0x00, 0x80, 0x00, 0xff),
- MakeRGBA(0x00, 0xA0, 0x00, 0xff),
- MakeRGBA(0x00, 0xC0, 0x00, 0xff),
- MakeRGBA(0x00, 0xE0, 0x00, 0xff),
- MakeRGBA(0x00, 0xFF, 0x00, 0xff),
- MakeRGBA(0x00, 0xFF, 0x00, 0xff),
- MakeRGBA(0x00, 0xFF, 0x00, 0xff),
- MakeRGBA(0x00, 0xFF, 0x00, 0xff),
+ MakeBGRA(0x00, 0x00, 0x00, 0xff),
+ MakeBGRA(0x00, 0x40, 0x00, 0xff),
+ MakeBGRA(0x00, 0x60, 0x00, 0xff),
+ MakeBGRA(0x00, 0x80, 0x00, 0xff),
+ MakeBGRA(0x00, 0xA0, 0x00, 0xff),
+ MakeBGRA(0x00, 0xC0, 0x00, 0xff),
+ MakeBGRA(0x00, 0xE0, 0x00, 0xff),
+ MakeBGRA(0x00, 0x00, 0x00, 0xff),
+ MakeBGRA(0x00, 0x40, 0x00, 0xff),
+ MakeBGRA(0x00, 0x60, 0x00, 0xff),
+ MakeBGRA(0x00, 0x80, 0x00, 0xff),
+ MakeBGRA(0x00, 0xA0, 0x00, 0xff),
+ MakeBGRA(0x00, 0xC0, 0x00, 0xff),
+ MakeBGRA(0x00, 0xE0, 0x00, 0xff),
+ MakeBGRA(0x00, 0xFF, 0x00, 0xff),
+ MakeBGRA(0x00, 0xFF, 0x00, 0xff),
+ MakeBGRA(0x00, 0xFF, 0x00, 0xff),
+ MakeBGRA(0x00, 0xFF, 0x00, 0xff),
};
/*
diff --git a/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc b/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
index 9b1f472ba9..59ae06174d 100644
--- a/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
+++ b/native_client_sdk/src/examples/demo/pi_generator/pi_generator.cc
@@ -75,7 +75,7 @@ int example_main(int argc, char* argv[]) {
PSEventSetFilter(PSE_ALL);
- PSContext2D_t* ctx = PSContext2DAllocate();
+ PSContext2D_t* ctx = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
bool running = true;
while (running) {
PSEvent* event;
diff --git a/native_client_sdk/src/examples/demo/voronoi/voronoi.cc b/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
index 7cadb1a1b5..99c2cbb69f 100644
--- a/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
+++ b/native_client_sdk/src/examples/demo/voronoi/voronoi.cc
@@ -73,7 +73,8 @@ inline double getseconds() {
return 0.0;
}
-inline uint32_t MakeRGBA(uint32_t r, uint32_t g, uint32_t b, uint32_t a) {
+// BGRA helper function, for constructing a pixel for a BGRA buffer.
+inline uint32_t MakeBGRA(uint32_t b, uint32_t g, uint32_t r, uint32_t a) {
return (((a) << 24) | ((r) << 16) | ((g) << 8) | (b));
}
} // namespace
@@ -162,7 +163,7 @@ void Voronoi::Reset() {
const float v = (frand() * 2.0f - 1.0f) * speed;
velocities_[i].Set(u, v);
// 'unique' color (well... unique enough for our purposes)
- colors_[i] = MakeRGBA(rand255(), rand255(), rand255(), 255);
+ colors_[i] = MakeBGRA(rand255(), rand255(), rand255(), 255);
}
}
@@ -173,7 +174,7 @@ Voronoi::Voronoi() : num_regions_(kDefaultNumRegions), num_threads_(0),
// By default, render from the dispatch thread.
workers_ = new ThreadPool(num_threads_);
PSEventSetFilter(PSE_ALL);
- ps_context_ = PSContext2DAllocate();
+ ps_context_ = PSContext2DAllocate(PP_IMAGEDATAFORMAT_BGRA_PREMUL);
}
Voronoi::~Voronoi() {
@@ -243,7 +244,7 @@ bool Voronoi::wTestRect(int* m, int x, int y, int w, int h) {
// If multithreading, this function is only called by the worker threads.
inline void Voronoi::wFillSpan(uint32_t* pixels, uint32_t color, int width) {
if (!draw_interiors_) {
- const uint32_t gray = MakeRGBA(128, 128, 128, 255);
+ const uint32_t gray = MakeBGRA(128, 128, 128, 255);
color = gray;
}
for (int i = 0; i < width; i += 4) {
@@ -394,8 +395,8 @@ void Voronoi::RenderDot(float x, float y, uint32_t color1, uint32_t color2) {
// Superimposes dots on the positions.
void Voronoi::SuperimposePositions() {
- const uint32_t white = MakeRGBA(255, 255, 255, 255);
- const uint32_t gray = MakeRGBA(192, 192, 192, 255);
+ const uint32_t white = MakeBGRA(255, 255, 255, 255);
+ const uint32_t gray = MakeBGRA(192, 192, 192, 255);
for (int i = 0; i < point_count_; i++) {
RenderDot(
screen_positions_[i].x, screen_positions_[i].y, white, gray);
diff --git a/native_client_sdk/src/examples/tutorial/load_progress/example.js b/native_client_sdk/src/examples/tutorial/load_progress/example.js
index faceef5620..3f45f6ab0d 100644
--- a/native_client_sdk/src/examples/tutorial/load_progress/example.js
+++ b/native_client_sdk/src/examples/tutorial/load_progress/example.js
@@ -39,13 +39,12 @@ function moduleLoadProgress(event) {
if (event.lengthComputable && event.total > 0) {
loadPercent = event.loaded / event.total * 100.0;
loadPercentString = loadPercent + '%';
+ common.logMessage('progress: ' + event.url + ' ' + loadPercentString +
+ ' (' + event.loaded + ' of ' + event.total + ' bytes)');
} else {
// The total length is not yet known.
- loadPercent = -1.0;
- loadPercentString = 'Computing...';
+ common.logMessage('progress: Computing...');
}
- common.logMessage('progress: ' + loadPercentString +
- ' (' + event.loaded + ' of ' + event.total + ' bytes)');
}
// Handler that gets called if an error occurred while loading the NaCl
diff --git a/native_client_sdk/src/libraries/nacl_io/dbgprint.c b/native_client_sdk/src/libraries/nacl_io/dbgprint.c
new file mode 100644
index 0000000000..b8a5bdf776
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/dbgprint.c
@@ -0,0 +1,36 @@
+/* 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/dbgprint.h"
+
+#include "nacl_io/kernel_wrap_real.h"
+
+#include <alloca.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+void dbgprintf(const char* format, ...) {
+ va_list args;
+ size_t wrote;
+ char* output;
+
+#ifdef _MSC_VER
+ /* TODO(sbc): vsnprintf on win32 does not return the
+ * size of the buffer needed. This can be implemented
+ * on win32 in terms of _vscprintf; */
+#error "not implemented for win32"
+#endif
+
+ va_start(args, format);
+ int len = vsnprintf(NULL, 0, format, args);
+ va_end(args);
+ output = alloca(len + 1);
+
+ va_start(args, format);
+ vsnprintf(output, len + 1, format, args);
+ va_end(args);
+
+ _real_write(2, output, strlen(output), &wrote);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/dbgprint.h b/native_client_sdk/src/libraries/nacl_io/dbgprint.h
new file mode 100644
index 0000000000..305fea5c8c
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/dbgprint.h
@@ -0,0 +1,16 @@
+/* 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_DBGPRINT_H_
+#define LIBRARIES_NACL_IO_DBGPRINT_H_
+
+#include "sdk_util/macros.h"
+
+EXTERN_C_BEGIN
+
+void dbgprintf(const char* format, ...);
+
+EXTERN_C_END
+
+#endif /* LIBRARIES_NACL_IO_DBGPRINT_H_ */
diff --git a/native_client_sdk/src/libraries/nacl_io/event_listener.cc b/native_client_sdk/src/libraries/nacl_io/event_listener.cc
index d8b293da47..11297b6c05 100644
--- a/native_client_sdk/src/libraries/nacl_io/event_listener.cc
+++ b/native_client_sdk/src/libraries/nacl_io/event_listener.cc
@@ -175,14 +175,14 @@ Error EventListener::Wait(EventData* events,
}
Error EventListener::Track(int id,
- const ScopedEventEmitter& emitter,
- uint32_t filter,
- uint64_t user_data) {
+ const ScopedEventEmitter& emitter,
+ uint32_t filter,
+ uint64_t user_data) {
AUTO_LOCK(info_lock_);
EventInfoMap_t::iterator it = event_info_map_.find(id);
// If it's not a streaming type, then it can not be added.
- if ((emitter->GetType() & (S_IFIFO | S_IFSOCK)) == 0)
+ if ((emitter->GetType() & (S_IFIFO | S_IFSOCK | S_IFCHR)) == 0)
return EPERM;
if (it != event_info_map_.end())
diff --git a/native_client_sdk/src/libraries/nacl_io/include/sys/ioctl.h b/native_client_sdk/src/libraries/nacl_io/include/sys/ioctl.h
new file mode 100644
index 0000000000..aa3774c698
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/include/sys/ioctl.h
@@ -0,0 +1,26 @@
+/* Copyright 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_INCLUDE_SYS_IOCTL_H_
+#define LIBRARIES_NACL_IO_INCLUDE_SYS_IOCTL_H_
+
+#include <sys/cdefs.h>
+
+#define TIOCGWINSZ 0x5413
+#define TIOCSWINSZ 0x5414
+
+struct winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+__BEGIN_DECLS
+
+int ioctl(int fd, unsigned long request, ...);
+
+__END_DECLS
+
+#endif /* LIBRARIES_NACL_IO_INCLUDE_SYS_IOCTL_H_ */
diff --git a/native_client_sdk/src/libraries/nacl_io/include/sys/termios.h b/native_client_sdk/src/libraries/nacl_io/include/sys/termios.h
index a8175659a1..7a4af07a6a 100644
--- a/native_client_sdk/src/libraries/nacl_io/include/sys/termios.h
+++ b/native_client_sdk/src/libraries/nacl_io/include/sys/termios.h
@@ -99,6 +99,11 @@
#define TCSADRAIN 1
#define TCSAFLUSH 2
+#define TCOOFF 0
+#define TCOON 1
+#define TCIOFF 2
+#define TCION 3
+
typedef unsigned char cc_t;
typedef unsigned short tcflag_t;
typedef char speed_t;
@@ -120,8 +125,17 @@ struct termios {
__BEGIN_DECLS
+speed_t cfgetispeed(const struct termios *termios_p);
+speed_t cfgetospeed(const struct termios *termios_p);
+int cfsetispeed(struct termios *termios_p, speed_t speed);
+int cfsetospeed(struct termios *termios_p, speed_t speed);
+int cfsetspeed(struct termios *termios_p, speed_t speed);
+
+int tcdrain(int fd);
+int tcflow(int fd, int action);
int tcflush(int fd, int queue_selector);
int tcgetattr(int fd, struct termios *termios_p);
+int tcsendbreak(int fd, int duration);
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
__END_DECLS
diff --git a/native_client_sdk/src/libraries/nacl_io/ioctl.h b/native_client_sdk/src/libraries/nacl_io/ioctl.h
index 1d27c61eb5..80c2c4fc9b 100644
--- a/native_client_sdk/src/libraries/nacl_io/ioctl.h
+++ b/native_client_sdk/src/libraries/nacl_io/ioctl.h
@@ -5,21 +5,40 @@
#ifndef LIBRARIES_NACL_IO_IOCTL_H_
#define LIBRARIES_NACL_IO_IOCTL_H_
-/* ioctl to tell a tty mount to prefix every message with a particular
- * null-terminated string. Accepts a pointer to a C string which will
- * be the prefix.
- */
-#define TIOCNACLPREFIX 0xadcd01
+#include <sys/types.h>
-/* ioctl to feed input to a tty mount. Accepts a pointer to the following
+/*
+ * ioctl to feed input to a tty node. Accepts a pointer to the following
* struct (tioc_nacl_input_string), which contains a pointer to an array
* of characters.
*/
#define TIOCNACLINPUT 0xadcd02
+/*
+ * ioctl to register an output handler with the tty node. Will fail
+ * with EALREADY if a handler is already registered. Expects an
+ * argument of type tioc_nacl_output. The handler will be called during
+ * calls to write() on the thread that calls write(), or, for echoed input
+ * during the TIOCNACLINPUT ioctl() on the thread calling ioctl(). The
+ * handler should return the number of bytes written/handled, or -errno
+ * if an error occured.
+ */
+#define TIOCNACLOUTPUT 0xadcd03
+
struct tioc_nacl_input_string {
size_t length;
const char* buffer;
};
+
+typedef ssize_t (*tioc_nacl_output_handler_t)(const char* buf,
+ size_t count,
+ void* user_data);
+
+struct tioc_nacl_output {
+ tioc_nacl_output_handler_t handler;
+ void* user_data;
+};
+
+
#endif /* LIBRARIES_NACL_IO_NACL_IO_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 d93c05b099..37d3fa43b7 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_handle.cc
@@ -29,6 +29,13 @@ KernelHandle::~KernelHandle() {
mount_.reset(NULL);
}
+// Returns the MountNodeSocket* if this node is a socket.
+MountNodeSocket* KernelHandle::socket_node() {
+ if (node_.get() && node_->IsaSock())
+ return reinterpret_cast<MountNodeSocket*>(node_.get());
+ return NULL;
+}
+
Error KernelHandle::Init(int open_mode) {
if (open_mode & O_APPEND) {
Error error = node_->GetSize(&offs_);
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 ad2b9002eb..fd76ddecfc 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_handle.h
@@ -19,6 +19,9 @@
namespace nacl_io {
+class MountNode;
+class MountNodeSocket;
+
// KernelHandle provides a reference counted container for the open
// file information, such as it's mount, node, access type and offset.
// KernelHandle can only be referenced when the KernelProxy lock is held.
@@ -41,6 +44,10 @@ class KernelHandle : public sdk_util::RefObject {
const ScopedMountNode& node() { return node_; }
const ScopedMount& mount() { return mount_; }
+ // Returns the MountNodeSocket* if this node is a socket otherwise returns
+ // NULL.
+ MountNodeSocket* socket_node();
+
private:
ScopedMount mount_;
ScopedMountNode node_;
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
index d1bad01831..b378e86886 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
@@ -22,6 +22,7 @@ using namespace nacl_io;
}
static KernelProxy* s_kp;
+static bool s_kp_owned;
void ki_init(void* kp) {
ki_init_ppapi(kp, 0, NULL);
@@ -32,8 +33,14 @@ void ki_init_ppapi(void* kp,
PPB_GetInterface get_browser_interface) {
kernel_wrap_init();
- if (kp == NULL) kp = new KernelProxy();
- s_kp = static_cast<KernelProxy*>(kp);
+ if (kp == NULL) {
+ s_kp = new KernelProxy();
+ s_kp_owned = true;
+ } else {
+ s_kp = static_cast<KernelProxy*>(kp);
+ s_kp_owned = false;
+ }
+
PepperInterface* ppapi = NULL;
if (instance && get_browser_interface)
@@ -48,10 +55,11 @@ int ki_is_initialized() {
void ki_uninit() {
kernel_wrap_uninit();
+ if (s_kp_owned)
+ delete s_kp;
s_kp = NULL;
}
-
int ki_chdir(const char* path) {
ON_NOSYS_RETURN(-1);
return s_kp->chdir(path);
@@ -258,6 +266,21 @@ int ki_tcsetattr(int fd, int optional_actions,
return s_kp->tcsetattr(fd, optional_actions, termios_p);
}
+int ki_kill(pid_t pid, int sig) {
+ ON_NOSYS_RETURN(-1);
+ return s_kp->kill(pid, sig);
+}
+
+sighandler_t ki_signal(int signum, sighandler_t handler) {
+ ON_NOSYS_RETURN(SIG_ERR);
+ return s_kp->sigset(signum, handler);
+}
+
+sighandler_t ki_sigset(int signum, sighandler_t handler) {
+ ON_NOSYS_RETURN(SIG_ERR);
+ return s_kp->sigset(signum, handler);
+}
+
#ifdef PROVIDES_SOCKET_API
// Socket Functions
int ki_accept(int fd, struct sockaddr* addr, socklen_t* len) {
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
index 6ef44b3a5a..c17b61c479 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
@@ -8,6 +8,7 @@
#include <ppapi/c/ppb.h>
#include <ppapi/c/pp_instance.h>
+#include "nacl_io/ossignal.h"
#include "nacl_io/ossocket.h"
#include "nacl_io/osstat.h"
#include "nacl_io/ostermios.h"
@@ -75,6 +76,9 @@ int ki_tcflush(int fd, int queue_selector);
int ki_tcgetattr(int fd, struct termios* termios_p);
int ki_tcsetattr(int fd, int optional_actions,
const struct termios *termios_p);
+int ki_kill(pid_t pid, int sig);
+sighandler_t ki_signal(int signum, sighandler_t handler);
+sighandler_t ki_sigset(int signum, sighandler_t handler);
#ifdef PROVIDES_SOCKET_API
// Socket Functions
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 292f91ebef..84e531e8fa 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -14,10 +14,12 @@
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
+#include <unistd.h>
#include <iterator>
#include <string>
+#include "nacl_io/dbgprint.h"
#include "nacl_io/host_resolver.h"
#include "nacl_io/kernel_handle.h"
#include "nacl_io/kernel_wrap_real.h"
@@ -27,6 +29,8 @@
#include "nacl_io/mount_http.h"
#include "nacl_io/mount_mem.h"
#include "nacl_io/mount_node.h"
+#include "nacl_io/mount_node_tcp.h"
+#include "nacl_io/mount_node_udp.h"
#include "nacl_io/mount_passthrough.h"
#include "nacl_io/osmman.h"
#include "nacl_io/ossocket.h"
@@ -43,7 +47,31 @@
namespace nacl_io {
-KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL) {
+class SignalEmitter : public EventEmitter {
+ public:
+ // From EventEmitter. The SignalEmitter exists in order
+ // to inturrupt anything waiting in select()/poll() when kill()
+ // is called. It is an edge trigger only and therefore has no
+ // persistent readable/wriable/error state.
+ uint32_t GetEventStatus() {
+ return 0;
+ }
+
+ int GetType() {
+ // For lack of a better type, report socket to signify it can be in an
+ // used to signal.
+ return S_IFSOCK;
+ }
+
+ void SignalOccurred() {
+ RaiseEvent(POLLERR);
+ }
+};
+
+KernelProxy::KernelProxy() : dev_(0), ppapi_(NULL),
+ sigwinch_handler_(SIG_IGN),
+ signal_emitter_(new SignalEmitter) {
+
}
KernelProxy::~KernelProxy() {
@@ -82,6 +110,10 @@ void KernelProxy::Init(PepperInterface* ppapi) {
#ifdef PROVIDES_SOCKET_API
host_resolver_.Init(ppapi_);
#endif
+
+ StringMap_t args;
+ socket_mount_.reset(new MountSocket());
+ socket_mount_->Init(0, args, ppapi);
}
int KernelProxy::open_resource(const char* path) {
@@ -704,11 +736,77 @@ int KernelProxy::tcsetattr(int fd, int optional_actions,
return 0;
}
+int KernelProxy::kill(pid_t pid, int sig) {
+ // Currently we don't even pretend that other processes exist
+ // so we can only send a signal to outselves. For kill(2)
+ // pid 0 means the current process group and -1 means all the
+ // processes we have permission to send signals to.
+ if (pid != getpid() && pid != -1 && pid != 0) {
+ errno = ESRCH;
+ return -1;
+ }
+
+ // Raise an event so that select/poll get interrupted.
+ signal_emitter_->SignalOccurred();
+ switch (sig) {
+ case SIGWINCH:
+ if (sigwinch_handler_ != SIG_IGN)
+ sigwinch_handler_(SIGWINCH);
+ break;
+
+ case SIGUSR1:
+ case SIGUSR2:
+ break;
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+sighandler_t KernelProxy::sigset(int signum, sighandler_t handler) {
+ switch (signum) {
+ // Handled signals.
+ case SIGWINCH: {
+ sighandler_t old_value = sigwinch_handler_;
+ if (handler == SIG_DFL)
+ handler = SIG_IGN;
+ sigwinch_handler_ = handler;
+ return old_value;
+ }
+
+ // Known signals
+ case SIGHUP:
+ case SIGINT:
+ case SIGKILL:
+ case SIGPIPE:
+ case SIGPOLL:
+ case SIGPROF:
+ case SIGTERM:
+ case SIGCHLD:
+ case SIGURG:
+ case SIGFPE:
+ case SIGILL:
+ case SIGQUIT:
+ case SIGSEGV:
+ case SIGTRAP:
+ if (handler == SIG_DFL)
+ return SIG_DFL;
+ break;
+ }
+
+ errno = EINVAL;
+ return SIG_ERR;
+}
+
#ifdef PROVIDES_SOCKET_API
int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
fd_set* exceptfds, struct timeval* timeout) {
ScopedEventListener listener(new EventListener);
+
std::vector<struct pollfd> fds;
fd_set readout, writeout, exceptout;
@@ -785,7 +883,7 @@ int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
// If the timeout is invalid or too long (larger than signed 32 bit).
if ((timeout->tv_sec < 0) || (timeout->tv_sec >= (INT_MAX / 1000)) ||
- (timeout->tv_usec < 0) || (timeout->tv_usec >= 1000) ||
+ (timeout->tv_usec < 0) || (timeout->tv_usec >= 1000000) ||
(ms < 0) || (ms >= INT_MAX)) {
errno = EINVAL;
return -1;
@@ -794,9 +892,24 @@ int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
ms_timeout = static_cast<int>(ms);
}
+ // Add a special node to listen for events
+ // coming from the KernelProxy itself (kill will
+ // generated a SIGERR event).
+ listener->Track(-1, signal_emitter_, POLLERR, -1);
+ event_track += 1;
+
events.resize(event_track);
+
+ bool interrupted = false;
listener->Wait(events.data(), event_track, ms_timeout, &ready_cnt);
for (fd = 0; static_cast<int>(fd) < ready_cnt; fd++) {
+ if (events[fd].user_data == static_cast<uint64_t>(-1)) {
+ if (events[fd].events & POLLERR) {
+ interrupted = true;
+ }
+ continue;
+ }
+
if (events[fd].events & POLLIN) {
FD_SET(events[fd].user_data, &readout);
event_cnt++;
@@ -812,6 +925,11 @@ int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
event_cnt++;
}
}
+
+ if (0 == event_cnt && interrupted) {
+ errno = EINTR;
+ return -1;
+ }
}
// Copy out the results
@@ -829,10 +947,11 @@ int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
int KernelProxy::poll(struct pollfd *fds, nfds_t nfds, int timeout) {
ScopedEventListener listener(new EventListener);
+ listener->Track(-1, signal_emitter_, POLLERR, 0);
int index;
size_t event_cnt = 0;
- size_t event_track = 0;
+ size_t event_track = 1;
for (index = 0; static_cast<nfds_t>(index) < nfds; index++) {
ScopedKernelHandle handle;
struct pollfd* info = &fds[index];
@@ -867,14 +986,23 @@ int KernelProxy::poll(struct pollfd *fds, nfds_t nfds, int timeout) {
std::vector<EventData> events;
int ready_cnt;
+ bool interrupted = false;
events.resize(event_track);
listener->Wait(events.data(), event_track, timeout, &ready_cnt);
for (index = 0; index < ready_cnt; index++) {
struct pollfd* info = &fds[events[index].user_data];
+ if (!info) {
+ interrupted = true;
+ continue;
+ }
info->revents = events[index].events;
event_cnt++;
}
+ if (0 == event_cnt && interrupted) {
+ errno = EINTR;
+ return -1;
+ }
}
return event_cnt;
@@ -907,8 +1035,13 @@ int KernelProxy::bind(int fd, const struct sockaddr* addr, socklen_t len) {
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
- errno = EINVAL;
- return -1;
+ Error err = handle->socket_node()->Bind(addr, len);
+ if (err != 0) {
+ errno = err;
+ return -1;
+ }
+
+ return 0;
}
int KernelProxy::connect(int fd, const struct sockaddr* addr, socklen_t len) {
@@ -921,8 +1054,13 @@ int KernelProxy::connect(int fd, const struct sockaddr* addr, socklen_t len) {
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
- errno = EACCES;
- return -1;
+ Error err = handle->socket_node()->Connect(addr, len);
+ if (err != 0) {
+ errno = err;
+ return -1;
+ }
+
+ return 0;
}
struct hostent* KernelProxy::gethostbyname(const char* name) {
@@ -939,8 +1077,13 @@ int KernelProxy::getpeername(int fd, struct sockaddr* addr, socklen_t* len) {
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
- errno = EINVAL;
- return -1;
+ Error err = handle->socket_node()->GetPeerName(addr, len);
+ if (err != 0) {
+ errno = err;
+ return -1;
+ }
+
+ return 0;
}
int KernelProxy::getsockname(int fd, struct sockaddr* addr, socklen_t* len) {
@@ -953,8 +1096,13 @@ int KernelProxy::getsockname(int fd, struct sockaddr* addr, socklen_t* len) {
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
- errno = EINVAL;
- return -1;
+ Error err = handle->socket_node()->GetSockName(addr, len);
+ if (err != 0) {
+ errno = err;
+ return -1;
+ }
+
+ return 0;
}
int KernelProxy::getsockopt(int fd,
@@ -997,8 +1145,14 @@ ssize_t KernelProxy::recv(int fd,
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
- errno = EINVAL;
- return -1;
+ int out_len = 0;
+ Error err = handle->socket_node()->Recv(buf, len, flags, &out_len);
+ if (err != 0) {
+ errno = err;
+ return -1;
+ }
+
+ return static_cast<ssize_t>(out_len);
}
ssize_t KernelProxy::recvfrom(int fd,
@@ -1021,8 +1175,19 @@ ssize_t KernelProxy::recvfrom(int fd,
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
- errno = EINVAL;
- return -1;
+ int out_len = 0;
+ Error err = handle->socket_node()->RecvFrom(buf,
+ len,
+ flags,
+ addr,
+ addrlen,
+ &out_len);
+ if (err != 0) {
+ errno = err;
+ return -1;
+ }
+
+ return static_cast<ssize_t>(out_len);
}
ssize_t KernelProxy::recvmsg(int fd, struct msghdr* msg, int flags) {
@@ -1049,8 +1214,14 @@ ssize_t KernelProxy::send(int fd, const void* buf, size_t len, int flags) {
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
- errno = EINVAL;
- return -1;
+ int out_len = 0;
+ Error err = handle->socket_node()->Send(buf, len, flags, &out_len);
+ if (err != 0) {
+ errno = err;
+ return -1;
+ }
+
+ return static_cast<ssize_t>(out_len);
}
ssize_t KernelProxy::sendto(int fd,
@@ -1073,8 +1244,16 @@ ssize_t KernelProxy::sendto(int fd,
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
- errno = EINVAL;
- return -1;
+ int out_len = 0;
+ Error err =
+ handle->socket_node()->SendTo(buf, len, flags, addr, addrlen, &out_len);
+
+ if (err != 0) {
+ errno = err;
+ return -1;
+ }
+
+ return static_cast<ssize_t>(out_len);
}
ssize_t KernelProxy::sendmsg(int fd, const struct msghdr* msg, int flags) {
@@ -1114,8 +1293,13 @@ int KernelProxy::shutdown(int fd, int how) {
if (AcquireSocketHandle(fd, &handle) == -1)
return -1;
- errno = EINVAL;
- return -1;
+ Error err = handle->socket_node()->Shutdown(how);
+ if (err != 0) {
+ errno = err;
+ return -1;
+ }
+
+ return 0;
}
int KernelProxy::socket(int domain, int type, int protocol) {
@@ -1124,13 +1308,29 @@ int KernelProxy::socket(int domain, int type, int protocol) {
return -1;
}
- if (SOCK_STREAM != type && SOCK_DGRAM != type) {
- errno = EPROTONOSUPPORT;
- return -1;
+ MountNodeSocket* sock = NULL;
+ switch (type) {
+ case SOCK_DGRAM:
+ sock = new MountNodeUDP(socket_mount_.get());
+ break;
+
+ case SOCK_STREAM:
+ sock = new MountNodeTCP(socket_mount_.get());
+ break;
+
+ default:
+ errno = EPROTONOSUPPORT;
+ return -1;
}
- errno = EACCES;
- return -1;
+ ScopedMountNode node(sock);
+ if (sock->Init(S_IREAD | S_IWRITE) == 0) {
+ ScopedKernelHandle handle(new KernelHandle(socket_mount_, node));
+ return AllocateFD(handle);
+ }
+
+ // If we failed to init, assume we don't have access.
+ return EACCES;
}
int KernelProxy::socketpair(int domain, int type, int protocol, int* sv) {
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 fc0191fe82..b8ca04eda2 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
@@ -11,6 +11,8 @@
#include "nacl_io/host_resolver.h"
#include "nacl_io/kernel_object.h"
#include "nacl_io/mount_factory.h"
+#include "nacl_io/mount_socket.h"
+#include "nacl_io/ossignal.h"
#include "nacl_io/ossocket.h"
#include "nacl_io/ostypes.h"
#include "nacl_io/osutime.h"
@@ -20,6 +22,9 @@ struct timeval;
namespace nacl_io {
class PepperInterface;
+class SignalEmitter;
+
+typedef sdk_util::ScopedRef<SignalEmitter> ScopedSignalEmitter;
// 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.
@@ -124,6 +129,9 @@ class KernelProxy : protected KernelObject {
virtual int tcsetattr(int fd, int optional_actions,
const struct termios *termios_p);
+ virtual int kill(pid_t pid, int sig);
+ virtual sighandler_t sigset(int signum, sighandler_t handler);
+
#ifdef PROVIDES_SOCKET_API
virtual int select(int nfds, fd_set* readfds, fd_set* writefds,
fd_set* exceptfds, struct timeval* timeout);
@@ -174,9 +182,11 @@ class KernelProxy : protected KernelObject {
protected:
MountFactoryMap_t factories_;
+ sdk_util::ScopedRef<MountSocket> socket_mount_;
int dev_;
PepperInterface* ppapi_;
static KernelProxy *s_instance_;
+ sighandler_t sigwinch_handler_;
#ifdef PROVIDES_SOCKET_API
HostResolver host_resolver_;
#endif
@@ -185,6 +195,7 @@ class KernelProxy : protected KernelObject {
virtual int AcquireSocketHandle(int fd, ScopedKernelHandle* handle);
#endif
+ ScopedSignalEmitter signal_emitter_;
DISALLOW_COPY_AND_ASSIGN(KernelProxy);
};
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
index 33a4c2d597..c7f8ce1dc8 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
@@ -5,9 +5,11 @@
#ifndef LIBRARIES_NACL_IO_KERNEL_WRAP_H_
#define LIBRARIES_NACL_IO_KERNEL_WRAP_H_
-#include <sys/types.h>
+#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
#include "nacl_io/ossocket.h"
#include "nacl_io/ostypes.h"
@@ -62,7 +64,6 @@ int ftruncate(int fd, off_t length) NOTHROW;
char* NAME(getcwd)(char* buf, getcwd_size_t size) NOTHROW;
char* getwd(char* buf) NOTHROW;
int getdents(int fd, void* buf, unsigned int count) NOTHROW;
-int ioctl(int d, int request, char* argp) NOTHROW;
int NAME(isatty)(int fd) NOTHROW;
int lchown(const char* path, uid_t owner, gid_t group) NOTHROW;
int link(const char* oldpath, const char* newpath) NOTHROW;
@@ -81,6 +82,7 @@ int NAME(open)(const char* path, int oflag, ...);
read_ssize_t NAME(read)(int fd, void* buf, size_t nbyte);
int remove(const char* path) NOTHROW;
int NAME(rmdir)(const char* path) NOTHROW;
+sighandler_t sigset(int sig, sighandler_t disp);
#if defined(WIN32)
int setenv(const char* name, const char* value, int overwrite);
int _stat32(const char* path, struct _stat32* buf);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
index c2a9e1f737..8c270b1da6 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
@@ -22,6 +22,7 @@
#include <sys/time.h>
#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap_real.h"
#include "nacl_io/osmman.h"
@@ -243,9 +244,6 @@ int WRAP(poll)(struct pollfd *fds, nfds_t nfds, int timeout, int* count) {
}
int WRAP(read)(int fd, void *buf, size_t count, size_t *nread) {
- if (!ki_is_initialized())
- return REAL(read)(fd, buf, count, nread);
-
ssize_t signed_nread = ki_read(fd, buf, count);
*nread = static_cast<size_t>(signed_nread);
return (signed_nread < 0) ? errno : 0;
@@ -277,22 +275,33 @@ int WRAP(stat)(const char *pathname, struct nacl_abi_stat *nacl_buf) {
}
int WRAP(write)(int fd, const void* buf, size_t count, size_t* nwrote) {
- if (!ki_is_initialized())
- return REAL(write)(fd, buf, count, nwrote);
-
ssize_t signed_nwrote = ki_write(fd, buf, count);
*nwrote = static_cast<size_t>(signed_nwrote);
return (signed_nwrote < 0) ? errno : 0;
}
+static void assign_real_pointers() {
+ static bool assigned = false;
+ if (!assigned) {
+ EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR)
+ assigned = true;
+ }
+}
+
+#define CHECK_REAL(func) \
+ if (!REAL(func)) \
+ assign_real_pointers();
+
// "real" functions, i.e. the unwrapped original functions.
int _real_close(int fd) {
+ CHECK_REAL(close);
return REAL(close)(fd);
}
int _real_fstat(int fd, struct stat* buf) {
struct nacl_abi_stat st;
+ CHECK_REAL(fstat);
int err = REAL(fstat)(fd, &st);
if (err) {
errno = err;
@@ -310,6 +319,7 @@ int _real_getdents(int fd, void* buf, size_t count, size_t* nread) {
size_t offset = 0;
size_t nacl_offset = 0;
size_t nacl_nread;
+ CHECK_REAL(getdents);
int err = REAL(getdents)(fd, (dirent*)nacl_buf, count, &nacl_nread);
if (err)
return err;
@@ -333,39 +343,48 @@ int _real_getdents(int fd, void* buf, size_t count, size_t* nread) {
}
int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) {
+ CHECK_REAL(seek);
return REAL(seek)(fd, offset, whence, new_offset);
}
int _real_mkdir(const char* pathname, mode_t mode) {
+ CHECK_REAL(mkdir);
return REAL(mkdir)(pathname, mode);
}
int _real_mmap(void** addr, size_t length, int prot, int flags, int fd,
off_t offset) {
+ CHECK_REAL(mmap);
return REAL(mmap)(addr, length, prot, flags, fd, offset);
}
int _real_munmap(void* addr, size_t length) {
+ CHECK_REAL(munmap);
return REAL(munmap)(addr, length);
}
int _real_open(const char* pathname, int oflag, mode_t cmode, int* newfd) {
+ CHECK_REAL(open);
return REAL(open)(pathname, oflag, cmode, newfd);
}
int _real_open_resource(const char* file, int* fd) {
+ CHECK_REAL(open_resource);
return REAL(open_resource)(file, fd);
}
int _real_read(int fd, void *buf, size_t count, size_t *nread) {
+ CHECK_REAL(read);
return REAL(read)(fd, buf, count, nread);
}
int _real_rmdir(const char* pathname) {
+ CHECK_REAL(rmdir);
return REAL(rmdir)(pathname);
}
int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
+ CHECK_REAL(write);
return REAL(write)(fd, buf, count, nwrote);
}
@@ -376,13 +395,9 @@ uint64_t usec_since_epoch() {
}
static bool s_wrapped = false;
-static bool s_assigned = false;
void kernel_wrap_init() {
if (!s_wrapped) {
- if (!s_assigned) {
- EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR)
- s_assigned = true;
- }
+ assign_real_pointers();
EXPAND_SYMBOL_LIST_OPERATION(USE_WRAP)
s_wrapped = true;
}
@@ -397,6 +412,4 @@ void kernel_wrap_uninit() {
EXTERN_C_END
-
#endif // defined(__native_client__) && defined(__GLIBC__)
-
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
index 34ab407f83..dcb3117ae3 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
@@ -9,6 +9,7 @@
#if defined(__native_client__) && !defined(__GLIBC__)
#include "nacl_io/kernel_wrap.h"
+
#include <assert.h>
#include <dirent.h>
#include <errno.h>
@@ -16,7 +17,9 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
+
#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap_real.h"
EXTERN_C_BEGIN
@@ -86,7 +89,11 @@ int WRAP(fstat)(int fd, struct stat* buf) {
}
int WRAP(getdents)(int fd, dirent* buf, size_t count, size_t* nread) {
- return (ki_getdents(fd, buf, count) < 0) ? errno : 0;
+ int rtn = ki_getdents(fd, buf, count);
+ if (rtn < 0)
+ return errno;
+ *nread = rtn;
+ return 0;
}
int WRAP(mmap)(void** addr, size_t length, int prot, int flags, int fd,
@@ -111,9 +118,6 @@ int WRAP(open)(const char* pathname, int oflag, mode_t cmode, int* newfd) {
}
int WRAP(read)(int fd, void* buf, size_t count, size_t* nread) {
- if (!ki_is_initialized())
- return REAL(read)(fd, buf, count, nread);
-
ssize_t signed_nread = ki_read(fd, buf, count);
*nread = static_cast<size_t>(signed_nread);
return (signed_nread < 0) ? errno : 0;
@@ -129,29 +133,43 @@ int WRAP(stat)(const char* pathname, struct stat* buf) {
}
int WRAP(write)(int fd, const void* buf, size_t count, size_t* nwrote) {
- if (!ki_is_initialized())
- return REAL(write)(fd, buf, count, nwrote);
-
ssize_t signed_nwrote = ki_write(fd, buf, count);
*nwrote = static_cast<size_t>(signed_nwrote);
return (signed_nwrote < 0) ? errno : 0;
}
+static void assign_real_pointers() {
+ static bool assigned = false;
+ if (!assigned) {
+ __libnacl_irt_filename_init();
+ EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR)
+ assigned = true;
+ }
+}
+
+#define CHECK_REAL(func) \
+ if (!REAL(func)) \
+ assign_real_pointers();
+
// "real" functions, i.e. the unwrapped original functions.
int _real_close(int fd) {
+ CHECK_REAL(close);
return REAL(close)(fd);
}
int _real_fstat(int fd, struct stat* buf) {
+ CHECK_REAL(fstat);
return REAL(fstat)(fd, buf);
}
-int _real_getdents(int fd, dirent* nacl_buf, size_t nacl_count, size_t* nread) {
- return REAL(getdents)(fd, nacl_buf, nacl_count, nread);
+int _real_getdents(int fd, void* nacl_buf, size_t nacl_count, size_t* nread) {
+ CHECK_REAL(getdents);
+ return REAL(getdents)(fd, static_cast<dirent*>(nacl_buf), nacl_count, nread);
}
int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) {
+ CHECK_REAL(seek);
return REAL(seek)(fd, offset, whence, new_offset);
}
@@ -161,14 +179,17 @@ int _real_mkdir(const char* pathname, mode_t mode) {
int _real_mmap(void** addr, size_t length, int prot, int flags, int fd,
off_t offset) {
+ CHECK_REAL(mmap);
return REAL(mmap)(addr, length, prot, flags, fd, offset);
}
int _real_munmap(void* addr, size_t length) {
+ CHECK_REAL(munmap);
return REAL(munmap)(addr, length);
}
int _real_open(const char* pathname, int oflag, mode_t cmode, int* newfd) {
+ CHECK_REAL(open);
return REAL(open)(pathname, oflag, cmode, newfd);
}
@@ -177,6 +198,7 @@ int _real_open_resource(const char* file, int* fd) {
}
int _real_read(int fd, void* buf, size_t count, size_t* nread) {
+ CHECK_REAL(read);
return REAL(read)(fd, buf, count, nread);
}
@@ -185,6 +207,7 @@ int _real_rmdir(const char* pathname) {
}
int _real_write(int fd, const void* buf, size_t count, size_t* nwrote) {
+ CHECK_REAL(write);
return REAL(write)(fd, buf, count, nwrote);
}
@@ -195,14 +218,10 @@ uint64_t usec_since_epoch() {
}
static bool s_wrapped = false;
-static bool s_assigned = false;
+
void kernel_wrap_init() {
if (!s_wrapped) {
- if (!s_assigned) {
- __libnacl_irt_filename_init();
- EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR)
- s_assigned = true;
- }
+ assign_real_pointers();
EXPAND_SYMBOL_LIST_OPERATION(USE_WRAP)
s_wrapped = true;
}
@@ -217,6 +236,4 @@ void kernel_wrap_uninit() {
EXTERN_C_END
-
#endif // defined(__native_client__) && !defined(__GLIBC__)
-
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index 4d75b2cd6d..533bcf4a10 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -11,6 +11,7 @@
'NAME' : 'nacl_io',
'TYPE' : 'lib',
'SOURCES' : [
+ 'dbgprint.c',
"event_emitter.cc",
"event_listener.cc",
"h_errno.cc",
@@ -32,15 +33,25 @@
"mount_node_html5fs.cc",
"mount_node_http.cc",
"mount_node_mem.cc",
+ "mount_node_socket.cc",
+ "mount_node_tcp.cc",
"mount_node_tty.cc",
+ "mount_node_udp.cc",
"mount_passthrough.cc",
+ "mount_socket.cc",
"nacl_io.cc",
"path.cc",
"pepper_interface.cc",
+ "pepper_interface_delegate.cc",
"real_pepper_interface.cc",
"syscalls/accept.c",
"syscalls/access.c",
"syscalls/bind.c",
+ "syscalls/cfgetispeed.c",
+ "syscalls/cfgetospeed.c",
+ "syscalls/cfsetspeed.c",
+ "syscalls/cfsetispeed.c",
+ "syscalls/cfsetospeed.c",
"syscalls/chdir.c",
"syscalls/chmod.c",
"syscalls/chown.c",
@@ -49,7 +60,6 @@
"syscalls/fsync.c",
"syscalls/ftruncate.c",
"syscalls/getcwd.c",
- "syscalls/getdents.c",
"syscalls/gethostbyname.c",
"syscalls/getpeername.c",
"syscalls/getsockname.c",
@@ -63,6 +73,7 @@
"syscalls/inet_ntop.cc",
"syscalls/ioctl.c",
"syscalls/isatty.c",
+ "syscalls/kill.c",
"syscalls/lchown.c",
"syscalls/link.c",
"syscalls/listen.c",
@@ -76,8 +87,11 @@
"syscalls/recvfrom.c",
"syscalls/recvmsg.c",
"syscalls/remove.c",
+ "syscalls/tcdrain.c",
+ "syscalls/tcflow.c",
"syscalls/tcflush.c",
"syscalls/tcgetattr.c",
+ "syscalls/tcsendbreak.c",
"syscalls/tcsetattr.c",
"syscalls/select.c",
"syscalls/send.c",
@@ -85,6 +99,8 @@
"syscalls/sendto.c",
"syscalls/setsockopt.c",
"syscalls/shutdown.c",
+ "syscalls/signal.c",
+ "syscalls/sigset.c",
"syscalls/socket.c",
"syscalls/socketpair.c",
"syscalls/unlink.c",
@@ -97,9 +113,10 @@
'HEADERS': [
{
'FILES': [
+ "dbgprint.h",
+ "error.h",
"event_emitter.h",
"event_listener.h",
- "error.h",
"host_resolver.h",
"inode_pool.h",
"ioctl.h",
@@ -109,9 +126,9 @@
"kernel_proxy.h",
"kernel_wrap.h",
"kernel_wrap_real.h",
- "mount.h",
"mount_dev.h",
"mount_factory.h",
+ "mount.h",
"mount_html5fs.h",
"mount_http.h",
"mount_mem.h",
@@ -121,12 +138,17 @@
"mount_node_html5fs.h",
"mount_node_http.h",
"mount_node_mem.h",
+ "mount_node_socket.h",
+ "mount_node_tcp.h",
"mount_node_tty.h",
+ "mount_node_udp.h",
"mount_passthrough.h",
+ "mount_socket.h",
"nacl_io.h",
"osdirent.h",
"osinttypes.h",
"osmman.h",
+ "ossignal.h",
"ossocket.h",
"osstat.h",
"ostime.h",
@@ -135,6 +157,8 @@
"osutime.h",
"ostermios.h",
"path.h",
+ "pepper_interface_delegate.h",
+ "pepper_interface_dummy.h",
"pepper_interface.h",
"real_pepper_interface.h",
"typed_mount_factory.h",
@@ -149,8 +173,10 @@
"netinet/tcp.h",
"netinet6/in6.h",
"poll.h",
+ "sys/ioctl.h",
"sys/mount.h",
"sys/select.h",
+ "sys/signal.h",
"sys/socket.h",
"sys/termios.h",
"sys/utsname.h",
@@ -165,8 +191,10 @@
"netinet/tcp.h",
"netinet6/in6.h",
"poll.h",
+ "sys/ioctl.h",
"sys/mount.h",
"sys/select.h",
+ "sys/signal.h",
"sys/socket.h",
"sys/termios.h",
"sys/utsname.h",
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 0394aff899..9d364d75fe 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_html5fs.cc
@@ -61,6 +61,11 @@ Error MountHtml5Fs::Mkdir(const Path& path, int permissions) {
if (error)
return error;
+ // FileRef returns PP_ERROR_NOACCESS which is translated to EACCES if you
+ // try to create the root directory. EEXIST is a better errno here.
+ if (path.Top())
+ return EEXIST;
+
ScopedResource fileref_resource(
ppapi(),
ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
@@ -138,7 +143,7 @@ Error MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
// 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();
+ bool main_thread = ppapi->GetCoreInterface()->IsMainThread();
PP_CompletionCallback cc =
main_thread ? PP_MakeCompletionCallback(
&MountHtml5Fs::FilesystemOpenCallbackThunk, this)
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 0116745ab4..4a0c0651d9 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
@@ -153,6 +153,8 @@ bool MountNode::IsaDir() { return (stat_.st_mode & S_IFDIR) != 0; }
bool MountNode::IsaFile() { return (stat_.st_mode & S_IFREG) != 0; }
+bool MountNode::IsaSock() { return (stat_.st_mode & S_IFSOCK) != 0; }
+
bool MountNode::IsaTTY() { return (stat_.st_mode & S_IFCHR) != 0; }
Error MountNode::AddChild(const std::string& name,
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 2afc88ba0d..661a194bfe 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.h
@@ -37,8 +37,8 @@ class MountNode : public EventListener {
virtual void Destroy();
public:
- // Declared in EventEmitter. defaults to signalled.
- virtual uint32_t GetEventStatus();
+ // Declared in EventEmitter. defaults to signalled.
+ virtual uint32_t GetEventStatus();
// Normal OS operations on a node (file), can be called by the kernel
// directly so it must lock and unlock appropriately. These functions
@@ -82,6 +82,7 @@ class MountNode : public EventListener {
virtual Error GetSize(size_t* out_size);
virtual bool IsaDir();
virtual bool IsaFile();
+ virtual bool IsaSock();
virtual bool IsaTTY();
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_char.h b/native_client_sdk/src/libraries/nacl_io/mount_node_char.h
index 48ad86fc65..ebb86166c4 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_char.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_char.h
@@ -14,6 +14,10 @@ class MountNodeCharDevice : public MountNode {
explicit MountNodeCharDevice(Mount* mount) : MountNode(mount) {
stat_.st_mode = S_IFCHR;
}
+
+ virtual uint32_t GetEventStatus() {
+ return 0;
+ }
};
}
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 09d957ad63..4d5b283060 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
@@ -70,7 +70,7 @@ int32_t ModeToOpenFlags(int mode) {
Error MountNodeHtml5Fs::FSync() {
// Cannot call Flush on a directory; simply do nothing.
- if (IsDirectory())
+ if (IsaDir())
return 0;
int32_t result = mount_->ppapi()->GetFileIoInterface()
@@ -95,7 +95,7 @@ Error MountNodeHtml5Fs::GetDents(size_t offs,
return EINVAL;
// If this is not a directory, fail
- if (!IsDirectory())
+ if (!IsaDir())
return ENOTDIR;
OutputBuffer output_buf = {NULL, 0};
@@ -121,20 +121,22 @@ Error MountNodeHtml5Fs::GetDents(size_t offs,
uint32_t 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.
-
- dirents.push_back(dirent());
- struct dirent& direntry = dirents.back();
- direntry.d_ino = 1; // Must be > 0.
- direntry.d_off = sizeof(struct dirent);
- direntry.d_reclen = sizeof(struct dirent);
- strncpy(direntry.d_name, file_name, file_name_length);
- direntry.d_name[file_name_length] = 0;
+ if (file_name) {
+ file_name_length = std::min(
+ static_cast<size_t>(file_name_length),
+ sizeof(static_cast<struct dirent*>(0)->d_name) - 1); // -1 for NULL.
+
+ dirents.push_back(dirent());
+ struct dirent& direntry = dirents.back();
+ direntry.d_ino = 1; // Must be > 0.
+ direntry.d_off = sizeof(struct dirent);
+ direntry.d_reclen = sizeof(struct dirent);
+ strncpy(direntry.d_name, file_name, file_name_length);
+ direntry.d_name[file_name_length] = 0;
+ }
+
+ mount_->ppapi()->GetVarInterface()->Release(file_name_var);
}
// Release the output buffer.
@@ -193,7 +195,7 @@ Error MountNodeHtml5Fs::Read(size_t offs,
int* out_bytes) {
*out_bytes = 0;
- if (IsDirectory())
+ if (IsaDir())
return EISDIR;
int32_t result =
@@ -210,7 +212,7 @@ Error MountNodeHtml5Fs::Read(size_t offs,
}
Error MountNodeHtml5Fs::FTruncate(off_t size) {
- if (IsDirectory())
+ if (IsaDir())
return EISDIR;
int32_t result = mount_->ppapi()->GetFileIoInterface()
@@ -226,7 +228,7 @@ Error MountNodeHtml5Fs::Write(size_t offs,
int* out_bytes) {
*out_bytes = 0;
- if (IsDirectory())
+ if (IsaDir())
return EISDIR;
int32_t result = mount_->ppapi()->GetFileIoInterface()
@@ -242,9 +244,16 @@ Error MountNodeHtml5Fs::Write(size_t offs,
return 0;
}
+int MountNodeHtml5Fs::GetType() {
+ return fileio_resource_ ? S_IFREG : S_IFDIR;
+}
+
Error MountNodeHtml5Fs::GetSize(size_t* out_size) {
*out_size = 0;
+ if (IsaDir())
+ return 0;
+
AUTO_LOCK(node_lock_);
PP_FileInfo info;
@@ -257,6 +266,14 @@ Error MountNodeHtml5Fs::GetSize(size_t* out_size) {
return 0;
}
+bool MountNodeHtml5Fs::IsaDir() {
+ return !fileio_resource_;
+}
+
+bool MountNodeHtml5Fs::IsaFile() {
+ return fileio_resource_;
+}
+
MountNodeHtml5Fs::MountNodeHtml5Fs(Mount* mount, PP_Resource fileref_resource)
: MountNode(mount),
fileref_resource_(fileref_resource),
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 57bc791c3f..6a4c0f59a6 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
@@ -30,7 +30,10 @@ class MountNodeHtml5Fs : public MountNode {
size_t count,
int* out_bytes);
+ virtual int GetType();
virtual Error GetSize(size_t *out_size);
+ virtual bool IsaDir();
+ virtual bool IsaFile();
protected:
MountNodeHtml5Fs(Mount* mount, PP_Resource fileref);
@@ -43,11 +46,6 @@ class MountNodeHtml5Fs : public MountNode {
PP_Resource fileref_resource_;
PP_Resource fileio_resource_; // 0 if the file is a directory.
- // Returns true if this node is a directory.
- bool IsDirectory() const {
- return !fileio_resource_;
- }
-
friend class MountHtml5Fs;
};
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc
new file mode 100644
index 0000000000..be524d51e7
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.cc
@@ -0,0 +1,263 @@
+// 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/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <errno.h>
+#include <string.h>
+
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_node_socket.h"
+#include "nacl_io/pepper_interface.h"
+
+#include "ppapi/c/pp_resource.h"
+#include "ppapi/c/ppb_net_address.h"
+
+namespace nacl_io {
+
+MountNodeSocket::MountNodeSocket(Mount* mount)
+ : MountNode(mount),
+ socket_resource_(0),
+ local_addr_(0),
+ remote_addr_(0) {
+ stat_.st_mode |= S_IFSOCK;
+}
+
+void MountNodeSocket::Destroy() {
+ if (socket_resource_)
+ mount_->ppapi()->ReleaseResource(socket_resource_);
+ if (local_addr_)
+ mount_->ppapi()->ReleaseResource(local_addr_);
+ if (remote_addr_)
+ mount_->ppapi()->ReleaseResource(remote_addr_);
+}
+
+// Default to always signaled, until socket select support is added.
+uint32_t MountNodeSocket::GetEventStatus() {
+ return POLLIN | POLLOUT;
+}
+
+// Assume that |addr| and |out_addr| are non-NULL.
+Error MountNodeSocket::MMap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ size_t offset,
+ void** out_addr) {
+ return EACCES;
+}
+
+// Normal read/write operations on a file
+Error MountNodeSocket::Read(size_t offs,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ return Recv(buf, count, 0, out_bytes);
+}
+
+Error MountNodeSocket::Write(size_t offs,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ if (0 == remote_addr_)
+ return EDESTADDRREQ;
+
+ return Send(buf, count, 0, out_bytes);
+}
+
+NetAddressInterface* MountNodeSocket::NetAddress() {
+ return mount_->ppapi()->GetNetAddressInterface();
+}
+
+PP_Resource MountNodeSocket::SockAddrToResource(const struct sockaddr* addr,
+ socklen_t len) {
+ if (AF_INET == addr->sa_family) {
+ PP_NetAddress_IPv4 addr4;
+ const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(addr);
+
+ if (len != sizeof(sockaddr_in))
+ return 0;
+
+ memset(&addr4, 0, sizeof(addr4));
+
+ addr4.port = sin->sin_port;
+ memcpy(addr4.addr, &sin->sin_addr, sizeof(addr4.addr));
+ return mount_->ppapi()->GetNetAddressInterface()->CreateFromIPv4Address(
+ mount_->ppapi()->GetInstance(), &addr4);
+ }
+
+ if (AF_INET6 == addr->sa_family) {
+ PP_NetAddress_IPv6 addr6;
+ const sockaddr_in6* sin = reinterpret_cast<const sockaddr_in6*>(addr);
+
+ if (len != sizeof(sockaddr_in6))
+ return 0;
+
+ memset(&addr6, 0, sizeof(addr6));
+
+ addr6.port = sin->sin6_port;
+ memcpy(addr6.addr, &sin->sin6_addr, sizeof(addr6.addr));
+ return mount_->ppapi()->GetNetAddressInterface()->CreateFromIPv6Address(
+ mount_->ppapi()->GetInstance(), &addr6);
+ }
+ return 0;
+}
+
+
+socklen_t MountNodeSocket::ResourceToSockAddr(PP_Resource addr,
+ socklen_t len,
+ struct sockaddr* out_addr) {
+ if (0 == addr)
+ return 0;
+
+ PP_NetAddress_IPv4 ipv4;
+ PP_NetAddress_IPv6 ipv6;
+
+ if (PP_TRUE == NetAddress()->DescribeAsIPv4Address(addr, &ipv4)) {
+ sockaddr_in addr4;
+ addr4.sin_family = AF_INET;
+ addr4.sin_port = ipv4.port;
+ memcpy(&addr4.sin_addr, ipv4.addr, sizeof(ipv4.addr));
+ memcpy(out_addr, &addr4, len);
+
+ // Returns required size not copied size like getpeername/getsockname.
+ return sizeof(sockaddr_in);
+ }
+
+ if (PP_TRUE == NetAddress()->DescribeAsIPv6Address(addr, &ipv6)) {
+ sockaddr_in6 addr6;
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = ipv6.port;
+ memcpy(&addr6.sin6_addr, ipv6.addr, sizeof(ipv6.addr));
+ memcpy(out_addr, &addr6, len);
+
+ // Returns required size not copied size like getpeername/getsockname.
+ return sizeof(sockaddr_in6);
+ }
+
+ return 0;
+}
+
+bool MountNodeSocket::IsEquivalentAddress(PP_Resource addr1,
+ PP_Resource addr2) {
+ if (addr1 == addr2)
+ return true;
+
+ char data1[sizeof(sockaddr_in6)];
+ char data2[sizeof(sockaddr_in6)];
+
+ sockaddr* saddr1 = reinterpret_cast<sockaddr*>(data1);
+ sockaddr* saddr2 = reinterpret_cast<sockaddr*>(data2);
+
+ socklen_t len1 = ResourceToSockAddr(addr1, sizeof(data1), saddr1);
+ socklen_t len2 = ResourceToSockAddr(addr2, sizeof(data2), saddr2);
+
+ if (len1 != len2)
+ return false;
+
+ return memcmp(saddr1, saddr2, len1) == 0;
+}
+
+
+Error MountNodeSocket::Accept(const struct sockaddr* addr, socklen_t len) {
+ return ENOSYS;
+}
+
+Error MountNodeSocket::Connect(const struct sockaddr* addr, socklen_t len) {
+ if (len < 1)
+ return EINVAL;
+
+ if (NULL == addr)
+ return EFAULT;
+
+ return EOPNOTSUPP;
+}
+
+Error MountNodeSocket::Listen(int backlog) {
+ return EOPNOTSUPP;
+}
+
+Error MountNodeSocket::GetSockOpt(int lvl,
+ int optname,
+ void* optval,
+ socklen_t* len) {
+ return EINVAL;
+}
+
+Error MountNodeSocket::SetSockOpt(int lvl,
+ int optname,
+ const void* optval,
+ socklen_t len) {
+ return EINVAL;
+}
+
+Error MountNodeSocket::Bind(const struct sockaddr* addr, socklen_t len) {
+ return EINVAL;
+}
+
+Error MountNodeSocket::Recv(void* buf, size_t len, int flags, int* out_len) {
+ return EINVAL;
+}
+
+Error MountNodeSocket::RecvFrom(void* buf,
+ size_t len,
+ int flags,
+ struct sockaddr* src_addr,
+ socklen_t* addrlen,
+ int* out_len) {
+ return EOPNOTSUPP;
+}
+
+Error MountNodeSocket::Send(const void* buf,
+ size_t len,
+ int flags,
+ int* out_len) {
+ return EOPNOTSUPP;
+}
+
+Error MountNodeSocket::SendTo(const void* buf,
+ size_t len,
+ int flags,
+ const struct sockaddr* dest_addr,
+ socklen_t addrlen,
+ int* out_len) {
+ return EOPNOTSUPP;
+}
+
+Error MountNodeSocket::Shutdown(int how) {
+ return EOPNOTSUPP;
+}
+
+
+Error MountNodeSocket::GetPeerName(struct sockaddr* addr, socklen_t* len) {
+ if (NULL == addr || NULL == len)
+ return EFAULT;
+
+ AUTO_LOCK(node_lock_);
+ if (remote_addr_ != 0) {
+ *len = ResourceToSockAddr(remote_addr_, *len, addr);
+ return 0;
+ }
+
+ return ENOTCONN;
+}
+
+Error MountNodeSocket::GetSockName(struct sockaddr* addr, socklen_t* len) {
+ if (NULL == addr || NULL == len)
+ return EFAULT;
+
+ AUTO_LOCK(node_lock_);
+ if (local_addr_ != 0) {
+ *len = ResourceToSockAddr(local_addr_, *len, addr);
+ return 0;
+ }
+
+ return ENOTCONN;
+}
+
+
+} // namespace nacl_io
+
+#endif // PROVIDES_SOCKET_API \ No newline at end of file
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h
new file mode 100644
index 0000000000..a133c19f4f
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_socket.h
@@ -0,0 +1,105 @@
+// 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_SOCKET_H_
+#define LIBRARIES_NACL_IO_MOUNT_NODE_SOCKET_H_
+
+#include "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <ppapi/c/pp_errors.h>
+#include <ppapi/c/pp_resource.h>
+#include <ppapi/c/ppb_net_address.h>
+
+#include "nacl_io/mount.h"
+#include "nacl_io/pepper_interface.h"
+
+namespace nacl_io {
+
+/* Only allow single maximum transfers of 64K or less. Socket users
+ * should be looping on Send/Recv size. */
+static const size_t MAX_SOCK_TRANSFER = 65536;
+
+class MountSocket;
+
+class MountNodeSocket : public MountNode {
+ public:
+ explicit MountNodeSocket(Mount* mount);
+
+ protected:
+ virtual void Destroy();
+ virtual Error Init(int flags) = 0;
+
+ public:
+ virtual uint32_t GetEventStatus();
+
+ // Normal read/write operations on a file (recv/send).
+ 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);
+
+ // Unsuported Functions
+ virtual Error Accept(const struct sockaddr* addr, socklen_t len);
+ virtual Error Listen(int backlog);
+ virtual Error GetSockOpt(int lvl, int optname, void* optval, socklen_t* len);
+ virtual Error SetSockOpt(int lvl,
+ int optname,
+ const void* optval,
+ socklen_t len);
+ virtual Error Shutdown(int how);
+ virtual Error MMap(void* addr,
+ size_t length,
+ int prot,
+ int flags,
+ size_t offset,
+ void** out_addr);
+
+ // Normal Functions.
+ virtual Error Bind(const struct sockaddr* addr, socklen_t len);
+ virtual Error Connect(const struct sockaddr* addr, socklen_t len);
+ virtual Error Recv(void* buf, size_t len, int flags, int* out_len);
+ virtual Error RecvFrom(void* buf,
+ size_t len,
+ int flags,
+ struct sockaddr* src_addr,
+ socklen_t* addrlen,
+ int* out_len);
+
+ virtual Error Send(const void* buf, size_t len, int flags, int* out_len);
+ virtual Error SendTo(const void* buf,
+ size_t len,
+ int flags,
+ const struct sockaddr* dest_addr,
+ socklen_t addrlen,
+ int* out_len);
+
+ virtual Error GetPeerName(struct sockaddr* addr, socklen_t* len);
+ virtual Error GetSockName(struct sockaddr* addr, socklen_t* len);
+
+ protected:
+ NetAddressInterface* NetAddress();
+ PP_Resource SockAddrToResource(const struct sockaddr* addr, socklen_t len);
+ socklen_t ResourceToSockAddr(PP_Resource addr,
+ socklen_t len,
+ struct sockaddr* out_addr);
+
+ bool IsEquivalentAddress(PP_Resource addr1, PP_Resource addr2);
+
+ protected:
+ PP_Resource socket_resource_;
+ PP_Resource local_addr_;
+ PP_Resource remote_addr_;
+
+ friend class KernelProxy;
+ friend class MountSocket;
+};
+
+
+} // namespace nacl_io
+
+
+#endif // PROVIDES_SOCKET_API
+#endif // LIBRARIES_NACL_IO_MOUNT_NODE_SOCKET_H_ \ No newline at end of file
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc
new file mode 100644
index 0000000000..5a5f9f12e1
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.cc
@@ -0,0 +1,146 @@
+// 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/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <errno.h>
+#include <string.h>
+#include <algorithm>
+
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_node_socket.h"
+#include "nacl_io/mount_node_tcp.h"
+#include "nacl_io/pepper_interface.h"
+
+namespace nacl_io {
+
+MountNodeTCP::MountNodeTCP(Mount* mount) : MountNodeSocket(mount) {}
+
+
+TCPSocketInterface* MountNodeTCP::TCPSocket() {
+ if (mount_->ppapi() == NULL)
+ return NULL;
+
+ return mount_->ppapi()->GetTCPSocketInterface();
+}
+
+Error MountNodeTCP::Init(int flags) {
+ if (TCPSocket() == NULL)
+ return EACCES;
+
+ socket_resource_ = TCPSocket()->Create(mount_->ppapi()->GetInstance());
+ if (0 == socket_resource_)
+ return EACCES;
+
+ return 0;
+}
+
+Error MountNodeTCP::Bind(const struct sockaddr* addr, socklen_t len) {
+ AUTO_LOCK(node_lock_);
+
+ if (0 == socket_resource_)
+ return EBADF;
+
+ /* Only bind once. */
+ if (local_addr_ != 0)
+ return EINVAL;
+
+ /* Lie, we won't know until we connect. */
+ return 0;
+}
+
+Error MountNodeTCP::Connect(const struct sockaddr* addr, socklen_t len) {
+ AUTO_LOCK(node_lock_);
+
+ if (0 == socket_resource_)
+ return EBADF;
+
+ if (remote_addr_ != 0)
+ return EISCONN;
+
+ remote_addr_ = SockAddrToResource(addr, len);
+ if (0 == remote_addr_)
+ return EINVAL;
+
+ int err = TCPSocket()->Connect(socket_resource_,
+ remote_addr_,
+ PP_BlockUntilComplete());
+
+ // If we fail, release the dest addr resource
+ if (err != PP_OK) {
+ mount_->ppapi()->ReleaseResource(remote_addr_);
+ remote_addr_ = 0;
+ return PPErrorToErrno(err);
+ }
+
+ local_addr_ = TCPSocket()->GetLocalAddress(socket_resource_);
+ mount_->ppapi()->AddRefResource(local_addr_);
+ return 0;
+}
+
+Error MountNodeTCP::Recv(void* buf, size_t len, int flags, int* out_len) {
+ AUTO_LOCK(node_lock_);
+ if (0 == socket_resource_)
+ return EBADF;
+
+ int capped_len = static_cast<int32_t>(std::min(len, MAX_SOCK_TRANSFER));
+ int err = TCPSocket()->Read(socket_resource_,
+ static_cast<char*>(buf),
+ capped_len,
+ PP_BlockUntilComplete());
+ if (err < 0)
+ return PPErrorToErrno(err);
+
+ *out_len = err;
+ return 0;
+}
+
+Error MountNodeTCP::RecvFrom(void* buf,
+ size_t len,
+ int flags,
+ struct sockaddr* src_addr,
+ socklen_t* addrlen,
+ int* out_len) {
+ Error err = Recv(buf, len, flags, out_len);
+ if (err == 0)
+ GetPeerName(src_addr, addrlen);
+ return err;
+}
+
+
+Error MountNodeTCP::Send(const void* buf, size_t len, int flags, int* out_len) {
+ AUTO_LOCK(node_lock_);
+
+ if (0 == socket_resource_)
+ return EBADF;
+
+ if (0 == remote_addr_)
+ return ENOTCONN;
+
+ int capped_len = static_cast<int32_t>(std::min(len, MAX_SOCK_TRANSFER));
+ int err = TCPSocket()->Write(socket_resource_,
+ static_cast<const char*>(buf),
+ capped_len,
+ PP_BlockUntilComplete());
+ if (err < 0)
+ return PPErrorToErrno(err);
+
+ *out_len = err;
+ return 0;
+}
+
+Error MountNodeTCP::SendTo(const void* buf,
+ size_t len,
+ int flags,
+ const struct sockaddr* dest_addr,
+ socklen_t addrlen,
+ int* out_len) {
+ return Send(buf, len, flags, out_len);
+}
+
+} // namespace nacl_io
+
+#endif // PROVIDES_SOCKET_API \ No newline at end of file
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h
new file mode 100644
index 0000000000..860e93bba1
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tcp.h
@@ -0,0 +1,52 @@
+// 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_TCP_H_
+#define LIBRARIES_NACL_IO_MOUNT_NODE_TCP_H_
+
+#include "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <ppapi/c/pp_resource.h>
+#include <ppapi/c/ppb_tcp_socket.h>
+
+#include "nacl_io/mount_node.h"
+#include "nacl_io/mount_node_socket.h"
+
+namespace nacl_io {
+
+class MountNodeTCP : public MountNodeSocket {
+ public:
+ explicit MountNodeTCP(Mount* mount);
+
+ virtual Error Init(int flags);
+
+ virtual Error Bind(const struct sockaddr* addr, socklen_t len);
+ virtual Error Connect(const struct sockaddr* addr, socklen_t len);
+
+ virtual Error Recv(void* buf, size_t len, int flags, int* out_len);
+ virtual Error RecvFrom(void* buf,
+ size_t len,
+ int flags,
+ struct sockaddr* src_addr,
+ socklen_t* addrlen,
+ int* out_len);
+
+ virtual Error Send(const void* buf, size_t len, int flags, int* out_len);
+ virtual Error SendTo(const void* buf,
+ size_t len,
+ int flags,
+ const struct sockaddr* dest_addr,
+ socklen_t addrlen,
+ int* out_len);
+
+ protected:
+ TCPSocketInterface* TCPSocket();
+};
+
+
+} // namespace nacl_io
+
+#endif // PROVIDES_SOCKET_API
+#endif // LIBRARIES_NACL_IO_MOUNT_NODE_TCP_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc
index 7b9fb7943a..534e53a28d 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.cc
@@ -6,8 +6,11 @@
#include <assert.h>
#include <errno.h>
+#include <signal.h>
#include <stdio.h>
#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
#include <algorithm>
@@ -24,10 +27,17 @@
#define IS_ECHOCTL CHECK_LFLAG(termios_, ECHOCTL)
#define IS_ICANON CHECK_LFLAG(termios_, ICANON)
+#define DEFAULT_TTY_COLS 80
+#define DEFAULT_TTY_ROWS 30
+
namespace nacl_io {
MountNodeTty::MountNodeTty(Mount* mount) : MountNodeCharDevice(mount),
- is_readable_(false) {
+ is_readable_(false),
+ did_resize_(false),
+ rows_(DEFAULT_TTY_ROWS),
+ cols_(DEFAULT_TTY_COLS) {
+ output_handler_.handler = NULL;
pthread_cond_init(&is_readable_cond_, NULL);
InitTermios();
}
@@ -68,49 +78,37 @@ Error MountNodeTty::Write(size_t offs,
const void* buf,
size_t count,
int* out_bytes) {
- return Write(offs, buf, count, out_bytes, false);
-}
-
-Error MountNodeTty::Write(size_t offs,
- const void* buf,
- size_t count,
- int* out_bytes,
- bool locked) {
+ AUTO_LOCK(output_lock_);
*out_bytes = 0;
- if (!mount_->ppapi())
- return ENOSYS;
+ // No handler registered.
+ if (output_handler_.handler == NULL)
+ return EIO;
- MessagingInterface* msg_intr = mount_->ppapi()->GetMessagingInterface();
- VarInterface* var_intr = mount_->ppapi()->GetVarInterface();
+ int rtn = output_handler_.handler(static_cast<const char*>(buf),
+ count,
+ output_handler_.user_data);
- if (!(var_intr && msg_intr))
- return ENOSYS;
+ // Negative return value means an error occured and the return
+ // value is a negated errno value.
+ if (rtn < 0)
+ return -rtn;
- // We append the prefix_ to the data in buf, then package it up
- // and post it as a message.
- const char* data = static_cast<const char*>(buf);
- std::string message;
- if (locked) {
- message = prefix_;
- } else {
- AUTO_LOCK(node_lock_);
- message = prefix_;
- }
-
- message.append(data, count);
- uint32_t len = static_cast<uint32_t>(message.size());
- struct PP_Var val = var_intr->VarFromUtf8(message.data(), len);
- msg_intr->PostMessage(mount_->ppapi()->GetInstance(), val);
- var_intr->Release(val);
- *out_bytes = count;
+ *out_bytes = rtn;
return 0;
}
Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
AUTO_LOCK(node_lock_);
+ did_resize_ = false;
while (!is_readable_) {
pthread_cond_wait(&is_readable_cond_, node_lock_.mutex());
+ if (!is_readable_ && did_resize_) {
+ // If an async resize event occured then return the failure and
+ // set EINTR.
+ *out_bytes = 0;
+ return EINTR;
+ }
}
size_t bytes_to_copy = std::min(count, input_buffer_.size());
@@ -151,7 +149,7 @@ Error MountNodeTty::Read(size_t offs, void* buf, size_t count, int* out_bytes) {
Error MountNodeTty::Echo(const char* string, int count) {
int wrote;
- Error error = Write(0, string, count, &wrote, true);
+ Error error = Write(0, string, count, &wrote);
if (error != 0 || wrote != count) {
// TOOD(sbc): Do something more useful in response to a
// failure to echo.
@@ -163,15 +161,11 @@ Error MountNodeTty::Echo(const char* string, int count) {
Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) {
AUTO_LOCK(node_lock_);
- if (message->length < prefix_.size() ||
- strncmp(message->buffer, prefix_.data(), prefix_.size()) != 0) {
- return ENOTTY;
- }
- const char* buffer = message->buffer + prefix_.size();
- int num_bytes = message->length - prefix_.size();
+ const char* buffer = message->buffer;
+ size_t num_bytes = message->length;
- for (int i = 0; i < num_bytes; i++) {
+ for (size_t i = 0; i < num_bytes; i++) {
char c = buffer[i];
// Transform characters according to input flags.
if (c == '\r') {
@@ -229,30 +223,60 @@ Error MountNodeTty::ProcessInput(struct tioc_nacl_input_string* message) {
is_readable_ = true;
}
- if (is_readable_)
+ if (is_readable_) {
+ RaiseEvent(POLLIN);
pthread_cond_broadcast(&is_readable_cond_);
+ }
+
return 0;
}
Error MountNodeTty::Ioctl(int request, char* arg) {
- if (request == TIOCNACLPREFIX) {
- // This ioctl is used to change the prefix for this tty node.
- // The prefix is used to distinguish messages intended for this
- // tty node from all the other messages cluttering up the
- // javascript postMessage() channel.
- AUTO_LOCK(node_lock_);
- prefix_ = arg;
- return 0;
- } else if (request == TIOCNACLINPUT) {
- // This ioctl is used to deliver data from the user to this tty node's
- // input buffer. We check if the prefix in the input data matches the
- // prefix for this node, and only deliver the data if so.
- struct tioc_nacl_input_string* message =
- reinterpret_cast<struct tioc_nacl_input_string*>(arg);
- return ProcessInput(message);
- } else {
- return EINVAL;
+ switch (request) {
+ case TIOCNACLOUTPUT: {
+ AUTO_LOCK(output_lock_);
+ if (arg == NULL) {
+ output_handler_.handler = NULL;
+ return 0;
+ }
+ if (output_handler_.handler != NULL)
+ return EALREADY;
+ output_handler_ = *reinterpret_cast<tioc_nacl_output*>(arg);
+ return 0;
+ }
+ case TIOCNACLINPUT: {
+ // This ioctl is used to deliver data from the user to this tty node's
+ // input buffer.
+ struct tioc_nacl_input_string* message =
+ reinterpret_cast<struct tioc_nacl_input_string*>(arg);
+ return ProcessInput(message);
+ }
+ case TIOCSWINSZ: {
+ struct winsize* size = reinterpret_cast<struct winsize*>(arg);
+ {
+ AUTO_LOCK(node_lock_);
+ rows_ = size->ws_row;
+ cols_ = size->ws_col;
+ }
+ kill(getpid(), SIGWINCH);
+
+ // Wake up any thread waiting on Read
+ {
+ AUTO_LOCK(node_lock_);
+ did_resize_ = true;
+ pthread_cond_broadcast(&is_readable_cond_);
+ }
+ return 0;
+ }
+ case TIOCGWINSZ: {
+ struct winsize* size = reinterpret_cast<struct winsize*>(arg);
+ size->ws_row = rows_;
+ size->ws_col = cols_;
+ return 0;
+ }
}
+
+ return EINVAL;
}
Error MountNodeTty::Tcgetattr(struct termios* termios_p) {
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h
index 0707420a0c..8bf5b17304 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_tty.h
@@ -5,6 +5,7 @@
#ifndef LIBRARIES_NACL_IO_MOUNT_NODE_TTY_H_
#define LIBRARIES_NACL_IO_MOUNT_NODE_TTY_H_
+#include <poll.h>
#include <pthread.h>
#include <deque>
@@ -38,21 +39,34 @@ class MountNodeTty : public MountNodeCharDevice {
virtual Error Tcsetattr(int optional_actions,
const struct termios *termios_p);
+ virtual uint32_t GetEventStatus() {
+ uint32_t status = POLLOUT;
+ if (is_readable_)
+ status |= POLLIN;
+ return status;
+ }
+
private:
- virtual Error Write(size_t offs,
- const void* buf,
- size_t count,
- int* out_bytes,
- bool locked);
Error ProcessInput(struct tioc_nacl_input_string* message);
Error Echo(const char* string, int count);
void InitTermios();
std::deque<char> input_buffer_;
bool is_readable_;
+ bool did_resize_;
pthread_cond_t is_readable_cond_;
- std::string prefix_;
struct termios termios_;
+
+ /// Current height of terminal in rows. Set via ioctl(2).
+ int rows_;
+ /// Current width of terminal in columns. Set via ioctl(2).
+ int cols_;
+
+ // Output handler for TTY. This is set via ioctl(2).
+ struct tioc_nacl_output output_handler_;
+ // Lock to protect output_handler_. This lock gets aquired whenever
+ // output_handler_ is used or set.
+ sdk_util::SimpleLock output_lock_;
};
}
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_udp.cc b/native_client_sdk/src/libraries/nacl_io/mount_node_udp.cc
new file mode 100644
index 0000000000..310a2bdf06
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_udp.cc
@@ -0,0 +1,188 @@
+// 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/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <errno.h>
+#include <string.h>
+#include <algorithm>
+
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_node_socket.h"
+#include "nacl_io/mount_node_udp.h"
+#include "nacl_io/pepper_interface.h"
+
+namespace nacl_io {
+
+MountNodeUDP::MountNodeUDP(Mount* mount) : MountNodeSocket(mount) {}
+
+
+UDPSocketInterface* MountNodeUDP::UDPSocket() {
+ if (mount_->ppapi() == NULL)
+ return NULL;
+
+ return mount_->ppapi()->GetUDPSocketInterface();
+}
+
+Error MountNodeUDP::Init(int flags) {
+ if (UDPSocket() == NULL)
+ return EACCES;
+
+ socket_resource_ = UDPSocket()->Create(mount_->ppapi()->GetInstance());
+ if (0 == socket_resource_)
+ return EACCES;
+
+ return 0;
+}
+
+Error MountNodeUDP::Bind(const struct sockaddr* addr, socklen_t len) {
+ if (0 == socket_resource_)
+ return EBADF;
+
+ /* Only bind once. */
+ if (local_addr_ != 0)
+ return EINVAL;
+
+ PP_Resource out_addr = SockAddrToResource(addr, len);
+ if (0 == out_addr)
+ return EINVAL;
+
+ int err = UDPSocket()->Bind(socket_resource_,
+ out_addr,
+ PP_BlockUntilComplete());
+ if (err != 0) {
+ mount_->ppapi()->ReleaseResource(out_addr);
+ return PPErrorToErrno(err);
+ }
+
+ local_addr_ = out_addr;
+ return 0;
+}
+
+Error MountNodeUDP::Connect(const struct sockaddr* addr, socklen_t len) {
+ if (0 == socket_resource_)
+ return EBADF;
+
+ /* Connect for UDP is the default dest, it's legal to change it. */
+ if (remote_addr_ != 0) {
+ mount_->ppapi()->ReleaseResource(remote_addr_);
+ remote_addr_ = 0;
+ }
+
+ remote_addr_ = SockAddrToResource(addr, len);
+ if (0 == remote_addr_)
+ return EINVAL;
+
+ return 0;
+}
+
+Error MountNodeUDP::RecvFromHelper(void* buf,
+ size_t len,
+ int flags,
+ PP_Resource* out_addr,
+ int* out_len) {
+ if (0 == socket_resource_)
+ return EBADF;
+
+ int capped_len = static_cast<int32_t>(std::min(len, MAX_SOCK_TRANSFER));
+ int err = UDPSocket()->RecvFrom(socket_resource_,
+ static_cast<char*>(buf),
+ capped_len,
+ out_addr,
+ PP_BlockUntilComplete());
+ if (err < 0)
+ return PPErrorToErrno(err);
+
+ *out_len = err;
+ return 0;
+}
+
+Error MountNodeUDP::Recv(void* buf, size_t len, int flags, int* out_len) {
+ while (1) {
+ int local_len = 0;
+ PP_Resource addr = 0;
+
+ int err = RecvFromHelper(buf, len, flags, &addr, &local_len);
+ if (err < 0)
+ return PPErrorToErrno(err);
+
+ /* If "connected" then only receive packets from the given remote. */
+ bool same = IsEquivalentAddress(addr, remote_addr_);
+ mount_->ppapi()->ReleaseResource(addr);
+
+ if (remote_addr_ != 0 && same)
+ continue;
+
+ *out_len = local_len;
+ return 0;
+ }
+}
+
+Error MountNodeUDP::RecvFrom(void* buf,
+ size_t len,
+ int flags,
+ struct sockaddr* src_addr,
+ socklen_t* addrlen,
+ int* out_len) {
+ PP_Resource addr = 0;
+ int err = RecvFromHelper(buf, len, flags, &addr, out_len);
+ if (err < 0)
+ return PPErrorToErrno(err);
+
+ if (src_addr)
+ *addrlen = ResourceToSockAddr(addr, *addrlen, src_addr);
+
+ mount_->ppapi()->ReleaseResource(addr);
+ return 0;
+}
+
+
+Error MountNodeUDP::SendToHelper(const void* buf,
+ size_t len,
+ int flags,
+ PP_Resource addr,
+ int* out_len) {
+ if (0 == socket_resource_)
+ return EBADF;
+
+ if (0 == addr)
+ return ENOTCONN;
+
+ int capped_len = static_cast<int32_t>(std::min(len, MAX_SOCK_TRANSFER));
+ int err = UDPSocket()->SendTo(socket_resource_,
+ static_cast<const char*>(buf),
+ capped_len,
+ addr,
+ PP_BlockUntilComplete());
+ if (err < 0)
+ return PPErrorToErrno(err);
+
+ *out_len = err;
+ return 0;
+}
+
+Error MountNodeUDP::Send(const void* buf, size_t len, int flags, int* out_len) {
+ return SendToHelper(buf, len, flags, remote_addr_, out_len);
+}
+
+Error MountNodeUDP::SendTo(const void* buf,
+ size_t len,
+ int flags,
+ const struct sockaddr* dest_addr,
+ socklen_t addrlen,
+ int* out_len) {
+ PP_Resource out_addr = SockAddrToResource(dest_addr, addrlen);
+ if (0 == out_addr)
+ return EINVAL;
+
+ Error err = SendToHelper(buf, len, flags, out_addr, out_len);
+ mount_->ppapi()->ReleaseResource(out_addr);
+ return err;
+}
+
+} // namespace nacl_io
+
+#endif // PROVIDES_SOCKET_API \ No newline at end of file
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node_udp.h b/native_client_sdk/src/libraries/nacl_io/mount_node_udp.h
new file mode 100644
index 0000000000..ac095f1760
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node_udp.h
@@ -0,0 +1,64 @@
+// 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_UDP_H_
+#define LIBRARIES_NACL_IO_MOUNT_NODE_UDP_H_
+
+#include "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <ppapi/c/pp_resource.h>
+#include <ppapi/c/ppb_udp_socket.h>
+
+#include "nacl_io/mount_node.h"
+#include "nacl_io/mount_node_socket.h"
+
+namespace nacl_io {
+
+class MountNodeUDP : public MountNodeSocket {
+ public:
+ explicit MountNodeUDP(Mount* mount);
+
+ virtual Error Init(int flags);
+
+ virtual Error Bind(const struct sockaddr* addr, socklen_t len);
+ virtual Error Connect(const struct sockaddr* addr, socklen_t len);
+
+ virtual Error Recv(void* buf, size_t len, int flags, int* out_len);
+ virtual Error RecvFrom(void* buf,
+ size_t len,
+ int flags,
+ struct sockaddr* src_addr,
+ socklen_t* addrlen,
+ int* out_len);
+
+ virtual Error Send(const void* buf, size_t len, int flags, int* out_len);
+ virtual Error SendTo(const void* buf,
+ size_t len,
+ int flags,
+ const struct sockaddr* dest_addr,
+ socklen_t addrlen,
+ int* out_len);
+
+ protected:
+ UDPSocketInterface* UDPSocket();
+
+ Error RecvFromHelper(void* buf,
+ size_t len,
+ int flags,
+ PP_Resource* addr,
+ int* out_len);
+
+ Error SendToHelper(const void* buf,
+ size_t len,
+ int flags,
+ PP_Resource dest_addr,
+ int* out_len);
+};
+
+
+} // namespace nacl_io
+
+#endif // PROVIDES_SOCKET_API
+#endif // LIBRARIES_NACL_IO_MOUNT_NODE_UDP_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_socket.cc b/native_client_sdk/src/libraries/nacl_io/mount_socket.cc
new file mode 100644
index 0000000000..141c930d5d
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_socket.cc
@@ -0,0 +1,28 @@
+// 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/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include <errno.h>
+
+#include "nacl_io/mount_node_socket.h"
+#include "nacl_io/mount_socket.h"
+
+namespace nacl_io {
+
+MountSocket::MountSocket() {}
+
+Error MountSocket::Access(const Path& path, int a_mode) { return EACCES; }
+Error MountSocket::Open(const Path& path,
+ int o_flags,
+ ScopedMountNode* out_node) { return EACCES; }
+
+Error MountSocket::Unlink(const Path& path) { return EACCES; }
+Error MountSocket::Mkdir(const Path& path, int permissions) { return EACCES; }
+Error MountSocket::Rmdir(const Path& path) { return EACCES; }
+Error MountSocket::Remove(const Path& path) { return EACCES; }
+
+} // namespace nacl_io
+#endif // PROVIDES_SOCKET_API \ No newline at end of file
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_socket.h b/native_client_sdk/src/libraries/nacl_io/mount_socket.h
new file mode 100644
index 0000000000..f235232c94
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/mount_socket.h
@@ -0,0 +1,37 @@
+// 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_SOCKET_H_
+#define LIBRARIES_NACL_IO_MOUNT_SOCKET_H_
+
+#include "nacl_io/ossocket.h"
+#ifdef PROVIDES_SOCKET_API
+
+#include "nacl_io/mount.h"
+
+namespace nacl_io {
+
+class MountSocket : public Mount {
+ protected:
+ MountSocket();
+
+ private:
+ virtual Error Access(const Path& path, int a_mode);
+ virtual Error Open(const Path& path,
+ int o_flags,
+ ScopedMountNode* 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);
+
+ private:
+ friend class KernelProxy;
+ DISALLOW_COPY_AND_ASSIGN(MountSocket);
+};
+
+} // namespace nacl_io
+
+#endif // PROVIDES_SOCKET_API
+#endif // LIBRARIES_NACL_IO_MOUNT_SOCKET_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/nacl_io.h b/native_client_sdk/src/libraries/nacl_io/nacl_io.h
index 058ba68c70..452221951c 100644
--- a/native_client_sdk/src/libraries/nacl_io/nacl_io.h
+++ b/native_client_sdk/src/libraries/nacl_io/nacl_io.h
@@ -89,7 +89,7 @@ void nacl_io_init_ppapi(PP_Instance instance,
* "foo/bar.txt" will attempt to read from the URL
* "http://example.com/path/foo/bar.txt".
* data: A string of parameters:
- * "allow_cross_origin_request": If "true", then reads from this
+ * "allow_cross_origin_requests": If "true", then reads from this
* filesystem will follow the CORS standard for cross-origin requests.
* See http://www.w3.org/TR/access-control.
* "allow_credentials": If "true", credentials are sent with cross-origin
diff --git a/native_client_sdk/src/libraries/nacl_io/ossignal.h b/native_client_sdk/src/libraries/nacl_io/ossignal.h
new file mode 100644
index 0000000000..3ce00718e4
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/ossignal.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_OSSIGNAL_H_
+#define LIBRARIES_NACL_IO_OSSIGNAL_H_
+
+#ifdef __native_client__
+#include <signal.h>
+#ifdef __GLIBC__
+typedef __sighandler_t sighandler_t;
+#else
+typedef _sig_func_ptr sighandler_t;
+#endif
+#endif
+
+#endif
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h b/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
index 1f2e1bfa95..f1fae29854 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
@@ -19,9 +19,15 @@
*/
BEGIN_INTERFACE(ConsoleInterface, PPB_Console, PPB_CONSOLE_INTERFACE_1_0)
- METHOD3(ConsoleInterface, void, Log, PP_Instance, PP_LogLevel, struct PP_Var)
+ METHOD3(ConsoleInterface, void, Log, PP_Instance, PP_LogLevel, PP_Var)
END_INTERFACE(ConsoleInterface, PPB_Console)
+BEGIN_INTERFACE(CoreInterface, PPB_Core, PPB_CORE_INTERFACE_1_0)
+ METHOD1(CoreInterface, void, AddRefResource, PP_Resource)
+ METHOD1(CoreInterface, void, ReleaseResource, PP_Resource)
+ METHOD0(CoreInterface, PP_Bool, IsMainThread)
+END_INTERFACE(CoreInterface, PPB_Core)
+
BEGIN_INTERFACE(FileIoInterface, PPB_FileIO, PPB_FILEIO_INTERFACE_1_0)
METHOD1(FileIoInterface, void, Close, PP_Resource)
METHOD1(FileIoInterface, PP_Resource, Create, PP_Resource)
@@ -60,12 +66,13 @@ BEGIN_INTERFACE(FileSystemInterface, PPB_FileSystem,
END_INTERFACE(FileSystemInterface, PPB_FileSystem)
BEGIN_INTERFACE(MessagingInterface, PPB_Messaging, PPB_MESSAGING_INTERFACE_1_0)
- METHOD2(MessagingInterface, void, PostMessage, PP_Instance, struct PP_Var)
+ METHOD2(MessagingInterface, void, PostMessage, PP_Instance, PP_Var)
END_INTERFACE(MessagingInterface, PPB_Messaging)
BEGIN_INTERFACE(VarInterface, PPB_Var, PPB_VAR_INTERFACE_1_1)
- METHOD1(VarInterface, void, Release, struct PP_Var)
- METHOD2(VarInterface, struct PP_Var, VarFromUtf8, const char *, uint32_t)
+ METHOD1(VarInterface, void, AddRef, PP_Var)
+ METHOD1(VarInterface, void, Release, PP_Var)
+ METHOD2(VarInterface, PP_Var, VarFromUtf8, const char *, uint32_t)
METHOD2(VarInterface, const char*, VarToUtf8, PP_Var, uint32_t*)
END_INTERFACE(VarInterface, PPB_Var)
@@ -83,6 +90,10 @@ END_INTERFACE(HostResolverInterface, PPB_HostResolver)
BEGIN_INTERFACE(NetAddressInterface, PPB_NetAddress,
PPB_NETADDRESS_INTERFACE_1_0)
+ METHOD2(NetAddressInterface, PP_Resource, CreateFromIPv4Address,
+ PP_Instance, PP_NetAddress_IPv4*)
+ METHOD2(NetAddressInterface, PP_Resource, CreateFromIPv6Address,
+ PP_Instance, PP_NetAddress_IPv6*)
METHOD1(NetAddressInterface, PP_Bool, IsNetAddress, PP_Resource)
METHOD1(NetAddressInterface, PP_NetAddress_Family, GetFamily, PP_Resource)
METHOD2(NetAddressInterface, PP_Bool, DescribeAsIPv4Address, PP_Resource,
@@ -113,3 +124,36 @@ BEGIN_INTERFACE(URLResponseInfoInterface, PPB_URLResponseInfo,
METHOD2(URLResponseInfoInterface, PP_Var, GetProperty, PP_Resource,
PP_URLResponseProperty)
END_INTERFACE(URLResponseInfoInterface, PPB_URLResponseInfo)
+
+BEGIN_INTERFACE(TCPSocketInterface, PPB_TCPSocket,
+ PPB_TCPSOCKET_INTERFACE_1_0)
+ METHOD1(TCPSocketInterface, PP_Resource, Create, PP_Instance)
+ METHOD1(TCPSocketInterface, PP_Bool, IsTCPSocket, PP_Resource)
+ METHOD3(TCPSocketInterface, int32_t, Connect, PP_Resource, PP_Resource,
+ PP_CompletionCallback)
+ METHOD1(TCPSocketInterface, PP_Resource, GetLocalAddress, PP_Resource)
+ METHOD1(TCPSocketInterface, PP_Resource, GetRemoteAddress, PP_Resource)
+ METHOD4(TCPSocketInterface, int32_t, Read, PP_Resource, char*, int32_t,
+ PP_CompletionCallback)
+ METHOD4(TCPSocketInterface, int32_t, Write, PP_Resource, const char*,
+ int32_t, PP_CompletionCallback)
+ METHOD1(TCPSocketInterface, void, Close, PP_Resource)
+ METHOD4(TCPSocketInterface, int32_t, SetOption, PP_Resource,
+ PP_TCPSocket_Option, PP_Var, PP_CompletionCallback)
+END_INTERFACE(TCPSocketInterface, PPB_TCPSocket)
+
+BEGIN_INTERFACE(UDPSocketInterface, PPB_UDPSocket,
+ PPB_UDPSOCKET_INTERFACE_1_0)
+ METHOD1(UDPSocketInterface, PP_Resource, Create, PP_Instance)
+ METHOD1(UDPSocketInterface, PP_Bool, IsUDPSocket, PP_Resource)
+ METHOD3(UDPSocketInterface, int32_t, Bind, PP_Resource, PP_Resource,
+ PP_CompletionCallback)
+ METHOD1(UDPSocketInterface, PP_Resource, GetBoundAddress, PP_Resource)
+ METHOD5(UDPSocketInterface, int32_t, RecvFrom, PP_Resource, char*, int32_t,
+ PP_Resource*, PP_CompletionCallback)
+ METHOD5(UDPSocketInterface, int32_t, SendTo, PP_Resource, const char*,
+ int32_t, PP_Resource, PP_CompletionCallback)
+ METHOD1(UDPSocketInterface, void, Close, PP_Resource)
+ METHOD4(UDPSocketInterface, int32_t, SetOption, PP_Resource,
+ PP_UDPSocket_Option, PP_Var, PP_CompletionCallback)
+END_INTERFACE(UDPSocketInterface, PPB_UDPSocket)
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper/define_empty_macros.h b/native_client_sdk/src/libraries/nacl_io/pepper/define_empty_macros.h
index 4fb479e48e..492730d843 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper/define_empty_macros.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper/define_empty_macros.h
@@ -4,6 +4,7 @@
#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString)
#define END_INTERFACE(BaseClass, PPInterface)
+#define METHOD0(Class, ReturnType, MethodName)
#define METHOD1(Class, ReturnType, MethodName, Type0)
#define METHOD2(Class, ReturnType, MethodName, Type0, Type1)
#define METHOD3(Class, ReturnType, MethodName, Type0, Type1, Type2)
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper/undef_macros.h b/native_client_sdk/src/libraries/nacl_io/pepper/undef_macros.h
index d1b8f50c77..848d4b3ef7 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper/undef_macros.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper/undef_macros.h
@@ -4,6 +4,7 @@
#undef BEGIN_INTERFACE
#undef END_INTERFACE
+#undef METHOD0
#undef METHOD1
#undef METHOD2
#undef METHOD3
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface.cc b/native_client_sdk/src/libraries/nacl_io/pepper_interface.cc
index e97c8198a4..84e8305fb7 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper_interface.cc
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface.cc
@@ -8,6 +8,14 @@
namespace nacl_io {
+void PepperInterface::AddRefResource(PP_Resource resource) {
+ GetCoreInterface()->AddRefResource(resource);
+}
+
+void PepperInterface::ReleaseResource(PP_Resource resource) {
+ GetCoreInterface()->ReleaseResource(resource);
+}
+
ScopedResource::ScopedResource(PepperInterface* ppapi, PP_Resource resource)
: ppapi_(ppapi),
resource_(resource) {
@@ -25,8 +33,11 @@ PP_Resource ScopedResource::Release() {
}
int PPErrorToErrno(int32_t err) {
+ // If not an error, then just return it.
+ if (err >= PP_OK)
+ return err;
+
switch (err) {
- case PP_OK: return 0;
case PP_OK_COMPLETIONPENDING: return 0;
case PP_ERROR_FAILED: return EPERM;
case PP_ERROR_ABORTED: return EPERM;
@@ -50,6 +61,12 @@ int PPErrorToErrno(int32_t err) {
case PP_ERROR_CONTEXT_LOST: return EPERM;
case PP_ERROR_NO_MESSAGE_LOOP: return EPERM;
case PP_ERROR_WRONG_THREAD: return EPERM;
+ case PP_ERROR_CONNECTION_ABORTED: return ECONNABORTED;
+ case PP_ERROR_CONNECTION_REFUSED: return ECONNREFUSED;
+ case PP_ERROR_CONNECTION_FAILED: return ECONNREFUSED;
+ case PP_ERROR_CONNECTION_TIMEDOUT: return ETIMEDOUT;
+ case PP_ERROR_ADDRESS_UNREACHABLE: return ENETUNREACH;
+ case PP_ERROR_ADDRESS_IN_USE: return EADDRINUSE;
}
return EINVAL;
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface.h b/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
index 6ffe1e68a4..ac8f6baa24 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
@@ -13,6 +13,7 @@
#include <ppapi/c/pp_resource.h>
#include <ppapi/c/pp_var.h>
#include <ppapi/c/ppb_console.h>
+#include <ppapi/c/ppb_core.h>
#include <ppapi/c/ppb_file_io.h>
#include <ppapi/c/ppb_file_ref.h>
#include <ppapi/c/ppb_file_system.h>
@@ -20,15 +21,36 @@
#include <ppapi/c/ppb_messaging.h>
#include <ppapi/c/ppb_messaging.h>
#include <ppapi/c/ppb_net_address.h>
+#include <ppapi/c/ppb_tcp_socket.h>
#include <ppapi/c/ppb_url_loader.h>
#include <ppapi/c/ppb_url_request_info.h>
#include <ppapi/c/ppb_url_response_info.h>
+#include <ppapi/c/ppb_udp_socket.h>
#include <ppapi/c/ppb_var.h>
#include <sdk_util/macros.h>
namespace nacl_io {
+// This class is the base interface for Pepper used by nacl_io.
+//
+// We use #include and macro magic to simplify adding new interfaces. The
+// resulting PepperInterface basically looks like this:
+//
+// class PepperInterface {
+// public:
+// virtual ~PepperInterface() {}
+// virtual PP_Instance GetInstance() = 0;
+// ...
+//
+// // Interface getters.
+// ConsoleInterface* GetConsoleInterface() = 0;
+// CoreInterface* GetCoreInterface() = 0;
+// FileIoInterface* GetFileIoInterface() = 0;
+// ... etc.
+// };
+//
+//
// Note: To add a new interface:
//
// 1. Using one of the other interfaces as a template, add your interface to
@@ -51,11 +73,18 @@ class PepperInterface {
public:
virtual ~PepperInterface() {}
virtual PP_Instance GetInstance() = 0;
- virtual void AddRefResource(PP_Resource) = 0;
- virtual void ReleaseResource(PP_Resource) = 0;
- virtual bool IsMainThread() = 0;
+
+ // Convenience functions. These forward to
+ // GetCoreInterface()->{AddRef,Release}Resource.
+ void AddRefResource(PP_Resource resource);
+ void ReleaseResource(PP_Resource resource);
// Interface getters.
+//
+// These macros expand to definitions like:
+//
+// CoreInterface* GetCoreInterface() = 0;
+//
#include "nacl_io/pepper/undef_macros.h"
#include "nacl_io/pepper/define_empty_macros.h"
#undef BEGIN_INTERFACE
@@ -65,6 +94,17 @@ class PepperInterface {
};
// Interface class definitions.
+//
+// Each class will be defined with all pure virtual methods, e.g:
+//
+// class CoreInterface {
+// public:
+// virtual ~CoreInterface() {}
+// virtual void AddRefResource() = 0;
+// virtual void ReleaseResource() = 0;
+// virtual PP_Bool IsMainThread() = 0;
+// };
+//
#include "nacl_io/pepper/undef_macros.h"
#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
class BaseClass { \
@@ -72,6 +112,8 @@ class PepperInterface {
virtual ~BaseClass() {}
#define END_INTERFACE(BaseClass, PPInterface) \
};
+#define METHOD0(Class, ReturnType, MethodName) \
+ virtual ReturnType MethodName() = 0;
#define METHOD1(Class, ReturnType, MethodName, Type0) \
virtual ReturnType MethodName(Type0) = 0;
#define METHOD2(Class, ReturnType, MethodName, Type0, Type1) \
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.cc b/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.cc
new file mode 100644
index 0000000000..384737e761
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.cc
@@ -0,0 +1,46 @@
+// 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/pepper_interface_delegate.h"
+
+namespace nacl_io {
+
+PepperInterfaceDelegate::PepperInterfaceDelegate(PP_Instance instance)
+ : instance_(instance) {
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+ BaseClass##delegate_ = NULL;
+#include "nacl_io/pepper/all_interfaces.h"
+}
+
+PepperInterfaceDelegate::~PepperInterfaceDelegate() {}
+
+PP_Instance PepperInterfaceDelegate::GetInstance() {
+ return instance_;
+}
+
+// Interface getters.
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+BaseClass* PepperInterfaceDelegate::Get##BaseClass() { \
+ return BaseClass##delegate_; \
+}
+#include "nacl_io/pepper/all_interfaces.h"
+
+// Interface delegate setters.
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+void PepperInterfaceDelegate::Set##BaseClass##Delegate( \
+ BaseClass* delegate) { \
+ BaseClass##delegate_ = delegate; \
+}
+#include "nacl_io/pepper/all_interfaces.h"
+
+} // namespace nacl_io
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.h b/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.h
new file mode 100644
index 0000000000..d6945a4b80
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface_delegate.h
@@ -0,0 +1,82 @@
+/* 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_PEPPER_INTERFACE_DELEGATE_H_
+#define LIBRARIES_NACL_IO_PEPPER_INTERFACE_DELEGATE_H_
+
+#include "nacl_io/pepper_interface.h"
+
+// This class allows you to delegate Interface requests to different
+// PepperInterface-derived classes.
+//
+// For example:
+// class FooPepperInterface : public PepperInterface {
+// ...
+// CoreInterface* GetCoreInterface() { ... };
+// ...
+// };
+//
+// class BarPepperInterface : public PepperInterface {
+// ...
+// VarInterface* GetVarInterface() { ... };
+// ...
+// };
+//
+// void SomeFunction() {
+// FooPepperInterface foo;
+// BarPepperInterface bar;
+// PepperInterfaceDelegate delegate(pp_instance);
+// delegate.SetCoreInterface(foo.GetCoreInterface());
+// delegate.SetVarInterface(bar.GetVarInterface());
+// ...
+// }
+
+namespace nacl_io {
+
+class PepperInterfaceDelegate : public PepperInterface {
+ public:
+ explicit PepperInterfaceDelegate(PP_Instance instance);
+ virtual ~PepperInterfaceDelegate();
+ virtual PP_Instance GetInstance();
+
+// Interface getters.
+//
+// These declarations look like:
+//
+// CoreInterface* GetCoreInterface();
+//
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+ virtual BaseClass* Get##BaseClass();
+#include "nacl_io/pepper/all_interfaces.h"
+
+// Interface delegate setters.
+//
+// These declarations look like:
+//
+// void SetCoreInterface(CoreInterface* delegate);
+//
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+ void Set##BaseClass##Delegate(BaseClass* delegate);
+#include "nacl_io/pepper/all_interfaces.h"
+
+ private:
+ PP_Instance instance_;
+// Interface delegate pointers.
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+ BaseClass* BaseClass##delegate_;
+#include "nacl_io/pepper/all_interfaces.h"
+};
+
+} // namespace nacl_io
+
+#endif // LIBRARIES_NACL_IO_PEPPER_INTERFACE_DELEGATE_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface_dummy.h b/native_client_sdk/src/libraries/nacl_io/pepper_interface_dummy.h
new file mode 100644
index 0000000000..5c2271ecf2
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface_dummy.h
@@ -0,0 +1,43 @@
+/* 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_PEPPER_INTERFACE_DUMMY_H_
+#define LIBRARIES_NACL_IO_PEPPER_INTERFACE_DUMMY_H_
+
+#include "nacl_io/pepper_interface.h"
+
+// This class simplifies implementing a PepperInterface-derived class where you
+// don't care about certain interfaces. All interface-getters return NULL by
+// default.
+//
+// For example:
+//
+// class FooPepperInterface : public PepperInterfaceDummy {
+// public:
+// CoreInterface* GetCoreInterface() { ... };
+// };
+//
+// // FooPepperInterface is not abstract -- all pure virtual functions have
+// been defined to return NULL.
+
+namespace nacl_io {
+
+class PepperInterfaceDummy : public PepperInterface {
+ public:
+ PepperInterfaceDummy() {}
+ virtual ~PepperInterfaceDummy() {}
+ virtual PP_Instance GetInstance() { return 0; }
+
+// Interface getters.
+#include "nacl_io/pepper/undef_macros.h"
+#include "nacl_io/pepper/define_empty_macros.h"
+#undef BEGIN_INTERFACE
+#define BEGIN_INTERFACE(BaseClass, PPInterface, InterfaceString) \
+ virtual BaseClass* Get##BaseClass() { return NULL; }
+#include "nacl_io/pepper/all_interfaces.h"
+};
+
+} // namespace nacl_io
+
+#endif // LIBRARIES_NACL_IO_PEPPER_INTERFACE_DUMMY_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc b/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc
index f7743b6861..53a8a0f1c8 100644
--- a/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc
+++ b/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.cc
@@ -19,6 +19,8 @@ namespace nacl_io {
private: \
const PPInterface* interface_; \
};
+#define METHOD0(Class, ReturnType, MethodName) \
+ virtual ReturnType MethodName();
#define METHOD1(Class, ReturnType, MethodName, Type0) \
virtual ReturnType MethodName(Type0);
#define METHOD2(Class, ReturnType, MethodName, Type0, Type1) \
@@ -40,6 +42,10 @@ namespace nacl_io {
#define END_INTERFACE(BaseClass, PPInterface)
+#define METHOD0(BaseClass, ReturnType, MethodName) \
+ ReturnType Real##BaseClass::MethodName() { \
+ return interface_->MethodName(); \
+ }
#define METHOD1(BaseClass, ReturnType, MethodName, Type0) \
ReturnType Real##BaseClass::MethodName(Type0 arg0) { \
return interface_->MethodName(arg0); \
@@ -69,17 +75,7 @@ namespace nacl_io {
RealPepperInterface::RealPepperInterface(PP_Instance instance,
PPB_GetInterface get_browser_interface)
- : instance_(instance),
- core_interface_(NULL),
- message_loop_interface_(NULL) {
-
- core_interface_ = static_cast<const PPB_Core*>(
- get_browser_interface(PPB_CORE_INTERFACE));
- message_loop_interface_ = static_cast<const PPB_MessageLoop*>(
- get_browser_interface(PPB_MESSAGELOOP_INTERFACE));
- assert(core_interface_);
- assert(message_loop_interface_);
-
+ : instance_(instance) {
#include "nacl_io/pepper/undef_macros.h"
#include "nacl_io/pepper/define_empty_macros.h"
#undef BEGIN_INTERFACE
@@ -94,20 +90,6 @@ PP_Instance RealPepperInterface::GetInstance() {
return instance_;
}
-void RealPepperInterface::AddRefResource(PP_Resource resource) {
- if (resource)
- core_interface_->AddRefResource(resource);
-}
-
-void RealPepperInterface::ReleaseResource(PP_Resource resource) {
- if (resource)
- core_interface_->ReleaseResource(resource);
-}
-
-bool RealPepperInterface::IsMainThread() {
- return core_interface_->IsMainThread();
-}
-
// Define getter function.
#include "nacl_io/pepper/undef_macros.h"
#include "nacl_io/pepper/define_empty_macros.h"
@@ -118,24 +100,5 @@ bool RealPepperInterface::IsMainThread() {
}
#include "nacl_io/pepper/all_interfaces.h"
-
-int32_t RealPepperInterface::InitializeMessageLoop() {
- int32_t result;
- PP_Resource message_loop = 0;
- if (core_interface_->IsMainThread()) {
- // TODO(binji): Spin up the main thread's ppapi work thread.
- assert(0);
- } else {
- message_loop = message_loop_interface_->GetCurrent();
- if (!message_loop) {
- message_loop = message_loop_interface_->Create(instance_);
- result = message_loop_interface_->AttachToCurrentThread(message_loop);
- assert(result == PP_OK);
- }
- }
-
- return PP_OK;
-}
-
} // namespace nacl_io
diff --git a/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.h b/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.h
index 0bddee171f..c6b0a18999 100644
--- a/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.h
+++ b/native_client_sdk/src/libraries/nacl_io/real_pepper_interface.h
@@ -26,9 +26,6 @@ class RealPepperInterface : public PepperInterface {
PPB_GetInterface get_browser_interface);
virtual PP_Instance GetInstance();
- virtual void AddRefResource(PP_Resource);
- virtual void ReleaseResource(PP_Resource);
- virtual bool IsMainThread();
// Interface getters.
#include "nacl_io/pepper/undef_macros.h"
@@ -38,12 +35,8 @@ class RealPepperInterface : public PepperInterface {
virtual BaseClass* Get##BaseClass();
#include "nacl_io/pepper/all_interfaces.h"
- int32_t InitializeMessageLoop();
-
private:
PP_Instance instance_;
- const PPB_Core* core_interface_;
- const PPB_MessageLoop* message_loop_interface_;
// Interface pointers.
#include "nacl_io/pepper/undef_macros.h"
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetispeed.c b/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetispeed.c
new file mode 100644
index 0000000000..747e234f9f
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetispeed.c
@@ -0,0 +1,10 @@
+/* Copyright 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/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+speed_t cfgetispeed(const struct termios *termios_p) {
+ return termios_p->c_ispeed;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetospeed.c b/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetospeed.c
new file mode 100644
index 0000000000..1e6ccb7339
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/cfgetospeed.c
@@ -0,0 +1,10 @@
+/* Copyright 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/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+speed_t cfgetospeed(const struct termios *termios_p) {
+ return termios_p->c_ospeed;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetispeed.c b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetispeed.c
new file mode 100644
index 0000000000..7ae776c9cc
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetispeed.c
@@ -0,0 +1,11 @@
+/* Copyright 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/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int cfsetispeed(struct termios *termios_p, speed_t speed) {
+ termios_p->c_ispeed = speed;
+ return 0;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetospeed.c b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetospeed.c
new file mode 100644
index 0000000000..7e13b1a781
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetospeed.c
@@ -0,0 +1,11 @@
+/* Copyright 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/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int cfsetospeed(struct termios *termios_p, speed_t speed) {
+ termios_p->c_ospeed = speed;
+ return 0;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetspeed.c b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetspeed.c
new file mode 100644
index 0000000000..3d618e32ba
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/cfsetspeed.c
@@ -0,0 +1,12 @@
+/* Copyright 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/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int cfsetspeed(struct termios *termios_p, speed_t speed) {
+ termios_p->c_ispeed = speed;
+ termios_p->c_ospeed = speed;
+ return 0;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/ioctl.c b/native_client_sdk/src/libraries/nacl_io/syscalls/ioctl.c
index dd235304d5..c1cd7d004a 100644
--- a/native_client_sdk/src/libraries/nacl_io/syscalls/ioctl.c
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/ioctl.c
@@ -2,9 +2,15 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
+#include <stdarg.h>
+
#include "nacl_io/kernel_intercept.h"
#include "nacl_io/kernel_wrap.h"
-int ioctl(int d, int request, char* argp) {
- return ki_ioctl(d, request, argp);
+int ioctl(int fd, unsigned long request, ...) {
+ va_list ap;
+ va_start(ap, request);
+ char* arg = va_arg(ap, char*);
+ va_end(ap);
+ return ki_ioctl(fd, request, arg);
}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/kill.c b/native_client_sdk/src/libraries/nacl_io/syscalls/kill.c
new file mode 100644
index 0000000000..9631516737
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/kill.c
@@ -0,0 +1,10 @@
+/* Copyright 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/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int kill(pid_t pid, int sig) {
+ return ki_kill(pid, sig);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/signal.c b/native_client_sdk/src/libraries/nacl_io/syscalls/signal.c
new file mode 100644
index 0000000000..a111add893
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/signal.c
@@ -0,0 +1,10 @@
+/* Copyright 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/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+sighandler_t signal(int signum, sighandler_t handler) {
+ return ki_signal(signum, handler);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/sigset.c b/native_client_sdk/src/libraries/nacl_io/syscalls/sigset.c
new file mode 100644
index 0000000000..258c495ea4
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/sigset.c
@@ -0,0 +1,10 @@
+/* Copyright 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/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+sighandler_t sigset(int signum, sighandler_t handler) {
+ return ki_sigset(signum, handler);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/getdents.c b/native_client_sdk/src/libraries/nacl_io/syscalls/tcdrain.c
index 649fea647d..49c078bb0c 100644
--- a/native_client_sdk/src/libraries/nacl_io/syscalls/getdents.c
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/tcdrain.c
@@ -1,10 +1,13 @@
-/* Copyright (c) 2013 The Chromium Authors. All rights reserved.
+/* Copyright 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 <errno.h>
+
#include "nacl_io/kernel_intercept.h"
#include "nacl_io/kernel_wrap.h"
-int getdents(int fd, void* buf, unsigned int count) {
- return ki_getdents(fd, buf, count);
+int tcdrain(int fd) {
+ errno = ENOSYS;
+ return -1;
}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/tcflow.c b/native_client_sdk/src/libraries/nacl_io/syscalls/tcflow.c
new file mode 100644
index 0000000000..a29915351c
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/tcflow.c
@@ -0,0 +1,13 @@
+/* Copyright 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 <errno.h>
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int tcflow(int fd, int action) {
+ errno = ENOSYS;
+ return -1;
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/tcsendbreak.c b/native_client_sdk/src/libraries/nacl_io/syscalls/tcsendbreak.c
new file mode 100644
index 0000000000..967446745e
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/tcsendbreak.c
@@ -0,0 +1,13 @@
+/* Copyright 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 <errno.h>
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_wrap.h"
+
+int tcsendbreak(int fd, int duration) {
+ errno = ENOSYS;
+ return -1;
+}
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
deleted file mode 100644
index b64770dd24..0000000000
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_html5fs_test.cc
+++ /dev/null
@@ -1,629 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <gmock/gmock.h>
-#include <ppapi/c/ppb_file_io.h>
-#include <ppapi/c/pp_directory_entry.h>
-#include <ppapi/c/pp_errors.h>
-#include <ppapi/c/pp_instance.h>
-#if defined(WIN32)
-#include <windows.h> // For Sleep()
-#endif
-
-#include "mock_util.h"
-#include "nacl_io/mount_html5fs.h"
-#include "nacl_io/osdirent.h"
-#include "nacl_io/osunistd.h"
-#include "pepper_interface_mock.h"
-
-using namespace nacl_io;
-using namespace sdk_util;
-
-using ::testing::_;
-using ::testing::DoAll;
-using ::testing::Invoke;
-using ::testing::Return;
-using ::testing::SaveArg;
-using ::testing::SetArgPointee;
-using ::testing::StrEq;
-using ::testing::WithArgs;
-
-namespace {
-
-class MountHtml5FsMock : public MountHtml5Fs {
- public:
- MountHtml5FsMock(StringMap_t map, PepperInterfaceMock* ppapi) {
- Init(1, map, ppapi);
- }
-
- ~MountHtml5FsMock() {}
-};
-
-class MountHtml5FsTest : public ::testing::Test {
- public:
- MountHtml5FsTest();
- ~MountHtml5FsTest();
- void SetUpFilesystemExpectations(PP_FileSystemType, int,
- bool async_callback=false);
-
- protected:
- PepperInterfaceMock* ppapi_;
- PP_CompletionCallback open_filesystem_callback_;
-
- static const PP_Instance instance_ = 123;
- static const PP_Resource filesystem_resource_ = 234;
-};
-
-MountHtml5FsTest::MountHtml5FsTest()
- : ppapi_(new PepperInterfaceMock(instance_)) {
-}
-
-MountHtml5FsTest::~MountHtml5FsTest() {
- delete ppapi_;
-}
-
-void MountHtml5FsTest::SetUpFilesystemExpectations(
- PP_FileSystemType fstype,
- int expected_size,
- bool async_callback) {
- FileSystemInterfaceMock* filesystem = ppapi_->GetFileSystemInterface();
- EXPECT_CALL(*filesystem, Create(instance_, fstype))
- .Times(1)
- .WillOnce(Return(filesystem_resource_));
-
- if (async_callback) {
- EXPECT_CALL(*filesystem, Open(filesystem_resource_, expected_size, _))
- .WillOnce(DoAll(SaveArg<2>(&open_filesystem_callback_),
- Return(int32_t(PP_OK))));
- EXPECT_CALL(*ppapi_, IsMainThread()).WillOnce(Return(PP_TRUE));
- } else {
- EXPECT_CALL(*filesystem, Open(filesystem_resource_, expected_size, _))
- .WillOnce(CallCallback<2>(int32_t(PP_OK)));
- EXPECT_CALL(*ppapi_, IsMainThread()).WillOnce(Return(PP_FALSE));
- }
-
- EXPECT_CALL(*ppapi_, ReleaseResource(filesystem_resource_));
-}
-
-class MountHtml5FsNodeTest : public MountHtml5FsTest {
- public:
- MountHtml5FsNodeTest();
- virtual void SetUp();
- virtual void TearDown();
-
- void SetUpNodeExpectations(PP_FileType file_type);
- void InitFilesystem();
- void InitNode();
-
- protected:
- ScopedRef<MountHtml5FsMock> mnt_;
- ScopedMountNode node_;
-
- FileRefInterfaceMock* fileref_;
- FileIoInterfaceMock* fileio_;
-
- static const char path_[];
- static const PP_Resource fileref_resource_ = 235;
- static const PP_Resource fileio_resource_ = 236;
-};
-
-// static
-const char MountHtml5FsNodeTest::path_[] = "/foo";
-
-MountHtml5FsNodeTest::MountHtml5FsNodeTest()
- : fileref_(NULL),
- fileio_(NULL) {
-}
-
-void MountHtml5FsNodeTest::SetUp() {
- fileref_ = ppapi_->GetFileRefInterface();
- fileio_ = ppapi_->GetFileIoInterface();
-}
-
-void MountHtml5FsNodeTest::TearDown() {
- node_.reset();
- mnt_.reset();
-}
-
-void MountHtml5FsNodeTest::SetUpNodeExpectations(PP_FileType file_type) {
- // Open.
- EXPECT_CALL(*fileref_, Create(filesystem_resource_, StrEq(&path_[0])))
- .WillOnce(Return(fileref_resource_));
- PP_FileInfo info;
- memset(&info, 0, sizeof(PP_FileInfo));
- info.type = file_type;
- EXPECT_CALL(*fileref_, Query(fileref_resource_, _, _))
- .WillOnce(DoAll(SetArgPointee<1>(info),
- Return(int32_t(PP_OK))));
- if (file_type != PP_FILETYPE_DIRECTORY) {
- EXPECT_CALL(*fileio_, Create(instance_)).WillOnce(Return(fileio_resource_));
- int32_t open_flags = PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE |
- PP_FILEOPENFLAG_CREATE;
- EXPECT_CALL(*fileio_,
- Open(fileio_resource_, fileref_resource_, open_flags, _))
- .WillOnce(Return(int32_t(PP_OK)));
-
- // Close.
- EXPECT_CALL(*fileio_, Close(fileio_resource_));
- EXPECT_CALL(*ppapi_, ReleaseResource(fileio_resource_));
- EXPECT_CALL(*fileio_, Flush(fileio_resource_, _));
- }
-
- // Close.
- EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource_));
-}
-
-void MountHtml5FsNodeTest::InitFilesystem() {
- StringMap_t map;
- mnt_.reset(new MountHtml5FsMock(map, ppapi_));
-}
-
-void MountHtml5FsNodeTest::InitNode() {
- ASSERT_EQ(0, mnt_->Open(Path(path_), O_CREAT | O_RDWR, &node_));
- ASSERT_NE((MountNode*)NULL, node_.get());
-}
-
-// Node test where the filesystem is opened synchronously; that is, the
-// creation of the mount blocks until the filesystem is ready.
-class MountHtml5FsNodeSyncTest : public MountHtml5FsNodeTest {
- public:
- void SetUpForFileType(PP_FileType file_type);
-
- virtual void SetUp();
-};
-
-void MountHtml5FsNodeSyncTest::SetUpForFileType(PP_FileType file_type) {
- MountHtml5FsNodeTest::SetUp();
- SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
- InitFilesystem();
- SetUpNodeExpectations(file_type);
- InitNode();
-}
-
-void MountHtml5FsNodeSyncTest::SetUp() {
- SetUpForFileType(PP_FILETYPE_REGULAR);
-}
-
-// Node test where the filesystem is opened synchronously, and the node is a
-// directory.
-class MountHtml5FsNodeSyncDirTest : public MountHtml5FsNodeSyncTest {
- public:
- virtual void SetUp();
-};
-
-void MountHtml5FsNodeSyncDirTest::SetUp() {
- SetUpForFileType(PP_FILETYPE_DIRECTORY);
-}
-
-void ReadDirectoryEntriesAction(const PP_ArrayOutput& output) {
- const int fileref_resource_1 = 238;
- const int fileref_resource_2 = 239;
-
- std::vector<PP_DirectoryEntry> entries;
- PP_DirectoryEntry entry1 = { fileref_resource_1, PP_FILETYPE_REGULAR };
- PP_DirectoryEntry entry2 = { fileref_resource_2, PP_FILETYPE_REGULAR };
- entries.push_back(entry1);
- entries.push_back(entry2);
-
- void* dest = output.GetDataBuffer(
- output.user_data, 2, sizeof(PP_DirectoryEntry));
- memcpy(dest, &entries[0], sizeof(PP_DirectoryEntry) * 2);
-}
-
-class MountHtml5FsNodeAsyncTest : public MountHtml5FsNodeTest {
- public:
- virtual void SetUp();
- virtual void TearDown();
-
- private:
- static void* ThreadThunk(void* param);
- void Thread();
-
- enum {
- STATE_INIT,
- STATE_INIT_NODE,
- STATE_INIT_NODE_FINISHED,
- } state_;
-
- pthread_t thread_;
- pthread_cond_t cond_;
- pthread_mutex_t mutex_;
-};
-
-void MountHtml5FsNodeAsyncTest::SetUp() {
- MountHtml5FsNodeTest::SetUp();
-
- state_ = STATE_INIT;
-
- pthread_create(&thread_, NULL, &MountHtml5FsNodeAsyncTest::ThreadThunk, this);
- pthread_mutex_init(&mutex_, NULL);
- pthread_cond_init(&cond_, NULL);
-
- // This test shows that even if the filesystem open callback happens after an
- // attempt to open a node, it still works (opening the node blocks until the
- // filesystem is ready).
- // true => asynchronous filesystem open.
- SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0, true);
- InitFilesystem();
- SetUpNodeExpectations(PP_FILETYPE_REGULAR);
-
- // Signal the other thread to try opening a Node.
- pthread_mutex_lock(&mutex_);
- state_ = STATE_INIT_NODE;
- pthread_cond_signal(&cond_);
- pthread_mutex_unlock(&mutex_);
-
- // Wait for a bit...
- // TODO(binji): this will be flaky. How to test this better?
-#if defined(WIN32)
- Sleep(500); // milliseconds
-#else
- usleep(500*1000); // microseconds
-#endif
-
- // Call the filesystem open callback.
- (*open_filesystem_callback_.func)(open_filesystem_callback_.user_data, PP_OK);
-
- // Wait for the other thread to unblock and signal us.
- pthread_mutex_lock(&mutex_);
- while (state_ != STATE_INIT_NODE_FINISHED)
- pthread_cond_wait(&cond_, &mutex_);
- pthread_mutex_unlock(&mutex_);
-}
-
-void MountHtml5FsNodeAsyncTest::TearDown() {
- pthread_cond_destroy(&cond_);
- pthread_mutex_destroy(&mutex_);
-
- MountHtml5FsNodeTest::TearDown();
-}
-
-void* MountHtml5FsNodeAsyncTest::ThreadThunk(void* param) {
- static_cast<MountHtml5FsNodeAsyncTest*>(param)->Thread();
- return NULL;
-}
-
-void MountHtml5FsNodeAsyncTest::Thread() {
- // Wait for the "main" thread to tell us to open the Node.
- pthread_mutex_lock(&mutex_);
- while (state_ != STATE_INIT_NODE)
- pthread_cond_wait(&cond_, &mutex_);
- pthread_mutex_unlock(&mutex_);
-
- // Opening the node blocks until the filesystem is open...
- InitNode();
-
- // Signal the "main" thread to tell it we're unblocked.
- pthread_mutex_lock(&mutex_);
- state_ = STATE_INIT_NODE_FINISHED;
- pthread_cond_signal(&cond_);
- pthread_mutex_unlock(&mutex_);
-}
-
-} // namespace
-
-
-TEST_F(MountHtml5FsTest, FilesystemType) {
- SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 100);
-
- StringMap_t map;
- map["type"] = "PERSISTENT";
- map["expected_size"] = "100";
- ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
-}
-
-TEST_F(MountHtml5FsTest, Access) {
- const char path[] = "/foo";
- const PP_Resource fileref_resource = 235;
- const PP_Resource fileio_resource = 236;
-
- // These are the default values.
- SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
-
- FileRefInterfaceMock* fileref = ppapi_->GetFileRefInterface();
- FileIoInterfaceMock* fileio = ppapi_->GetFileIoInterface();
-
- EXPECT_CALL(*fileref, Create(filesystem_resource_, StrEq(&path[0])))
- .WillOnce(Return(fileref_resource));
- PP_FileInfo info;
- memset(&info, 0, sizeof(PP_FileInfo));
- info.type = PP_FILETYPE_REGULAR;
- EXPECT_CALL(*fileref, Query(fileref_resource, _, _))
- .WillOnce(DoAll(SetArgPointee<1>(info),
- Return(int32_t(PP_OK))));
- EXPECT_CALL(*fileio, Create(instance_)).WillOnce(Return(fileio_resource));
- int32_t open_flags = PP_FILEOPENFLAG_READ;
- EXPECT_CALL(*fileio,
- Open(fileio_resource, fileref_resource, open_flags, _))
- .WillOnce(Return(int32_t(PP_OK)));
- EXPECT_CALL(*fileio, Close(fileio_resource));
- EXPECT_CALL(*fileio, Flush(fileio_resource, _));
- EXPECT_CALL(*ppapi_, ReleaseResource(fileio_resource));
- EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
-
- StringMap_t map;
- ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
-
- ASSERT_EQ(0, mnt->Access(Path(path), R_OK | W_OK | X_OK));
-}
-
-TEST_F(MountHtml5FsTest, AccessFileNotFound) {
- const char path[] = "/foo";
- const PP_Resource fileref_resource = 235;
- const PP_Resource fileio_resource = 236;
-
- // These are the default values.
- SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
-
- FileRefInterfaceMock* fileref = ppapi_->GetFileRefInterface();
- FileIoInterfaceMock* fileio = ppapi_->GetFileIoInterface();
-
- // Report the file as missing.
- EXPECT_CALL(*fileref, Create(filesystem_resource_, StrEq(&path[0])))
- .WillOnce(Return(fileref_resource));
- PP_FileInfo info;
- memset(&info, 0, sizeof(PP_FileInfo));
- info.type = PP_FILETYPE_REGULAR;
- EXPECT_CALL(*fileref, Query(fileref_resource, _, _))
- .WillOnce(DoAll(SetArgPointee<1>(info),
- Return(int32_t(PP_ERROR_FILENOTFOUND))));
- EXPECT_CALL(*fileio, Create(instance_)).WillOnce(Return(fileio_resource));
- int32_t open_flags = PP_FILEOPENFLAG_READ;
- EXPECT_CALL(*fileio,
- Open(fileio_resource, fileref_resource, open_flags, _))
- .WillOnce(Return(int32_t(PP_ERROR_FILENOTFOUND)));
- EXPECT_CALL(*fileio, Close(fileio_resource));
- EXPECT_CALL(*fileio, Flush(fileio_resource, _));
- EXPECT_CALL(*ppapi_, ReleaseResource(fileio_resource));
- EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
-
- StringMap_t map;
- ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
-
- ASSERT_EQ(ENOENT, mnt->Access(Path(path), F_OK));
-}
-
-TEST_F(MountHtml5FsTest, Mkdir) {
- const char path[] = "/foo";
- const PP_Resource fileref_resource = 235;
-
- // These are the default values.
- SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
-
- FileRefInterfaceMock* fileref = ppapi_->GetFileRefInterface();
-
- EXPECT_CALL(*fileref, Create(filesystem_resource_, StrEq(&path[0])))
- .WillOnce(Return(fileref_resource));
- EXPECT_CALL(*fileref, MakeDirectory(fileref_resource, _, _))
- .WillOnce(Return(int32_t(PP_OK)));
- EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
-
- StringMap_t map;
- ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
-
- const int permissions = 0; // unused.
- int32_t result = mnt->Mkdir(Path(path), permissions);
- ASSERT_EQ(0, result);
-}
-
-TEST_F(MountHtml5FsTest, Remove) {
- const char path[] = "/foo";
- const PP_Resource fileref_resource = 235;
-
- // These are the default values.
- SetUpFilesystemExpectations(PP_FILESYSTEMTYPE_LOCALPERSISTENT, 0);
-
- FileRefInterfaceMock* fileref = ppapi_->GetFileRefInterface();
-
- EXPECT_CALL(*fileref, Create(filesystem_resource_, StrEq(&path[0])))
- .WillOnce(Return(fileref_resource));
- EXPECT_CALL(*fileref, Delete(fileref_resource, _))
- .WillOnce(Return(int32_t(PP_OK)));
- EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource));
-
- StringMap_t map;
- ScopedRef<MountHtml5FsMock> mnt(new MountHtml5FsMock(map, ppapi_));
-
- int32_t result = mnt->Remove(Path(path));
- ASSERT_EQ(0, result);
-}
-
-TEST_F(MountHtml5FsNodeAsyncTest, AsyncFilesystemOpen) {
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, OpenAndClose) {
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, Write) {
- const int offset = 10;
- const int count = 20;
- const char buffer[30] = {0};
-
- EXPECT_CALL(*fileio_, Write(fileio_resource_, offset, &buffer[0], count, _))
- .WillOnce(Return(count));
-
- int result = 0;
- EXPECT_EQ(0, node_->Write(offset, &buffer, count, &result));
- EXPECT_EQ(count, result);
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, Read) {
- const int offset = 10;
- const int count = 20;
- char buffer[30] = {0};
-
- EXPECT_CALL(*fileio_, Read(fileio_resource_, offset, &buffer[0], count, _))
- .WillOnce(Return(count));
-
- int result = 0;
- EXPECT_EQ(0, node_->Read(offset, &buffer, count, &result));
- EXPECT_EQ(count, result);
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, GetStat) {
- const int size = 123;
- const int creation_time = 1000;
- const int access_time = 2000;
- const int modified_time = 3000;
-
- PP_FileInfo info;
- info.size = size;
- info.type = PP_FILETYPE_REGULAR;
- info.system_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
- info.creation_time = creation_time;
- info.last_access_time = access_time;
- info.last_modified_time = modified_time;
-
- EXPECT_CALL(*fileref_, Query(fileref_resource_, _, _))
- .WillOnce(DoAll(SetArgPointee<1>(info),
- Return(int32_t(PP_OK))));
-
- struct stat statbuf;
- int result = node_->GetStat(&statbuf);
-
- EXPECT_EQ(0, result);
- EXPECT_EQ(S_IFREG | S_IWRITE | S_IREAD, statbuf.st_mode);
- EXPECT_EQ(size, statbuf.st_size);
- EXPECT_EQ(access_time, statbuf.st_atime);
- EXPECT_EQ(modified_time, statbuf.st_mtime);
- EXPECT_EQ(creation_time, statbuf.st_ctime);
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, FTruncate) {
- const int size = 123;
- EXPECT_CALL(*fileio_, SetLength(fileio_resource_, size, _))
- .WillOnce(Return(int32_t(PP_OK)));
-
- int result = node_->FTruncate(size);
- EXPECT_EQ(0, result);
-}
-
-TEST_F(MountHtml5FsNodeSyncTest, GetDents) {
- struct dirent dirents[2];
- memset(&dirents[0], 0, sizeof(dirents));
-
- // Should fail for regular files.
- 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) {
-}
-
-TEST_F(MountHtml5FsNodeSyncDirTest, Write) {
- const int offset = 10;
- const int count = 20;
- const char buffer[30] = {0};
-
- // Should fail for directories.
- int result_bytes = 0;
- EXPECT_EQ(EISDIR, node_->Write(offset, &buffer, count, &result_bytes));
- ASSERT_EQ(0, result_bytes);
-}
-
-TEST_F(MountHtml5FsNodeSyncDirTest, Read) {
- const int offset = 10;
- const int count = 20;
- char buffer[30] = {0};
-
- // Should fail for directories.
- int result_bytes = 0;
- EXPECT_EQ(EISDIR, node_->Read(offset, &buffer, count, &result_bytes));
- ASSERT_EQ(0, result_bytes);
-}
-
-TEST_F(MountHtml5FsNodeSyncDirTest, GetStat) {
- const int creation_time = 1000;
- const int access_time = 2000;
- const int modified_time = 3000;
-
- PP_FileInfo info;
- info.size = 0;
- info.type = PP_FILETYPE_DIRECTORY;
- info.system_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
- info.creation_time = creation_time;
- info.last_access_time = access_time;
- info.last_modified_time = modified_time;
-
- EXPECT_CALL(*fileref_, Query(fileref_resource_, _, _))
- .WillOnce(DoAll(SetArgPointee<1>(info),
- Return(int32_t(PP_OK))));
-
- struct stat statbuf;
- int result = node_->GetStat(&statbuf);
-
- EXPECT_EQ(0, result);
- EXPECT_EQ(S_IFDIR | S_IWRITE | S_IREAD, statbuf.st_mode);
- EXPECT_EQ(0, statbuf.st_size);
- EXPECT_EQ(access_time, statbuf.st_atime);
- EXPECT_EQ(modified_time, statbuf.st_mtime);
- EXPECT_EQ(creation_time, statbuf.st_ctime);
-}
-
-TEST_F(MountHtml5FsNodeSyncDirTest, FTruncate) {
- const int size = 123;
- // Should fail for directories.
- EXPECT_EQ(EISDIR, node_->FTruncate(size));
-}
-
-TEST_F(MountHtml5FsNodeSyncDirTest, GetDents) {
- const int fileref_resource_1 = 238;
- const int fileref_resource_2 = 239;
-
- const int fileref_name_id_1 = 240;
- const char fileref_name_cstr_1[] = "bar";
- PP_Var fileref_name_1;
- fileref_name_1.type = PP_VARTYPE_STRING;
- fileref_name_1.value.as_id = fileref_name_id_1;
-
- const int fileref_name_id_2 = 241;
- const char fileref_name_cstr_2[] = "quux";
- PP_Var fileref_name_2;
- fileref_name_2.type = PP_VARTYPE_STRING;
- fileref_name_2.value.as_id = fileref_name_id_2;
-
- VarInterfaceMock* var = ppapi_->GetVarInterface();
-
- EXPECT_CALL(*fileref_, ReadDirectoryEntries(fileref_resource_, _, _))
- .WillOnce(DoAll(WithArgs<1>(Invoke(ReadDirectoryEntriesAction)),
- Return(int32_t(PP_OK))));
-
- EXPECT_CALL(*fileref_, GetName(fileref_resource_1))
- .WillOnce(Return(fileref_name_1));
- EXPECT_CALL(*fileref_, GetName(fileref_resource_2))
- .WillOnce(Return(fileref_name_2));
-
- EXPECT_CALL(*var, VarToUtf8(IsEqualToVar(fileref_name_1), _))
- .WillOnce(Return(fileref_name_cstr_1));
- EXPECT_CALL(*var, VarToUtf8(IsEqualToVar(fileref_name_2), _))
- .WillOnce(Return(fileref_name_cstr_2));
-
- EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource_1));
- EXPECT_CALL(*ppapi_, ReleaseResource(fileref_resource_2));
-
- struct dirent dirents[2];
- 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_bytes = 0;
- EXPECT_EQ(
- 0,
- node_->GetDents(0, &dirents[0], sizeof(dirent) * 2 + 2, &result_bytes));
-
- 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);
- EXPECT_STREQ(fileref_name_cstr_1, dirents[0].d_name);
- EXPECT_LT(0, dirents[1].d_ino); // 0 is an invalid inode number.
- EXPECT_EQ(sizeof(dirent), dirents[1].d_off);
- EXPECT_EQ(sizeof(dirent), dirents[1].d_reclen);
- EXPECT_STREQ(fileref_name_cstr_2, dirents[1].d_name);
-}
-
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc
index 743dabea96..d422cf7469 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.cc
@@ -1,6 +1,6 @@
// Copyright 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.auto
+// found in the LICENSE file.
#include <stdlib.h>
#include <string.h>
@@ -21,11 +21,11 @@
#include "ppapi_simple/ps_instance.h"
#include "ppapi_simple/ps_interface.h"
-PSContext2D_t* PSContext2DAllocate() {
+PSContext2D_t* PSContext2DAllocate(PP_ImageDataFormat format) {
PSContext2D_t* ctx = (PSContext2D_t*) malloc(sizeof(PSContext2D_t));
memset(ctx, 0, sizeof(PSContext2D_t));
- ctx->format = PSInterfaceImageData()->GetNativeImageDataFormat();
+ ctx->format = format;
return ctx;
}
@@ -41,6 +41,10 @@ void PSContext2DFree(PSContext2D_t* ctx) {
free(ctx);
}
+PP_ImageDataFormat PSContext2DGetNativeImageDataFormat() {
+ return PSInterfaceImageData()->GetNativeImageDataFormat();
+}
+
// Update the 2D context if the message is appropriate, returning non-zero
// if the event was consumed.
int PSContext2DHandleEvent(PSContext2D_t* ctx, PSEvent* event) {
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h
index 30d0cf9cc7..74541ec186 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_context_2d.h
@@ -34,10 +34,17 @@ typedef struct {
* various PPAPI operations on the developer's behalf, such as processing view
* change events, swapping buffers, etc...
*/
-PSContext2D_t* PSContext2DAllocate();
+PSContext2D_t* PSContext2DAllocate(PP_ImageDataFormat format);
void PSContext2DFree(PSContext2D_t* ctx);
/*
+ * PSContext2DGetNativeFormat
+ *
+ * Query the native system image format.
+ */
+PP_ImageDataFormat PSContext2DGetNativeImageDataFormat();
+
+/*
* PSContext2DHandleEvent
*
* Updates the context such as allocating, freeing, or sizing graphics and
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc
index 2c073f02a6..8aa50b9fd9 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.cc
@@ -7,6 +7,7 @@
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -96,7 +97,8 @@ PSInstance::PSInstance(PP_Instance instance)
main_loop_(NULL),
events_enabled_(PSE_NONE),
verbosity_(PSV_WARN),
- fd_tty_(-1) {
+ tty_fd_(-1),
+ tty_prefix_(NULL) {
// Set the single Instance object
s_InstanceObject = this;
@@ -207,11 +209,19 @@ bool PSInstance::ProcessProperties() {
int fd2 = open(getenv("PS_STDERR"), O_WRONLY);
dup2(fd2, 2);
- const char* tty_prefix = getenv("PS_TTY_PREFIX");
- if (tty_prefix) {
- fd_tty_ = open("/dev/tty", O_WRONLY);
- if (fd_tty_ >= 0) {
- ioctl(fd_tty_, TIOCNACLPREFIX, const_cast<char*>(tty_prefix));
+ tty_prefix_ = getenv("PS_TTY_PREFIX");
+ if (tty_prefix_) {
+ tty_fd_ = open("/dev/tty", O_WRONLY);
+ if (tty_fd_ >= 0) {
+ RegisterMessageHandler(tty_prefix_, MessageHandlerInputStatic, this);
+ const char* tty_resize = getenv("PS_TTY_RESIZE");
+ if (tty_resize)
+ RegisterMessageHandler(tty_resize, MessageHandlerResizeStatic, this);
+
+ tioc_nacl_output handler;
+ handler.handler = TtyOutputHandlerStatic;
+ handler.user_data = this;
+ ioctl(tty_fd_, TIOCNACLOUTPUT, reinterpret_cast<char*>(&handler));
} else {
Error("Failed to open /dev/tty.\n");
}
@@ -310,31 +320,113 @@ void PSInstance::PostEvent(PSEventType type, PP_Resource resource) {
event_queue_.Enqueue(env);
}
+ssize_t PSInstance::TtyOutputHandler(const char* buf, size_t count) {
+ // We prepend the prefix_ to the data in buf, then package it up
+ // and post it as a message to javascript.
+ const char* data = static_cast<const char*>(buf);
+ std::string message = tty_prefix_;
+ message.append(data, count);
+ PostMessage(pp::Var(message));
+ return count;
+}
+
+void PSInstance::MessageHandlerInput(const pp::Var& message) {
+ // Since our message may contain null characters, we can't send it as a
+ // naked C string, so we package it up in this struct before sending it
+ // to the ioctl.
+ assert(message.is_string());
+ std::string buffer = message.AsString();
+
+ struct tioc_nacl_input_string ioctl_message;
+ ioctl_message.length = buffer.size();
+ ioctl_message.buffer = buffer.c_str();
+ int ret =
+ ioctl(tty_fd_, TIOCNACLINPUT, reinterpret_cast<char*>(&ioctl_message));
+ if (ret != 0 && errno != ENOTTY) {
+ Error("ioctl returned unexpected error: %d.\n", ret);
+ }
+}
+
+void PSInstance::MessageHandlerResize(const pp::Var& message) {
+ assert(message.is_array());
+ pp::VarArray array(message);
+ assert(array.GetLength() == 2);
+
+ struct winsize size;
+ memset(&size, 0, sizeof(size));
+ size.ws_col = array.Get(0).AsInt();
+ size.ws_row = array.Get(1).AsInt();
+ ioctl(tty_fd_, TIOCSWINSZ, reinterpret_cast<char*>(&size));
+}
+
+ssize_t PSInstance::TtyOutputHandlerStatic(const char* buf,
+ size_t count,
+ void* user_data) {
+ PSInstance* instance = reinterpret_cast<PSInstance*>(user_data);
+ return instance->TtyOutputHandler(buf, count);
+}
+
+void PSInstance::MessageHandlerInputStatic(const pp::Var& key,
+ const pp::Var& value,
+ void* user_data) {
+ PSInstance* instance = reinterpret_cast<PSInstance*>(user_data);
+ instance->MessageHandlerInput(value);
+}
+
+void PSInstance::MessageHandlerResizeStatic(const pp::Var& key,
+ const pp::Var& value,
+ void* user_data) {
+ PSInstance* instance = reinterpret_cast<PSInstance*>(user_data);
+ instance->MessageHandlerResize(value);
+}
+
+void PSInstance::RegisterMessageHandler(std::string message_name,
+ MessageHandler_t handler,
+ void* user_data) {
+ if (handler == NULL) {
+ message_handlers_.erase(message_name);
+ return;
+ }
+
+ MessageHandler message_handler = { handler, user_data };
+ message_handlers_[message_name] = message_handler;
+}
+
void PSInstance::PostEvent(PSEventType type, const PP_Var& var) {
assert(PSE_INSTANCE_HANDLEMESSAGE == type);
- // If the user has specified a tty_prefix_ (using ioctl), then we'll give the
- // tty node a chance to vacuum up any messages beginning with that prefix. If
- // the message does not start with the prefix, the ioctl call will return
- // ENOENT and we'll pass the message through to the event queue.
- if (fd_tty_ >= 0 && var.type == PP_VARTYPE_STRING) {
- uint32_t message_len;
- const char* message = PSInterfaceVar()->VarToUtf8(var, &message_len);
- std::string message_str(message, message + message_len);
-
- // Since our message may contain null characters, we can't send it as a
- // naked C string, so we package it up in this struct before sending it
- // to the ioctl.
- struct tioc_nacl_input_string ioctl_message;
- ioctl_message.length = message_len;
- ioctl_message.buffer = message_str.data();
- int ret =
- ioctl(fd_tty_, TIOCNACLINPUT, reinterpret_cast<char*>(&ioctl_message));
- if (ret != 0 && errno != ENOTTY) {
- Error("ioctl returned unexpected error: %d.\n", ret);
+ // If the user has specified a tty_prefix_, then filter out the
+ // matching message here and pass them to the tty node via
+ // ioctl() rather then adding them to the event queue.
+ pp::Var event(var);
+ if (tty_fd_ >= 0 && event.is_string()) {
+ std::string message = event.AsString();
+ size_t prefix_len = strlen(tty_prefix_);
+ if (message.size() > prefix_len) {
+ if (!strncmp(message.c_str(), tty_prefix_, prefix_len)) {
+ MessageHandlerInput(pp::Var(message.substr(prefix_len)));
+ return;
+ }
}
+ }
- return;
+ // If the message is a dictionary then see if it matches one
+ // of the specific handlers, then call that handler rather than
+ // queuing an event.
+ if (tty_fd_ >= 0 && event.is_dictionary()) {
+ pp::VarDictionary dictionary(var);
+ pp::VarArray keys = dictionary.GetKeys();
+ if (keys.GetLength() == 1) {
+ pp::Var key = keys.Get(0);
+ MessageHandlerMap::iterator iter =
+ message_handlers_.find(key.AsString());
+ if (iter != message_handlers_.end()) {
+ MessageHandler_t handler = iter->second.handler;
+ void* user_data = iter->second.user_data;
+ handler(key, dictionary.Get(key), user_data);
+ return;
+ }
+ }
}
PSInterfaceVar()->AddRef(var);
diff --git a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h
index 2df1550dbb..1829bee3ce 100644
--- a/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h
+++ b/native_client_sdk/src/libraries/ppapi_simple/ps_instance.h
@@ -26,6 +26,14 @@
#include "sdk_util/thread_safe_queue.h"
+typedef void (*MessageHandler_t)(const pp::Var& key,
+ const pp::Var& value,
+ void* user_data);
+
+struct MessageHandler {
+ MessageHandler_t handler;
+ void* user_data;
+};
// The basic instance class which also inherits the MouseLock and
// Graphics3DClient interfaces.
@@ -73,7 +81,37 @@ class PSInstance : public pp::Instance, pp::MouseLock, pp::Graphics3DClient {
PSEvent* WaitAcquireEvent();
void ReleaseEvent(PSEvent* event);
+ // Register a message handler for messages that arrive
+ // from JavaScript with a give names. Messages are of the
+ // form: { message_name : <value> }.
+ //
+ // PSInstance will then not generate events but instead
+ // cause the handler to be called upon message arrival.
+ // If handler is NULL then the current handler will be
+ // removed. Example usage:
+ //
+ // JavaScript:
+ // nacl_module.postMessage({'foo': 123});
+ //
+ // C++:
+ // void MyMessageHandler(const pp::Var& key,
+ // const pp::Var& value,
+ // void* user_data) {
+ // assert(key.is_string());
+ // assert(key.AsString() == "foo");
+ // assert(value.is_int());
+ // assert(value.AsInt() == 123);
+ // }
+ // ...
+ // instance_->RegisterMessageHandler("foo", &MyMessageHandler, NULL);
+ //
+ void RegisterMessageHandler(std::string message_name,
+ MessageHandler_t handler,
+ void* user_data);
+
protected:
+ typedef std::map<std::string, MessageHandler> MessageHandlerMap;
+
// Callback functions triggered by Pepper
//
// These functions are called on the main pepper thread, so they must
@@ -113,6 +151,26 @@ class PSInstance : public pp::Instance, pp::MouseLock, pp::Graphics3DClient {
private:
static void* MainThreadThunk(void *start_info);
+ ssize_t TtyOutputHandler(const char* buf, size_t count);
+ void MessageHandlerInput(const pp::Var& message);
+ void MessageHandlerResize(const pp::Var& message);
+
+ static ssize_t TtyOutputHandlerStatic(const char* buf, size_t count,
+ void* user_data);
+
+ /// Handle input message from JavaScript. The value is
+ /// expected to be of type string.
+ static void MessageHandlerInputStatic(const pp::Var& key,
+ const pp::Var& value,
+ void* user_data);
+
+
+ /// Handle resizs message from JavaScript. The value is
+ /// expected to be an array of 2 integers representing the
+ /// number of columns and rows in the TTY.
+ static void MessageHandlerResizeStatic(const pp::Var& key,
+ const pp::Var& value,
+ void* user_data);
protected:
pp::MessageLoop* main_loop_;
@@ -120,7 +178,11 @@ class PSInstance : public pp::Instance, pp::MouseLock, pp::Graphics3DClient {
sdk_util::ThreadSafeQueue<PSEvent> event_queue_;
uint32_t events_enabled_;
Verbosity verbosity_;
- int fd_tty_;
+
+ // TTY handling
+ int tty_fd_;
+ const char* tty_prefix_;
+ MessageHandlerMap message_handlers_;
PSMainFunc_t main_cb_;
diff --git a/native_client_sdk/src/libraries/sdk_util/auto_lock.h b/native_client_sdk/src/libraries/sdk_util/auto_lock.h
index b4892691f1..b969416ad7 100644
--- a/native_client_sdk/src/libraries/sdk_util/auto_lock.h
+++ b/native_client_sdk/src/libraries/sdk_util/auto_lock.h
@@ -24,7 +24,7 @@ class AutoLock {
}
~AutoLock() {
- if (lock_) pthread_mutex_unlock(lock_);
+ Unlock();
}
void Unlock() {
diff --git a/native_client_sdk/src/libraries/third_party/newlib-extras/sys/signal.h b/native_client_sdk/src/libraries/third_party/newlib-extras/sys/signal.h
new file mode 100644
index 0000000000..36093b6b29
--- /dev/null
+++ b/native_client_sdk/src/libraries/third_party/newlib-extras/sys/signal.h
@@ -0,0 +1,311 @@
+/* sys/signal.h */
+
+#ifndef _SYS_SIGNAL_H
+#define _SYS_SIGNAL_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "_ansi.h"
+#include <sys/features.h>
+#include <sys/types.h>
+
+/* #ifndef __STRICT_ANSI__*/
+
+typedef unsigned long sigset_t;
+
+#if defined(__rtems__)
+
+#if defined(_POSIX_REALTIME_SIGNALS)
+
+/* sigev_notify values
+ NOTE: P1003.1c/D10, p. 34 adds SIGEV_THREAD. */
+
+#define SIGEV_NONE 1 /* No asynchronous notification shall be delivered */
+ /* when the event of interest occurs. */
+#define SIGEV_SIGNAL 2 /* A queued signal, with an application defined */
+ /* value, shall be delivered when the event of */
+ /* interest occurs. */
+#define SIGEV_THREAD 3 /* A notification function shall be called to */
+ /* perform notification. */
+
+/* Signal Generation and Delivery, P1003.1b-1993, p. 63
+ NOTE: P1003.1c/D10, p. 34 adds sigev_notify_function and
+ sigev_notify_attributes to the sigevent structure. */
+
+union sigval {
+ int sival_int; /* Integer signal value */
+ void *sival_ptr; /* Pointer signal value */
+};
+
+struct sigevent {
+ int sigev_notify; /* Notification type */
+ int sigev_signo; /* Signal number */
+ union sigval sigev_value; /* Signal value */
+
+#if defined(_POSIX_THREADS)
+ void (*sigev_notify_function)( union sigval );
+ /* Notification function */
+ pthread_attr_t *sigev_notify_attributes; /* Notification Attributes */
+#endif
+};
+
+/* Signal Actions, P1003.1b-1993, p. 64 */
+/* si_code values, p. 66 */
+
+#define SI_USER 1 /* Sent by a user. kill(), abort(), etc */
+#define SI_QUEUE 2 /* Sent by sigqueue() */
+#define SI_TIMER 3 /* Sent by expiration of a timer_settime() timer */
+#define SI_ASYNCIO 4 /* Indicates completion of asycnhronous IO */
+#define SI_MESGQ 5 /* Indicates arrival of a message at an empty queue */
+
+typedef struct {
+ int si_signo; /* Signal number */
+ int si_code; /* Cause of the signal */
+ union sigval si_value; /* Signal value */
+} siginfo_t;
+#endif
+
+/* 3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76 */
+
+#define SA_NOCLDSTOP 1 /* Do not generate SIGCHLD when children stop */
+#define SA_SIGINFO 2 /* Invoke the signal catching function with */
+ /* three arguments instead of one. */
+
+/* struct sigaction notes from POSIX:
+ *
+ * (1) Routines stored in sa_handler should take a single int as
+ * their argument although the POSIX standard does not require this.
+ * This is not longer true since at least POSIX.1-2008
+ * (2) The fields sa_handler and sa_sigaction may overlap, and a conforming
+ * application should not use both simultaneously.
+ */
+
+typedef void (*_sig_func_ptr)(int);
+
+struct sigaction {
+ int sa_flags; /* Special flags to affect behavior of signal */
+ sigset_t sa_mask; /* Additional set of signals to be blocked */
+ /* during execution of signal-catching */
+ /* function. */
+ union {
+ _sig_func_ptr _handler; /* SIG_DFL, SIG_IGN, or pointer to a function */
+#if defined(_POSIX_REALTIME_SIGNALS)
+ void (*_sigaction)( int, siginfo_t *, void * );
+#endif
+ } _signal_handlers;
+};
+
+#define sa_handler _signal_handlers._handler
+#if defined(_POSIX_REALTIME_SIGNALS)
+#define sa_sigaction _signal_handlers._sigaction
+#endif
+
+#elif defined(__CYGWIN__)
+#include <cygwin/signal.h>
+#else
+#define SA_NOCLDSTOP 1 /* only value supported now for sa_flags */
+
+typedef void (*_sig_func_ptr)(int);
+
+struct sigaction
+{
+ _sig_func_ptr sa_handler;
+ sigset_t sa_mask;
+ int sa_flags;
+};
+#endif /* defined(__rtems__) */
+
+#define SIG_SETMASK 0 /* set mask with sigprocmask() */
+#define SIG_BLOCK 1 /* set of signals to block */
+#define SIG_UNBLOCK 2 /* set of signals to, well, unblock */
+
+/* These depend upon the type of sigset_t, which right now
+ is always a long.. They're in the POSIX namespace, but
+ are not ANSI. */
+#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0)
+#define sigdelset(what,sig) (*(what) &= ~(1<<(sig)), 0)
+#define sigemptyset(what) (*(what) = 0, 0)
+#define sigfillset(what) (*(what) = ~(0), 0)
+#define sigismember(what,sig) (((*(what)) & (1<<(sig))) != 0)
+
+int _EXFUN(sigprocmask, (int how, const sigset_t *set, sigset_t *oset));
+
+#if defined(_POSIX_THREADS)
+int _EXFUN(pthread_sigmask, (int how, const sigset_t *set, sigset_t *oset));
+#endif
+
+/* protos for functions found in winsup sources for CYGWIN */
+#if defined(__CYGWIN__) || defined(__rtems__) || defined (__native_client__)
+#undef sigaddset
+#undef sigdelset
+#undef sigemptyset
+#undef sigfillset
+#undef sigismember
+
+int _EXFUN(kill, (pid_t, int));
+int _EXFUN(killpg, (pid_t, int));
+int _EXFUN(sigaction, (int, const struct sigaction *, struct sigaction *));
+int _EXFUN(sigaddset, (sigset_t *, const int));
+int _EXFUN(sigdelset, (sigset_t *, const int));
+int _EXFUN(sigismember, (const sigset_t *, int));
+int _EXFUN(sigfillset, (sigset_t *));
+int _EXFUN(sigemptyset, (sigset_t *));
+int _EXFUN(sigpending, (sigset_t *));
+int _EXFUN(sigsuspend, (const sigset_t *));
+int _EXFUN(sigpause, (int));
+
+#if defined(_POSIX_THREADS)
+#ifdef __CYGWIN__
+# ifndef _CYGWIN_TYPES_H
+# error You need the winsup sources or a cygwin installation to compile the cygwin version of newlib.
+# endif
+#endif
+int _EXFUN(pthread_kill, (pthread_t thread, int sig));
+#endif
+
+#if defined(_POSIX_REALTIME_SIGNALS)
+
+/* 3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76
+ NOTE: P1003.1c/D10, p. 39 adds sigwait(). */
+
+int _EXFUN(sigwaitinfo, (const sigset_t *set, siginfo_t *info));
+int _EXFUN(sigtimedwait,
+ (const sigset_t *set, siginfo_t *info, const struct timespec *timeout)
+);
+int _EXFUN(sigwait, (const sigset_t *set, int *sig));
+
+/* 3.3.9 Queue a Signal to a Process, P1003.1b-1993, p. 78 */
+int _EXFUN(sigqueue, (pid_t pid, int signo, const union sigval value));
+
+#endif /* defined(_POSIX_REALTIME_SIGNALS) */
+
+#endif /* defined(__CYGWIN__) || defined(__rtems__) */
+
+/* #endif __STRICT_ANSI__ */
+
+#if defined(___AM29K__)
+/* These all need to be defined for ANSI C, but I don't think they are
+ meaningful. */
+#define SIGABRT 1
+#define SIGFPE 1
+#define SIGILL 1
+#define SIGINT 1
+#define SIGSEGV 1
+#define SIGTERM 1
+/* These need to be defined for POSIX, and some others do too. */
+#define SIGHUP 1
+#define SIGQUIT 1
+#define NSIG 2
+#elif defined(__GO32__)
+#define SIGINT 1
+#define SIGKILL 2
+#define SIGPIPE 3
+#define SIGFPE 4
+#define SIGHUP 5
+#define SIGTERM 6
+#define SIGSEGV 7
+#define SIGTSTP 8
+#define SIGQUIT 9
+#define SIGTRAP 10
+#define SIGILL 11
+#define SIGEMT 12
+#define SIGALRM 13
+#define SIGBUS 14
+#define SIGLOST 15
+#define SIGSTOP 16
+#define SIGABRT 17
+#define SIGUSR1 18
+#define SIGUSR2 19
+#define NSIG 20
+#elif !defined(SIGTRAP)
+#define SIGHUP 1 /* hangup */
+#define SIGINT 2 /* interrupt */
+#define SIGQUIT 3 /* quit */
+#define SIGILL 4 /* illegal instruction (not reset when caught) */
+#define SIGTRAP 5 /* trace trap (not reset when caught) */
+#define SIGIOT 6 /* IOT instruction */
+#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */
+#define SIGEMT 7 /* EMT instruction */
+#define SIGFPE 8 /* floating point exception */
+#define SIGKILL 9 /* kill (cannot be caught or ignored) */
+#define SIGBUS 10 /* bus error */
+#define SIGSEGV 11 /* segmentation violation */
+#define SIGSYS 12 /* bad argument to system call */
+#define SIGPIPE 13 /* write on a pipe with no one to read it */
+#define SIGALRM 14 /* alarm clock */
+#define SIGTERM 15 /* software termination signal from kill */
+
+#if defined(__rtems__)
+#define SIGURG 16 /* urgent condition on IO channel */
+#define SIGSTOP 17 /* sendable stop signal not from tty */
+#define SIGTSTP 18 /* stop signal from tty */
+#define SIGCONT 19 /* continue a stopped process */
+#define SIGCHLD 20 /* to parent on child stop or exit */
+#define SIGCLD 20 /* System V name for SIGCHLD */
+#define SIGTTIN 21 /* to readers pgrp upon background tty read */
+#define SIGTTOU 22 /* like TTIN for output if (tp->t_local&LTOSTOP) */
+#define SIGIO 23 /* input/output possible signal */
+#define SIGPOLL SIGIO /* System V name for SIGIO */
+#define SIGWINCH 24 /* window changed */
+#define SIGUSR1 25 /* user defined signal 1 */
+#define SIGUSR2 26 /* user defined signal 2 */
+
+/* Real-Time Signals Range, P1003.1b-1993, p. 61
+ NOTE: By P1003.1b-1993, this should be at least RTSIG_MAX
+ (which is a minimum of 8) signals.
+ */
+#define SIGRTMIN 27
+#define SIGRTMAX 31
+#define __SIGFIRSTNOTRT SIGHUP
+#define __SIGLASTNOTRT SIGUSR2
+
+#define NSIG 32 /* signal 0 implied */
+
+#elif defined(__svr4__)
+/* svr4 specifics. different signals above 15, and sigaction. */
+#define SIGUSR1 16
+#define SIGUSR2 17
+#define SIGCLD 18
+#define SIGPWR 19
+#define SIGWINCH 20
+#define SIGPOLL 22 /* 20 for x.out binaries!!!! */
+#define SIGSTOP 23 /* sendable stop signal not from tty */
+#define SIGTSTP 24 /* stop signal from tty */
+#define SIGCONT 25 /* continue a stopped process */
+#define SIGTTIN 26 /* to readers pgrp upon background tty read */
+#define SIGTTOU 27 /* like TTIN for output if (tp->t_local&LTOSTOP) */
+#define NSIG 28
+#else
+#define SIGURG 16 /* urgent condition on IO channel */
+#define SIGSTOP 17 /* sendable stop signal not from tty */
+#define SIGTSTP 18 /* stop signal from tty */
+#define SIGCONT 19 /* continue a stopped process */
+#define SIGCHLD 20 /* to parent on child stop or exit */
+#define SIGCLD 20 /* System V name for SIGCHLD */
+#define SIGTTIN 21 /* to readers pgrp upon background tty read */
+#define SIGTTOU 22 /* like TTIN for output if (tp->t_local&LTOSTOP) */
+#define SIGIO 23 /* input/output possible signal */
+#define SIGPOLL SIGIO /* System V name for SIGIO */
+#define SIGXCPU 24 /* exceeded CPU time limit */
+#define SIGXFSZ 25 /* exceeded file size limit */
+#define SIGVTALRM 26 /* virtual time alarm */
+#define SIGPROF 27 /* profiling time alarm */
+#define SIGWINCH 28 /* window changed */
+#define SIGLOST 29 /* resource lost (eg, record-lock lost) */
+#define SIGUSR1 30 /* user defined signal 1 */
+#define SIGUSR2 31 /* user defined signal 2 */
+#define NSIG 32 /* signal 0 implied */
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef _SIGNAL_H_
+/* Some applications take advantage of the fact that <sys/signal.h>
+ * and <signal.h> are equivalent in glibc. Allow for that here. */
+#include <signal.h>
+#endif
+#endif /* _SYS_SIGNAL_H */
diff --git a/native_client_sdk/src/libraries/nacl_io_test/event_test.cc b/native_client_sdk/src/tests/nacl_io_socket_test/event_test.cc
index c342799afa..7a854d7c23 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/event_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/event_test.cc
@@ -325,7 +325,7 @@ struct SignalInfo {
uint32_t events;
};
-void *SignalEmitter(void *ptr) {
+static void *SignalEmitterThread(void *ptr) {
SignalInfo* info = (SignalInfo*) ptr;
struct timespec ts;
ts.tv_sec = 0;
@@ -356,7 +356,7 @@ TEST(EventTest, EmitterSignalling) {
siginfo.ms_wait = TIMEOUT_SHORT;
siginfo.events = KE_EXPECTED | KE_FILTERED;
pthread_t tid;
- pthread_create(&tid, NULL, SignalEmitter, &siginfo);
+ pthread_create(&tid, NULL, SignalEmitterThread, &siginfo);
// Wait for the signal from the other thread and time it.
gettimeofday(&start, NULL);
diff --git a/native_client_sdk/src/tests/nacl_io_socket_test/example.dsc b/native_client_sdk/src/tests/nacl_io_socket_test/example.dsc
new file mode 100644
index 0000000000..6340d66ec5
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/example.dsc
@@ -0,0 +1,37 @@
+{
+ 'TOOLS': ['newlib', 'glibc', 'pnacl'],
+
+ # Need to add ../../examples for common.js
+ 'SEARCH': ['.', '../../examples'],
+ 'TARGETS': [
+ {
+ 'NAME' : 'nacl_io_socket_test',
+ 'TYPE' : 'main',
+ 'SOURCES' : [
+ 'main.cc',
+ 'socket_test.cc',
+ ],
+ 'DEPS': ['ppapi_simple', 'nacl_io'],
+ # Order matters here: gtest has a "main" function that will be used if
+ # referenced before ppapi.
+ 'LIBS': ['gmock', 'ppapi_cpp', 'ppapi', 'gtest', 'pthread'],
+ 'INCLUDES': ['$(NACL_SDK_ROOT)/include/gtest/internal'],
+ 'CXXFLAGS': ['-Wno-sign-compare', '-Wno-unused-private-field'],
+ 'CFLAGS_GCC': ['-Wno-unused-local-typedefs'],
+ }
+ ],
+ 'DATA': [
+ 'example.js'
+ ],
+ 'DEST': 'tests',
+ 'NAME': 'nacl_io_socket_test',
+ 'TITLE': 'NaCl IO Socket test',
+ 'PRE': '''\nCHROME_ARGS = --allow-nacl-socket-api=localhost\n''',
+ 'SOCKET_PERMISSIONS': [
+ "tcp-listen:*:*",
+ "tcp-connect",
+ "resolve-host",
+ "udp-bind:*:*",
+ "udp-send-to:*:*"
+ ]
+}
diff --git a/native_client_sdk/src/tests/nacl_io_socket_test/example.js b/native_client_sdk/src/tests/nacl_io_socket_test/example.js
new file mode 100644
index 0000000000..1a6a8bf868
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/example.js
@@ -0,0 +1,126 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Called by the common.js module.
+
+function runTCPEchoServer(port) {
+ console.log("Starting server on TCP port: " + port);
+ chrome.socket.create("tcp", {}, function(createInfo) {
+ var listeningSocket = createInfo.socketId;
+ chrome.socket.listen(listeningSocket,
+ '127.0.0.1',
+ port,
+ 10,
+ function(result) {
+ if (result !== 0) {
+ console.log("Listen failed: " + result);
+ return;
+ }
+
+ chrome.socket.accept(listeningSocket, function(acceptInfo) {
+ if (result !== 0) {
+ console.log("Accept failed: " + result);
+ return;
+ }
+
+ var newSock = acceptInfo.socketId;
+
+ var readCallback = function(readInfo) {
+ if (readInfo.resultCode < 0) {
+ console.log("Read failed: " + readInfo.resultCode);
+ chrome.socket.destroy(newSock);
+ return;
+ }
+
+ chrome.socket.write(newSock, readInfo.data, function(writeInfo) {})
+ chrome.socket.read(newSock, readCallback);
+ }
+
+ chrome.socket.read(newSock, readCallback);
+ })
+ })
+ })
+}
+
+function moduleDidLoad() {
+ // The module is not hidden by default so we can easily see if the plugin
+ // failed to load.
+ common.hideModule();
+ runTCPEchoServer(4006);
+}
+
+var currentTestEl = null;
+
+function startCommand(testName) {
+ var testListEl = document.getElementById('tests');
+ var testEl = document.createElement('li');
+ var testRowEl = document.createElement('div');
+ var testNameEl = document.createElement('span');
+ var testResultEl = document.createElement('span');
+ testRowEl.classList.add('row');
+ testNameEl.classList.add('name');
+ testNameEl.textContent = testName;
+ testResultEl.classList.add('result');
+ testRowEl.appendChild(testNameEl);
+ testRowEl.appendChild(testResultEl);
+ testEl.appendChild(testRowEl);
+ testListEl.appendChild(testEl);
+
+ currentTestEl = testEl;
+}
+
+function failCommand(fileName, lineNumber, summary) {
+ var testMessageEl = document.createElement('pre');
+ testMessageEl.textContent += fileName + ':' + lineNumber + ': ' + summary;
+ currentTestEl.appendChild(testMessageEl);
+}
+
+function endCommand(testName, testResult) {
+ var testRowEl = currentTestEl.querySelector('.row');
+ var testResultEl = currentTestEl.querySelector('.result');
+ testRowEl.classList.add(testResult);
+ testResultEl.textContent = testResult;
+}
+
+function handleMessage(event) {
+ var msg = event.data;
+ var firstColon = msg.indexOf(':');
+ var cmd = msg.substr(0, firstColon);
+ var cmdFunctionName = cmd + 'Command';
+ var cmdFunction = window[cmdFunctionName];
+
+ if (typeof(cmdFunction) !== 'function') {
+ console.log('Unknown command: ' + cmd);
+ console.log(' message: ' + msg);
+ return;
+ }
+
+ var argCount = cmdFunction.length;
+
+ // Don't use split, because it will split all commas (for example any commas
+ // in the test failure summary).
+ var argList = msg.substr(firstColon + 1);
+ args = [];
+ for (var i = 0; i < argCount - 1; ++i) {
+ var arg;
+ var comma = argList.indexOf(',');
+ if (comma === -1) {
+ if (i !== argCount - 1) {
+ console.log('Bad arg count to command "' + cmd + '", expected ' +
+ argCount);
+ console.log(' message: ' + msg);
+ } else {
+ arg = argList;
+ }
+ } else {
+ arg = argList.substr(0, comma);
+ argList = argList.substr(comma + 1);
+ }
+ args.push(arg);
+ }
+
+ // Last argument is the rest of the message.
+ args.push(argList);
+
+ cmdFunction.apply(null, args);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/index.html b/native_client_sdk/src/tests/nacl_io_socket_test/index.html
index ba54317929..ba54317929 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/index.html
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/index.html
diff --git a/native_client_sdk/src/libraries/nacl_io_test/main.cc b/native_client_sdk/src/tests/nacl_io_socket_test/main.cc
index ef7b09433a..ef7b09433a 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/main.cc
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/main.cc
diff --git a/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc b/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc
new file mode 100644
index 0000000000..fe22ae18e0
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_socket_test/socket_test.cc
@@ -0,0 +1,191 @@
+// Copyright 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 <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <map>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/ossocket.h"
+#include "nacl_io/ostypes.h"
+
+#ifdef PROVIDES_SOCKET_API
+
+using namespace nacl_io;
+using namespace sdk_util;
+
+// No error expected
+#define ENONE 0
+#define LOCAL_HOST 0x7F000001
+#define PORT1 4006
+#define PORT2 4007
+#define ANY_PORT 0
+
+
+namespace {
+class SocketTest : public ::testing::Test {
+ public:
+ SocketTest() : sock1(0), sock2(0) {}
+
+ ~SocketTest() {
+ EXPECT_EQ(0, close(sock1));
+ EXPECT_EQ(0, close(sock2));
+ }
+
+ void IP4ToSockAddr(uint32_t ip, uint16_t port, struct sockaddr_in* addr) {
+ memset(addr, 0, sizeof(*addr));
+
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(port);
+ addr->sin_addr.s_addr = htonl(ip);
+ }
+
+ int Bind(int fd, uint32_t ip, uint16_t port) {
+ sockaddr_in addr;
+ socklen_t addrlen = sizeof(addr);
+
+ IP4ToSockAddr(ip, port, &addr);
+ int err = bind(fd, (sockaddr*) &addr, addrlen);
+
+ if (err == -1)
+ return errno;
+ return 0;
+ }
+
+ void SetupPorts() {
+ EXPECT_EQ(Bind(sock1, LOCAL_HOST, 0), ENONE);
+ EXPECT_EQ(Bind(sock2, LOCAL_HOST, 0), ENONE);
+ }
+
+ public:
+ int sock1;
+ int sock2;
+};
+
+class SocketTestUDP : public SocketTest {
+ public:
+ SocketTestUDP() {
+ sock1 = socket(AF_INET, SOCK_DGRAM, 0);
+ sock2 = socket(AF_INET, SOCK_DGRAM, 0);
+
+ EXPECT_LT(-1, sock1);
+ EXPECT_LT(-1, sock2);
+ }
+};
+
+class SocketTestTCP : public SocketTest {
+ public:
+ SocketTestTCP() {
+ sock1 = socket(AF_INET, SOCK_STREAM, 0);
+ sock2 = socket(AF_INET, SOCK_STREAM, 0);
+
+ EXPECT_LT(-1, sock1);
+ EXPECT_LT(-1, sock2);
+ }
+};
+
+} // namespace
+
+TEST(SocketTestSimple, Socket) {
+ EXPECT_EQ(-1, socket(AF_UNIX, SOCK_STREAM, 0));
+ EXPECT_EQ(errno, EAFNOSUPPORT);
+ EXPECT_EQ(-1, socket(AF_INET, SOCK_RAW, 0));
+ EXPECT_EQ(errno, EPROTONOSUPPORT);
+
+ int sock1 = socket(AF_INET, SOCK_DGRAM, 0);
+ EXPECT_NE(-1, sock1);
+
+ int sock2 = socket(AF_INET6, SOCK_DGRAM, 0);
+ EXPECT_NE(-1, sock2);
+
+ int sock3 = socket(AF_INET, SOCK_STREAM, 0);
+ EXPECT_NE(-1, sock3);
+
+ int sock4 = socket(AF_INET6, SOCK_STREAM, 0);
+ EXPECT_NE(-1, sock4);
+
+ close(sock1);
+ close(sock2);
+ close(sock3);
+ close(sock4);
+}
+
+TEST_F(SocketTestUDP, Bind) {
+ // Bind away.
+ EXPECT_EQ(Bind(sock1, LOCAL_HOST, PORT1), ENONE);
+
+ // Invalid to rebind a socket.
+ EXPECT_EQ(Bind(sock1, LOCAL_HOST, PORT1), EINVAL);
+
+ // Addr in use.
+ EXPECT_EQ(Bind(sock2, LOCAL_HOST, PORT1), EADDRINUSE);
+
+ // Bind with a wildcard.
+ EXPECT_EQ(Bind(sock2, LOCAL_HOST, ANY_PORT), ENONE);
+
+ // Invalid to rebind after wildcard
+ EXPECT_EQ(Bind(sock2, LOCAL_HOST, PORT1), EINVAL);
+
+}
+
+TEST_F(SocketTestUDP, SendRcv) {
+ char outbuf[256];
+ char inbuf[512];
+
+ memset(outbuf, 1, sizeof(outbuf));
+ memset(inbuf, 0, sizeof(inbuf));
+
+ EXPECT_EQ(Bind(sock1, LOCAL_HOST, PORT1), ENONE);
+ EXPECT_EQ(Bind(sock2, LOCAL_HOST, PORT2), ENONE);
+
+ sockaddr_in addr;
+ socklen_t addrlen = sizeof(addr);
+ IP4ToSockAddr(LOCAL_HOST, PORT2, &addr);
+
+ int len1 =
+ sendto(sock1, outbuf, sizeof(outbuf), 0, (sockaddr *) &addr, addrlen);
+ EXPECT_EQ(sizeof(outbuf), len1);
+
+ // Ensure the buffers are different
+ EXPECT_NE(0, memcmp(outbuf, inbuf, sizeof(outbuf)));
+ memset(&addr, 0, sizeof(addr));
+
+ // Try to receive the previously sent packet
+ int len2 =
+ recvfrom(sock2, inbuf, sizeof(inbuf), 0, (sockaddr *) &addr, &addrlen);
+ EXPECT_EQ(sizeof(outbuf), len2);
+ EXPECT_EQ(sizeof(sockaddr_in), addrlen);
+ EXPECT_EQ(PORT1, htons(addr.sin_port));
+
+ // Now they should be the same
+ EXPECT_EQ(0, memcmp(outbuf, inbuf, sizeof(outbuf)));
+}
+
+#if 0
+TEST_F(SocketTestTCP, Connect) {
+ int sock = socket(AF_INET, SOCK_STREAM, 0);
+ EXPECT_NE(-1, sock);
+
+ sockaddr_in addr;
+ socklen_t addrlen = sizeof(addr);
+
+ IP4ToSockAddr(LOCAL_HOST, PORT1, &addr);
+ int err = connect(sock, (sockaddr*) &addr, addrlen);
+ EXPECT_EQ(ENONE, err) << "Failed with errno: " << errno << "\n";
+}
+#endif
+
+#endif // PROVIDES_SOCKETPAIR_API
diff --git a/native_client_sdk/src/tests/nacl_io_test/event_test.cc b/native_client_sdk/src/tests/nacl_io_test/event_test.cc
new file mode 100644
index 0000000000..11326bf083
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/event_test.cc
@@ -0,0 +1,481 @@
+/* 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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "gtest/gtest.h"
+
+#include "nacl_io/event_emitter.h"
+#include "nacl_io/event_listener.h"
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/kernel_wrap.h"
+
+
+using namespace nacl_io;
+using namespace sdk_util;
+
+class EventEmitterTester : public MountNode {
+ public:
+ EventEmitterTester() : MountNode(NULL), event_status_(0), event_cnt_(0) {}
+
+ void SetEventStatus(uint32_t bits) { event_status_ = bits; }
+ uint32_t GetEventStatus() { return event_status_; }
+
+ Error Ioctl(int request, char* arg) {
+ event_status_ = static_cast<uint32_t>(request);
+ return 0;
+ }
+
+ int GetType() { return S_IFSOCK; }
+ int NumEvents() { return event_cnt_; }
+
+ public:
+ // Make this function public for testing
+ void RaiseEvent(uint32_t events) {
+ EventEmitter::RaiseEvent(events);
+ }
+
+ // Called after registering locally, but while lock is still held.
+ void ChainRegisterEventInfo(const ScopedEventInfo& event) {
+ event_cnt_++;
+ }
+
+ // Called before unregistering locally, but while lock is still held.
+ void ChainUnregisterEventInfo(const ScopedEventInfo& event) {
+ event_cnt_--;
+ }
+
+ protected:
+ uint32_t event_status_;
+ uint32_t event_cnt_;
+};
+
+
+const int MAX_EVENTS = 8;
+
+// IDs for Emitters
+const int ID_EMITTER = 5;
+const int ID_LISTENER = 6;
+const int ID_EMITTER_DUP = 7;
+
+// Kernel Event values
+const uint32_t KE_EXPECTED = 4;
+const uint32_t KE_FILTERED = 2;
+const uint32_t KE_NONE = 0;
+
+// User Data values
+const uint64_t USER_DATA_A = 1;
+const uint64_t USER_DATA_B = 5;
+
+// Timeout durations
+const int TIMEOUT_IMMEDIATE = 0;
+const int TIMEOUT_SHORT= 100;
+const int TIMEOUT_LONG = 500;
+const int TIMEOUT_NEVER = -1;
+const int TIMEOUT_VERY_LONG = 1000;
+
+// We subtract TIMEOUT_SLOP from the expected minimum timed due to rounding
+// and clock drift converting between absolute and relative time. This should
+// only be 1 for Less Than, and 1 for rounding, but we use 10 since we don't
+// care about real precision, aren't testing of the underlying
+// implementations and don't want flakiness.
+const int TIMEOUT_SLOP = 10;
+
+TEST(EventTest, EmitterBasic) {
+ ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
+ ScopedRef<EventEmitter> null_emitter;
+
+ ScopedEventListener listener(new EventListener);
+
+ // Verify construction
+ EXPECT_EQ(0, emitter->NumEvents());
+ EXPECT_EQ(0, emitter->GetEventStatus());
+
+ // Verify status
+ emitter->SetEventStatus(KE_EXPECTED);
+ EXPECT_EQ(KE_EXPECTED, emitter->GetEventStatus());
+
+ // Fail to update or free an ID not in the set
+ EXPECT_EQ(ENOENT, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_A));
+ EXPECT_EQ(ENOENT, listener->Free(ID_EMITTER));
+
+ // Fail to Track self
+ EXPECT_EQ(EINVAL, listener->Track(ID_LISTENER,
+ listener,
+ KE_EXPECTED,
+ USER_DATA_A));
+
+ // Set the emitter filter and data
+ EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+ EXPECT_EQ(1, emitter->NumEvents());
+
+ // Fail to add the same ID
+ EXPECT_EQ(EEXIST,
+ listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+ EXPECT_EQ(1, emitter->NumEvents());
+
+ int event_cnt = 0;
+ EventData ev[MAX_EVENTS];
+
+ // Do not allow a wait with a zero events count.
+ EXPECT_EQ(EINVAL, listener->Wait(ev, 0, TIMEOUT_IMMEDIATE, &event_cnt));
+
+ // Do not allow a wait with a negative events count.
+ EXPECT_EQ(EINVAL, listener->Wait(ev, -1, TIMEOUT_IMMEDIATE, &event_cnt));
+
+ // Do not allow a wait with a NULL EventData pointer
+ EXPECT_EQ(EFAULT,
+ listener->Wait(NULL, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+
+ // Return with no events if the Emitter has no signals set.
+ memset(ev, 0, sizeof(ev));
+ event_cnt = 100;
+ emitter->SetEventStatus(KE_NONE);
+ EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+ EXPECT_EQ(0, event_cnt);
+
+ // Return with no events if the Emitter has a filtered signals set.
+ memset(ev, 0, sizeof(ev));
+ event_cnt = 100;
+ emitter->SetEventStatus(KE_FILTERED);
+ EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+ EXPECT_EQ(0, event_cnt);
+
+ // Return with one event if the Emitter has the expected signal set.
+ memset(ev, 0, sizeof(ev));
+ event_cnt = 100;
+ emitter->SetEventStatus(KE_EXPECTED);
+ EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+ EXPECT_EQ(1, event_cnt);
+ EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+ EXPECT_EQ(KE_EXPECTED, ev[0].events);
+
+ // Return with one event containing only the expected signal.
+ memset(ev, 0, sizeof(ev));
+ event_cnt = 100;
+ emitter->SetEventStatus(KE_EXPECTED | KE_FILTERED);
+ EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+ EXPECT_EQ(1, event_cnt);
+ EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+ EXPECT_EQ(KE_EXPECTED, ev[0].events);
+
+ // Change the USER_DATA on an existing event
+ EXPECT_EQ(0, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_B));
+
+ // Return with one event signaled with the alternate USER DATA
+ memset(ev, 0, sizeof(ev));
+ event_cnt = 100;
+ emitter->SetEventStatus(KE_EXPECTED | KE_FILTERED);
+ EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, 0, &event_cnt));
+ EXPECT_EQ(1, event_cnt);
+ EXPECT_EQ(USER_DATA_B, ev[0].user_data);
+ EXPECT_EQ(KE_EXPECTED, ev[0].events);
+
+ // Reset the USER_DATA.
+ EXPECT_EQ(0, listener->Update(ID_EMITTER, KE_EXPECTED, USER_DATA_A));
+
+ // Support adding a DUP.
+ EXPECT_EQ(0, listener->Track(ID_EMITTER_DUP,
+ emitter,
+ KE_EXPECTED,
+ USER_DATA_A));
+ EXPECT_EQ(2, emitter->NumEvents());
+
+ // Return unsignaled.
+ memset(ev, 0, sizeof(ev));
+ emitter->SetEventStatus(KE_NONE);
+ event_cnt = 100;
+ EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+ EXPECT_EQ(0, event_cnt);
+
+ // Return with two event signaled with expected data.
+ memset(ev, 0, sizeof(ev));
+ emitter->SetEventStatus(KE_EXPECTED);
+ event_cnt = 100;
+ EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_IMMEDIATE, &event_cnt));
+ EXPECT_EQ(2, event_cnt);
+ EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+ EXPECT_EQ(KE_EXPECTED, ev[0].events);
+ EXPECT_EQ(USER_DATA_A, ev[1].user_data);
+ EXPECT_EQ(KE_EXPECTED, ev[1].events);
+}
+
+long Duration(struct timeval* start, struct timeval* end) {
+ if (start->tv_usec > end->tv_usec) {
+ end->tv_sec -= 1;
+ end->tv_usec += 1000000;
+ }
+ long cur_time = 1000 * (end->tv_sec - start->tv_sec);
+ cur_time += (end->tv_usec - start->tv_usec) / 1000;
+ return cur_time;
+}
+
+
+// Run a timed wait, and return the average of 8 iterations to reduce
+// chance of false negative on outlier.
+const int TRIES_TO_AVERAGE = 8;
+bool TimedListen(ScopedEventListener& listen,
+ EventData* ev,
+ int ev_max,
+ int ev_expect,
+ int ms_wait,
+ long* duration) {
+
+ struct timeval start;
+ struct timeval end;
+ long total_time = 0;
+
+ for (int a=0; a < TRIES_TO_AVERAGE; a++) {
+ gettimeofday(&start, NULL);
+
+ int signaled;
+
+ EXPECT_EQ(0, listen->Wait(ev, ev_max, ms_wait, &signaled));
+ EXPECT_EQ(signaled, ev_expect);
+
+ if (signaled != ev_expect) {
+ return false;
+ }
+
+ gettimeofday(&end, NULL);
+
+ long cur_time = Duration(&start, &end);
+ total_time += cur_time;
+ }
+
+ *duration = total_time / TRIES_TO_AVERAGE;
+ return true;
+}
+
+
+// NOTE: These timing tests are potentially flaky, the real test is
+// for the zero timeout should be, has the ConditionVariable been waited on?
+// Once we provide a debuggable SimpleCond and SimpleLock we can actually test
+// the correct thing.
+
+// Normal scheduling would expect us to see ~10ms accuracy, but we'll
+// use a much bigger number (yet smaller than the MAX_MS_TIMEOUT).
+const int SCHEDULING_GRANULARITY = 100;
+
+const int EXPECT_ONE_EVENT = 1;
+const int EXPECT_NO_EVENT = 0;
+
+TEST(EventTest, EmitterTimeout) {
+ ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
+ ScopedEventListener listener(new EventListener());
+ long duration;
+
+ EventData ev[MAX_EVENTS];
+ memset(ev, 0, sizeof(ev));
+ EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+
+ // Return immediately when emitter is signaled, with no timeout
+ emitter->SetEventStatus(KE_EXPECTED);
+ memset(ev, 0, sizeof(ev));
+ EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
+ TIMEOUT_IMMEDIATE, &duration));
+ EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+ EXPECT_EQ(KE_EXPECTED, ev[0].events);
+ EXPECT_EQ(0, duration);
+
+ // Return immediately when emitter is signaled, even with timeout
+ emitter->SetEventStatus(KE_EXPECTED);
+ memset(ev, 0, sizeof(ev));
+ EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
+ TIMEOUT_LONG, &duration));
+ EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+ EXPECT_EQ(KE_EXPECTED, ev[0].events);
+ EXPECT_GT(SCHEDULING_GRANULARITY, duration);
+
+ // Return immediately if Emiiter is already signaled when blocking forever.
+ emitter->SetEventStatus(KE_EXPECTED);
+ memset(ev, 0, sizeof(ev));
+ EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_ONE_EVENT,
+ TIMEOUT_NEVER, &duration));
+ EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+ EXPECT_EQ(KE_EXPECTED, ev[0].events);
+ EXPECT_GT(SCHEDULING_GRANULARITY, duration);
+
+ // Return immediately if Emitter is no signaled when not blocking.
+ emitter->SetEventStatus(KE_NONE);
+ memset(ev, 0, sizeof(ev));
+ EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_NO_EVENT,
+ TIMEOUT_IMMEDIATE, &duration));
+ EXPECT_EQ(0, duration);
+
+ // Wait TIMEOUT_LONG if the emitter is not in a signaled state.
+ emitter->SetEventStatus(KE_NONE);
+ memset(ev, 0, sizeof(ev));
+ EXPECT_TRUE(TimedListen(listener, ev, MAX_EVENTS, EXPECT_NO_EVENT,
+ TIMEOUT_LONG, &duration));
+ EXPECT_LT(TIMEOUT_LONG - TIMEOUT_SLOP, duration);
+ EXPECT_GT(TIMEOUT_LONG + SCHEDULING_GRANULARITY, duration);
+}
+
+struct SignalInfo {
+ EventEmitterTester* em;
+ unsigned int ms_wait;
+ uint32_t events;
+};
+
+static void *SignalEmitterThread(void *ptr) {
+ SignalInfo* info = (SignalInfo*) ptr;
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = info->ms_wait * 1000000;
+
+ nanosleep(&ts, NULL);
+
+ info->em->RaiseEvent(info->events);
+ return NULL;
+}
+
+TEST(EventTest, EmitterSignalling) {
+ ScopedRef<EventEmitterTester> emitter(new EventEmitterTester());
+ ScopedEventListener listener(new EventListener);
+
+ SignalInfo siginfo;
+ struct timeval start;
+ struct timeval end;
+ long duration;
+
+ EventData ev[MAX_EVENTS];
+ memset(ev, 0, sizeof(ev));
+ EXPECT_EQ(0, listener->Track(ID_EMITTER, emitter, KE_EXPECTED, USER_DATA_A));
+
+ // Setup another thread to wait 1/4 of the max time, and signal both
+ // an expected, and unexpected value.
+ siginfo.em = emitter.get();
+ siginfo.ms_wait = TIMEOUT_SHORT;
+ siginfo.events = KE_EXPECTED | KE_FILTERED;
+ pthread_t tid;
+ pthread_create(&tid, NULL, SignalEmitterThread, &siginfo);
+
+ // Wait for the signal from the other thread and time it.
+ gettimeofday(&start, NULL);
+ int cnt = 0;
+ EXPECT_EQ(0, listener->Wait(ev, MAX_EVENTS, TIMEOUT_VERY_LONG, &cnt));
+ EXPECT_EQ(1, cnt);
+ gettimeofday(&end, NULL);
+
+ // Verify the wait duration, and that we only recieved the expected signal.
+ duration = Duration(&start, &end);
+ EXPECT_GT(TIMEOUT_SHORT + SCHEDULING_GRANULARITY, duration);
+ EXPECT_LT(TIMEOUT_SHORT - TIMEOUT_SLOP, duration);
+ EXPECT_EQ(USER_DATA_A, ev[0].user_data);
+ EXPECT_EQ(KE_EXPECTED, ev[0].events);
+}
+
+
+namespace {
+
+class KernelProxyPolling : public KernelProxy {
+ public:
+ virtual int socket(int domain, int type, int protocol) {
+ ScopedMount mnt;
+ ScopedMountNode node(new EventEmitterTester());
+ ScopedKernelHandle handle(new KernelHandle(mnt, node));
+
+ Error error = handle->Init(0);
+ if (error) {
+ errno = error;
+ return -1;
+ }
+
+ return AllocateFD(handle);
+ }
+};
+
+class KernelProxyPollingTest : public ::testing::Test {
+ public:
+ void SetUp() {
+ ki_init(&kp_);
+ }
+
+ void TearDown() {
+ ki_uninit();
+ }
+
+ protected:
+ KernelProxyPolling kp_;
+};
+
+} // namespace
+
+
+#define SOCKET_CNT 4
+void SetFDs(fd_set* set, int* fds) {
+ FD_ZERO(set);
+
+ FD_SET(0, set);
+ FD_SET(1, set);
+ FD_SET(2, set);
+
+ for (int index = 0; index < SOCKET_CNT; index++)
+ FD_SET(fds[index], set);
+}
+
+TEST_F(KernelProxyPollingTest, Select) {
+ int fds[SOCKET_CNT];
+
+ fd_set rd_set;
+ fd_set wr_set;
+
+ FD_ZERO(&rd_set);
+ FD_ZERO(&wr_set);
+
+ FD_SET(0, &rd_set);
+ FD_SET(1, &rd_set);
+ FD_SET(2, &rd_set);
+
+ FD_SET(0, &wr_set);
+ FD_SET(1, &wr_set);
+ FD_SET(2, &wr_set);
+
+ // Expect normal files to select as read, write, and error
+ int cnt = select(4, &rd_set, &rd_set, &rd_set, NULL);
+ EXPECT_EQ(3 * 3, cnt);
+ EXPECT_NE(0, FD_ISSET(0, &rd_set));
+ EXPECT_NE(0, FD_ISSET(1, &rd_set));
+ EXPECT_NE(0, FD_ISSET(2, &rd_set));
+
+ for (int index = 0 ; index < SOCKET_CNT; index++) {
+ fds[index] = socket(0, 0, 0);
+ EXPECT_NE(-1, fds[index]);
+ }
+
+ // Highest numbered fd
+ const int fdnum = fds[SOCKET_CNT - 1] + 1;
+
+ // Expect only the normal files to select
+ SetFDs(&rd_set, fds);
+ cnt = select(fds[SOCKET_CNT-1] + 1, &rd_set, NULL, NULL, NULL);
+ EXPECT_EQ(3, cnt);
+ EXPECT_NE(0, FD_ISSET(0, &rd_set));
+ EXPECT_NE(0, FD_ISSET(1, &rd_set));
+ EXPECT_NE(0, FD_ISSET(2, &rd_set));
+ for (int index = 0 ; index < SOCKET_CNT; index++) {
+ EXPECT_EQ(0, FD_ISSET(fds[index], &rd_set));
+ }
+
+ // Poke one of the pollable nodes to be READ ready
+ ioctl(fds[0], POLLIN, NULL);
+
+ // Expect normal files to be read/write and one pollable node to be read.
+ SetFDs(&rd_set, fds);
+ SetFDs(&wr_set, fds);
+ cnt = select(fdnum, &rd_set, &wr_set, NULL, NULL);
+ EXPECT_EQ(7, cnt);
+ EXPECT_NE(0, FD_ISSET(fds[0], &rd_set));
+ EXPECT_EQ(0, FD_ISSET(fds[0], &wr_set));
+}
+
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/example.dsc b/native_client_sdk/src/tests/nacl_io_test/example.dsc
index 3c1226e7a8..1afb68af51 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/example.dsc
+++ b/native_client_sdk/src/tests/nacl_io_test/example.dsc
@@ -10,6 +10,14 @@
'TYPE' : 'main',
'SOURCES' : [
'event_test.cc',
+ 'fake_core_interface.cc',
+ 'fake_core_interface.h',
+ 'fake_pepper_interface_html5fs.cc',
+ 'fake_pepper_interface_html5fs.h',
+ 'fake_resource_manager.cc',
+ 'fake_resource_manager.h',
+ 'fake_var_interface.cc',
+ 'fake_var_interface.h',
'kernel_object_test.cc',
'kernel_proxy_mock.cc',
'kernel_proxy_mock.h',
@@ -17,6 +25,7 @@
'kernel_wrap_test.cc',
'main.cc',
'mock_util.h',
+ 'mount_dev_mock.h',
'mount_html5fs_test.cc',
'mount_http_test.cc',
'mount_mock.cc',
@@ -24,11 +33,13 @@
'mount_node_mock.cc',
'mount_node_mock.h',
'mount_node_test.cc',
+ 'mount_node_tty_test.cc',
'mount_test.cc',
'path_test.cc',
'pepper_interface_mock.cc',
'pepper_interface_mock.h',
- 'socket_test.cc',
+ 'socket_test.cc',
+ 'syscalls_test.cc',
],
'DEPS': ['ppapi_simple', 'nacl_io'],
# Order matters here: gtest has a "main" function that will be used if
diff --git a/native_client_sdk/src/tests/nacl_io_test/example.js b/native_client_sdk/src/tests/nacl_io_test/example.js
new file mode 100644
index 0000000000..3a65c8961f
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/example.js
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Called by the common.js module.
+function moduleDidLoad() {
+ // The module is not hidden by default so we can easily see if the plugin
+ // failed to load.
+ common.hideModule();
+}
+
+var currentTestEl = null;
+var failedTests = 0;
+var testsFinished = false;
+
+function startCommand(testName) {
+ var testListEl = document.getElementById('tests');
+ var testEl = document.createElement('li');
+ var testRowEl = document.createElement('div');
+ var testNameEl = document.createElement('span');
+ var testResultEl = document.createElement('span');
+ testRowEl.classList.add('row');
+ testNameEl.classList.add('name');
+ testNameEl.textContent = testName;
+ testResultEl.classList.add('result');
+ testRowEl.appendChild(testNameEl);
+ testRowEl.appendChild(testResultEl);
+ testEl.appendChild(testRowEl);
+ testListEl.appendChild(testEl);
+
+ currentTestEl = testEl;
+}
+
+function failCommand(fileName, lineNumber, summary) {
+ var testMessageEl = document.createElement('pre');
+ testMessageEl.textContent += fileName + ':' + lineNumber + ': ' + summary;
+ currentTestEl.appendChild(testMessageEl);
+ failedTests++;
+}
+
+function endCommand(testName, testResult) {
+ var testRowEl = currentTestEl.querySelector('.row');
+ var testResultEl = currentTestEl.querySelector('.result');
+ testRowEl.classList.add(testResult);
+ testResultEl.textContent = testResult;
+}
+
+function testendCommand() {
+ testsFinished = true;
+}
+
+function handleMessage(event) {
+ var msg = event.data;
+ var firstColon = msg.indexOf(':');
+ var cmd = firstColon !== -1 ? msg.substr(0, firstColon) : msg;
+ var cmdFunctionName = cmd + 'Command';
+ var cmdFunction = window[cmdFunctionName];
+
+ if (typeof(cmdFunction) !== 'function') {
+ console.log('Unknown command: ' + cmd);
+ console.log(' message: ' + msg);
+ return;
+ }
+
+ var argCount = cmdFunction.length;
+
+ // Don't use split, because it will split all commas (for example any commas
+ // in the test failure summary).
+ var argList = msg.substr(firstColon + 1);
+ args = [];
+ for (var i = 0; i < argCount - 1; ++i) {
+ var arg;
+ var comma = argList.indexOf(',');
+ if (comma === -1) {
+ if (i !== argCount - 1) {
+ console.log('Bad arg count to command "' + cmd + '", expected ' +
+ argCount);
+ console.log(' message: ' + msg);
+ } else {
+ arg = argList;
+ }
+ } else {
+ arg = argList.substr(0, comma);
+ argList = argList.substr(comma + 1);
+ }
+ args.push(arg);
+ }
+
+ // Last argument is the rest of the message.
+ args.push(argList);
+
+ cmdFunction.apply(null, args);
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.cc b/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.cc
new file mode 100644
index 0000000000..85759c4589
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.cc
@@ -0,0 +1,15 @@
+// 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 "fake_core_interface.h"
+
+FakeCoreInterface::FakeCoreInterface() {}
+
+void FakeCoreInterface::AddRefResource(PP_Resource handle) {
+ return resource_manager_.AddRef(handle);
+}
+
+void FakeCoreInterface::ReleaseResource(PP_Resource handle) {
+ return resource_manager_.Release(handle);
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.h b/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.h
new file mode 100644
index 0000000000..cae326fe74
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_core_interface.h
@@ -0,0 +1,28 @@
+// 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_TEST_FAKE_CORE_INTERFACE_H_
+#define LIBRARIES_NACL_IO_TEST_FAKE_CORE_INTERFACE_H_
+
+#include "fake_resource_manager.h"
+#include "nacl_io/pepper_interface.h"
+#include "sdk_util/macros.h"
+
+class FakeCoreInterface : public nacl_io::CoreInterface {
+ public:
+ FakeCoreInterface();
+
+ virtual void AddRefResource(PP_Resource handle);
+ virtual void ReleaseResource(PP_Resource handle);
+ virtual PP_Bool IsMainThread() { return PP_FALSE; }
+
+ FakeResourceManager* resource_manager() { return &resource_manager_; }
+
+ private:
+ FakeResourceManager resource_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeCoreInterface);
+};
+
+#endif // LIBRARIES_NACL_IO_TEST_FAKE_CORE_INTERFACE_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.cc b/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.cc
new file mode 100644
index 0000000000..3bc39897ba
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.cc
@@ -0,0 +1,707 @@
+// 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 "fake_pepper_interface_html5fs.h"
+
+#include <string.h>
+
+#include <algorithm>
+
+#include <ppapi/c/pp_completion_callback.h>
+#include <ppapi/c/pp_errors.h>
+
+#include "gtest/gtest.h"
+
+namespace {
+
+class FakeInstanceResource : public FakeResource {
+ public:
+ FakeInstanceResource() : filesystem_template(NULL) {}
+ static const char* classname() { return "FakeInstanceResource"; }
+
+ FakeHtml5FsFilesystem* filesystem_template; // Weak reference.
+};
+
+class FakeFileSystemResource : public FakeResource {
+ public:
+ FakeFileSystemResource() : filesystem(NULL), opened(false) {}
+ ~FakeFileSystemResource() { delete filesystem; }
+ static const char* classname() { return "FakeFileSystemResource"; }
+
+ FakeHtml5FsFilesystem* filesystem; // Owned.
+ bool opened;
+};
+
+class FakeFileRefResource : public FakeResource {
+ public:
+ FakeFileRefResource() : filesystem(NULL) {}
+ static const char* classname() { return "FakeFileRefResource"; }
+
+ FakeHtml5FsFilesystem* filesystem; // Weak reference.
+ FakeHtml5FsFilesystem::Path path;
+};
+
+class FakeFileIoResource : public FakeResource {
+ public:
+ FakeFileIoResource() : node(NULL), open_flags(0) {}
+ static const char* classname() { return "FakeFileIoResource"; }
+
+ FakeHtml5FsNode* node; // Weak reference.
+ int32_t open_flags;
+};
+
+// Helper function to call the completion callback if it is defined (an
+// asynchronous call), or return the result directly if it isn't (a synchronous
+// call).
+//
+// Use like this:
+// if (<some error condition>)
+// return RunCompletionCallback(callback, PP_ERROR_FUBAR);
+//
+// /* Everything worked OK */
+// return RunCompletionCallback(callback, PP_OK);
+int32_t RunCompletionCallback(PP_CompletionCallback* callback, int32_t result) {
+ if (callback->func) {
+ PP_RunCompletionCallback(callback, result);
+ return PP_OK_COMPLETIONPENDING;
+ }
+ return result;
+}
+
+} // namespace
+
+FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info) : info_(info) {}
+
+FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info,
+ const std::vector<uint8_t>& contents)
+ : info_(info), contents_(contents) {}
+
+FakeHtml5FsNode::FakeHtml5FsNode(const PP_FileInfo& info,
+ const std::string& contents)
+ : info_(info) {
+ std::copy(contents.begin(), contents.end(), std::back_inserter(contents_));
+}
+
+int32_t FakeHtml5FsNode::Read(int64_t offset,
+ char* buffer,
+ int32_t bytes_to_read) {
+ if (offset < 0)
+ return PP_ERROR_FAILED;
+
+ bytes_to_read =
+ std::max(0, std::min<int32_t>(bytes_to_read, contents_.size() - offset));
+ memcpy(buffer, contents_.data() + offset, bytes_to_read);
+ return bytes_to_read;
+}
+
+int32_t FakeHtml5FsNode::Write(int64_t offset,
+ const char* buffer,
+ int32_t bytes_to_write) {
+ if (offset < 0)
+ return PP_ERROR_FAILED;
+
+ size_t new_size = offset + bytes_to_write;
+ if (new_size > contents_.size())
+ contents_.resize(new_size);
+
+ memcpy(contents_.data() + offset, buffer, bytes_to_write);
+ info_.size = new_size;
+ return bytes_to_write;
+}
+
+int32_t FakeHtml5FsNode::Append(const char* buffer, int32_t bytes_to_write) {
+ return Write(contents_.size(), buffer, bytes_to_write);
+}
+
+int32_t FakeHtml5FsNode::SetLength(int64_t length) {
+ contents_.resize(length);
+ info_.size = length;
+ return PP_OK;
+}
+
+void FakeHtml5FsNode::GetInfo(PP_FileInfo* out_info) { *out_info = info_; }
+
+bool FakeHtml5FsNode::IsRegular() const {
+ return info_.type == PP_FILETYPE_REGULAR;
+}
+
+bool FakeHtml5FsNode::IsDirectory() const {
+ return info_.type == PP_FILETYPE_DIRECTORY;
+}
+
+FakeHtml5FsFilesystem::FakeHtml5FsFilesystem()
+ : filesystem_type_(PP_FILESYSTEMTYPE_INVALID) {
+ Clear();
+}
+
+FakeHtml5FsFilesystem::FakeHtml5FsFilesystem(PP_FileSystemType type)
+ : filesystem_type_(type) {
+ Clear();
+}
+
+FakeHtml5FsFilesystem::FakeHtml5FsFilesystem(
+ const FakeHtml5FsFilesystem& filesystem,
+ PP_FileSystemType type)
+ : node_map_(filesystem.node_map_), filesystem_type_(type) {}
+
+void FakeHtml5FsFilesystem::Clear() {
+ node_map_.clear();
+ // Always have a root node.
+ AddDirectory("/", NULL);
+}
+
+bool FakeHtml5FsFilesystem::AddEmptyFile(const Path& path,
+ FakeHtml5FsNode** out_node) {
+ return AddFile(path, std::vector<uint8_t>(), out_node);
+}
+
+bool FakeHtml5FsFilesystem::AddFile(const Path& path,
+ const std::string& contents,
+ FakeHtml5FsNode** out_node) {
+ std::vector<uint8_t> data;
+ std::copy(contents.begin(), contents.end(), std::back_inserter(data));
+ return AddFile(path, data, out_node);
+}
+
+bool FakeHtml5FsFilesystem::AddFile(const Path& path,
+ const std::vector<uint8_t>& contents,
+ FakeHtml5FsNode** out_node) {
+ NodeMap::iterator iter = node_map_.find(path);
+ if (iter != node_map_.end()) {
+ if (out_node)
+ *out_node = NULL;
+ return false;
+ }
+
+ PP_FileInfo info;
+ info.size = contents.size();
+ info.type = PP_FILETYPE_REGULAR;
+ info.system_type = filesystem_type_;
+ info.creation_time = 0;
+ info.last_access_time = 0;
+ info.last_modified_time = 0;
+
+ FakeHtml5FsNode node(info, contents);
+ std::pair<NodeMap::iterator, bool> result =
+ node_map_.insert(NodeMap::value_type(path, node));
+
+ EXPECT_EQ(true, result.second);
+ if (out_node)
+ *out_node = &result.first->second;
+ return true;
+}
+
+bool FakeHtml5FsFilesystem::AddDirectory(const Path& path,
+ FakeHtml5FsNode** out_node) {
+ NodeMap::iterator iter = node_map_.find(path);
+ if (iter != node_map_.end()) {
+ if (out_node)
+ *out_node = NULL;
+ return false;
+ }
+
+ PP_FileInfo info;
+ info.size = 0;
+ info.type = PP_FILETYPE_DIRECTORY;
+ info.system_type = filesystem_type_;
+ info.creation_time = 0;
+ info.last_access_time = 0;
+ info.last_modified_time = 0;
+
+ FakeHtml5FsNode node(info);
+ std::pair<NodeMap::iterator, bool> result =
+ node_map_.insert(NodeMap::value_type(path, node));
+
+ EXPECT_EQ(true, result.second);
+ if (out_node)
+ *out_node = &result.first->second;
+ return true;
+}
+
+bool FakeHtml5FsFilesystem::RemoveNode(const Path& path) {
+ return node_map_.erase(path) >= 1;
+}
+
+FakeHtml5FsNode* FakeHtml5FsFilesystem::GetNode(const Path& path) {
+ NodeMap::iterator iter = node_map_.find(path);
+ if (iter == node_map_.end())
+ return NULL;
+ return &iter->second;
+}
+
+bool FakeHtml5FsFilesystem::GetDirectoryEntries(
+ const Path& path,
+ DirectoryEntries* out_dir_entries) const {
+ out_dir_entries->clear();
+
+ NodeMap::const_iterator iter = node_map_.find(path);
+ if (iter == node_map_.end())
+ return false;
+
+ const FakeHtml5FsNode& dir_node = iter->second;
+ if (!dir_node.IsDirectory())
+ return false;
+
+ for (NodeMap::const_iterator iter = node_map_.begin();
+ iter != node_map_.end();
+ ++iter) {
+ const Path& node_path = iter->first;
+ if (node_path.find(path) == std::string::npos)
+ continue;
+
+ // A node is not a child of itself.
+ if (&iter->second == &dir_node)
+ continue;
+
+ // Only consider children, not descendants. If we find a forward slash, then
+ // the node must be in a subdirectory.
+ if (node_path.find('/', path.size() + 1) != std::string::npos)
+ continue;
+
+ // The directory entry names do not include the path.
+ Path entry_path = node_path;
+ size_t last_slash = node_path.rfind('/');
+ if (last_slash != std::string::npos)
+ entry_path.erase(0, last_slash + 1);
+
+ DirectoryEntry entry;
+ entry.path = entry_path;
+ entry.node = &iter->second;
+ out_dir_entries->push_back(entry);
+ }
+
+ return true;
+}
+
+// static
+FakeHtml5FsFilesystem::Path FakeHtml5FsFilesystem::GetParentPath(
+ const Path& path) {
+ size_t last_slash = path.rfind('/');
+ if (last_slash == 0)
+ return "/";
+
+ EXPECT_EQ(std::string::npos, last_slash);
+ return path.substr(0, last_slash);
+}
+
+FakeFileIoInterface::FakeFileIoInterface(FakeCoreInterface* core_interface)
+ : core_interface_(core_interface) {}
+
+PP_Resource FakeFileIoInterface::Create(PP_Resource) {
+ return CREATE_RESOURCE(core_interface_->resource_manager(),
+ FakeFileIoResource,
+ new FakeFileIoResource);
+}
+
+int32_t FakeFileIoInterface::Open(PP_Resource file_io,
+ PP_Resource file_ref,
+ int32_t open_flags,
+ PP_CompletionCallback callback) {
+ FakeFileIoResource* file_io_resource =
+ core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+ if (file_io_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ bool flag_write = !!(open_flags & PP_FILEOPENFLAG_WRITE);
+ bool flag_create = !!(open_flags & PP_FILEOPENFLAG_CREATE);
+ bool flag_truncate = !!(open_flags & PP_FILEOPENFLAG_TRUNCATE);
+ bool flag_exclusive = !!(open_flags & PP_FILEOPENFLAG_EXCLUSIVE);
+ bool flag_append = !!(open_flags & PP_FILEOPENFLAG_APPEND);
+
+ if ((flag_append && flag_write) || (flag_truncate && !flag_write))
+ return PP_ERROR_BADARGUMENT;
+
+ FakeFileRefResource* file_ref_resource =
+ core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
+ if (file_ref_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ const FakeHtml5FsFilesystem::Path& path = file_ref_resource->path;
+ FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
+ FakeHtml5FsNode* node = filesystem->GetNode(path);
+ bool node_exists = node != NULL;
+
+ if (!node_exists) {
+ if (!flag_create)
+ return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
+
+ bool result = filesystem->AddEmptyFile(path, &node);
+ EXPECT_EQ(true, result);
+ } else {
+ if (flag_create && flag_exclusive)
+ return RunCompletionCallback(&callback, PP_ERROR_FILEEXISTS);
+ }
+
+ file_io_resource->node = node;
+ file_io_resource->open_flags = open_flags;
+
+ if (flag_truncate)
+ return RunCompletionCallback(&callback, node->SetLength(0));
+
+ return RunCompletionCallback(&callback, PP_OK);
+}
+
+int32_t FakeFileIoInterface::Query(PP_Resource file_io,
+ PP_FileInfo* info,
+ PP_CompletionCallback callback) {
+ FakeFileIoResource* file_io_resource =
+ core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+ if (file_io_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ if (!file_io_resource->node)
+ return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+ file_io_resource->node->GetInfo(info);
+ return RunCompletionCallback(&callback, PP_OK);
+}
+
+int32_t FakeFileIoInterface::Read(PP_Resource file_io,
+ int64_t offset,
+ char* buffer,
+ int32_t bytes_to_read,
+ PP_CompletionCallback callback) {
+ FakeFileIoResource* file_io_resource =
+ core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+ if (file_io_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ if (bytes_to_read < 0)
+ return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+ if ((file_io_resource->open_flags & PP_FILEOPENFLAG_READ) !=
+ PP_FILEOPENFLAG_READ) {
+ return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
+ }
+
+ if (!file_io_resource->node)
+ return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+ int32_t result = file_io_resource->node->Read(offset, buffer, bytes_to_read);
+ return RunCompletionCallback(&callback, result);
+}
+
+int32_t FakeFileIoInterface::Write(PP_Resource file_io,
+ int64_t offset,
+ const char* buffer,
+ int32_t bytes_to_write,
+ PP_CompletionCallback callback) {
+ FakeFileIoResource* file_io_resource =
+ core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+ if (file_io_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ if ((file_io_resource->open_flags & PP_FILEOPENFLAG_WRITE) !=
+ PP_FILEOPENFLAG_WRITE) {
+ return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
+ }
+
+ if (!file_io_resource->node)
+ return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+ int32_t result;
+ if ((file_io_resource->open_flags & PP_FILEOPENFLAG_APPEND) ==
+ PP_FILEOPENFLAG_APPEND) {
+ result = file_io_resource->node->Append(buffer, bytes_to_write);
+ } else {
+ result = file_io_resource->node->Write(offset, buffer, bytes_to_write);
+ }
+
+ return RunCompletionCallback(&callback, result);
+}
+
+int32_t FakeFileIoInterface::SetLength(PP_Resource file_io,
+ int64_t length,
+ PP_CompletionCallback callback) {
+ FakeFileIoResource* file_io_resource =
+ core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+ if (file_io_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ if ((file_io_resource->open_flags & PP_FILEOPENFLAG_WRITE) !=
+ PP_FILEOPENFLAG_WRITE) {
+ return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
+ }
+
+ if (!file_io_resource->node)
+ return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+ int32_t result = file_io_resource->node->SetLength(length);
+ return RunCompletionCallback(&callback, result);
+}
+
+int32_t FakeFileIoInterface::Flush(PP_Resource file_io,
+ PP_CompletionCallback callback) {
+ FakeFileIoResource* file_io_resource =
+ core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+ if (file_io_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ if (!file_io_resource->node)
+ return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+ return RunCompletionCallback(&callback, PP_OK);
+}
+
+void FakeFileIoInterface::Close(PP_Resource file_io) {
+ FakeFileIoResource* file_io_resource =
+ core_interface_->resource_manager()->Get<FakeFileIoResource>(file_io);
+ if (file_io_resource == NULL)
+ return;
+
+ file_io_resource->node = NULL;
+ file_io_resource->open_flags = 0;
+}
+
+FakeFileRefInterface::FakeFileRefInterface(FakeCoreInterface* core_interface,
+ FakeVarInterface* var_interface)
+ : core_interface_(core_interface), var_interface_(var_interface) {}
+
+PP_Resource FakeFileRefInterface::Create(PP_Resource file_system,
+ const char* path) {
+ FakeFileSystemResource* file_system_resource =
+ core_interface_->resource_manager()->Get<FakeFileSystemResource>(
+ file_system);
+ if (file_system_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ if (!file_system_resource->opened)
+ return PP_ERROR_FAILED;
+
+ if (path == NULL)
+ return PP_ERROR_FAILED;
+
+ size_t path_len = strlen(path);
+ if (path_len == 0)
+ return PP_ERROR_FAILED;
+
+ FakeFileRefResource* file_ref_resource = new FakeFileRefResource;
+ file_ref_resource->filesystem = file_system_resource->filesystem;
+ file_ref_resource->path = path;
+
+ // Remove a trailing slash from the path, unless it is the root path.
+ if (path_len > 1 && file_ref_resource->path[path_len - 1] == '/')
+ file_ref_resource->path.erase(path_len - 1);
+
+ return CREATE_RESOURCE(core_interface_->resource_manager(),
+ FakeFileRefResource,
+ file_ref_resource);
+}
+
+PP_Var FakeFileRefInterface::GetName(PP_Resource file_ref) {
+ FakeFileRefResource* file_ref_resource =
+ core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
+ if (file_ref_resource == NULL)
+ return PP_MakeUndefined();
+
+ return var_interface_->VarFromUtf8(file_ref_resource->path.c_str(),
+ file_ref_resource->path.size());
+}
+
+int32_t FakeFileRefInterface::MakeDirectory(PP_Resource directory_ref,
+ PP_Bool make_ancestors,
+ PP_CompletionCallback callback) {
+ FakeFileRefResource* directory_ref_resource =
+ core_interface_->resource_manager()->Get<FakeFileRefResource>(
+ directory_ref);
+ if (directory_ref_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ // TODO(binji): We don't currently use make_ancestors==PP_TRUE in nacl_io, so
+ // I won't bother implementing it.
+ if (make_ancestors == PP_TRUE)
+ return PP_ERROR_FAILED;
+
+ FakeHtml5FsFilesystem* filesystem = directory_ref_resource->filesystem;
+ FakeHtml5FsFilesystem::Path path = directory_ref_resource->path;
+
+ // Pepper returns PP_ERROR_NOACCESS when trying to create the root directory,
+ // not PP_ERROR_FILEEXISTS, as you might expect.
+ if (path == "/")
+ return RunCompletionCallback(&callback, PP_ERROR_NOACCESS);
+
+ FakeHtml5FsNode* node = filesystem->GetNode(path);
+ if (node != NULL)
+ return RunCompletionCallback(&callback, PP_ERROR_FILEEXISTS);
+
+ FakeHtml5FsFilesystem::Path parent_path = filesystem->GetParentPath(path);
+ FakeHtml5FsNode* parent_node = filesystem->GetNode(parent_path);
+ if (parent_node == NULL)
+ return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
+
+ if (!parent_node->IsDirectory())
+ return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+ bool result = filesystem->AddDirectory(directory_ref_resource->path, NULL);
+ EXPECT_EQ(true, result);
+ return RunCompletionCallback(&callback, PP_OK);
+}
+
+int32_t FakeFileRefInterface::Delete(PP_Resource file_ref,
+ PP_CompletionCallback callback) {
+ FakeFileRefResource* file_ref_resource =
+ core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
+ if (file_ref_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
+ FakeHtml5FsFilesystem::Path path = file_ref_resource->path;
+ FakeHtml5FsNode* node = filesystem->GetNode(path);
+ if (node == NULL)
+ return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
+
+ filesystem->RemoveNode(path);
+ return RunCompletionCallback(&callback, PP_OK);
+}
+
+int32_t FakeFileRefInterface::Query(PP_Resource file_ref,
+ PP_FileInfo* info,
+ PP_CompletionCallback callback) {
+ FakeFileRefResource* file_ref_resource =
+ core_interface_->resource_manager()->Get<FakeFileRefResource>(file_ref);
+ if (file_ref_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ FakeHtml5FsFilesystem* filesystem = file_ref_resource->filesystem;
+ FakeHtml5FsFilesystem::Path path = file_ref_resource->path;
+ FakeHtml5FsNode* node = filesystem->GetNode(path);
+ if (node == NULL)
+ return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
+
+ node->GetInfo(info);
+ return RunCompletionCallback(&callback, PP_OK);
+}
+
+int32_t FakeFileRefInterface::ReadDirectoryEntries(
+ PP_Resource directory_ref,
+ const PP_ArrayOutput& output,
+ PP_CompletionCallback callback) {
+ FakeFileRefResource* directory_ref_resource =
+ core_interface_->resource_manager()->Get<FakeFileRefResource>(
+ directory_ref);
+ if (directory_ref_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ FakeHtml5FsFilesystem* filesystem = directory_ref_resource->filesystem;
+ FakeHtml5FsFilesystem::Path path = directory_ref_resource->path;
+ FakeHtml5FsNode* node = filesystem->GetNode(path);
+ if (node == NULL)
+ return RunCompletionCallback(&callback, PP_ERROR_FILENOTFOUND);
+
+ if (!node->IsDirectory())
+ return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+ FakeHtml5FsFilesystem::DirectoryEntries fake_dir_entries;
+ filesystem->GetDirectoryEntries(path, &fake_dir_entries);
+
+ uint32_t element_count = fake_dir_entries.size();
+ uint32_t element_size = sizeof(fake_dir_entries[0]);
+ void* data_buffer =
+ (*output.GetDataBuffer)(output.user_data, element_count, element_size);
+
+ if (data_buffer == NULL)
+ return RunCompletionCallback(&callback, PP_ERROR_FAILED);
+
+ PP_DirectoryEntry* dir_entries = static_cast<PP_DirectoryEntry*>(data_buffer);
+ for (uint32_t i = 0; i < element_count; ++i) {
+ const FakeHtml5FsFilesystem::DirectoryEntry& fake_dir_entry =
+ fake_dir_entries[i];
+
+ FakeFileRefResource* file_ref_resource = new FakeFileRefResource;
+ file_ref_resource->filesystem = directory_ref_resource->filesystem;
+ file_ref_resource->path = fake_dir_entry.path;
+ PP_Resource file_ref = CREATE_RESOURCE(core_interface_->resource_manager(),
+ FakeFileRefResource,
+ file_ref_resource);
+
+ dir_entries[i].file_ref = file_ref;
+ dir_entries[i].file_type = fake_dir_entry.node->file_type();
+ }
+
+ return RunCompletionCallback(&callback, PP_OK);
+}
+
+FakeFileSystemInterface::FakeFileSystemInterface(
+ FakeCoreInterface* core_interface)
+ : core_interface_(core_interface) {}
+
+PP_Resource FakeFileSystemInterface::Create(PP_Instance instance,
+ PP_FileSystemType filesystem_type) {
+ FakeInstanceResource* instance_resource =
+ core_interface_->resource_manager()->Get<FakeInstanceResource>(instance);
+ if (instance_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ FakeFileSystemResource* file_system_resource = new FakeFileSystemResource;
+ file_system_resource->filesystem = new FakeHtml5FsFilesystem(
+ *instance_resource->filesystem_template, filesystem_type);
+
+ return CREATE_RESOURCE(core_interface_->resource_manager(),
+ FakeFileSystemResource,
+ file_system_resource);
+}
+
+int32_t FakeFileSystemInterface::Open(PP_Resource file_system,
+ int64_t expected_size,
+ PP_CompletionCallback callback) {
+ FakeFileSystemResource* file_system_resource =
+ core_interface_->resource_manager()->Get<FakeFileSystemResource>(
+ file_system);
+ if (file_system_resource == NULL)
+ return PP_ERROR_BADRESOURCE;
+
+ file_system_resource->opened = true;
+ return RunCompletionCallback(&callback, PP_OK);
+}
+
+FakePepperInterfaceHtml5Fs::FakePepperInterfaceHtml5Fs()
+ : file_system_interface_(&core_interface_),
+ file_ref_interface_(&core_interface_, &var_interface_),
+ file_io_interface_(&core_interface_) {
+ Init();
+}
+
+FakePepperInterfaceHtml5Fs::FakePepperInterfaceHtml5Fs(
+ const FakeHtml5FsFilesystem& filesystem)
+ : filesystem_template_(filesystem),
+ file_system_interface_(&core_interface_),
+ file_ref_interface_(&core_interface_, &var_interface_),
+ file_io_interface_(&core_interface_),
+ instance_(0) {
+ Init();
+}
+
+void FakePepperInterfaceHtml5Fs::Init() {
+ FakeInstanceResource* instance_resource = new FakeInstanceResource;
+ instance_resource->filesystem_template = &filesystem_template_;
+
+ instance_ = CREATE_RESOURCE(core_interface_.resource_manager(),
+ FakeInstanceResource,
+ instance_resource);
+}
+
+FakePepperInterfaceHtml5Fs::~FakePepperInterfaceHtml5Fs() {
+ core_interface_.ReleaseResource(instance_);
+}
+
+nacl_io::CoreInterface* FakePepperInterfaceHtml5Fs::GetCoreInterface() {
+ return &core_interface_;
+}
+
+nacl_io::FileSystemInterface*
+FakePepperInterfaceHtml5Fs::GetFileSystemInterface() {
+ return &file_system_interface_;
+}
+
+nacl_io::FileRefInterface* FakePepperInterfaceHtml5Fs::GetFileRefInterface() {
+ return &file_ref_interface_;
+}
+
+nacl_io::FileIoInterface* FakePepperInterfaceHtml5Fs::GetFileIoInterface() {
+ return &file_io_interface_;
+}
+
+nacl_io::VarInterface* FakePepperInterfaceHtml5Fs::GetVarInterface() {
+ return &var_interface_;
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.h b/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.h
new file mode 100644
index 0000000000..6e10844aee
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_pepper_interface_html5fs.h
@@ -0,0 +1,200 @@
+// 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_TEST_FAKE_PEPPER_INTERFACE_HTML5FS_H_
+#define LIBRARIES_NACL_IO_TEST_FAKE_PEPPER_INTERFACE_HTML5FS_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <ppapi/c/pp_directory_entry.h>
+
+#include "fake_core_interface.h"
+#include "fake_var_interface.h"
+#include "nacl_io/pepper_interface_dummy.h"
+#include "sdk_util/macros.h"
+
+// This class is a fake implementation of the interfaces necessary to access
+// the HTML5 Filesystem from NaCl.
+//
+// Example:
+// FakePepperInterfaceHtml5Fs ppapi_html5fs;
+// ...
+// PP_Resource ref_resource = ppapi_html5fs.GetFileRefInterface()->Create(
+// ppapi_html5fs.GetInstance(),
+// "/some/path");
+// ...
+//
+// NOTE: This pepper interface creates an instance resource that can only be
+// used with FakePepperInterfaceHtml5Fs, not other fake pepper implementations.
+
+class FakeHtml5FsNode {
+ public:
+ FakeHtml5FsNode(const PP_FileInfo& info);
+ FakeHtml5FsNode(const PP_FileInfo& info,
+ const std::vector<uint8_t>& contents);
+ FakeHtml5FsNode(const PP_FileInfo& info, const std::string& contents);
+
+ int32_t Read(int64_t offset, char* buffer, int32_t bytes_to_read);
+ int32_t Write(int64_t offset, const char* buffer, int32_t bytes_to_write);
+ int32_t Append(const char* buffer, int32_t bytes_to_write);
+ int32_t SetLength(int64_t length);
+ void GetInfo(PP_FileInfo* out_info);
+ bool IsRegular() const;
+ bool IsDirectory() const;
+ PP_FileType file_type() const { return info_.type; }
+
+ // These times are not modified by the fake implementation.
+ void set_creation_time(PP_Time time) { info_.creation_time = time; }
+ void set_last_access_time(PP_Time time) { info_.last_access_time = time; }
+ void set_last_modified_time(PP_Time time) { info_.last_modified_time = time; }
+
+ private:
+ PP_FileInfo info_;
+ std::vector<uint8_t> contents_;
+};
+
+class FakeHtml5FsFilesystem {
+ public:
+ typedef std::string Path;
+
+ struct DirectoryEntry {
+ Path path;
+ const FakeHtml5FsNode* node;
+ };
+ typedef std::vector<DirectoryEntry> DirectoryEntries;
+
+ FakeHtml5FsFilesystem();
+ explicit FakeHtml5FsFilesystem(PP_FileSystemType type);
+ FakeHtml5FsFilesystem(const FakeHtml5FsFilesystem& filesystem,
+ PP_FileSystemType type);
+
+ void Clear();
+ bool AddEmptyFile(const Path& path, FakeHtml5FsNode** out_node);
+ bool AddFile(const Path& path,
+ const std::string& contents,
+ FakeHtml5FsNode** out_node);
+ bool AddFile(const Path& path,
+ const std::vector<uint8_t>& contents,
+ FakeHtml5FsNode** out_node);
+ bool AddDirectory(const Path& path, FakeHtml5FsNode** out_node);
+ bool RemoveNode(const Path& path);
+
+ FakeHtml5FsNode* GetNode(const Path& path);
+ bool GetDirectoryEntries(const Path& path,
+ DirectoryEntries* out_dir_entries) const;
+ PP_FileSystemType filesystem_type() const { return filesystem_type_; }
+ static Path GetParentPath(const Path& path);
+
+ private:
+ typedef std::map<Path, FakeHtml5FsNode> NodeMap;
+ NodeMap node_map_;
+ PP_FileSystemType filesystem_type_;
+};
+
+class FakeFileIoInterface : public nacl_io::FileIoInterface {
+ public:
+ explicit FakeFileIoInterface(FakeCoreInterface* core_interface);
+
+ PP_Resource Create(PP_Resource instance);
+ int32_t Open(PP_Resource file_io,
+ PP_Resource file_ref,
+ int32_t open_flags,
+ PP_CompletionCallback callback);
+ int32_t Query(PP_Resource file_io,
+ PP_FileInfo* info,
+ PP_CompletionCallback callback);
+ int32_t Read(PP_Resource file_io,
+ int64_t offset,
+ char* buffer,
+ int32_t bytes_to_read,
+ PP_CompletionCallback callback);
+ int32_t Write(PP_Resource file_io,
+ int64_t offset,
+ const char* buffer,
+ int32_t bytes_to_write,
+ PP_CompletionCallback callback);
+ int32_t SetLength(PP_Resource file_io,
+ int64_t length,
+ PP_CompletionCallback callback);
+ int32_t Flush(PP_Resource file_io, PP_CompletionCallback callback);
+ void Close(PP_Resource file_io);
+
+ private:
+ FakeCoreInterface* core_interface_; // Weak reference.
+
+ DISALLOW_COPY_AND_ASSIGN(FakeFileIoInterface);
+};
+
+class FakeFileRefInterface : public nacl_io::FileRefInterface {
+ public:
+ FakeFileRefInterface(FakeCoreInterface* core_interface,
+ FakeVarInterface* var_interface);
+
+ PP_Resource Create(PP_Resource file_system, const char* path);
+ PP_Var GetName(PP_Resource file_ref);
+ int32_t MakeDirectory(PP_Resource directory_ref,
+ PP_Bool make_ancestors,
+ PP_CompletionCallback callback);
+ int32_t Delete(PP_Resource file_ref, PP_CompletionCallback callback);
+ int32_t Query(PP_Resource file_ref,
+ PP_FileInfo* info,
+ PP_CompletionCallback callback);
+ int32_t ReadDirectoryEntries(PP_Resource file_ref,
+ const PP_ArrayOutput& output,
+ PP_CompletionCallback callback);
+
+ private:
+ FakeCoreInterface* core_interface_; // Weak reference.
+ FakeVarInterface* var_interface_; // Weak reference.
+
+ DISALLOW_COPY_AND_ASSIGN(FakeFileRefInterface);
+};
+
+class FakeFileSystemInterface : public nacl_io::FileSystemInterface {
+ public:
+ FakeFileSystemInterface(FakeCoreInterface* core_interface);
+
+ PP_Resource Create(PP_Instance instance, PP_FileSystemType type);
+ int32_t Open(PP_Resource file_system,
+ int64_t expected_size,
+ PP_CompletionCallback callback);
+
+ private:
+ FakeCoreInterface* core_interface_; // Weak reference.
+
+ DISALLOW_COPY_AND_ASSIGN(FakeFileSystemInterface);
+};
+
+class FakePepperInterfaceHtml5Fs : public nacl_io::PepperInterfaceDummy {
+ public:
+ FakePepperInterfaceHtml5Fs();
+ explicit FakePepperInterfaceHtml5Fs(const FakeHtml5FsFilesystem& filesystem);
+ ~FakePepperInterfaceHtml5Fs();
+
+ virtual PP_Instance GetInstance() { return instance_; }
+ virtual nacl_io::CoreInterface* GetCoreInterface();
+ virtual nacl_io::FileSystemInterface* GetFileSystemInterface();
+ virtual nacl_io::FileRefInterface* GetFileRefInterface();
+ virtual nacl_io::FileIoInterface* GetFileIoInterface();
+ virtual nacl_io::VarInterface* GetVarInterface();
+
+ FakeHtml5FsFilesystem* filesystem_template() { return &filesystem_template_; }
+
+ private:
+ void Init();
+
+ FakeCoreInterface core_interface_;
+ FakeVarInterface var_interface_;
+ FakeHtml5FsFilesystem filesystem_template_;
+ FakeFileSystemInterface file_system_interface_;
+ FakeFileRefInterface file_ref_interface_;
+ FakeFileIoInterface file_io_interface_;
+ PP_Instance instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakePepperInterfaceHtml5Fs);
+};
+
+#endif // LIBRARIES_NACL_IO_TEST_FAKE_PEPPER_INTERFACE_HTML5FS_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.cc b/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.cc
new file mode 100644
index 0000000000..f9c3ab26c3
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.cc
@@ -0,0 +1,116 @@
+// 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 "fake_resource_manager.h"
+#include "gtest/gtest.h"
+#include "sdk_util/auto_lock.h"
+
+FakeResourceManager::FakeResourceManager() : next_handle_(1) {}
+
+FakeResourceManager::~FakeResourceManager() {
+ // The ref counts for all resources should be zero.
+ for (ResourceMap::iterator iter = resource_map_.begin();
+ iter != resource_map_.end();
+ ++iter) {
+ const FakeResourceTracker* resource_tracker = iter->second;
+ EXPECT_EQ(0, resource_tracker->ref_count()) << "Leaked resource "
+ << resource_tracker->classname()
+ << "(" << iter->first
+ << "), created at "
+ << resource_tracker->file()
+ << ":"
+ << resource_tracker->line();
+ }
+}
+
+PP_Resource FakeResourceManager::Create(FakeResource* resource,
+ const char* classname,
+ const char* file,
+ int line) {
+ AUTO_LOCK(lock_);
+ PP_Resource handle = next_handle_++;
+ FakeResourceTracker* resource_tracker =
+ new FakeResourceTracker(resource, classname, file, line);
+ std::pair<ResourceMap::iterator, bool> result =
+ resource_map_.insert(ResourceMap::value_type(handle, resource_tracker));
+ EXPECT_TRUE(result.second);
+ result.first->second->AddRef();
+ return handle;
+}
+
+void FakeResourceManager::AddRef(PP_Resource handle) {
+ AUTO_LOCK(lock_);
+ ResourceMap::iterator iter = resource_map_.find(handle);
+ ASSERT_NE(resource_map_.end(), iter) << "AddRefing unknown resource "
+ << handle;
+
+ FakeResourceTracker* resource_tracker = iter->second;
+ EXPECT_LT(0, resource_tracker->ref_count()) << "AddRefing freed resource "
+ << resource_tracker->classname()
+ << "(" << handle
+ << "), created at "
+ << resource_tracker->file() << ":"
+ << resource_tracker->line();
+ resource_tracker->AddRef();
+}
+
+void FakeResourceManager::Release(PP_Resource handle) {
+ AUTO_LOCK(lock_);
+ ResourceMap::iterator iter = resource_map_.find(handle);
+ ASSERT_NE(resource_map_.end(), iter) << "Releasing unknown resource "
+ << handle;
+
+ FakeResourceTracker* resource_tracker = iter->second;
+ EXPECT_LT(0, resource_tracker->ref_count()) << "Releasing freed resource "
+ << resource_tracker->classname()
+ << "(" << handle
+ << "), created at "
+ << resource_tracker->file() << ":"
+ << resource_tracker->line();
+ resource_tracker->Release();
+}
+
+FakeResourceTracker* FakeResourceManager::Get(PP_Resource handle) {
+ AUTO_LOCK(lock_);
+ ResourceMap::iterator iter = resource_map_.find(handle);
+ if (iter == resource_map_.end()) {
+ // Can't use FAIL() because it tries to return void.
+ EXPECT_TRUE(false) << "Trying to get resource " << handle
+ << " that doesn't exist!";
+ return NULL;
+ }
+
+ FakeResourceTracker* resource_tracker = iter->second;
+ EXPECT_LT(0, resource_tracker->ref_count()) << "Accessing freed resource "
+ << resource_tracker->classname()
+ << "(" << handle
+ << "), created at "
+ << resource_tracker->file() << ":"
+ << resource_tracker->line();
+
+ return iter->second;
+}
+
+FakeResourceTracker::FakeResourceTracker(FakeResource* resource,
+ const char* classname,
+ const char* file,
+ int line)
+ : resource_(resource),
+ classname_(classname),
+ file_(file),
+ line_(line),
+ ref_count_(0) {}
+
+FakeResourceTracker::~FakeResourceTracker() { delete resource_; }
+
+bool FakeResourceTracker::CheckType(const char* other_classname) const {
+ if (strcmp(other_classname, classname_) != 0) {
+ // Repeat the expectation, just to print out a nice error message before we
+ // crash. :)
+ EXPECT_STREQ(classname_, other_classname);
+ return false;
+ }
+
+ return true;
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.h b/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.h
new file mode 100644
index 0000000000..f545e910c6
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_resource_manager.h
@@ -0,0 +1,99 @@
+// 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_TEST_FAKE_RESOURCE_MANAGER_H_
+#define LIBRARIES_NACL_IO_TEST_FAKE_RESOURCE_MANAGER_H_
+
+#include <map>
+
+#include <ppapi/c/pp_resource.h>
+
+#include "sdk_util/atomicops.h"
+#include "sdk_util/macros.h"
+#include "sdk_util/simple_lock.h"
+
+class FakeResource;
+class FakeResourceTracker;
+
+class FakeResourceManager {
+ public:
+ FakeResourceManager();
+ ~FakeResourceManager();
+
+ PP_Resource Create(FakeResource* resource,
+ const char* classname,
+ const char* file,
+ int line);
+ void AddRef(PP_Resource handle);
+ void Release(PP_Resource handle);
+ template <typename T>
+ T* Get(PP_Resource handle);
+
+ private:
+ FakeResourceTracker* Get(PP_Resource handle);
+
+ typedef std::map<PP_Resource, FakeResourceTracker*> ResourceMap;
+ PP_Resource next_handle_;
+ ResourceMap resource_map_;
+ sdk_util::SimpleLock lock_; // Protects next_handle_ and resource_map_.
+
+ DISALLOW_COPY_AND_ASSIGN(FakeResourceManager);
+};
+
+// FakeResourceTracker wraps a FakeResource to keep metadata about the
+// resource, including its refcount, the type of resource, etc.
+class FakeResourceTracker {
+ public:
+ FakeResourceTracker(FakeResource* resource,
+ const char* classname,
+ const char* file,
+ int line);
+ ~FakeResourceTracker();
+
+ void AddRef() { sdk_util::AtomicAddFetch(&ref_count_, 1); }
+ void Release() { sdk_util::AtomicAddFetch(&ref_count_, -1); }
+ int32_t ref_count() const { return ref_count_; }
+
+ template <typename T>
+ T* resource() {
+ if (!CheckType(T::classname()))
+ return NULL;
+
+ return static_cast<T*>(resource_);
+ }
+
+ const char* classname() const { return classname_; }
+ const char* file() const { return file_; }
+ int line() const { return line_; }
+
+ private:
+ bool CheckType(const char* classname) const;
+
+ FakeResource* resource_; // Owned.
+ const char* classname_; // Weak reference.
+ const char* file_; // Weak reference.
+ int line_;
+ int32_t ref_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeResourceTracker);
+};
+
+class FakeResource {
+ public:
+ FakeResource() {}
+ virtual ~FakeResource() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FakeResource);
+};
+
+template <typename T>
+inline T* FakeResourceManager::Get(PP_Resource handle) {
+ return Get(handle)->resource<T>();
+}
+
+#define CREATE_RESOURCE(MANAGER, TYPE, RESOURCE) \
+ (MANAGER)->Create(RESOURCE, #TYPE, __FILE__, __LINE__)
+
+#endif // LIBRARIES_NACL_IO_TEST_FAKE_RESOURCE_MANAGER_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.cc b/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.cc
new file mode 100644
index 0000000000..f67a0defb6
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.cc
@@ -0,0 +1,93 @@
+// 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 "fake_var_interface.h"
+#include "gtest/gtest.h"
+
+FakeVarInterface::FakeVarInterface() : next_id_(1) {}
+
+FakeVarInterface::~FakeVarInterface() {
+ // The ref counts for all vars should be zero.
+ for (VarMap::const_iterator iter = var_map_.begin(); iter != var_map_.end();
+ ++iter) {
+ const FakeStringVar& string_var = iter->second;
+ EXPECT_EQ(0, string_var.ref_count) << "Non-zero refcount on string var "
+ << iter->first << " with value \""
+ << string_var.value << "\"";
+ }
+}
+
+void FakeVarInterface::AddRef(PP_Var var) {
+ // From ppb_var.h:
+ // AddRef() adds a reference to the given var. If this is not a refcounted
+ // object, this function will do nothing so you can always call it no matter
+ // what the type.
+ if (var.type != PP_VARTYPE_STRING)
+ return;
+
+ VarMap::iterator iter = var_map_.find(var.value.as_id);
+ if (iter == var_map_.end())
+ return;
+
+ FakeStringVar& string_var = iter->second;
+ EXPECT_LT(0, string_var.ref_count) << "AddRefing freed string var "
+ << var.value.as_id << " with value \""
+ << string_var.value << "\"";
+ string_var.ref_count++;
+}
+
+void FakeVarInterface::Release(PP_Var var) {
+ // From ppb_var.h:
+ // Release() removes a reference to given var, deleting it if the internal
+ // reference count becomes 0. If the given var is not a refcounted object,
+ // this function will do nothing so you can always call it no matter what
+ // the type.
+ if (var.type != PP_VARTYPE_STRING)
+ return;
+
+ VarMap::iterator iter = var_map_.find(var.value.as_id);
+ if (iter == var_map_.end())
+ return;
+
+ FakeStringVar& string_var = iter->second;
+ EXPECT_LT(0, string_var.ref_count) << "Releasing freed string var "
+ << var.value.as_id << " with value \""
+ << string_var.value << "\"";
+ string_var.ref_count--;
+}
+
+PP_Var FakeVarInterface::VarFromUtf8(const char* data, uint32_t len) {
+ Id id = next_id_++;
+
+ FakeStringVar string_var;
+ string_var.value.assign(data, len);
+ string_var.ref_count = 1;
+
+ var_map_[id] = string_var;
+
+ struct PP_Var result = {PP_VARTYPE_STRING, 0, {PP_FALSE}};
+ result.value.as_id = id;
+ return result;
+}
+
+const char* FakeVarInterface::VarToUtf8(PP_Var var, uint32_t* out_len) {
+ if (var.type != PP_VARTYPE_STRING) {
+ *out_len = 0;
+ return NULL;
+ }
+
+ VarMap::const_iterator iter = var_map_.find(var.value.as_id);
+ if (iter == var_map_.end()) {
+ *out_len = 0;
+ return NULL;
+ }
+
+ const FakeStringVar& string_var = iter->second;
+ EXPECT_LT(0, string_var.ref_count) << "VarToUtf8 on freed string var "
+ << var.value.as_id << " with value \""
+ << string_var.value << "\"";
+
+ *out_len = string_var.value.length();
+ return string_var.value.c_str();
+}
diff --git a/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.h b/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.h
new file mode 100644
index 0000000000..0d59ac628a
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/fake_var_interface.h
@@ -0,0 +1,41 @@
+// 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_TEST_FAKE_VAR_INTERFACE_H_
+#define LIBRARIES_NACL_IO_TEST_FAKE_VAR_INTERFACE_H_
+
+#include <map>
+#include <string>
+
+#include <ppapi/c/pp_var.h>
+
+#include "nacl_io/pepper_interface.h"
+#include "sdk_util/macros.h"
+
+class FakeVarInterface : public nacl_io::VarInterface {
+ public:
+ FakeVarInterface();
+ ~FakeVarInterface();
+
+ virtual void AddRef(PP_Var var);
+ virtual void Release(PP_Var var);
+ virtual PP_Var VarFromUtf8(const char* data, uint32_t len);
+ virtual const char* VarToUtf8(PP_Var var, uint32_t* out_len);
+
+ private:
+ typedef uint64_t Id;
+
+ struct FakeStringVar {
+ std::string value;
+ int32_t ref_count;
+ };
+
+ typedef std::map<Id, FakeStringVar> VarMap;
+ Id next_id_;
+ VarMap var_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeVarInterface);
+};
+
+#endif // LIBRARIES_NACL_IO_TEST_FAKE_VAR_INTERFACE_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/index.html b/native_client_sdk/src/tests/nacl_io_test/index.html
new file mode 100644
index 0000000000..ba54317929
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/index.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<!--
+Copyright (c) 2012 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<head>
+ <meta http-equiv="Pragma" content="no-cache">
+ <meta http-equiv="Expires" content="-1">
+ <title>{{title}}</title>
+ <script type="text/javascript" src="common.js"></script>
+ <script type="text/javascript" src="example.js"></script>
+ <style>
+ .result { padding-left: 10px; }
+ .ok { background-color: #0f0; }
+ .failed { background-color: #f00; }
+ </style>
+</head>
+<body {{attrs}}>
+ <h1>{{title}}</h1>
+ <h2>Status: <code id="statusField">NO-STATUS</code></h2>
+ <!-- The NaCl plugin will be embedded inside the element with id "listener".
+ See common.js.-->
+ <div id="listener"></div>
+ <ul id="tests" style="list-style:none;"></ul>
+</body>
+</html>
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc
index 025402f3a5..4ec3136113 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_object_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_object_test.cc
@@ -10,13 +10,13 @@
#include <map>
#include <string>
+#include "gtest/gtest.h"
+
#include "nacl_io/kernel_handle.h"
#include "nacl_io/kernel_object.h"
#include "nacl_io/mount.h"
#include "nacl_io/path.h"
-#include "gtest/gtest.h"
-
using namespace nacl_io;
namespace {
@@ -29,7 +29,6 @@ class MountNodeRefMock : public MountNode {
class MountRefMock : public Mount {
public:
MountRefMock() {}
- ~MountRefMock() {}
public:
Error Access(const Path& path, int a_mode) { return ENOSYS; }
@@ -47,26 +46,22 @@ class KernelHandleRefMock : public KernelHandle {
public:
KernelHandleRefMock(const ScopedMount& mnt, const ScopedMountNode& node)
: KernelHandle(mnt, node) {}
-
- ~KernelHandleRefMock() {}
};
class KernelObjectTest : public ::testing::Test {
public:
- KernelObjectTest() {
- proxy = new KernelObject;
+ void SetUp() {
mnt.reset(new MountRefMock());
node.reset(new MountNodeRefMock(mnt.get()));
}
- ~KernelObjectTest() {
+ void TearDown() {
// mnt is ref-counted, it doesn't need to be explicitly deleted.
node.reset(NULL);
mnt.reset(NULL);
- delete proxy;
}
- KernelObject* proxy;
+ KernelObject proxy;
ScopedMount mnt;
ScopedMountNode node;
};
@@ -102,13 +97,13 @@ TEST_F(KernelObjectTest, Referencing) {
// Allocating an FD should cause the KernelProxy to ref the handle and
// the node and mount should be unchanged.
- int fd1 = proxy->AllocateFD(handle_a);
+ int fd1 = proxy.AllocateFD(handle_a);
EXPECT_EQ(3, handle_a->RefCount());
EXPECT_EQ(2, mnt->RefCount());
EXPECT_EQ(2, node->RefCount());
// If we "dup" the handle, we should bump the ref count on the handle
- int fd2 = proxy->AllocateFD(handle_b);
+ int fd2 = proxy.AllocateFD(handle_b);
EXPECT_EQ(4, handle_a->RefCount());
EXPECT_EQ(2, mnt->RefCount());
EXPECT_EQ(2, node->RefCount());
@@ -124,8 +119,8 @@ TEST_F(KernelObjectTest, Referencing) {
EXPECT_EQ(2, node->RefCount());
// We should find the handle by either fd
- EXPECT_EQ(0, proxy->AcquireHandle(fd1, &handle_a));
- EXPECT_EQ(0, proxy->AcquireHandle(fd2, &handle_b));
+ EXPECT_EQ(0, proxy.AcquireHandle(fd1, &handle_a));
+ EXPECT_EQ(0, proxy.AcquireHandle(fd2, &handle_b));
EXPECT_EQ(raw_handle, handle_a.get());
EXPECT_EQ(raw_handle, handle_b.get());
@@ -135,11 +130,11 @@ TEST_F(KernelObjectTest, Referencing) {
// A non existent fd should fail, and handleA should decrement as handleB
// is released by the call.
- EXPECT_EQ(EBADF, proxy->AcquireHandle(-1, &handle_b));
+ EXPECT_EQ(EBADF, proxy.AcquireHandle(-1, &handle_b));
EXPECT_EQ(NULL, handle_b.get());
EXPECT_EQ(3, handle_a->RefCount());
- EXPECT_EQ(EBADF, proxy->AcquireHandle(100, &handle_b));
+ EXPECT_EQ(EBADF, proxy.AcquireHandle(100, &handle_b));
EXPECT_EQ(NULL, handle_b.get());
// Now only the KernelProxy should reference the KernelHandle in the
@@ -150,12 +145,12 @@ TEST_F(KernelObjectTest, Referencing) {
EXPECT_EQ(2, raw_handle->RefCount());
EXPECT_EQ(2, mnt->RefCount());
EXPECT_EQ(2, node->RefCount());
- proxy->FreeFD(fd2);
+ proxy.FreeFD(fd2);
EXPECT_EQ(1, raw_handle->RefCount());
EXPECT_EQ(2, mnt->RefCount());
EXPECT_EQ(2, node->RefCount());
- proxy->FreeFD(fd1);
+ proxy.FreeFD(fd1);
EXPECT_EQ(1, mnt->RefCount());
EXPECT_EQ(1, node->RefCount());
}
@@ -172,12 +167,12 @@ TEST_F(KernelObjectTest, FreeAndReassignFD) {
EXPECT_EQ(2, node->RefCount());
EXPECT_EQ(1, raw_handle->RefCount());
- proxy->AllocateFD(handle);
+ proxy.AllocateFD(handle);
EXPECT_EQ(2, mnt->RefCount());
EXPECT_EQ(2, node->RefCount());
EXPECT_EQ(2, raw_handle->RefCount());
- proxy->FreeAndReassignFD(5, handle);
+ proxy.FreeAndReassignFD(5, handle);
EXPECT_EQ(2, mnt->RefCount());
EXPECT_EQ(2, node->RefCount());
EXPECT_EQ(3, raw_handle->RefCount());
@@ -185,7 +180,7 @@ TEST_F(KernelObjectTest, FreeAndReassignFD) {
handle.reset();
EXPECT_EQ(2, raw_handle->RefCount());
- proxy->AcquireHandle(5, &handle);
+ proxy.AcquireHandle(5, &handle);
EXPECT_EQ(3, raw_handle->RefCount());
EXPECT_EQ(raw_handle, handle.get());
}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_mock.cc
index e3791fa4fa..e3791fa4fa 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_mock.cc
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_mock.h
index 159e3cba1a..8a301ace8f 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_mock.h
@@ -10,6 +10,7 @@
#include "gmock/gmock.h"
#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/ossignal.h"
#include "nacl_io/ossocket.h"
#include "nacl_io/ostermios.h"
@@ -34,25 +35,28 @@ class KernelProxyMock : public nacl_io::KernelProxy {
MOCK_METHOD1(getwd, char*(char*));
MOCK_METHOD3(ioctl, int(int, int, char*));
MOCK_METHOD1(isatty, int(int));
+ MOCK_METHOD2(kill, int(int, int));
MOCK_METHOD3(lchown, int(const char*, uid_t, gid_t));
+ MOCK_METHOD2(link, int(const char*, const char*));
MOCK_METHOD3(lseek, off_t(int, off_t, int));
MOCK_METHOD2(mkdir, int(const char*, mode_t));
+ MOCK_METHOD6(mmap, void*(void*, size_t, int, int, int, size_t));
MOCK_METHOD5(mount, int(const char*, const char*, const char*, unsigned long,
const void*));
MOCK_METHOD2(open, int(const char*, int));
MOCK_METHOD3(read, ssize_t(int, void*, size_t));
MOCK_METHOD1(remove, int(const char*));
MOCK_METHOD1(rmdir, int(const char*));
+ MOCK_METHOD2(signal, sighandler_t(int, sighandler_t));
+ MOCK_METHOD2(sigset, sighandler_t(int, sighandler_t));
MOCK_METHOD2(stat, int(const char*, struct stat*));
+ MOCK_METHOD2(symlink, int(const char*, const char*));
MOCK_METHOD2(tcgetattr, int(int, struct termios*));
MOCK_METHOD3(tcsetattr, int(int, int, const struct termios*));
MOCK_METHOD1(umount, int(const char*));
MOCK_METHOD1(unlink, int(const char*));
MOCK_METHOD2(utime, int(const char*, const struct utimbuf*));
MOCK_METHOD3(write, ssize_t(int, const void*, size_t));
- MOCK_METHOD2(link, int(const char*, const char*));
- MOCK_METHOD2(symlink, int(const char*, const char*));
- MOCK_METHOD6(mmap, void*(void*, size_t, int, int, int, size_t));
MOCK_METHOD1(open_resource, int(const char*));
#ifdef PROVIDES_SOCKET_API
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
index 1eabdd03e4..18cc6a9110 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_proxy_test.cc
@@ -52,20 +52,21 @@ class KernelProxyFriend : public KernelProxy {
class KernelProxyTest : public ::testing::Test {
public:
- KernelProxyTest() : kp_(new KernelProxyFriend) {
- ki_init(kp_);
+ KernelProxyTest() {}
+
+ void SetUp() {
+ ki_init(&kp_);
// Unmount the passthrough FS and mount a memfs.
- EXPECT_EQ(0, kp_->umount("/"));
- EXPECT_EQ(0, kp_->mount("", "/", "memfs", 0, NULL));
+ EXPECT_EQ(0, kp_.umount("/"));
+ EXPECT_EQ(0, kp_.mount("", "/", "memfs", 0, NULL));
}
- ~KernelProxyTest() {
+ void TearDown() {
ki_uninit();
- delete kp_;
}
protected:
- KernelProxyFriend* kp_;
+ KernelProxyFriend kp_;
};
} // namespace
@@ -76,7 +77,7 @@ TEST_F(KernelProxyTest, FileLeak) {
int file_num;
int garbage[buffer_size];
- MountMem* mount = (MountMem*)kp_->RootMount();
+ MountMem* mount = (MountMem*)kp_.RootMount();
ScopedMountNode root;
EXPECT_EQ(0, mount->Open(Path("/"), O_RDONLY, &root));
@@ -290,15 +291,18 @@ class KernelProxyMountMock : public KernelProxy {
class KernelProxyMountTest : public ::testing::Test {
public:
- KernelProxyMountTest() : kp_(new KernelProxyMountMock) { ki_init(kp_); }
+ KernelProxyMountTest() {}
+
+ void SetUp() {
+ ki_init(&kp_);
+ }
- ~KernelProxyMountTest() {
+ void TearDown() {
ki_uninit();
- delete kp_;
}
private:
- KernelProxy* kp_;
+ KernelProxyMountMock kp_;
};
} // namespace
@@ -382,15 +386,18 @@ class KernelProxyMockMMap : public KernelProxy {
class KernelProxyMMapTest : public ::testing::Test {
public:
- KernelProxyMMapTest() : kp_(new KernelProxyMockMMap) { ki_init(kp_); }
+ KernelProxyMMapTest() {}
- ~KernelProxyMMapTest() {
+ void SetUp() {
+ ki_init(&kp_);
+ }
+
+ void TearDown() {
ki_uninit();
- delete kp_;
}
private:
- KernelProxy* kp_;
+ KernelProxyMockMMap kp_;
};
} // namespace
@@ -458,22 +465,23 @@ class KernelProxyError : public KernelProxy {
class KernelProxyErrorTest : public ::testing::Test {
public:
- KernelProxyErrorTest() : kp_(new KernelProxyError) {
- ki_init(kp_);
+ KernelProxyErrorTest() {}
+
+ void SetUp() {
+ ki_init(&kp_);
// Unmount the passthrough FS and mount a testfs.
- EXPECT_EQ(0, kp_->umount("/"));
- EXPECT_EQ(0, kp_->mount("", "/", "testfs", 0, NULL));
+ EXPECT_EQ(0, kp_.umount("/"));
+ EXPECT_EQ(0, kp_.mount("", "/", "testfs", 0, NULL));
}
- ~KernelProxyErrorTest() {
+ void TearDown() {
ki_uninit();
- delete kp_;
}
- ScopedRef<MountMock> mnt() { return kp_->mnt(); }
+ ScopedRef<MountMock> mnt() { return kp_.mnt(); }
private:
- KernelProxyError* kp_;
+ KernelProxyError kp_;
};
} // namespace
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc b/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc
index 34db64a746..4472d8c592 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/kernel_wrap_test.cc
@@ -179,8 +179,14 @@ TEST_F(KernelWrapTest, getcwd) {
}
TEST_F(KernelWrapTest, getdents) {
- EXPECT_CALL(mock, getdents(456, NULL, 567)).Times(1);
- getdents(456, NULL, 567);
+#ifndef __GLIBC__
+ // TODO(sbc): Find a way to test the getdents wrapper under glibc.
+ // It looks like the only way to excerside it is to call readdir(2).
+ // There is an internal glibc function __getdents that will call the
+ // IRT but that cannot be accessed from here as glibc does not export it.
+ EXPECT_CALL(mock, getdents(456, NULL, 567)).WillOnce(Return(678));
+ EXPECT_EQ(getdents(456, NULL, 567), 678);
+#endif
}
// gcc gives error: getwd is deprecated.
@@ -207,6 +213,11 @@ TEST_F(KernelWrapTest, isatty) {
isatty(678);
}
+TEST_F(KernelWrapTest, kill) {
+ EXPECT_CALL(mock, kill(22, 33)).Times(1);
+ kill(22, 33);
+}
+
TEST_F(KernelWrapTest, lchown) {
uid_t uid = kDummyUid;
gid_t gid = kDummyGid;
@@ -256,6 +267,19 @@ TEST_F(KernelWrapTest, rmdir) {
rmdir("rmdir");
}
+static void handler(int) {
+}
+
+TEST_F(KernelWrapTest, sigset) {
+ EXPECT_CALL(mock, sigset(22, handler)).Times(1);
+ sigset(22, handler);
+}
+
+TEST_F(KernelWrapTest, signal) {
+ EXPECT_CALL(mock, sigset(22, handler)).Times(1);
+ signal(22, handler);
+}
+
TEST_F(KernelWrapTest, stat) {
struct stat in_statbuf;
MakeDummyStatbuf(&in_statbuf);
diff --git a/native_client_sdk/src/tests/nacl_io_test/main.cc b/native_client_sdk/src/tests/nacl_io_test/main.cc
new file mode 100644
index 0000000000..9df6d4bde7
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/main.cc
@@ -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.
+
+#include <string>
+
+#include "gtest/gtest.h"
+
+#if defined(SEL_LDR)
+
+int main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+
+#else
+
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/var.h"
+#include "ppapi_simple/ps_main.h"
+
+#if defined(WIN32)
+#include <Windows.h>
+#undef PostMessage
+#endif
+
+class GTestEventListener : public ::testing::EmptyTestEventListener {
+ public:
+ // TestEventListener overrides.
+ virtual void OnTestStart(const ::testing::TestInfo& test_info) {
+ std::stringstream msg;
+ msg << "start:" << test_info.test_case_name() << "." << test_info.name();
+ pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+ }
+
+ virtual void OnTestPartResult(
+ const ::testing::TestPartResult& test_part_result) {
+ if (test_part_result.failed()) {
+ std::stringstream msg;
+ msg << "fail:" << test_part_result.file_name() << ","
+ << test_part_result.line_number() << ","
+ << test_part_result.summary();
+ pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+ }
+ }
+
+ virtual void OnTestEnd(const ::testing::TestInfo& test_info) {
+ std::stringstream msg;
+ msg << "end:" << test_info.test_case_name() << "." << test_info.name()
+ << "," << (test_info.result()->Failed() ? "failed" : "ok");
+ pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+ }
+
+ virtual void OnTestProgramEnd(const ::testing::UnitTest&) {
+ pp::Instance(PSGetInstanceId()).PostMessage("testend");
+ }
+};
+
+int example_main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners()
+ .Append(new GTestEventListener());
+ return RUN_ALL_TESTS();
+}
+
+// Register the function to call once the Instance Object is initialized.
+// see: pappi_simple/ps_main.h
+PPAPI_SIMPLE_REGISTER_MAIN(example_main);
+
+#endif
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mock_util.h b/native_client_sdk/src/tests/nacl_io_test/mock_util.h
index 290d6cdede..7f29f0f674 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mock_util.h
+++ b/native_client_sdk/src/tests/nacl_io_test/mock_util.h
@@ -16,9 +16,6 @@ ACTION_TEMPLATE(CallCallback,
if (callback.func) {
(*callback.func)(callback.user_data, result);
}
-
- // Dummy return value.
- return 0;
}
MATCHER_P(IsEqualToVar, var, "") {
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_dev_mock.h b/native_client_sdk/src/tests/nacl_io_test/mount_dev_mock.h
new file mode 100644
index 0000000000..10ee830244
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_dev_mock.h
@@ -0,0 +1,24 @@
+// 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_TEST_MOUNT_NODE_MOCK_H_
+#define LIBRARIES_NACL_IO_TEST_MOUNT_NODE_MOCK_H_
+
+#include "gmock/gmock.h"
+
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_dev.h"
+
+#define NULL_NODE ((MountNode*) NULL)
+
+class MountDevMock : public nacl_io::MountDev {
+ public:
+ MountDevMock() {
+ nacl_io::StringMap_t map;
+ Init(1, map, NULL);
+ }
+ int num_nodes() { return (int) inode_pool_.size(); }
+};
+
+#endif // LIBRARIES_NACL_IO_TEST_MOUNT_NODE_MOCK_H_
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_html5fs_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_html5fs_test.cc
new file mode 100644
index 0000000000..73cd749e7e
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_html5fs_test.cc
@@ -0,0 +1,448 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <errno.h>
+#include <fcntl.h>
+#include <gmock/gmock.h>
+#include <ppapi/c/ppb_file_io.h>
+#include <ppapi/c/pp_directory_entry.h>
+#include <ppapi/c/pp_errors.h>
+#include <ppapi/c/pp_instance.h>
+#if defined(WIN32)
+#include <windows.h> // For Sleep()
+#endif
+
+#include "nacl_io/mount_html5fs.h"
+#include "nacl_io/osdirent.h"
+#include "nacl_io/osunistd.h"
+#include "nacl_io/pepper_interface_delegate.h"
+#include "sdk_util/scoped_ref.h"
+#include "fake_pepper_interface_html5fs.h"
+#include "mock_util.h"
+#include "pepper_interface_mock.h"
+
+using namespace nacl_io;
+using namespace sdk_util;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Invoke;
+using ::testing::Mock;
+using ::testing::Return;
+
+namespace {
+
+class MountHtml5FsForTesting : public MountHtml5Fs {
+ public:
+ MountHtml5FsForTesting(StringMap_t& args, PepperInterface* ppapi) {
+ Error error = Init(1, args, ppapi);
+ EXPECT_EQ(0, error);
+ }
+};
+
+class MountHtml5FsTest : public ::testing::Test {
+ public:
+ MountHtml5FsTest();
+
+ protected:
+ FakePepperInterfaceHtml5Fs ppapi_html5_;
+ PepperInterfaceMock ppapi_mock_;
+ PepperInterfaceDelegate ppapi_;
+};
+
+MountHtml5FsTest::MountHtml5FsTest()
+ : ppapi_mock_(ppapi_html5_.GetInstance()),
+ ppapi_(ppapi_html5_.GetInstance()) {
+ // Default delegation to the html5 pepper interface.
+ ppapi_.SetCoreInterfaceDelegate(ppapi_html5_.GetCoreInterface());
+ ppapi_.SetFileSystemInterfaceDelegate(ppapi_html5_.GetFileSystemInterface());
+ ppapi_.SetFileRefInterfaceDelegate(ppapi_html5_.GetFileRefInterface());
+ ppapi_.SetFileIoInterfaceDelegate(ppapi_html5_.GetFileIoInterface());
+ ppapi_.SetVarInterfaceDelegate(ppapi_html5_.GetVarInterface());
+}
+
+} // namespace
+
+TEST_F(MountHtml5FsTest, FilesystemType) {
+ const char* filesystem_type_strings[] = {"", "PERSISTENT", "TEMPORARY", NULL};
+ PP_FileSystemType filesystem_type_values[] = {
+ PP_FILESYSTEMTYPE_LOCALPERSISTENT, // Default to persistent.
+ PP_FILESYSTEMTYPE_LOCALPERSISTENT, PP_FILESYSTEMTYPE_LOCALTEMPORARY};
+
+ const char* expected_size_strings[] = {"100", "12345", NULL};
+ const int expected_size_values[] = {100, 12345};
+
+ FileSystemInterfaceMock* filesystem_mock =
+ ppapi_mock_.GetFileSystemInterface();
+
+ FakeFileSystemInterface* filesystem_fake =
+ static_cast<FakeFileSystemInterface*>(
+ ppapi_html5_.GetFileSystemInterface());
+
+ for (int i = 0; filesystem_type_strings[i] != NULL; ++i) {
+ const char* filesystem_type_string = filesystem_type_strings[i];
+ PP_FileSystemType expected_filesystem_type = filesystem_type_values[i];
+
+ for (int j = 0; expected_size_strings[j] != NULL; ++j) {
+ const char* expected_size_string = expected_size_strings[j];
+ int64_t expected_expected_size = expected_size_values[j];
+
+ ppapi_.SetFileSystemInterfaceDelegate(filesystem_mock);
+
+ ON_CALL(*filesystem_mock, Create(_, _)).WillByDefault(
+ Invoke(filesystem_fake, &FakeFileSystemInterface::Create));
+
+ EXPECT_CALL(*filesystem_mock,
+ Create(ppapi_.GetInstance(), expected_filesystem_type));
+
+ EXPECT_CALL(*filesystem_mock, Open(_, expected_expected_size, _))
+ .WillOnce(DoAll(CallCallback<2>(int32_t(PP_OK)),
+ Return(int32_t(PP_OK_COMPLETIONPENDING))));
+
+ StringMap_t map;
+ map["type"] = filesystem_type_string;
+ map["expected_size"] = expected_size_string;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ Mock::VerifyAndClearExpectations(&filesystem_mock);
+ }
+ }
+}
+
+TEST_F(MountHtml5FsTest, Access) {
+ EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/foo", NULL));
+
+ StringMap_t map;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ ASSERT_EQ(0, mnt->Access(Path("/foo"), R_OK | W_OK | X_OK));
+ ASSERT_EQ(ENOENT, mnt->Access(Path("/bar"), F_OK));
+}
+
+TEST_F(MountHtml5FsTest, Mkdir) {
+ StringMap_t map;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ // mkdir at the root should return EEXIST, not EACCES.
+ EXPECT_EQ(EEXIST, mnt->Mkdir(Path("/"), 0644));
+
+ Path path("/foo");
+ ASSERT_EQ(ENOENT, mnt->Access(path, F_OK));
+ ASSERT_EQ(0, mnt->Mkdir(path, 0644));
+
+ struct stat stat;
+ ScopedMountNode node;
+ ASSERT_EQ(0, mnt->Open(path, O_RDONLY, &node));
+ EXPECT_EQ(0, node->GetStat(&stat));
+ EXPECT_EQ(S_IFDIR, stat.st_mode & S_IFDIR);
+}
+
+TEST_F(MountHtml5FsTest, Remove) {
+ EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/foo", NULL));
+
+ StringMap_t map;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ Path path("/foo");
+ ASSERT_EQ(0, mnt->Access(path, F_OK));
+ ASSERT_EQ(0, mnt->Remove(path));
+ EXPECT_EQ(ENOENT, mnt->Access(path, F_OK));
+}
+
+// Unlink + Rmdir forward to Remove unconditionally, which will not fail if the
+// file type is wrong.
+TEST_F(MountHtml5FsTest, DISABLED_Unlink) {
+ EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/file", NULL));
+ EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
+
+ StringMap_t map;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ ASSERT_EQ(EISDIR, mnt->Unlink(Path("/dir")));
+ EXPECT_EQ(0, mnt->Unlink(Path("/file")));
+ EXPECT_EQ(ENOENT, mnt->Access(Path("/file"), F_OK));
+ EXPECT_EQ(0, mnt->Access(Path("/dir"), F_OK));
+}
+
+// Unlink + Rmdir forward to Remove unconditionally, which will not fail if the
+// file type is wrong.
+TEST_F(MountHtml5FsTest, DISABLED_Rmdir) {
+ EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddEmptyFile("/file", NULL));
+ EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
+
+ StringMap_t map;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ ASSERT_EQ(ENOTDIR, mnt->Rmdir(Path("/file")));
+ EXPECT_EQ(0, mnt->Rmdir(Path("/dir")));
+ EXPECT_EQ(ENOENT, mnt->Access(Path("/dir"), F_OK));
+ EXPECT_EQ(0, mnt->Access(Path("/file"), F_OK));
+}
+
+TEST_F(MountHtml5FsTest, OpenForCreate) {
+ StringMap_t map;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ Path path("/foo");
+ EXPECT_EQ(ENOENT, mnt->Access(path, F_OK));
+
+ ScopedMountNode node;
+ EXPECT_EQ(0, mnt->Open(path, O_CREAT | O_RDWR, &node));
+
+ // Write some data.
+ char contents[] = "contents";
+ int bytes_written = 0;
+ EXPECT_EQ(0, node->Write(0, &contents[0], strlen(contents), &bytes_written));
+ EXPECT_EQ(strlen(contents), bytes_written);
+
+ // Create again.
+ ASSERT_EQ(0, mnt->Open(path, O_CREAT, &node));
+
+ // Check that the file still has data.
+ size_t size;
+ EXPECT_EQ(0, node->GetSize(&size));
+ EXPECT_EQ(strlen(contents), size);
+
+ // Open exclusively.
+ EXPECT_EQ(EEXIST, mnt->Open(path, O_CREAT | O_EXCL, &node));
+
+ // Try to truncate without write access.
+ EXPECT_EQ(EINVAL, mnt->Open(path, O_CREAT | O_TRUNC, &node));
+
+ // Open and truncate.
+ ASSERT_EQ(0, mnt->Open(path, O_CREAT | O_TRUNC | O_WRONLY, &node));
+
+ // File should be empty.
+ EXPECT_EQ(0, node->GetSize(&size));
+ EXPECT_EQ(0, size);
+}
+
+TEST_F(MountHtml5FsTest, Read) {
+ const char contents[] = "contents";
+ EXPECT_TRUE(
+ ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
+ EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
+
+ StringMap_t map;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ ScopedMountNode node;
+ EXPECT_EQ(0, mnt->Open(Path("/file"), O_RDONLY, &node));
+
+ char buffer[10] = {0};
+ int bytes_read = 0;
+ EXPECT_EQ(0, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+ EXPECT_EQ(strlen(contents), bytes_read);
+ EXPECT_STREQ(contents, buffer);
+
+ // Read nothing past the end of the file.
+ EXPECT_EQ(0, node->Read(100, &buffer[0], sizeof(buffer), &bytes_read));
+ EXPECT_EQ(0, bytes_read);
+
+ // Read part of the data.
+ EXPECT_EQ(0, node->Read(4, &buffer[0], sizeof(buffer), &bytes_read));
+ ASSERT_EQ(strlen(contents) - 4, bytes_read);
+ buffer[bytes_read] = 0;
+ EXPECT_STREQ("ents", buffer);
+
+ // Writing should fail.
+ int bytes_written = 1; // Set to a non-zero value.
+ EXPECT_EQ(EACCES, node->Write(0, &buffer[0], sizeof(buffer), &bytes_written));
+ EXPECT_EQ(0, bytes_written);
+
+ // Reading from a directory should fail.
+ EXPECT_EQ(0, mnt->Open(Path("/dir"), O_RDONLY, &node));
+ EXPECT_EQ(EISDIR, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+}
+
+TEST_F(MountHtml5FsTest, Write) {
+ const char contents[] = "contents";
+ EXPECT_TRUE(
+ ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
+ EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
+
+ StringMap_t map;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ ScopedMountNode node;
+ ASSERT_EQ(0, mnt->Open(Path("/file"), O_WRONLY, &node));
+
+ // Reading should fail.
+ char buffer[10];
+ int bytes_read = 1; // Set to a non-zero value.
+ EXPECT_EQ(EACCES, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+ EXPECT_EQ(0, bytes_read);
+
+ // Reopen as read-write.
+ ASSERT_EQ(0, mnt->Open(Path("/file"), O_RDWR, &node));
+
+ int bytes_written = 1; // Set to a non-zero value.
+ EXPECT_EQ(0, node->Write(3, "struct", 6, &bytes_written));
+ EXPECT_EQ(6, bytes_written);
+
+ EXPECT_EQ(0, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+ EXPECT_EQ(9, bytes_read);
+ buffer[bytes_read] = 0;
+ EXPECT_STREQ("construct", buffer);
+
+ // Writing to a directory should fail.
+ EXPECT_EQ(0, mnt->Open(Path("/dir"), O_RDWR, &node));
+ EXPECT_EQ(EISDIR, node->Write(0, &buffer[0], sizeof(buffer), &bytes_read));
+}
+
+TEST_F(MountHtml5FsTest, GetStat) {
+ const int creation_time = 1000;
+ const int access_time = 2000;
+ const int modified_time = 3000;
+ const char contents[] = "contents";
+
+ // Create fake file.
+ FakeHtml5FsNode* fake_node;
+ EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddFile(
+ "/file", contents, &fake_node));
+ fake_node->set_creation_time(creation_time);
+ fake_node->set_last_access_time(access_time);
+ fake_node->set_last_modified_time(modified_time);
+
+ // Create fake directory.
+ EXPECT_TRUE(
+ ppapi_html5_.filesystem_template()->AddDirectory("/dir", &fake_node));
+ fake_node->set_creation_time(creation_time);
+ fake_node->set_last_access_time(access_time);
+ fake_node->set_last_modified_time(modified_time);
+
+ StringMap_t map;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ ScopedMountNode node;
+ ASSERT_EQ(0, mnt->Open(Path("/file"), O_RDONLY, &node));
+
+ struct stat statbuf;
+ EXPECT_EQ(0, node->GetStat(&statbuf));
+ EXPECT_EQ(S_IFREG | S_IWRITE | S_IREAD, statbuf.st_mode);
+ EXPECT_EQ(strlen(contents), statbuf.st_size);
+ EXPECT_EQ(access_time, statbuf.st_atime);
+ EXPECT_EQ(creation_time, statbuf.st_ctime);
+ EXPECT_EQ(modified_time, statbuf.st_mtime);
+
+ // Test Get* and Isa* methods.
+ size_t size;
+ EXPECT_EQ(0, node->GetSize(&size));
+ EXPECT_EQ(strlen(contents), size);
+ EXPECT_FALSE(node->IsaDir());
+ EXPECT_TRUE(node->IsaFile());
+ EXPECT_FALSE(node->IsaTTY());
+
+ // GetStat on a directory...
+ EXPECT_EQ(0, mnt->Open(Path("/dir"), O_RDONLY, &node));
+ EXPECT_EQ(0, node->GetStat(&statbuf));
+ EXPECT_EQ(S_IFDIR | S_IWRITE | S_IREAD, statbuf.st_mode);
+ EXPECT_EQ(0, statbuf.st_size);
+ EXPECT_EQ(access_time, statbuf.st_atime);
+ EXPECT_EQ(creation_time, statbuf.st_ctime);
+ EXPECT_EQ(modified_time, statbuf.st_mtime);
+
+ // Test Get* and Isa* methods.
+ EXPECT_EQ(0, node->GetSize(&size));
+ EXPECT_EQ(0, size);
+ EXPECT_TRUE(node->IsaDir());
+ EXPECT_FALSE(node->IsaFile());
+ EXPECT_FALSE(node->IsaTTY());
+}
+
+TEST_F(MountHtml5FsTest, FTruncate) {
+ const char contents[] = "contents";
+ EXPECT_TRUE(
+ ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
+ EXPECT_TRUE(ppapi_html5_.filesystem_template()->AddDirectory("/dir", NULL));
+
+ StringMap_t map;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ ScopedMountNode node;
+ ASSERT_EQ(0, mnt->Open(Path("/file"), O_RDWR, &node));
+
+ char buffer[10] = {0};
+ int bytes_read = 0;
+
+ // First make the file shorter...
+ EXPECT_EQ(0, node->FTruncate(4));
+ EXPECT_EQ(0, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+ EXPECT_EQ(4, bytes_read);
+ buffer[bytes_read] = 0;
+ EXPECT_STREQ("cont", buffer);
+
+ // Now make the file longer...
+ EXPECT_EQ(0, node->FTruncate(8));
+ EXPECT_EQ(0, node->Read(0, &buffer[0], sizeof(buffer), &bytes_read));
+ EXPECT_EQ(8, bytes_read);
+ buffer[bytes_read] = 0;
+ EXPECT_STREQ("cont\0\0\0\0", buffer);
+
+ // Ftruncate should fail for a directory.
+ EXPECT_EQ(0, mnt->Open(Path("/dir"), O_RDONLY, &node));
+ EXPECT_EQ(EISDIR, node->FTruncate(4));
+}
+
+TEST_F(MountHtml5FsTest, GetDents) {
+ const char contents[] = "contents";
+ EXPECT_TRUE(
+ ppapi_html5_.filesystem_template()->AddFile("/file", contents, NULL));
+
+ StringMap_t map;
+ ScopedRef<MountHtml5FsForTesting> mnt(
+ new MountHtml5FsForTesting(map, &ppapi_));
+
+ ScopedMountNode root;
+ ASSERT_EQ(0, mnt->Open(Path("/"), O_RDONLY, &root));
+
+ ScopedMountNode node;
+ ASSERT_EQ(0, mnt->Open(Path("/file"), O_RDWR, &node));
+
+ // Should fail for regular files.
+ struct dirent dirents[3];
+ int bytes_read = 1; // Set to a non-zero value.
+
+ memset(&dirents[0], 0, sizeof(dirents));
+ EXPECT_EQ(ENOTDIR,
+ node->GetDents(0, &dirents[0], sizeof(dirents), &bytes_read));
+ EXPECT_EQ(0, bytes_read);
+
+ // Should work with root directory.
+ // +2 to test a size that is not a multiple of sizeof(dirent).
+ // Expect it to round down.
+ memset(&dirents[0], 0, sizeof(dirents));
+ EXPECT_EQ(0, root->GetDents(0, &dirents[0], sizeof(dirent) + 2, &bytes_read));
+ EXPECT_EQ(sizeof(dirent), bytes_read);
+ EXPECT_EQ(sizeof(dirent), dirents[0].d_off);
+ EXPECT_EQ(sizeof(dirent), dirents[0].d_reclen);
+ EXPECT_STREQ("file", dirents[0].d_name);
+
+ // Add another file...
+ ASSERT_EQ(0, mnt->Open(Path("/file2"), O_CREAT, &node));
+
+ // Read the root directory again.
+ memset(&dirents[0], 0, sizeof(dirents));
+ EXPECT_EQ(0, root->GetDents(0, &dirents[0], sizeof(dirents), &bytes_read));
+ EXPECT_EQ(sizeof(dirent) * 2, bytes_read);
+
+ for (int i = 0; i < 2; ++i) {
+ EXPECT_LT(0, dirents[i].d_ino); // 0 is an invalid ino.
+ EXPECT_EQ(sizeof(dirent), dirents[i].d_off);
+ EXPECT_EQ(sizeof(dirent), dirents[i].d_reclen);
+ // Could be "file" or "file2".
+ EXPECT_TRUE(strncmp("file", dirents[i].d_name, 4) == 0);
+ }
+}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_http_test.cc
index 926fe28e09..25c907f54f 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_http_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_http_test.cc
@@ -189,6 +189,7 @@ class MountHttpNodeTest : public MountHttpTest {
MountHttpMock* mnt_;
ScopedMountNode node_;
+ CoreInterfaceMock* core_;
VarInterfaceMock* var_;
URLLoaderInterfaceMock* loader_;
URLRequestInfoInterfaceMock* request_;
@@ -223,6 +224,7 @@ void MountHttpNodeTest::SetMountArgs(const StringMap_t& args) {
}
void MountHttpNodeTest::ExpectOpen(const char* method) {
+ core_ = ppapi_.GetCoreInterface();
loader_ = ppapi_.GetURLLoaderInterface();
request_ = ppapi_.GetURLRequestInfoInterface();
response_ = ppapi_.GetURLResponseInfoInterface();
@@ -252,13 +254,14 @@ void MountHttpNodeTest::ExpectOpen(const char* method) {
#undef EXPECT_SET_PROPERTY
EXPECT_CALL(*loader_, Open(loader_resource_, request_resource_, _))
- .WillOnce(CallCallback<2>(int32_t(PP_OK)));
+ .WillOnce(DoAll(CallCallback<2>(int32_t(PP_OK)),
+ Return(int32_t(PP_OK_COMPLETIONPENDING))));
EXPECT_CALL(*loader_, GetResponseInfo(loader_resource_))
.WillOnce(Return(response_resource_));
- EXPECT_CALL(ppapi_, ReleaseResource(loader_resource_));
- EXPECT_CALL(ppapi_, ReleaseResource(request_resource_));
- EXPECT_CALL(ppapi_, ReleaseResource(response_resource_));
+ EXPECT_CALL(*core_, ReleaseResource(loader_resource_));
+ EXPECT_CALL(*core_, ReleaseResource(request_resource_));
+ EXPECT_CALL(*core_, ReleaseResource(response_resource_));
}
void MountHttpNodeTest::ExpectHeaders(const char* headers) {
@@ -343,6 +346,8 @@ void MountHttpNodeTest::TearDown() {
delete mnt_;
}
+// TODO(binji): These tests are all broken now. In another CL, I'll reimplement
+// these tests using an HTTP fake.
TEST_F(MountHttpNodeTest, DISABLED_OpenAndCloseNoCache) {
StringMap_t smap;
smap["cache_content"] = "false";
@@ -353,7 +358,7 @@ TEST_F(MountHttpNodeTest, DISABLED_OpenAndCloseNoCache) {
OpenNode();
}
-TEST_F(MountHttpNodeTest, OpenAndCloseNotFound) {
+TEST_F(MountHttpNodeTest, DISABLED_OpenAndCloseNotFound) {
StringMap_t smap;
smap["cache_content"] = "false";
SetMountArgs(StringMap_t());
@@ -363,7 +368,7 @@ TEST_F(MountHttpNodeTest, OpenAndCloseNotFound) {
ASSERT_EQ(ENOENT, mnt_->Open(Path(path_), O_RDONLY, &node_));
}
-TEST_F(MountHttpNodeTest, OpenAndCloseServerError) {
+TEST_F(MountHttpNodeTest, DISABLED_OpenAndCloseServerError) {
StringMap_t smap;
smap["cache_content"] = "false";
SetMountArgs(StringMap_t());
@@ -373,7 +378,7 @@ TEST_F(MountHttpNodeTest, OpenAndCloseServerError) {
ASSERT_EQ(EIO, mnt_->Open(Path(path_), O_RDONLY, &node_));
}
-TEST_F(MountHttpNodeTest, GetStat) {
+TEST_F(MountHttpNodeTest, DISABLED_GetStat) {
StringMap_t smap;
smap["cache_content"] = "false";
SetMountArgs(StringMap_t());
@@ -407,7 +412,7 @@ TEST_F(MountHttpNodeTest, DISABLED_AccessWrite) {
ASSERT_EQ(EACCES, mnt_->Access(Path(path_), W_OK));
}
-TEST_F(MountHttpNodeTest, AccessNotFound) {
+TEST_F(MountHttpNodeTest, DISABLED_AccessNotFound) {
StringMap_t smap;
smap["cache_content"] = "false";
SetMountArgs(StringMap_t());
@@ -417,7 +422,7 @@ TEST_F(MountHttpNodeTest, AccessNotFound) {
ASSERT_EQ(ENOENT, mnt_->Access(Path(path_), R_OK));
}
-TEST_F(MountHttpNodeTest, ReadCached) {
+TEST_F(MountHttpNodeTest, DISABLED_ReadCached) {
size_t result_size = 0;
int result_bytes = 0;
@@ -490,7 +495,7 @@ TEST_F(MountHttpNodeTest, DISABLED_ReadCachedNoContentLength) {
EXPECT_EQ(42, result_size);
}
-TEST_F(MountHttpNodeTest, ReadCachedUnderrun) {
+TEST_F(MountHttpNodeTest, DISABLED_ReadCachedUnderrun) {
size_t result_size = 0;
int result_bytes = 0;
@@ -520,7 +525,7 @@ TEST_F(MountHttpNodeTest, ReadCachedUnderrun) {
EXPECT_EQ(26, result_size);
}
-TEST_F(MountHttpNodeTest, ReadCachedOverrun) {
+TEST_F(MountHttpNodeTest, DISABLED_ReadCachedOverrun) {
size_t result_size = 0;
int result_bytes = 0;
@@ -550,7 +555,7 @@ TEST_F(MountHttpNodeTest, ReadCachedOverrun) {
EXPECT_EQ(15, result_size);
}
-TEST_F(MountHttpNodeTest, ReadPartial) {
+TEST_F(MountHttpNodeTest, DISABLED_ReadPartial) {
int result_bytes = 0;
StringMap_t args;
@@ -584,7 +589,7 @@ TEST_F(MountHttpNodeTest, ReadPartial) {
EXPECT_STREQ("abcdefghi", &buf[0]);
}
-TEST_F(MountHttpNodeTest, ReadPartialNoServerSupport) {
+TEST_F(MountHttpNodeTest, DISABLED_ReadPartialNoServerSupport) {
int result_bytes = 0;
StringMap_t args;
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_mock.cc b/native_client_sdk/src/tests/nacl_io_test/mount_mock.cc
index 1006822ed2..1006822ed2 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_mock.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_mock.cc
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_mock.h b/native_client_sdk/src/tests/nacl_io_test/mount_mock.h
index 10d1cf230a..10d1cf230a 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_mock.h
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_mock.h
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.cc b/native_client_sdk/src/tests/nacl_io_test/mount_node_mock.cc
index 695af3adc6..695af3adc6 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_node_mock.cc
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.h b/native_client_sdk/src/tests/nacl_io_test/mount_node_mock.h
index 3354682c7b..3354682c7b 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_node_mock.h
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_node_mock.h
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc
index 875122ab33..962c3d0600 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_node_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_node_test.cc
@@ -5,6 +5,8 @@
#include <errno.h>
#include <fcntl.h>
+#include "gtest/gtest.h"
+
#include "nacl_io/error.h"
#include "nacl_io/ioctl.h"
#include "nacl_io/kernel_proxy.h"
@@ -14,8 +16,6 @@
#include "nacl_io/mount_node_mem.h"
#include "nacl_io/osdirent.h"
-#include "gtest/gtest.h"
-
#define NULL_NODE ((MountNode*) NULL)
using namespace nacl_io;
@@ -28,21 +28,10 @@ class MockMemory : public MountNodeMem {
~MockMemory() { s_AllocNum--; }
- Error Init(int mode) { return MountNodeMem::Init(mode); }
- Error AddChild(const std::string& name, const ScopedMountNode& node) {
- return MountNodeMem::AddChild(name, node);
- }
- Error RemoveChild(const std::string& name) {
- return MountNodeMem::RemoveChild(name);
- }
- Error FindChild(const std::string& name, ScopedMountNode* out_node) {
- return MountNodeMem::FindChild(name, out_node);
- }
- void Link() { MountNodeMem::Link(); }
- void Unlink() { MountNodeMem::Unlink(); }
-
- protected:
using MountNodeMem::Init;
+ using MountNodeMem::AddChild;
+ using MountNodeMem::RemoveChild;
+ using MountNodeMem::FindChild;
};
class MockDir : public MountNodeDir {
@@ -51,39 +40,28 @@ class MockDir : public MountNodeDir {
~MockDir() { s_AllocNum--; }
- Error Init(int mode) { return MountNodeDir::Init(mode); }
- Error AddChild(const std::string& name, const ScopedMountNode& node) {
- return MountNodeDir::AddChild(name, node);
- }
- Error RemoveChild(const std::string& name) {
- return MountNodeDir::RemoveChild(name);
- }
- Error FindChild(const std::string& name, ScopedMountNode* out_node) {
- return MountNodeDir::FindChild(name, out_node);
- }
- void Link() { MountNodeDir::Link(); }
- void Unlink() { MountNodeDir::Unlink(); }
-
- protected:
using MountNodeDir::Init;
+ using MountNodeDir::AddChild;
+ using MountNodeDir::RemoveChild;
+ using MountNodeDir::FindChild;
};
TEST(MountNodeTest, File) {
- MockMemory* file = new MockMemory;
+ MockMemory file;
ScopedMountNode result_node;
size_t result_size = 0;
int result_bytes = 0;
- EXPECT_EQ(0, file->Init(S_IREAD | S_IWRITE));
+ EXPECT_EQ(0, file.Init(S_IREAD | S_IWRITE));
// Test properties
- EXPECT_EQ(0, file->GetLinks());
- EXPECT_EQ(S_IREAD | S_IWRITE, file->GetMode());
- EXPECT_EQ(S_IFREG, file->GetType());
- EXPECT_FALSE(file->IsaDir());
- EXPECT_TRUE(file->IsaFile());
- EXPECT_FALSE(file->IsaTTY());
- EXPECT_EQ(0, file->RefCount());
+ EXPECT_EQ(0, file.GetLinks());
+ EXPECT_EQ(S_IREAD | S_IWRITE, file.GetMode());
+ EXPECT_EQ(S_IFREG, file.GetType());
+ EXPECT_FALSE(file.IsaDir());
+ EXPECT_TRUE(file.IsaFile());
+ EXPECT_FALSE(file.IsaTTY());
+ EXPECT_EQ(0, file.RefCount());
// Test IO
char buf1[1024];
@@ -92,102 +70,101 @@ TEST(MountNodeTest, File) {
buf1[a] = a;
memset(buf2, 0, sizeof(buf2));
- EXPECT_EQ(0, file->GetSize(&result_size));
+ 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, file.Read(0, buf2, sizeof(buf2), &result_bytes));
EXPECT_EQ(0, result_bytes);
- EXPECT_EQ(0, file->GetSize(&result_size));
+ 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(0, file.Write(0, buf1, sizeof(buf1), &result_bytes));
EXPECT_EQ(sizeof(buf1), result_bytes);
- EXPECT_EQ(0, file->GetSize(&result_size));
+ 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(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;
- EXPECT_EQ(0, file->GetStat(&s));
+ EXPECT_EQ(0, file.GetStat(&s));
EXPECT_LT(0, s.st_ino); // 0 is an invalid inode number.
EXPECT_EQ(sizeof(buf1), s.st_size);
// Directory operations should fail
struct dirent d;
- EXPECT_EQ(ENOTDIR, file->GetDents(0, &d, sizeof(d), &result_bytes));
- EXPECT_EQ(ENOTDIR, file->AddChild("", result_node));
- EXPECT_EQ(ENOTDIR, file->RemoveChild(""));
- EXPECT_EQ(ENOTDIR, file->FindChild("", &result_node));
+ EXPECT_EQ(ENOTDIR, file.GetDents(0, &d, sizeof(d), &result_bytes));
+ EXPECT_EQ(ENOTDIR, file.AddChild("", result_node));
+ EXPECT_EQ(ENOTDIR, file.RemoveChild(""));
+ EXPECT_EQ(ENOTDIR, file.FindChild("", &result_node));
EXPECT_EQ(NULL_NODE, result_node.get());
-
- delete file;
}
TEST(MountNodeTest, Directory) {
- MockDir* root = new MockDir();
+ s_AllocNum = 0;
+ MockDir root;
ScopedMountNode result_node;
size_t result_size = 0;
int result_bytes = 0;
- root->Init(S_IREAD | S_IWRITE);
+ root.Init(S_IREAD | S_IWRITE);
// Test properties
- EXPECT_EQ(0, root->GetLinks());
- EXPECT_EQ(S_IREAD | S_IWRITE, root->GetMode());
- EXPECT_EQ(S_IFDIR, root->GetType());
- EXPECT_TRUE(root->IsaDir());
- EXPECT_FALSE(root->IsaFile());
- EXPECT_FALSE(root->IsaTTY());
- EXPECT_EQ(0, root->RefCount());
+ EXPECT_EQ(0, root.GetLinks());
+ EXPECT_EQ(S_IREAD | S_IWRITE, root.GetMode());
+ EXPECT_EQ(S_IFDIR, root.GetType());
+ EXPECT_TRUE(root.IsaDir());
+ EXPECT_FALSE(root.IsaFile());
+ EXPECT_FALSE(root.IsaTTY());
+ EXPECT_EQ(0, root.RefCount());
// IO operations should fail
char buf1[1024];
- EXPECT_EQ(0, root->GetSize(&result_size));
+ 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));
+ 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* raw_file = new MockMemory;
EXPECT_EQ(0, raw_file->Init(S_IREAD | S_IWRITE));
ScopedMountNode file(raw_file);
- EXPECT_EQ(0, root->RefCount());
+ EXPECT_EQ(0, root.RefCount());
EXPECT_EQ(1, file->RefCount());
- EXPECT_EQ(0, root->AddChild("F1", file));
+ EXPECT_EQ(0, root.AddChild("F1", file));
EXPECT_EQ(1, file->GetLinks());
EXPECT_EQ(2, file->RefCount());
// Test that the directory is there
struct dirent d;
- EXPECT_EQ(0, root->GetDents(0, &d, sizeof(d), &result_bytes));
+ 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), &result_bytes));
+ 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(0, root.AddChild("F2", file));
EXPECT_EQ(2, file->GetLinks());
EXPECT_EQ(3, file->RefCount());
- EXPECT_EQ(EEXIST, root->AddChild("F1", file));
+ EXPECT_EQ(EEXIST, root.AddChild("F1", file));
EXPECT_EQ(2, file->GetLinks());
EXPECT_EQ(3, file->RefCount());
EXPECT_EQ(2, s_AllocNum);
- EXPECT_EQ(0, root->FindChild("F1", &result_node));
+ EXPECT_EQ(0, root.FindChild("F1", &result_node));
EXPECT_NE(NULL_NODE, result_node.get());
- EXPECT_EQ(0, root->FindChild("F2", &result_node));
+ EXPECT_EQ(0, root.FindChild("F2", &result_node));
EXPECT_NE(NULL_NODE, result_node.get());
- EXPECT_EQ(ENOENT, root->FindChild("F3", &result_node));
+ EXPECT_EQ(ENOENT, root.FindChild("F3", &result_node));
EXPECT_EQ(NULL_NODE, result_node.get());
EXPECT_EQ(2, s_AllocNum);
- EXPECT_EQ(0, root->RemoveChild("F1"));
+ EXPECT_EQ(0, root.RemoveChild("F1"));
EXPECT_EQ(1, file->GetLinks());
EXPECT_EQ(2, file->RefCount());
- EXPECT_EQ(0, root->RemoveChild("F2"));
+ EXPECT_EQ(0, root.RemoveChild("F2"));
EXPECT_EQ(0, file->GetLinks());
EXPECT_EQ(1, file->RefCount());
EXPECT_EQ(2, s_AllocNum);
diff --git a/native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc
new file mode 100644
index 0000000000..c9a67cd54f
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_node_tty_test.cc
@@ -0,0 +1,249 @@
+// 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 <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "mount_dev_mock.h"
+#include "nacl_io/ioctl.h"
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/mount.h"
+#include "nacl_io/mount_dev.h"
+#include "nacl_io/mount_mem.h"
+#include "nacl_io/osdirent.h"
+
+using namespace nacl_io;
+
+namespace {
+
+class TtyTest : public ::testing::Test {
+ public:
+ void SetUp() {
+ ki_init(&kp_);
+ ASSERT_EQ(0, mnt_.Access(Path("/tty"), R_OK | W_OK));
+ ASSERT_EQ(EACCES, mnt_.Access(Path("/tty"), X_OK));
+ ASSERT_EQ(0, mnt_.Open(Path("/tty"), O_RDWR, &dev_tty_));
+ ASSERT_NE(NULL_NODE, dev_tty_.get());
+ }
+
+ void TearDown() {
+ ki_uninit();
+ }
+
+ protected:
+ KernelProxy kp_;
+ MountDevMock mnt_;
+ ScopedMountNode dev_tty_;
+};
+
+TEST_F(TtyTest, InvalidIoctl) {
+ // 123 is not a valid ioctl request.
+ EXPECT_EQ(EINVAL, dev_tty_->Ioctl(123, NULL));
+}
+
+TEST_F(TtyTest, TtyInput) {
+ // Now let's try sending some data over.
+ // First we create the message.
+ std::string message("hello, how are you?\n");
+ struct tioc_nacl_input_string packaged_message;
+ packaged_message.length = message.size();
+ packaged_message.buffer = message.data();
+
+ // Now we make buffer we'll read into.
+ // We fill the buffer and a backup buffer with arbitrary data
+ // and compare them after reading to make sure read doesn't
+ // clobber parts of the buffer it shouldn't.
+ int bytes_read;
+ char buffer[100];
+ char backup_buffer[100];
+ memset(buffer, 'a', 100);
+ memset(backup_buffer, 'a', 100);
+
+ // Now we actually send the data
+ EXPECT_EQ(0, dev_tty_->Ioctl(TIOCNACLINPUT,
+ reinterpret_cast<char*>(&packaged_message)));
+
+ // We read a small chunk first to ensure it doesn't give us
+ // more than we ask for.
+ EXPECT_EQ(0, dev_tty_->Read(0, buffer, 5, &bytes_read));
+ EXPECT_EQ(bytes_read, 5);
+ EXPECT_EQ(0, memcmp(message.data(), buffer, 5));
+ EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, 95));
+
+ // Now we ask for more data than is left in the tty, to ensure
+ // it doesn't give us more than is there.
+ EXPECT_EQ(0, dev_tty_->Read(0, buffer + 5, 95, &bytes_read));
+ EXPECT_EQ(bytes_read, message.size() - 5);
+ EXPECT_EQ(0, memcmp(message.data(), buffer, message.size()));
+ EXPECT_EQ(0, memcmp(buffer + message.size(),
+ backup_buffer + message.size(),
+ 100 - message.size()));
+}
+
+struct user_data_t {
+ const char* output_buf;
+ size_t output_count;
+};
+
+static ssize_t output_handler(const char* buf, size_t count, void* data) {
+ user_data_t* user_data = static_cast<user_data_t*>(data);
+ user_data->output_buf = buf;
+ user_data->output_count = count;
+ return count;
+}
+
+TEST_F(TtyTest, TtyOutput) {
+ // When no handler is registered then all writes should return EIO
+ int bytes_written = 10;
+ const char* message = "hello\n";
+ int message_len = strlen(message);
+ EXPECT_EQ(EIO, dev_tty_->Write(0, message, message_len, &bytes_written));
+
+ // Setup output handler with user_data to record calls.
+ user_data_t user_data;
+ user_data.output_buf = NULL;
+ user_data.output_count = 0;
+
+ tioc_nacl_output handler;
+ handler.handler = output_handler;
+ handler.user_data = &user_data;
+
+ EXPECT_EQ(0, dev_tty_->Ioctl(TIOCNACLOUTPUT,
+ reinterpret_cast<char*>(&handler)));
+
+ EXPECT_EQ(0, dev_tty_->Write(0, message, message_len, &bytes_written));
+ EXPECT_EQ(message_len, bytes_written);
+ EXPECT_EQ(message_len, user_data.output_count);
+ EXPECT_EQ(0, strncmp(user_data.output_buf, message, message_len));
+}
+
+// Returns:
+// 0 -> Not readable
+// 1 -> Readable
+// -1 -> Error occured
+static int IsReadable(int fd) {
+ struct timeval timeout = { 0, 0 };
+ fd_set readfds;
+ fd_set errorfds;
+ FD_ZERO(&readfds);
+ FD_ZERO(&errorfds);
+ FD_SET(fd, &readfds);
+ FD_SET(fd, &errorfds);
+ int rtn = ki_select(fd + 1, &readfds, NULL, &errorfds, &timeout);
+ if (rtn == 0)
+ return 0; // not readable
+ if (rtn != 1)
+ return -1; // error
+ if (FD_ISSET(fd, &errorfds))
+ return -1; // error
+ if (!FD_ISSET(fd, &readfds))
+ return -1; // error
+ return 1; // readable
+}
+
+TEST_F(TtyTest, TtySelect) {
+ struct timeval timeout;
+ fd_set readfds;
+ fd_set writefds;
+ fd_set errorfds;
+
+ int tty_fd = ki_open("/dev/tty", O_RDONLY);
+ ASSERT_TRUE(tty_fd >= 0) << "tty open failed: " << errno;
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&errorfds);
+ FD_SET(tty_fd, &readfds);
+ FD_SET(tty_fd, &errorfds);
+ // 10 millisecond timeout
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 10 * 1000;
+ // Should timeout when no input is available.
+ int rtn = ki_select(tty_fd + 1, &readfds, NULL, &errorfds, &timeout);
+ ASSERT_EQ(rtn, 0) << "select failed: " << rtn << " err=" << strerror(errno);
+ ASSERT_FALSE(FD_ISSET(tty_fd, &readfds));
+ ASSERT_FALSE(FD_ISSET(tty_fd, &errorfds));
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&errorfds);
+ FD_SET(tty_fd, &readfds);
+ FD_SET(tty_fd, &writefds);
+ FD_SET(tty_fd, &errorfds);
+ // TTY should be writable on startup.
+ rtn = ki_select(tty_fd + 1, &readfds, &writefds, &errorfds, NULL);
+ ASSERT_EQ(rtn, 1);
+ ASSERT_TRUE(FD_ISSET(tty_fd, &writefds));
+ ASSERT_FALSE(FD_ISSET(tty_fd, &readfds));
+ ASSERT_FALSE(FD_ISSET(tty_fd, &errorfds));
+
+ // Send 4 bytes to TTY input
+ struct tioc_nacl_input_string input;
+ input.buffer = "input:test";
+ input.length = strlen(input.buffer);
+ char* ioctl_arg = reinterpret_cast<char*>(&input);
+ ASSERT_EQ(0, ki_ioctl(tty_fd, TIOCNACLINPUT, ioctl_arg));
+
+ // TTY should not be readable until newline in written
+ ASSERT_EQ(IsReadable(tty_fd), 0);
+
+ input.buffer = "input:\n";
+ input.length = strlen(input.buffer);
+ ASSERT_EQ(0, ki_ioctl(tty_fd, TIOCNACLINPUT, ioctl_arg));
+
+ // TTY should now be readable
+ ASSERT_EQ(IsReadable(tty_fd), 1);
+
+ ki_close(tty_fd);
+}
+
+int g_recieved_signal = 0;
+
+void sighandler(int sig) {
+ g_recieved_signal = sig;
+}
+
+TEST_F(TtyTest, WindowSize) {
+ // Get current window size
+ struct winsize old_winsize = { 0 };
+ ASSERT_EQ(0, dev_tty_->Ioctl(TIOCGWINSZ,
+ reinterpret_cast<char*>(&old_winsize)));
+
+ // Install signal handler
+ sighandler_t new_handler = sighandler;
+ sighandler_t old_handler = ki_signal(SIGWINCH, new_handler);
+ ASSERT_NE(old_handler, SIG_ERR) << "signal return error: " << errno;
+
+ // Set a new windows size
+ struct winsize winsize;
+ winsize.ws_col = 100;
+ winsize.ws_row = 200;
+ EXPECT_EQ(0, dev_tty_->Ioctl(TIOCSWINSZ,
+ reinterpret_cast<char*>(&winsize)));
+ EXPECT_EQ(g_recieved_signal, SIGWINCH);
+
+ // Restore old signal handler
+ EXPECT_EQ(new_handler, ki_signal(SIGWINCH, old_handler));
+
+ // Verify new window size can be queried correctly.
+ winsize.ws_col = 0;
+ winsize.ws_row = 0;
+ EXPECT_EQ(0, dev_tty_->Ioctl(TIOCGWINSZ,
+ reinterpret_cast<char*>(&winsize)));
+ EXPECT_EQ(winsize.ws_col, 100);
+ EXPECT_EQ(winsize.ws_row, 200);
+
+ // Restore original windows size.
+ EXPECT_EQ(0, dev_tty_->Ioctl(TIOCSWINSZ,
+ reinterpret_cast<char*>(&old_winsize)));
+}
+
+}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc b/native_client_sdk/src/tests/nacl_io_test/mount_test.cc
index 4829ccf076..ce3475efaa 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/mount_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/mount_test.cc
@@ -9,9 +9,9 @@
#include <string>
#include "gtest/gtest.h"
+#include "mount_dev_mock.h"
#include "nacl_io/ioctl.h"
#include "nacl_io/mount.h"
-#include "nacl_io/mount_dev.h"
#include "nacl_io/mount_mem.h"
#include "nacl_io/osdirent.h"
#include "nacl_io/osunistd.h"
@@ -30,21 +30,10 @@ class MountMemMock : public MountMem {
int num_nodes() { return (int) inode_pool_.size(); }
};
-class MountDevMock : public MountDev {
- public:
- MountDevMock() {
- StringMap_t map;
- Init(1, map, NULL);
- }
- int num_nodes() { return (int) inode_pool_.size(); }
-};
-
} // namespace
-#define NULL_NODE ((MountNode*) NULL)
-
TEST(MountTest, Sanity) {
- MountMemMock* mnt = new MountMemMock();
+ MountMemMock mnt;
ScopedMountNode file;
ScopedMountNode root;
@@ -55,37 +44,37 @@ TEST(MountTest, Sanity) {
char buf1[1024];
// A memory mount starts with one directory node: the root.
- EXPECT_EQ(1, mnt->num_nodes());
+ EXPECT_EQ(1, mnt.num_nodes());
// Fail to open non existent file
- EXPECT_EQ(ENOENT, mnt->Access(Path("/foo"), R_OK | W_OK));
- EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &result_node));
+ EXPECT_EQ(ENOENT, mnt.Access(Path("/foo"), R_OK | W_OK));
+ EXPECT_EQ(ENOENT, mnt.Open(Path("/foo"), O_RDWR, &result_node));
EXPECT_EQ(NULL, result_node.get());
- EXPECT_EQ(1, mnt->num_nodes());
+ EXPECT_EQ(1, mnt.num_nodes());
// Create a file
- EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &file));
+ EXPECT_EQ(0, mnt.Open(Path("/foo"), O_RDWR | O_CREAT, &file));
EXPECT_NE(NULL_NODE, file.get());
if (file == NULL)
return;
// We now have a directory and a file. The file has a two references
// one returned to the test, one for the name->inode map.
- EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(2, mnt.num_nodes());
EXPECT_EQ(2, file->RefCount());
- EXPECT_EQ(0, mnt->Access(Path("/foo"), R_OK | W_OK));
- EXPECT_EQ(EACCES, mnt->Access(Path("/foo"), X_OK));
+ EXPECT_EQ(0, mnt.Access(Path("/foo"), R_OK | W_OK));
+ EXPECT_EQ(EACCES, mnt.Access(Path("/foo"), X_OK));
// Write access should be allowed on the root directory.
- EXPECT_EQ(0, mnt->Access(Path("/"), R_OK | W_OK));
- EXPECT_EQ(EACCES, mnt->Access(Path("/"), X_OK));
+ EXPECT_EQ(0, mnt.Access(Path("/"), R_OK | W_OK));
+ EXPECT_EQ(EACCES, mnt.Access(Path("/"), X_OK));
// Open the root directory for write should fail.
- EXPECT_EQ(EISDIR, mnt->Open(Path("/"), O_RDWR, &root));
- EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(EISDIR, mnt.Open(Path("/"), O_RDWR, &root));
+ EXPECT_EQ(2, mnt.num_nodes());
// Open the root directory, should not create a new file
- EXPECT_EQ(0, mnt->Open(Path("/"), O_RDONLY, &root));
- EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(0, mnt.Open(Path("/"), O_RDONLY, &root));
+ EXPECT_EQ(2, mnt.num_nodes());
EXPECT_NE(NULL_NODE, root.get());
if (NULL != root) {
struct dirent dirs[2];
@@ -96,13 +85,13 @@ TEST(MountTest, Sanity) {
// Fail to re-create the same file
EXPECT_EQ(EEXIST,
- mnt->Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node));
+ mnt.Open(Path("/foo"), O_RDWR | O_CREAT | O_EXCL, &result_node));
EXPECT_EQ(NULL_NODE, result_node.get());
- EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(2, mnt.num_nodes());
// Fail to create a directory with the same name
- EXPECT_EQ(EEXIST, mnt->Mkdir(Path("/foo"), O_RDWR));
- EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(EEXIST, mnt.Mkdir(Path("/foo"), O_RDWR));
+ EXPECT_EQ(2, mnt.num_nodes());
// Attempt to READ/WRITE
EXPECT_EQ(0, file->GetSize(&result_size));
@@ -113,14 +102,14 @@ TEST(MountTest, Sanity) {
EXPECT_EQ(sizeof(buf1), result_size);
EXPECT_EQ(0, file->Read(0, buf1, sizeof(buf1), &result_bytes));
EXPECT_EQ(sizeof(buf1), result_bytes);
- EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(2, mnt.num_nodes());
EXPECT_EQ(2, file->RefCount());
// Attempt to open the same file, create another ref to it, but does not
// create a new file.
- EXPECT_EQ(0, mnt->Open(Path("/foo"), O_RDWR | O_CREAT, &result_node));
+ EXPECT_EQ(0, mnt.Open(Path("/foo"), O_RDWR | O_CREAT, &result_node));
EXPECT_EQ(3, file->RefCount());
- EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(2, mnt.num_nodes());
EXPECT_EQ(file.get(), result_node.get());
EXPECT_EQ(0, file->GetSize(&result_size));
EXPECT_EQ(sizeof(buf1), result_size);
@@ -128,92 +117,92 @@ TEST(MountTest, Sanity) {
// Remove our references so that only the Mount holds it
file.reset();
result_node.reset();
- EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(2, mnt.num_nodes());
// This should have deleted the object
- EXPECT_EQ(0, mnt->Unlink(Path("/foo")));
- EXPECT_EQ(1, mnt->num_nodes());
+ EXPECT_EQ(0, mnt.Unlink(Path("/foo")));
+ EXPECT_EQ(1, mnt.num_nodes());
// We should fail to find it
- EXPECT_EQ(ENOENT, mnt->Unlink(Path("/foo")));
- EXPECT_EQ(1, mnt->num_nodes());
+ EXPECT_EQ(ENOENT, mnt.Unlink(Path("/foo")));
+ EXPECT_EQ(1, mnt.num_nodes());
// Recreate foo as a directory
- EXPECT_EQ(0, mnt->Mkdir(Path("/foo"), O_RDWR));
- EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(0, mnt.Mkdir(Path("/foo"), O_RDWR));
+ EXPECT_EQ(2, mnt.num_nodes());
// Create a file (exclusively)
- EXPECT_EQ(0, mnt->Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file));
+ EXPECT_EQ(0, mnt.Open(Path("/foo/bar"), O_RDWR | O_CREAT | O_EXCL, &file));
EXPECT_NE(NULL_NODE, file.get());
if (NULL == file)
return;
EXPECT_EQ(2, file->RefCount());
- EXPECT_EQ(3, mnt->num_nodes());
+ EXPECT_EQ(3, mnt.num_nodes());
// Attempt to delete the directory and fail
- EXPECT_EQ(ENOTEMPTY, mnt->Rmdir(Path("/foo")));
+ EXPECT_EQ(ENOTEMPTY, mnt.Rmdir(Path("/foo")));
EXPECT_EQ(2, root->RefCount());
EXPECT_EQ(2, file->RefCount());
- EXPECT_EQ(3, mnt->num_nodes());
+ EXPECT_EQ(3, mnt.num_nodes());
// Unlink the file, we should have the only file ref at this point.
- EXPECT_EQ(0, mnt->Unlink(Path("/foo/bar")));
+ EXPECT_EQ(0, mnt.Unlink(Path("/foo/bar")));
EXPECT_EQ(2, root->RefCount());
EXPECT_EQ(1, file->RefCount());
- EXPECT_EQ(3, mnt->num_nodes());
+ EXPECT_EQ(3, mnt.num_nodes());
// Deref the file, to make it go away
file.reset();
- EXPECT_EQ(2, mnt->num_nodes());
+ EXPECT_EQ(2, mnt.num_nodes());
// Deref the directory
- EXPECT_EQ(0, mnt->Rmdir(Path("/foo")));
- EXPECT_EQ(1, mnt->num_nodes());
+ EXPECT_EQ(0, mnt.Rmdir(Path("/foo")));
+ EXPECT_EQ(1, mnt.num_nodes());
// Verify the directory is gone
- EXPECT_EQ(ENOENT, mnt->Access(Path("/foo"), F_OK));
- EXPECT_EQ(ENOENT, mnt->Open(Path("/foo"), O_RDWR, &file));
+ EXPECT_EQ(ENOENT, mnt.Access(Path("/foo"), F_OK));
+ EXPECT_EQ(ENOENT, mnt.Open(Path("/foo"), O_RDWR, &file));
EXPECT_EQ(NULL_NODE, file.get());
}
TEST(MountTest, MemMountRemove) {
- MountMemMock* mnt = new MountMemMock();
+ MountMemMock mnt;
ScopedMountNode file;
ScopedMountNode result_node;
- EXPECT_EQ(0, mnt->Mkdir(Path("/dir"), O_RDWR));
- EXPECT_EQ(0, mnt->Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
+ EXPECT_EQ(0, mnt.Mkdir(Path("/dir"), O_RDWR));
+ EXPECT_EQ(0, mnt.Open(Path("/file"), O_RDWR | O_CREAT | O_EXCL, &file));
EXPECT_NE(NULL_NODE, file.get());
- EXPECT_EQ(3, mnt->num_nodes());
+ EXPECT_EQ(3, mnt.num_nodes());
file.reset();
- EXPECT_EQ(0, mnt->Remove(Path("/dir")));
- EXPECT_EQ(2, mnt->num_nodes());
- EXPECT_EQ(0, mnt->Remove(Path("/file")));
- EXPECT_EQ(1, mnt->num_nodes());
+ EXPECT_EQ(0, mnt.Remove(Path("/dir")));
+ EXPECT_EQ(2, mnt.num_nodes());
+ EXPECT_EQ(0, mnt.Remove(Path("/file")));
+ EXPECT_EQ(1, mnt.num_nodes());
EXPECT_EQ(ENOENT,
- mnt->Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
+ mnt.Open(Path("/dir/foo"), O_CREAT | O_RDWR, &result_node));
EXPECT_EQ(NULL_NODE, result_node.get());
- EXPECT_EQ(ENOENT, mnt->Open(Path("/file"), O_RDONLY, &result_node));
+ EXPECT_EQ(ENOENT, mnt.Open(Path("/file"), O_RDONLY, &result_node));
EXPECT_EQ(NULL_NODE, result_node.get());
}
TEST(MountTest, DevAccess) {
// Should not be able to open non-existent file.
- MountDevMock* mnt = new MountDevMock();
- ASSERT_EQ(ENOENT, mnt->Access(Path("/foo"), F_OK));
+ MountDevMock mnt;
+ ASSERT_EQ(ENOENT, mnt.Access(Path("/foo"), F_OK));
}
TEST(MountTest, DevNull) {
- MountDevMock* mnt = new MountDevMock();
+ MountDevMock mnt;
ScopedMountNode dev_null;
int result_bytes = 0;
- ASSERT_EQ(0, mnt->Access(Path("/null"), R_OK | W_OK));
- ASSERT_EQ(EACCES, mnt->Access(Path("/null"), X_OK));
- ASSERT_EQ(0, mnt->Open(Path("/null"), O_RDWR, &dev_null));
+ ASSERT_EQ(0, mnt.Access(Path("/null"), R_OK | W_OK));
+ ASSERT_EQ(EACCES, mnt.Access(Path("/null"), X_OK));
+ ASSERT_EQ(0, mnt.Open(Path("/null"), O_RDWR, &dev_null));
ASSERT_NE(NULL_NODE, dev_null.get());
// Writing to /dev/null should write everything.
@@ -229,13 +218,13 @@ TEST(MountTest, DevNull) {
}
TEST(MountTest, DevZero) {
- MountDevMock* mnt = new MountDevMock();
+ MountDevMock mnt;
ScopedMountNode dev_zero;
int result_bytes = 0;
- ASSERT_EQ(0, mnt->Access(Path("/zero"), R_OK | W_OK));
- ASSERT_EQ(EACCES, mnt->Access(Path("/zero"), X_OK));
- ASSERT_EQ(0, mnt->Open(Path("/zero"), O_RDWR, &dev_zero));
+ ASSERT_EQ(0, mnt.Access(Path("/zero"), R_OK | W_OK));
+ ASSERT_EQ(EACCES, mnt.Access(Path("/zero"), X_OK));
+ ASSERT_EQ(0, mnt.Open(Path("/zero"), O_RDWR, &dev_zero));
ASSERT_NE(NULL_NODE, dev_zero.get());
// Writing to /dev/zero should write everything.
@@ -258,13 +247,13 @@ TEST(MountTest, DevZero) {
// Disabled due to intermittent failures on linux: http://crbug.com/257257
TEST(MountTest, DISABLED_DevUrandom) {
- MountDevMock* mnt = new MountDevMock();
+ MountDevMock mnt;
ScopedMountNode dev_urandom;
int result_bytes = 0;
- ASSERT_EQ(0, mnt->Access(Path("/urandom"), R_OK | W_OK));
- ASSERT_EQ(EACCES, mnt->Access(Path("/urandom"), X_OK));
- ASSERT_EQ(0, mnt->Open(Path("/urandom"), O_RDWR, &dev_urandom));
+ ASSERT_EQ(0, mnt.Access(Path("/urandom"), R_OK | W_OK));
+ ASSERT_EQ(EACCES, mnt.Access(Path("/urandom"), X_OK));
+ ASSERT_EQ(0, mnt.Open(Path("/urandom"), O_RDWR, &dev_urandom));
ASSERT_NE(NULL_NODE, dev_urandom.get());
// Writing to /dev/urandom should write everything.
@@ -302,67 +291,3 @@ TEST(MountTest, DISABLED_DevUrandom) {
EXPECT_LE(chi_squared, 293.24);
}
-
-TEST(MountTest, DevTty) {
- MountDevMock* mnt = new MountDevMock();
- ScopedMountNode dev_tty;
-
- ASSERT_EQ(0, mnt->Access(Path("/tty"), R_OK | W_OK));
- ASSERT_EQ(EACCES, mnt->Access(Path("/tty"), X_OK));
- ASSERT_EQ(0, mnt->Open(Path("/tty"), O_RDWR, &dev_tty));
- ASSERT_NE(NULL_NODE, dev_tty.get());
-
- // 123 is not a valid ioctl request.
- EXPECT_EQ(EINVAL, dev_tty->Ioctl(123, NULL));
-
- // TIOCNACLPREFIX is, it should set the prefix.
- std::string prefix("__my_awesome_prefix__");
- EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLPREFIX,
- const_cast<char*>(prefix.c_str())));
-
- // Now let's try sending some data over.
- // First we create the message.
- std::string content("hello, how are you?\n");
- std::string message = prefix.append(content);
- struct tioc_nacl_input_string packaged_message;
- packaged_message.length = message.size();
- packaged_message.buffer = message.data();
-
- // Now we make buffer we'll read into.
- // We fill the buffer and a backup buffer with arbitrary data
- // and compare them after reading to make sure read doesn't
- // clobber parts of the buffer it shouldn't.
- int bytes_read;
- char buffer[100];
- char backup_buffer[100];
- memset(buffer, 'a', 100);
- memset(backup_buffer, 'a', 100);
-
- // Now we actually send the data
- EXPECT_EQ(0, dev_tty->Ioctl(TIOCNACLINPUT,
- reinterpret_cast<char*>(&packaged_message)));
-
- // We read a small chunk first to ensure it doesn't give us
- // more than we ask for.
- EXPECT_EQ(0, dev_tty->Read(0, buffer, 5, &bytes_read));
- EXPECT_EQ(bytes_read, 5);
- EXPECT_EQ(0, memcmp(content.data(), buffer, 5));
- EXPECT_EQ(0, memcmp(buffer + 5, backup_buffer + 5, 95));
-
- // Now we ask for more data than is left in the tty, to ensure
- // it doesn't give us more than is there.
- EXPECT_EQ(0, dev_tty->Read(0, buffer + 5, 95, &bytes_read));
- EXPECT_EQ(bytes_read, content.size() - 5);
- EXPECT_EQ(0, memcmp(content.data(), buffer, content.size()));
- EXPECT_EQ(0, memcmp(buffer + content.size(),
- backup_buffer + content.size(),
- 100 - content.size()));
-
- // Now we try to send something with an invalid prefix
- std::string bogus_message("Woah there, this message has no valid prefix");
- struct tioc_nacl_input_string bogus_pack;
- bogus_pack.length = bogus_message.size();
- bogus_pack.buffer = bogus_message.data();
- EXPECT_EQ(ENOTTY, dev_tty->Ioctl(TIOCNACLINPUT,
- reinterpret_cast<char*>(&bogus_pack)));
-}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/path_test.cc b/native_client_sdk/src/tests/nacl_io_test/path_test.cc
index ab12f3995e..29dce11359 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/path_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/path_test.cc
@@ -3,11 +3,12 @@
// found in the LICENSE file.
#include <fcntl.h>
-#include "nacl_io/kernel_proxy.h"
-#include "nacl_io/path.h"
#include "gtest/gtest.h"
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/path.h"
+
using namespace nacl_io;
TEST(PathTest, SanityChecks) {
diff --git a/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.cc b/native_client_sdk/src/tests/nacl_io_test/pepper_interface_mock.cc
index 18f14efc05..18f14efc05 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/pepper_interface_mock.cc
diff --git a/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.h b/native_client_sdk/src/tests/nacl_io_test/pepper_interface_mock.h
index ae4b579668..9e610bd462 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/pepper_interface_mock.h
+++ b/native_client_sdk/src/tests/nacl_io_test/pepper_interface_mock.h
@@ -17,6 +17,8 @@
virtual ~BaseClass##Mock();
#define END_INTERFACE(BaseClass, PPInterface) \
};
+#define METHOD0(Class, ReturnType, MethodName) \
+ MOCK_METHOD0(MethodName, ReturnType());
#define METHOD1(Class, ReturnType, MethodName, Type0) \
MOCK_METHOD1(MethodName, ReturnType(Type0));
#define METHOD2(Class, ReturnType, MethodName, Type0, Type1) \
@@ -37,9 +39,6 @@ class PepperInterfaceMock : public nacl_io::PepperInterface {
~PepperInterfaceMock();
virtual PP_Instance GetInstance();
- MOCK_METHOD1(AddRefResource, void(PP_Resource));
- MOCK_METHOD1(ReleaseResource, void(PP_Resource));
- MOCK_METHOD0(IsMainThread, bool());
// Interface getters.
#include "nacl_io/pepper/undef_macros.h"
diff --git a/native_client_sdk/src/tests/nacl_io_test/signal_test.cc b/native_client_sdk/src/tests/nacl_io_test/signal_test.cc
new file mode 100644
index 0000000000..856e2505a8
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/signal_test.cc
@@ -0,0 +1,28 @@
+// Copyright 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 <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+
+TEST(Signal, KillSignals) {
+ EXPECT_LT(ki_kill(123, NULL, &len), 0);
+ EXPECT_EQ(errno, EFAULT);
+ EXPECT_EQ(errno, 0x2211);
+}
+
+TEST(Siganl, Ntohl) {
+ uint8_t network_bytes[4] = { 0x44, 0x33, 0x22, 0x11 };
+ uint32_t network_long;
+ memcpy(&network_long, network_bytes, 4);
+ uint32_t host_long = ntohl(network_long);
+ EXPECT_EQ(host_long, 0x44332211);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc b/native_client_sdk/src/tests/nacl_io_test/socket_test.cc
index e98aa7a087..90c59dd99c 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc
+++ b/native_client_sdk/src/tests/nacl_io_test/socket_test.cc
@@ -1,9 +1,14 @@
// Copyright 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 <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
+#include <netinet/in.h>
#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <map>
@@ -25,17 +30,18 @@ using namespace sdk_util;
namespace {
class SocketTest : public ::testing::Test {
public:
- SocketTest() : kp_(new KernelProxy) {
- ki_init(kp_);
+ SocketTest() {}
+
+ void SetUp() {
+ ki_init(&kp_);
}
- ~SocketTest() {
+ void TearDown() {
ki_uninit();
- delete kp_;
}
protected:
- KernelProxy* kp_;
+ KernelProxy kp_;
};
} // namespace
@@ -235,16 +241,6 @@ TEST_F(SocketTest, Socket) {
EXPECT_EQ(errno, EAFNOSUPPORT);
EXPECT_LT(ki_socket(AF_INET, SOCK_RAW, 0), 0);
EXPECT_EQ(errno, EPROTONOSUPPORT);
-
- // These four af/protocol combinations should be supported.
- EXPECT_LT(ki_socket(AF_INET, SOCK_STREAM, 0), 0);
- EXPECT_EQ(errno, EACCES);
- EXPECT_LT(ki_socket(AF_INET, SOCK_DGRAM, 0), 0);
- EXPECT_EQ(errno, EACCES);
- EXPECT_LT(ki_socket(AF_INET6, SOCK_STREAM, 0), 0);
- EXPECT_EQ(errno, EACCES);
- EXPECT_LT(ki_socket(AF_INET6, SOCK_DGRAM, 0), 0);
- EXPECT_EQ(errno, EACCES);
}
TEST_F(SocketTest, Socketpair) {
diff --git a/native_client_sdk/src/tests/nacl_io_test/syscalls_test.cc b/native_client_sdk/src/tests/nacl_io_test/syscalls_test.cc
new file mode 100644
index 0000000000..76eea7feb2
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/syscalls_test.cc
@@ -0,0 +1,119 @@
+// Copyright 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 <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "nacl_io/kernel_intercept.h"
+#include "nacl_io/kernel_proxy.h"
+
+using namespace nacl_io;
+using namespace sdk_util;
+
+namespace {
+class TestsWithKI : public ::testing::Test {
+ public:
+ TestsWithKI() {}
+
+ void SetUp() {
+ ki_init(&kp_);
+ }
+
+ void TearDown() {
+ ki_uninit();
+ }
+
+ protected:
+ KernelProxy kp_;
+};
+
+class SyscallsKill : public TestsWithKI {
+};
+
+class SyscallsSignal : public TestsWithKI {
+};
+
+TEST_F(SyscallsKill, KillSignals) {
+ // SIGSEGV can't be sent via kill(2)
+ ASSERT_EQ(-1, kill(0, SIGSEGV)) << "kill(SEGV) failed to return an error";
+ ASSERT_EQ(EINVAL, errno) << "kill(SEGV) failedd to set errno to EINVAL";
+
+ // Our implemenation should understand SIGWINCH
+ ASSERT_EQ(0, kill(0, SIGWINCH)) << "kill(SIGWINCH) failed: " << errno;
+
+ // And USR1/USR2
+ ASSERT_EQ(0, kill(0, SIGUSR1)) << "kill(SIGUSR1) failed: " << errno;
+ ASSERT_EQ(0, kill(0, SIGUSR2)) << "kill(SIGUSR2) failed: " << errno;
+}
+
+TEST_F(SyscallsKill, KillPIDValues) {
+ // Any PID other than 0, -1 and getpid() should yield ESRCH
+ // since there is only one valid process under NaCl
+ int mypid = getpid();
+ ASSERT_EQ(0, kill(0, SIGWINCH));
+ ASSERT_EQ(0, kill(-1, SIGWINCH));
+ ASSERT_EQ(0, kill(mypid, SIGWINCH));
+
+ // Don't use mypid + 1 since getpid() actually returns -1
+ // when the IRT interface is missing (e.g. within chrome),
+ // and 0 is always a valid PID when calling kill().
+ int invalid_pid = mypid + 10;
+ ASSERT_EQ(-1, kill(invalid_pid, SIGWINCH));
+ ASSERT_EQ(ESRCH, errno);
+}
+
+static bool g_handler_called = false;
+void sighandler(int) {
+ g_handler_called = true;
+}
+
+TEST_F(SyscallsSignal, SignalValues) {
+ ASSERT_EQ(signal(SIGSEGV, sighandler), SIG_ERR)
+ << "registering SEGV handler didn't fail";
+ ASSERT_EQ(errno, EINVAL) << "signal(SEGV) failed to set errno to EINVAL";
+
+ ASSERT_EQ(signal(-1, sighandler), SIG_ERR)
+ << "registering handler for invalid signal didn't fail";
+ ASSERT_EQ(errno, EINVAL) << "signal(-1) failed to set errno to EINVAL";
+}
+
+TEST_F(SyscallsSignal, HandlerValues) {
+ // Unsupported signal.
+ ASSERT_NE(SIG_ERR, signal(SIGSEGV, SIG_DFL));
+ ASSERT_EQ(SIG_ERR, signal(SIGSEGV, SIG_IGN));
+ ASSERT_EQ(SIG_ERR, signal(SIGSEGV, sighandler));
+
+ // Supported signal.
+ ASSERT_NE(SIG_ERR, signal(SIGWINCH, SIG_DFL));
+ ASSERT_NE(SIG_ERR, signal(SIGWINCH, SIG_IGN));
+ ASSERT_NE(SIG_ERR, signal(SIGWINCH, sighandler));
+}
+
+TEST_F(SyscallsSignal, Sigwinch) {
+ g_handler_called = false;
+
+ // Register WINCH handler
+ sighandler_t newsig = sighandler;
+ sighandler_t oldsig = signal(SIGWINCH, newsig);
+ ASSERT_NE(oldsig, SIG_ERR);
+
+ // Send signal.
+ kill(0, SIGWINCH);
+
+ // Verify that handler was called
+ EXPECT_TRUE(g_handler_called);
+
+ // Restore existing handler
+ oldsig = signal(SIGWINCH, oldsig);
+
+ // Verify the our newsig was returned as previous handler
+ ASSERT_EQ(oldsig, newsig);
+}
+
+} // namespace
diff --git a/native_client_sdk/src/tests/nacl_io_test/test.js b/native_client_sdk/src/tests/nacl_io_test/test.js
new file mode 100644
index 0000000000..d0c376cacc
--- /dev/null
+++ b/native_client_sdk/src/tests/nacl_io_test/test.js
@@ -0,0 +1,18 @@
+// 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.
+
+function addTests() {
+ common.tester.addAsyncTest('nacl_io_test', function (test) {
+ var intervalId = window.setInterval(function () {
+ if (!testsFinished)
+ return;
+
+ window.clearInterval(intervalId);
+ if (failedTests > 0)
+ test.fail('tests failed');
+ else
+ test.pass();
+ }, 100);
+ });
+}
diff --git a/native_client_sdk/src/tests/sdk_util_test/example.dsc b/native_client_sdk/src/tests/sdk_util_test/example.dsc
new file mode 100644
index 0000000000..8c7ee198af
--- /dev/null
+++ b/native_client_sdk/src/tests/sdk_util_test/example.dsc
@@ -0,0 +1,29 @@
+{
+ 'TOOLS': ['newlib', 'glibc', 'pnacl'],
+ 'SEL_LDR': True,
+
+ # Need to add ../../examples for common.js
+ 'SEARCH': ['.', '../../examples'],
+ 'TARGETS': [
+ {
+ 'NAME' : 'sdk_util_test',
+ 'TYPE' : 'main',
+ 'SOURCES' : [
+ 'main.cc',
+ ],
+ 'DEPS': ['ppapi_simple', 'sdk_util', 'nacl_io'],
+ # Order matters here: gtest has a "main" function that will be used if
+ # referenced before ppapi.
+ 'LIBS': ['gmock', 'ppapi_cpp', 'ppapi', 'gtest', 'pthread'],
+ 'INCLUDES': ['$(NACL_SDK_ROOT)/include/gtest/internal'],
+ 'CXXFLAGS': ['-Wno-sign-compare', '-Wno-unused-private-field'],
+ 'CFLAGS_GCC': ['-Wno-unused-local-typedefs'],
+ }
+ ],
+ 'DATA': [
+ 'example.js'
+ ],
+ 'DEST': 'tests',
+ 'NAME': 'sdk_util_test',
+ 'TITLE': 'SDK Util test',
+}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/example.js b/native_client_sdk/src/tests/sdk_util_test/example.js
index bd175944b9..d004ac4510 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/example.js
+++ b/native_client_sdk/src/tests/sdk_util_test/example.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 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.
// Called by the common.js module.
diff --git a/native_client_sdk/src/tests/sdk_util_test/index.html b/native_client_sdk/src/tests/sdk_util_test/index.html
new file mode 100644
index 0000000000..20b24b5d90
--- /dev/null
+++ b/native_client_sdk/src/tests/sdk_util_test/index.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<!--
+Copyright 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.
+-->
+<head>
+ <meta http-equiv="Pragma" content="no-cache">
+ <meta http-equiv="Expires" content="-1">
+ <title>{{title}}</title>
+ <script type="text/javascript" src="common.js"></script>
+ <script type="text/javascript" src="example.js"></script>
+ <style>
+ .result { padding-left: 10px; }
+ .ok { background-color: #0f0; }
+ .failed { background-color: #f00; }
+ </style>
+</head>
+<body {{attrs}}>
+ <h1>{{title}}</h1>
+ <h2>Status: <code id="statusField">NO-STATUS</code></h2>
+ <!-- The NaCl plugin will be embedded inside the element with id "listener".
+ See common.js.-->
+ <div id="listener"></div>
+ <ul id="tests" style="list-style:none;"></ul>
+</body>
+</html>
diff --git a/native_client_sdk/src/tests/sdk_util_test/main.cc b/native_client_sdk/src/tests/sdk_util_test/main.cc
new file mode 100644
index 0000000000..7dedcc62ae
--- /dev/null
+++ b/native_client_sdk/src/tests/sdk_util_test/main.cc
@@ -0,0 +1,66 @@
+// Copyright 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 <string>
+
+#include "gtest/gtest.h"
+
+#if defined(SEL_LDR)
+
+int main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+
+#else
+
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/var.h"
+#include "ppapi_simple/ps_main.h"
+
+#if defined(WIN32)
+#include <Windows.h>
+#undef PostMessage
+#endif
+
+class GTestEventListener : public ::testing::EmptyTestEventListener {
+ public:
+ // TestEventListener overrides.
+ virtual void OnTestStart(const ::testing::TestInfo& test_info) {
+ std::stringstream msg;
+ msg << "start:" << test_info.test_case_name() << "." << test_info.name();
+ pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+ }
+
+ virtual void OnTestPartResult(
+ const ::testing::TestPartResult& test_part_result) {
+ if (test_part_result.failed()) {
+ std::stringstream msg;
+ msg << "fail:" << test_part_result.file_name() << ","
+ << test_part_result.line_number() << ","
+ << test_part_result.summary();
+ pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+ }
+ }
+
+ virtual void OnTestEnd(const ::testing::TestInfo& test_info) {
+ std::stringstream msg;
+ msg << "end:" << test_info.test_case_name() << "." << test_info.name()
+ << "," << (test_info.result()->Failed() ? "failed" : "ok");
+ pp::Instance(PSGetInstanceId()).PostMessage(msg.str());
+ }
+};
+
+int example_main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners()
+ .Append(new GTestEventListener());
+ return RUN_ALL_TESTS();
+}
+
+// Register the function to call once the Instance Object is initialized.
+// see: pappi_simple/ps_main.h
+PPAPI_SIMPLE_REGISTER_MAIN(example_main);
+
+#endif
diff --git a/native_client_sdk/src/tools/common.mk b/native_client_sdk/src/tools/common.mk
index 3082072540..4fc67e68f4 100644
--- a/native_client_sdk/src/tools/common.mk
+++ b/native_client_sdk/src/tools/common.mk
@@ -455,13 +455,13 @@ run: all
ifndef NACL_ARCH
$(error Cannot run in sel_ldr unless $$NACL_ARCH is set)
endif
- $(SEL_LDR_PATH) $(SEL_LDR_ARGS) $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe
+ $(SEL_LDR_PATH) $(SEL_LDR_ARGS) $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe -- $(NEXE_ARGS)
debug: all
ifndef NACL_ARCH
$(error Cannot run in sel_ldr unless $$NACL_ARCH is set)
endif
- $(SEL_LDR_PATH) -d $(SEL_LDR_ARGS) $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe
+ $(SEL_LDR_PATH) -d $(SEL_LDR_ARGS) $(OUTDIR)/$(TARGET)_$(NACL_ARCH).nexe -- $(NEXE_ARGS)
else
PAGE ?= index.html
PAGE_TC_CONFIG ?= "$(PAGE)?tc=$(TOOLCHAIN)&config=$(CONFIG)"