summaryrefslogtreecommitdiffstats
path: root/native_client_sdk/doc_generated/devguide/coding/nacl_io.html
blob: 757899a56f420bed3e8c32f2085b1e5fdb7c0fe1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
{{+bindTo:partials.standard_nacl_article}}

<section id="the-nacl-io-library">
<span id="nacl-io"></span><h1 id="the-nacl-io-library"><span id="nacl-io"></span>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><p class="first"><a class="reference internal" href="#the-nacl-io-demo" id="id3">The nacl_io demo</a></p>
<ul class="small-gap">
<li><a class="reference internal" href="#building-and-running-the-demo" id="id4">Building and running the demo</a></li>
<li><a class="reference internal" href="#a-look-at-the-code" id="id5">A look at the code</a></li>
</ul>
</li>
<li><a class="reference internal" href="#reference-information" id="id6">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&#8217;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>. 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>.</p>
<p>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&#8217;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="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&#8217;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(
      &quot;&quot;,  /* source */
      &quot;/persistent&quot;,  /* target */
      &quot;html5fs&quot;,  /* filesystemtype */
      0,  /* mountflags */
      &quot;type=PERSISTENT,expected_size=1048576&quot;);  /* data specific to the html5fs type */

  pthread_create(&amp;g_handle_message_thread, NULL, &amp;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&#8217;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 persistant 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
&#8220;ordinary&#8221; 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(&quot;Error: fwrite takes 2 parameters.&quot;);
    return 1;
  }

  file_index_string = params[0];
  file = GetFileFromIndexString(file_index_string, NULL);
  data = params[1];
  data_len = strlen(data);

  if (!file) {
    *output = PrintfToNewString(&quot;Error: Unknown file handle %s.&quot;,
                                file_index_string);
    return 2;
  }

  bytes_written = fwrite(data, 1, data_len, file);

  *output = PrintfToNewString(&quot;fwrite\1%s\1%d&quot;, 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}}