1 .. _nacl_io: 2 3 ################### 4 The nacl_io Library 5 ################### 6 7 .. contents:: 8 :local: 9 :backlinks: none 10 :depth: 2 11 12 Introduction 13 ============ 14 15 ``nacl_io`` is a utility library that provides implementations of standard 16 C APIs such as POSIX I/O (``stdio.h``) and BSD sockets (``sys/socket.h``). 17 Its primary function is to allow code that uses these standard APIs to be 18 compiled and used in a Native Client module. The library is included as part 19 of Native Client SDK and is implemented in on top of Pepper API. 20 21 Since Native Client modules cannot access the host machine's file system 22 directly, nacl_io provides several alternative filesystem types which 23 can be used by the application. For example, the Chrome browser supports the 24 `HTML5 File System API 25 <http://www.html5rocks.com/en/tutorials/file/filesystem/>`_ which provides 26 access to a protected area of the local file system. This filesystem can 27 be accessed by an HTML page using JavaScript commands, and also by a Native 28 Client module using the Pepper :doc:`File IO API <file-io>`. With nacl_io 29 a Native Client application can mount an HTML5 filesystem and access it via 30 standard POSIX I/O function such as ``fopen``, ``fseek``, ``fread``, 31 ``fwrite``, and ``fclose``, or their low level UNIX counterparts ``open``, 32 ``lseek``, ``read``, ``write`` and ``close``. 33 34 As well as the HTML5 file system, nacl_io provides several other file system 35 types which are described in the table below: 36 37 =========== ================================================================== 38 File System Description 39 =========== ================================================================== 40 memfs An in-memory file system 41 html5fs An HTML5 local file system, which can be persistent or temporary 42 http Maps files on a remote webserver into the local filesystem. 43 dev A file system containing special files (e.g.: ``/dev/null``) 44 =========== ================================================================== 45 46 Using nacl_io 47 ============= 48 49 Using nacl_io is mostly just a matter of using the standard POSIX C library 50 functions. However, there are some steps required to initialize the library 51 and setup the filesystem mounts. In general the following steps will be needed 52 to use nacl_io in a NaCl application: 53 54 #. Link the application with the nacl_io library (``-lnacl_io``) 55 #. Initialize nacl_io at startup using the ``nacl_io_init_ppapi`` or 56 ``nacl_io_init`` functions. 57 #. Mount any desired filesystems using the ``mount`` function. The arguments 58 to ``mount`` for the different filesystem types are detailed in 59 ``include/nacl_io/nacl_io.h``. 60 #. If you are going to mount an HTML5 file system, be sure to allocate space 61 for it. You can either set the ``unlimitedStorage`` permission in the app's 62 Web Store manifest file, or call the HTML5 QuotaManagement API. These 63 options are explained in the :ref:`File IO documentation <quota_management>`. 64 #. Make sure that file and socket API calls are all made from the background 65 thread. This is because the main Pepper thread does not support the blocking 66 behavior needed by the POSIX I/O operations. 67 68 The nacl_io demo 69 ================ 70 71 Building and running the demo 72 ----------------------------- 73 74 The demo application launches a Native Client module that mounts three file 75 systems and displays a set of controls that let you work with them: 76 77 .. image:: /images/nacl_io1.png 78 79 Follow these steps to build and run the demo: 80 81 * Open a terminal in the demo directory:: 82 83 $ cd $NACL_SDK_ROOT/examples/demo/nacl_io_demo 84 85 * run the demo:: 86 87 $ make run 88 89 Once the demo is running, try these operations: 90 91 #. select the fopen command (when you select a command the fields in the line 92 below will change according to the command) 93 #. type in the filename ``/persistent/test`` 94 #. check the write checkbox and press the fopen button 95 #. select the fwrite command and select the file ``/persistent/test`` in the 96 menu that appears below on the left 97 #. enter some data and press the fwrite button 98 #. select the fclose command, be sure the file ``/persistent/test`` is selected 99 in the menu, and press the fclose button 100 #. select the fopen command 101 #. type in the filename ``/persistent/test`` 102 #. check the fread checkbox and press the fopen button 103 #. select the fread command, be sure the file /persistent/test is selected in 104 the menu, enter a byte count, and press the fread button 105 106 A look at the code 107 ------------------ 108 109 The demo is written C and comprises three files. 110 111 nacl_io_demo.c 112 ^^^^^^^^^^^^^^ 113 114 This is the demo's main file. The code here creates and initializes the Native 115 Client module instance. The Pepper function ``Instance_DidCreate`` initializes 116 nacl_io and mounts an HTML5 filesystem at ``/persistent``. 117 118 .. naclcode:: 119 120 static PP_Bool Instance_DidCreate(PP_Instance instance, 121 uint32_t argc, 122 const char* argn[], 123 const char* argv[]) { 124 g_instance = instance; 125 nacl_io_init_ppapi(instance, get_browser_interface); 126 mount( 127 "", /* source */ 128 "/persistent", /* target */ 129 "html5fs", /* filesystemtype */ 130 0, /* mountflags */ 131 "type=PERSISTENT,expected_size=1048576"); /* data specific to the html5fs type */ 132 133 pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL); 134 InitializeMessageQueue(); 135 136 return PP_TRUE; 137 } 138 139 Space is allocated to the ``/persistent`` file system after the module is 140 initialized. This is accomplished by the ``domContentLoaded`` function in 141 the file ``example.js``. This script is included in the module's html page (see 142 ``examples/demo/index.html``): 143 144 .. naclcode:: 145 146 function domContentLoaded(name, tc, config, width, height) { 147 navigator.webkitPersistentStorage.requestQuota(window.PERSISTENT, 1024 * 1024, 148 function(bytes) { 149 common.updateStatus( 150 'Allocated ' + bytes + ' bytes of persistant storage.'); 151 common.createNaClModule(name, tc, config, width, height); 152 common.attachDefaultListeners(); 153 }, 154 function(e) { alert('Failed to allocate space') }); 155 } 156 157 The ``Instance_DidCreate`` function also creates a worker thread that receives 158 messages sent from the html page and performs the specified file system 159 operations. The logic for the worker thread is encoded in the other two files, 160 described below. 161 162 queue.c 163 ^^^^^^^ 164 165 This file implements a circular queue that is used to receive messages from the 166 browser UI to the Native Client module. The file system commands in the 167 enqueued messages are executed on the worker thread. This keeps blocking calls 168 (like fread) off the main Native Client thread, which is a good thing. The 169 queue is initialized in nacl_io_demo.c ``Instance_DidCreate``. 170 171 handlers.c 172 ^^^^^^^^^^ 173 174 This file implements the stdio calls associated with the commands sent from the 175 browser. There is a separate ``Handle*`` function for each command: fopen, 176 fclose, fseek, fread, fwrite. The handlers are called from the 177 ``HandleMessage`` function in nacl_io_demo.c, which runs in the worker 178 thread managing the message queue. The code for the ``fwrite`` handler appears 179 below. Notice that it does not contain any PPAPI calls and looks like 180 "ordinary" C code. 181 182 183 .. naclcode:: 184 185 int HandleFwrite(int num_params, char** params, char** output) { 186 FILE* file; 187 const char* file_index_string; 188 const char* data; 189 size_t data_len; 190 size_t bytes_written; 191 192 if (num_params != 2) { 193 *output = PrintfToNewString("Error: fwrite takes 2 parameters."); 194 return 1; 195 } 196 197 file_index_string = params[0]; 198 file = GetFileFromIndexString(file_index_string, NULL); 199 data = params[1]; 200 data_len = strlen(data); 201 202 if (!file) { 203 *output = PrintfToNewString("Error: Unknown file handle %s.", 204 file_index_string); 205 return 2; 206 } 207 208 bytes_written = fwrite(data, 1, data_len, file); 209 210 *output = PrintfToNewString("fwrite\1%s\1%d", file_index_string, 211 bytes_written); 212 return 0; 213 } 214 215 Reference information 216 ===================== 217 218 The example discussed here is included in the SDK in the directory 219 ``examples/demo/nacl_io_demo``. 220 221 The nacl_io library is included in the SDK toolchain and is not a part of the 222 Pepper API. For reference information related to the nacl_io interface see 223 its header file in the SDK directory, located at 224 ``include/nacl_io/nacl_io.h``. 225 226 For more about the HTML5 file system read the `specification 227 <http://dev.w3.org/2009/dap/file-system/pub/FileSystem/>`_. 228