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