| {{+bindTo:partials.standard_nacl_article}} |
| |
| <b><font color="#cc0000"> |
| NOTE: |
| Deprecation of the technologies described here has been announced |
| for platforms other than ChromeOS.<br/> |
| Please visit our |
| <a href="/native-client/migration">migration guide</a> |
| for details. |
| </font></b> |
| <hr/><section id="the-nacl-io-library"> |
| <h1 id="the-nacl-io-library">The nacl_io Library</h1> |
| <div class="contents local" id="contents" style="display: none"> |
| <ul class="small-gap"> |
| <li><a class="reference internal" href="#introduction" id="id1">Introduction</a></li> |
| <li><a class="reference internal" href="#using-nacl-io" id="id2">Using nacl_io</a></li> |
| <li><a class="reference internal" href="#logging-in-nacl-io" id="id3">Logging in nacl_io</a></li> |
| <li><p class="first"><a class="reference internal" href="#the-nacl-io-demo" id="id4">The nacl_io demo</a></p> |
| <ul class="small-gap"> |
| <li><a class="reference internal" href="#building-and-running-the-demo" id="id5">Building and running the demo</a></li> |
| <li><a class="reference internal" href="#a-look-at-the-code" id="id6">A look at the code</a></li> |
| </ul> |
| </li> |
| <li><a class="reference internal" href="#reference-information" id="id7">Reference Information</a></li> |
| </ul> |
| |
| </div><h2 id="introduction">Introduction</h2> |
| <p><code>nacl_io</code> is a utility library that provides implementations of standard |
| C APIs such as POSIX I/O (<code>stdio.h</code>) and BSD sockets (<code>sys/socket.h</code>). |
| Its primary function is to allow code that uses these standard APIs to be |
| compiled and used in a Native Client module. The library is included as part |
| of Native Client SDK and is implemented in on top of Pepper API.</p> |
| <p>Since Native Client modules cannot access the host machine’s file system |
| directly, nacl_io provides several alternative filesystem types which can be |
| used by the application. For example, the Chrome browser supports the <a class="reference external" href="http://www.html5rocks.com/en/tutorials/file/filesystem/">HTML5 |
| File System API</a> |
| which provides access to a protected area of the local file system. This |
| filesystem can be accessed by an HTML page using JavaScript commands, and also |
| by a Native Client module using the Pepper <a class="reference internal" href="/native-client/devguide/coding/file-io.html"><em>File IO API</em></a>.</p> |
| <p>With nacl_io a Native Client application can mount an HTML5 filesystem and |
| access it via standard POSIX I/O function such as <code>fopen</code>, <code>fseek</code>, |
| <code>fread</code>, <code>fwrite</code>, and <code>fclose</code>, or their low level UNIX counterparts |
| <code>open</code>, <code>lseek</code>, <code>read</code>, <code>write</code> and <code>close</code>. As well as the HTML5 |
| file system, nacl_io provides several other file system types which are |
| described in the table below:</p> |
| <table border="1" class="docutils"> |
| <colgroup> |
| </colgroup> |
| <thead valign="bottom"> |
| <tr class="row-odd"><th class="head">File System</th> |
| <th class="head">Description</th> |
| </tr> |
| </thead> |
| <tbody valign="top"> |
| <tr class="row-even"><td>memfs</td> |
| <td>An in-memory file system</td> |
| </tr> |
| <tr class="row-odd"><td>html5fs</td> |
| <td>An HTML5 local file system, which can be persistent or temporary</td> |
| </tr> |
| <tr class="row-even"><td>http</td> |
| <td>Maps files on a remote webserver into the local filesystem.</td> |
| </tr> |
| <tr class="row-odd"><td>dev</td> |
| <td>A file system containing special files (e.g.: <code>/dev/null</code>)</td> |
| </tr> |
| </tbody> |
| </table> |
| <h2 id="using-nacl-io">Using nacl_io</h2> |
| <p>Using nacl_io is mostly just a matter of using the standard POSIX C library |
| functions. However, there are some steps required to initialize the library |
| and setup the filesystem mounts. In general the following steps will be needed |
| to use nacl_io in a NaCl application:</p> |
| <ol class="arabic simple"> |
| <li>Link the application with the nacl_io library (<code>-lnacl_io</code>)</li> |
| <li>Initialize nacl_io at startup using the <code>nacl_io_init_ppapi</code> or |
| <code>nacl_io_init</code> functions.</li> |
| <li>Mount any desired filesystems using the <code>mount</code> function. The arguments |
| to <code>mount</code> for the different filesystem types are detailed in |
| <code>include/nacl_io/nacl_io.h</code>.</li> |
| <li>If you are going to mount an HTML5 file system, be sure to allocate space |
| for it. You can either set the <code>unlimitedStorage</code> permission in the app’s |
| Web Store manifest file, or call the HTML5 QuotaManagement API. These |
| 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> |
| <li>Make sure that file and socket API calls are all made from the background |
| thread. This is because the main Pepper thread does not support the blocking |
| behavior needed by the POSIX I/O operations.</li> |
| </ol> |
| <h2 id="logging-in-nacl-io">Logging in nacl_io</h2> |
| <p>Unlike most input/output for nacl_io, internal logging writes directly to the |
| <code>stderr</code> stream of the NaCl process. It deliberately bypasses the standard |
| library functions implemented in nacl_io to avoid circular calls to itself.</p> |
| <h2 id="the-nacl-io-demo">The nacl_io demo</h2> |
| <h3 id="building-and-running-the-demo">Building and running the demo</h3> |
| <p>The demo application launches a Native Client module that mounts three file |
| systems and displays a set of controls that let you work with them:</p> |
| <img alt="/native-client/images/nacl_io1.png" src="/native-client/images/nacl_io1.png" /> |
| <p>Follow these steps to build and run the demo:</p> |
| <ul class="small-gap"> |
| <li><p class="first">Open a terminal in the demo directory:</p> |
| <pre class="prettyprint"> |
| $ cd $NACL_SDK_ROOT/examples/demo/nacl_io_demo |
| </pre> |
| </li> |
| <li><p class="first">run the demo:</p> |
| <pre class="prettyprint"> |
| $ make run |
| </pre> |
| </li> |
| </ul> |
| <p>Once the demo is running, try these operations:</p> |
| <ol class="arabic simple"> |
| <li>select the fopen command (when you select a command the fields in the line |
| below will change according to the command)</li> |
| <li>type in the filename <code>/persistent/test</code></li> |
| <li>check the write checkbox and press the fopen button</li> |
| <li>select the fwrite command and select the file <code>/persistent/test</code> in the |
| menu that appears below on the left</li> |
| <li>enter some data and press the fwrite button</li> |
| <li>select the fclose command, be sure the file <code>/persistent/test</code> is selected |
| in the menu, and press the fclose button</li> |
| <li>select the fopen command</li> |
| <li>type in the filename <code>/persistent/test</code></li> |
| <li>check the fread checkbox and press the fopen button</li> |
| <li>select the fread command, be sure the file /persistent/test is selected in |
| the menu, enter a byte count, and press the fread button</li> |
| </ol> |
| <h3 id="a-look-at-the-code">A look at the code</h3> |
| <p>The demo is written C and comprises three files.</p> |
| <h4 id="nacl-io-demo-c">nacl_io_demo.c</h4> |
| <p>This is the demo’s main file. The code here creates and initializes the Native |
| Client module instance. The Pepper function <code>Instance_DidCreate</code> initializes |
| nacl_io and mounts an HTML5 filesystem at <code>/persistent</code>.</p> |
| <pre class="prettyprint"> |
| static PP_Bool Instance_DidCreate(PP_Instance instance, |
| uint32_t argc, |
| const char* argn[], |
| const char* argv[]) { |
| g_instance = instance; |
| nacl_io_init_ppapi(instance, get_browser_interface); |
| mount( |
| "", /* source */ |
| "/persistent", /* target */ |
| "html5fs", /* filesystemtype */ |
| 0, /* mountflags */ |
| "type=PERSISTENT,expected_size=1048576"); /* data specific to the html5fs type */ |
| |
| pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL); |
| InitializeMessageQueue(); |
| |
| return PP_TRUE; |
| } |
| </pre> |
| <p>Space is allocated to the <code>/persistent</code> file system after the module is |
| initialized. This is accomplished by the <code>domContentLoaded</code> function in |
| the file <code>example.js</code>. This script is included in the module’s html page (see |
| <code>examples/demo/index.html</code>):</p> |
| <pre class="prettyprint"> |
| function domContentLoaded(name, tc, config, width, height) { |
| navigator.webkitPersistentStorage.requestQuota(window.PERSISTENT, 1024 * 1024, |
| function(bytes) { |
| common.updateStatus( |
| 'Allocated ' + bytes + ' bytes of persistent storage.'); |
| common.createNaClModule(name, tc, config, width, height); |
| common.attachDefaultListeners(); |
| }, |
| function(e) { alert('Failed to allocate space') }); |
| } |
| </pre> |
| <p>The <code>Instance_DidCreate</code> function also creates a worker thread that receives |
| messages sent from the html page and performs the specified file system |
| operations. The logic for the worker thread is encoded in the other two files, |
| described below.</p> |
| <h4 id="queue-c">queue.c</h4> |
| <p>This file implements a circular queue that is used to receive messages from the |
| browser UI to the Native Client module. The file system commands in the |
| enqueued messages are executed on the worker thread. This keeps blocking calls |
| (like fread) off the main Native Client thread, which is a good thing. The |
| queue is initialized in nacl_io_demo.c <code>Instance_DidCreate</code>.</p> |
| <h4 id="handlers-c">handlers.c</h4> |
| <p>This file implements the stdio calls associated with the commands sent from the |
| browser. There is a separate <code>Handle*</code> function for each command: fopen, |
| fclose, fseek, fread, fwrite. The handlers are called from the |
| <code>HandleMessage</code> function in nacl_io_demo.c, which runs in the worker |
| thread managing the message queue. The code for the <code>fwrite</code> handler appears |
| below. Notice that it does not contain any PPAPI calls and looks like |
| “ordinary” C code.</p> |
| <pre class="prettyprint"> |
| int HandleFwrite(int num_params, char** params, char** output) { |
| FILE* file; |
| const char* file_index_string; |
| const char* data; |
| size_t data_len; |
| size_t bytes_written; |
| |
| if (num_params != 2) { |
| *output = PrintfToNewString("Error: fwrite takes 2 parameters."); |
| return 1; |
| } |
| |
| file_index_string = params[0]; |
| file = GetFileFromIndexString(file_index_string, NULL); |
| data = params[1]; |
| data_len = strlen(data); |
| |
| if (!file) { |
| *output = PrintfToNewString("Error: Unknown file handle %s.", |
| file_index_string); |
| return 2; |
| } |
| |
| bytes_written = fwrite(data, 1, data_len, file); |
| |
| *output = PrintfToNewString("fwrite\1%s\1%d", file_index_string, |
| bytes_written); |
| return 0; |
| } |
| </pre> |
| <h2 id="reference-information">Reference Information</h2> |
| <p>The example discussed here is included in the SDK in the directory |
| <code>examples/demo/nacl_io_demo</code>.</p> |
| <p>The nacl_io library is included in the SDK toolchain and is not a part of the |
| Pepper API. For reference information related to the nacl_io interface see |
| its header file in the SDK directory, located at |
| <code>include/nacl_io/nacl_io.h</code>.</p> |
| <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> |
| </section> |
| |
| {{/partials.standard_nacl_article}} |