file-io.html revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1{{+bindTo:partials.standard_nacl_article}}
2
3<section id="file-i-o">
4<span id="devguide-coding-fileio"></span><h1 id="file-i-o"><span id="devguide-coding-fileio"></span>File I/O</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="id2">Introduction</a></li>
8<li><a class="reference internal" href="#reference-information" id="id3">Reference information</a></li>
9<li><p class="first"><a class="reference internal" href="#local-file-i-o" id="id4">Local file I/O</a></p>
10<ul class="small-gap">
11<li><a class="reference internal" href="#enabling-local-file-i-o" id="id5">Enabling local file I/O</a></li>
12<li><a class="reference internal" href="#testing-local-file-i-o" id="id6">Testing local file I/O</a></li>
13</ul>
14</li>
15<li><p class="first"><a class="reference internal" href="#the-file-io-example" id="id7">The <code>file_io</code> example</a></p>
16<ul class="small-gap">
17<li><a class="reference internal" href="#file-i-o-overview" id="id8">File I/O overview</a></li>
18<li><a class="reference internal" href="#creating-and-writing-a-file" id="id9">Creating and writing a file</a></li>
19<li><a class="reference internal" href="#opening-and-reading-a-file" id="id10">Opening and reading a file</a></li>
20<li><a class="reference internal" href="#deleting-a-file" id="id11">Deleting a file</a></li>
21<li><a class="reference internal" href="#making-a-directory" id="id12">Making a directory</a></li>
22<li><a class="reference internal" href="#listing-the-contents-of-a-directory" id="id13">Listing the contents of a directory</a></li>
23</ul>
24</li>
25<li><p class="first"><a class="reference internal" href="#file-io-deep-dive" id="id14"><code>file_io</code> deep dive</a></p>
26<ul class="small-gap">
27<li><a class="reference internal" href="#opening-a-file-system-and-preparing-for-file-i-o" id="id15">Opening a file system and preparing for file I/O</a></li>
28<li><a class="reference internal" href="#handling-messages-from-javascript" id="id16">Handling messages from JavaScript</a></li>
29<li><a class="reference internal" href="#saving-a-file" id="id17">Saving a file</a></li>
30<li><a class="reference internal" href="#loading-a-file" id="id18">Loading a file</a></li>
31<li><a class="reference internal" href="#id1" id="id19">Deleting a file</a></li>
32<li><a class="reference internal" href="#listing-files-in-a-directory" id="id20">Listing files in a directory</a></li>
33<li><a class="reference internal" href="#making-a-new-directory" id="id21">Making a new directory</a></li>
34</ul>
35</li>
36</ul>
37
38</div><section id="introduction">
39<h2 id="introduction">Introduction</h2>
40<p>This chapter describes how to use the <a class="reference external" href="https://developers.google.com/native-client/peppercpp/classpp_1_1_file_i_o">FileIO API</a>
41to read and write files using a local secure data store.</p>
42<p>You might use the File IO API with the URL Loading APIs to create an overall
43data download and caching solution for your NaCl applications. For example:</p>
44<ol class="arabic simple">
45<li>Use the File IO APIs to check the local disk to see if a file exists that
46your program needs.</li>
47<li>If the file exists locally, load it into memory using the File IO API. If
48the file doesn&#8217;t exist locally, use the URL Loading API to retrieve the
49file from the server.</li>
50<li>Use the File IO API to write the file to disk.</li>
51<li>Load the file into memory using the File IO API when needed by your
52application.</li>
53</ol>
54<p>The example discussed in this chapter is included in the SDK in the directory
55<code>examples/api/file_io</code>.</p>
56</section><section id="reference-information">
57<h2 id="reference-information">Reference information</h2>
58<p>For reference information related to FileIO, see the following documentation:</p>
59<ul class="small-gap">
60<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/file__io_8h">file_io.h</a> - API
61to create a FileIO object</li>
62<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/file__ref_8h">file_ref.h</a> - API
63to create a file reference or &#8220;weak pointer&#8221; to a file in a file system</li>
64<li><a class="reference external" href="https://developers.google.com/native-client/peppercpp/file__system_8h">file_system.h</a> -
65API to create a file system associated with a file</li>
66</ul>
67</section><section id="local-file-i-o">
68<h2 id="local-file-i-o">Local file I/O</h2>
69<p>Chrome provides an obfuscated, restricted area on disk to which a web app can
70safely <a class="reference external" href="https://developers.google.com/chrome/whitepapers/storage#persistent">read and write files</a>. The
71Pepper FileIO, FileRef, and FileSystem APIs (collectively called the File IO
72APIs) allow you to access this sandboxed local disk so you can read and write
73files and manage caching yourself. The data is persistent between launches of
74Chrome, and is not removed unless your application deletes it or the user
75manually deletes it. There is no limit to the amount of local data you can
76use, other than the actual space available on the local drive.</p>
77<section id="enabling-local-file-i-o">
78<span id="enabling-file-access"></span><span id="quota-management"></span><h3 id="enabling-local-file-i-o"><span id="enabling-file-access"></span><span id="quota-management"></span>Enabling local file I/O</h3>
79<p>The easiest way to enable the writing of persistent local data is to include
80the <a class="reference external" href="http://developer.chrome.com/extensions/declare_permissions.html#unlimitedStorage">unlimitedStorage permission</a>
81in your Chrome Web Store manifest file. With this permission you can use the
82Pepper FileIO API without the need to request disk space at run time. When
83the user installs the app Chrome displays a message announcing that the app
84writes to the local disk.</p>
85<p>If you do not use the <code>unlimitedStorage</code> permission you must include
86JavaScript code that calls the <a class="reference external" href="http://updates.html5rocks.com/2011/11/Quota-Management-API-Fast-Facts">HTML5 Quota Management API</a> to
87explicitly request local disk space before using the FileIO API. In this case
88Chrome will prompt the user to accept a requestQuota call every time one is
89made.</p>
90</section><section id="testing-local-file-i-o">
91<h3 id="testing-local-file-i-o">Testing local file I/O</h3>
92<p>You should be aware that using the <code>unlimitedStorage</code> manifest permission
93constrains the way you can test your app. Three of the four techniques
94described in <a class="reference internal" href="/native-client/devguide/devcycle/running.html"><em>Running Native Client Applications</em></a>
95read the Chrome Web Store manifest file and enable the <code>unlimitedStorage</code>
96permission when it appears, but the first technique (local server) does not.
97If you want to test the file IO portion of your app with a simple local server,
98you need to include JavaScript code that calls the HTML5 Quota Management API.
99When you deliver your application you can replace this code with the
100<code>unlimitedStorage</code> manifest permission.</p>
101</section></section><section id="the-file-io-example">
102<h2 id="the-file-io-example">The <code>file_io</code> example</h2>
103<p>The Native Client SDK includes an example, <code>file_io</code>, that demonstrates how
104to read and write a local disk file. Since you will probably run the example
105from a local server without a Chrome Web Store manifest file, the example&#8217;s
106index file uses JavaScript to perform the Quota Management setup as described
107above. The example has these primary files:</p>
108<ul class="small-gap">
109<li><code>index.html</code> - The HTML code that launches the Native Client module and
110displays the user interface.</li>
111<li><code>example.js</code> - JavaScript code that requests quota (as described above). It
112also listens for user interaction with the user interface, and forwards the
113requests to the Native Client module.</li>
114<li><code>file_io.cc</code> - The code that sets up and provides an entry point to the
115Native Client module.</li>
116</ul>
117<p>The remainder of this section covers the code in the <code>file_io.cc</code> file for
118reading and writing files.</p>
119<section id="file-i-o-overview">
120<h3 id="file-i-o-overview">File I/O overview</h3>
121<p>Like many Pepper APIs, the File IO API includes a set of methods that execute
122asynchronously and that invoke callback functions in your Native Client module.
123Unlike most other examples, the <code>file_io</code> example also demonstrates how to
124make Pepper calls synchronously on a worker thread.</p>
125<p>It is illegal to make blocking calls to Pepper on the module&#8217;s main thread.
126This restriction is lifted when running on a worker thread&#8212;this is called
127&#8220;calling Pepper off the main thread&#8221;. This often simplifies the logic of your
128code; multiple asynchronous Pepper functions can be called from one function on
129your worker thread, so you can use the stack and standard control flow
130structures normally.</p>
131<p>The high-level flow for the <code>file_io</code> example is described below.  Note that
132methods in the namespace <code>pp</code> are part of the Pepper C++ API.</p>
133</section><section id="creating-and-writing-a-file">
134<h3 id="creating-and-writing-a-file">Creating and writing a file</h3>
135<p>Following are the high-level steps involved in creating and writing to a
136file:</p>
137<ol class="arabic simple">
138<li><code>pp::FileIO::Open</code> is called with the <code>PP_FILEOPEN_FLAG_CREATE</code> flag to
139create a file.  Because the callback function is <code>pp::BlockUntilComplete</code>,
140this thread is blocked until <code>Open</code> succeeds or fails.</li>
141<li><code>pp::FileIO::Write</code> is called to write the contents. Again, the thread is
142blocked until the call to <code>Write</code> completes. If there is more data to
143write, <code>Write</code> is called again.</li>
144<li>When there is no more data to write, call <code>pp::FileIO::Flush</code>.</li>
145</ol>
146</section><section id="opening-and-reading-a-file">
147<h3 id="opening-and-reading-a-file">Opening and reading a file</h3>
148<p>Following are the high-level steps involved in opening and reading a file:</p>
149<ol class="arabic simple">
150<li><code>pp::FileIO::Open</code> is called to open the file. Because the callback
151function is <code>pp::BlockUntilComplete</code>, this thread is blocked until Open
152succeeds or fails.</li>
153<li><code>pp::FileIO::Query</code> is called to query information about the file, such as
154its file size. The thread is blocked until <code>Query</code> completes.</li>
155<li><code>pp::FileIO::Read</code> is called to read the contents. The thread is blocked
156until <code>Read</code> completes. If there is more data to read, <code>Read</code> is called
157again.</li>
158</ol>
159</section><section id="deleting-a-file">
160<h3 id="deleting-a-file">Deleting a file</h3>
161<p>Deleting a file is straightforward: call <code>pp::FileRef::Delete</code>. The thread is
162blocked until <code>Delete</code> completes.</p>
163</section><section id="making-a-directory">
164<h3 id="making-a-directory">Making a directory</h3>
165<p>Making a directory is also straightforward: call <code>pp::File::MakeDirectory</code>.
166The thread is blocked until <code>MakeDirectory</code> completes.</p>
167</section><section id="listing-the-contents-of-a-directory">
168<h3 id="listing-the-contents-of-a-directory">Listing the contents of a directory</h3>
169<p>Following are the high-level steps involved in listing a directory:</p>
170<ol class="arabic simple">
171<li><code>pp::FileRef::ReadDirectoryEntries</code> is called, and given a directory entry
172to list. A callback is given as well; many of the other functions use
173<code>pp::BlockUntilComplete</code>, but <code>ReadDirectoryEntries</code> returns results in
174its callback, so it must be specified.</li>
175<li>When the call to <code>ReadDirectoryEntries</code> completes, it calls
176<code>ListCallback</code> which packages up the results into a string message, and
177sends it to JavaScript.</li>
178</ol>
179</section></section><section id="file-io-deep-dive">
180<h2 id="file-io-deep-dive"><code>file_io</code> deep dive</h2>
181<p>The <code>file_io</code> example displays a user interface with a couple of fields and
182several buttons. Following is a screenshot of the <code>file_io</code> example:</p>
183<img alt="/native-client/images/fileioexample.png" src="/native-client/images/fileioexample.png" />
184<p>Each radio button is a file operation you can perform, with some reasonable
185default values for filenames. Try typing a message in the large input box and
186clicking <code>Save</code>, then switching to the <code>Load File</code> operation, and
187clicking <code>Load</code>.</p>
188<p>Let&#8217;s take a look at what is going on under the hood.</p>
189<section id="opening-a-file-system-and-preparing-for-file-i-o">
190<h3 id="opening-a-file-system-and-preparing-for-file-i-o">Opening a file system and preparing for file I/O</h3>
191<p><code>pp::Instance::Init</code> is called when an instance of a module is created. In
192this example, <code>Init</code> starts a new thread (via the <code>pp::SimpleThread</code>
193class), and tells it to open the filesystem:</p>
194<pre class="prettyprint">
195virtual bool Init(uint32_t /*argc*/,
196                  const char * /*argn*/ [],
197                  const char * /*argv*/ []) {
198  file_thread_.Start();
199  // Open the file system on the file_thread_. Since this is the first
200  // operation we perform there, and because we do everything on the
201  // file_thread_ synchronously, this ensures that the FileSystem is open
202  // before any FileIO operations execute.
203  file_thread_.message_loop().PostWork(
204      callback_factory_.NewCallback(&amp;FileIoInstance::OpenFileSystem));
205  return true;
206}
207</pre>
208<p>When the file thread starts running, it will call <code>OpenFileSystem</code>. This
209calls <code>pp::FileSystem::Open</code> and blocks the file thread until the function
210returns.</p>
211<aside class="note">
212Note that the call to <code>pp::FileSystem::Open</code> uses
213<code>pp::BlockUntilComplete</code> as its callback. This is only possible because we
214are running off the main thread; if you try to make a blocking call from the
215main thread, the function will return the error
216<code>PP_ERROR_BLOCKS_MAIN_THREAD</code>.
217</aside>
218<pre class="prettyprint">
219void OpenFileSystem(int32_t /*result*/) {
220  int32_t rv = file_system_.Open(1024 * 1024, pp::BlockUntilComplete());
221  if (rv == PP_OK) {
222    file_system_ready_ = true;
223    // Notify the user interface that we're ready
224    PostMessage(&quot;READY|&quot;);
225  } else {
226    ShowErrorMessage(&quot;Failed to open file system&quot;, rv);
227  }
228}
229</pre>
230</section><section id="handling-messages-from-javascript">
231<h3 id="handling-messages-from-javascript">Handling messages from JavaScript</h3>
232<p>When you click the <code>Save</code> button, JavaScript posts a message to the NaCl
233module with the file operation to perform sent as a string (See <a class="reference internal" href="/native-client/devguide/coding/message-system.html"><em>Messaging
234System</em></a> for more details on message passing). The string is
235parsed by <code>HandleMessage</code>, and new work is added to the file thread:</p>
236<pre class="prettyprint">
237virtual void HandleMessage(const pp::Var&amp; var_message) {
238  if (!var_message.is_string())
239    return;
240
241  // Parse message into: instruction file_name_length file_name [file_text]
242  std::string message = var_message.AsString();
243  std::string instruction;
244  std::string file_name;
245  std::stringstream reader(message);
246  int file_name_length;
247
248  reader &gt;&gt; instruction &gt;&gt; file_name_length;
249  file_name.resize(file_name_length);
250  reader.ignore(1);  // Eat the delimiter
251  reader.read(&amp;file_name[0], file_name_length);
252
253  ...
254
255  // Dispatch the instruction
256  if (instruction == kLoadPrefix) {
257    file_thread_.message_loop().PostWork(
258        callback_factory_.NewCallback(&amp;FileIoInstance::Load, file_name));
259  } else if (instruction == kSavePrefix) {
260    ...
261  }
262}
263</pre>
264</section><section id="saving-a-file">
265<h3 id="saving-a-file">Saving a file</h3>
266<p><code>FileIoInstance::Save</code> is called when the <code>Save</code> button is pressed. First,
267it checks to see that the FileSystem has been successfully opened:</p>
268<pre class="prettyprint">
269if (!file_system_ready_) {
270  ShowErrorMessage(&quot;File system is not open&quot;, PP_ERROR_FAILED);
271  return;
272}
273</pre>
274<p>It then creates a <code>pp::FileRef</code> resource with the name of the file. A
275<code>FileRef</code> resource is a weak reference to a file in the FileSystem; that is,
276a file can still be deleted even if there are outstanding <code>FileRef</code>
277resources.</p>
278<pre class="prettyprint">
279pp::FileRef ref(file_system_, file_name.c_str());
280</pre>
281<p>Next, a <code>pp::FileIO</code> resource is created and opened. The call to
282<code>pp::FileIO::Open</code> passes <code>PP_FILEOPEFLAG_WRITE</code> to open the file for
283writing, <code>PP_FILEOPENFLAG_CREATE</code> to create a new file if it doesn&#8217;t already
284exist and <code>PP_FILEOPENFLAG_TRUNCATE</code> to clear the file of any previous
285content:</p>
286<pre class="prettyprint">
287pp::FileIO file(this);
288
289int32_t open_result =
290    file.Open(ref,
291              PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE |
292                  PP_FILEOPENFLAG_TRUNCATE,
293              pp::BlockUntilComplete());
294if (open_result != PP_OK) {
295  ShowErrorMessage(&quot;File open for write failed&quot;, open_result);
296  return;
297}
298</pre>
299<p>Now that the file is opened, it is written to in chunks. In an asynchronous
300model, this would require writing a separate function, storing the current
301state on the free store and a chain of callbacks. Because this function is
302called off the main thread, <code>pp::FileIO::Write</code> can be called synchronously
303and a conventional do/while loop can be used:</p>
304<pre class="prettyprint">
305int64_t offset = 0;
306int32_t bytes_written = 0;
307do {
308  bytes_written = file.Write(offset,
309                             file_contents.data() + offset,
310                             file_contents.length(),
311                             pp::BlockUntilComplete());
312  if (bytes_written &gt; 0) {
313    offset += bytes_written;
314  } else {
315    ShowErrorMessage(&quot;File write failed&quot;, bytes_written);
316    return;
317  }
318} while (bytes_written &lt; static_cast&lt;int64_t&gt;(file_contents.length()));
319</pre>
320<p>Finally, the file is flushed to push all changes to disk:</p>
321<pre class="prettyprint">
322int32_t flush_result = file.Flush(pp::BlockUntilComplete());
323if (flush_result != PP_OK) {
324  ShowErrorMessage(&quot;File fail to flush&quot;, flush_result);
325  return;
326}
327</pre>
328</section><section id="loading-a-file">
329<h3 id="loading-a-file">Loading a file</h3>
330<p><code>FileIoInstance::Load</code> is called when the <code>Load</code> button is pressed. Like
331the <code>Save</code> function, <code>Load</code> first checks to see if the FileSystem has been
332successfully opened, and creates a new <code>FileRef</code>:</p>
333<pre class="prettyprint">
334if (!file_system_ready_) {
335  ShowErrorMessage(&quot;File system is not open&quot;, PP_ERROR_FAILED);
336  return;
337}
338pp::FileRef ref(file_system_, file_name.c_str());
339</pre>
340<p>Next, <code>Load</code> creates and opens a new <code>FileIO</code> resource, passing
341<code>PP_FILEOPENFLAG_READ</code> to open the file for reading. The result is compared
342to <code>PP_ERROR_FILENOTFOUND</code> to give a better error message when the file
343doesn&#8217;t exist:</p>
344<pre class="prettyprint">
345int32_t open_result =
346    file.Open(ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete());
347if (open_result == PP_ERROR_FILENOTFOUND) {
348  ShowErrorMessage(&quot;File not found&quot;, open_result);
349  return;
350} else if (open_result != PP_OK) {
351  ShowErrorMessage(&quot;File open for read failed&quot;, open_result);
352  return;
353}
354</pre>
355<p>Then <code>Load</code> calls <code>pp::FileIO::Query</code> to get metadata about the file, such
356as its size. This is used to allocate a <code>std::vector</code> buffer that holds the
357data from the file in memory:</p>
358<pre class="prettyprint">
359int32_t query_result = file.Query(&amp;info, pp::BlockUntilComplete());
360if (query_result != PP_OK) {
361  ShowErrorMessage(&quot;File query failed&quot;, query_result);
362  return;
363}
364
365...
366
367std::vector&lt;char&gt; data(info.size);
368</pre>
369<p>Similar to <code>Save</code>, a conventional while loop is used to read the file into
370the newly allocated buffer:</p>
371<pre class="prettyprint">
372int64_t offset = 0;
373int32_t bytes_read = 0;
374int32_t bytes_to_read = info.size;
375while (bytes_to_read &gt; 0) {
376  bytes_read = file.Read(offset,
377                         &amp;data[offset],
378                         data.size() - offset,
379                         pp::BlockUntilComplete());
380  if (bytes_read &gt; 0) {
381    offset += bytes_read;
382    bytes_to_read -= bytes_read;
383  } else if (bytes_read &lt; 0) {
384    // If bytes_read &lt; PP_OK then it indicates the error code.
385    ShowErrorMessage(&quot;File read failed&quot;, bytes_read);
386    return;
387  }
388}
389</pre>
390<p>Finally, the contents of the file are sent back to JavaScript, to be displayed
391on the page. This example uses &#8220;<code>DISP|</code>&#8221; as a prefix command for display
392information:</p>
393<pre class="prettyprint">
394std::string string_data(data.begin(), data.end());
395PostMessage(&quot;DISP|&quot; + string_data);
396ShowStatusMessage(&quot;Load success&quot;);
397</pre>
398</section><section id="id1">
399<h3 id="id1">Deleting a file</h3>
400<p><code>FileIoInstance::Delete</code> is called when the <code>Delete</code> button is pressed.
401First, it checks whether the FileSystem has been opened, and creates a new
402<code>FileRef</code>:</p>
403<pre class="prettyprint">
404if (!file_system_ready_) {
405  ShowErrorMessage(&quot;File system is not open&quot;, PP_ERROR_FAILED);
406  return;
407}
408pp::FileRef ref(file_system_, file_name.c_str());
409</pre>
410<p>Unlike <code>Save</code> and <code>Load</code>, <code>Delete</code> is called on the <code>FileRef</code> resource,
411not a <code>FileIO</code> resource. Note that the result is checked for
412<code>PP_ERROR_FILENOTFOUND</code> to give a better error message when trying to delete
413a non-existent file:</p>
414<pre class="prettyprint">
415int32_t result = ref.Delete(pp::BlockUntilComplete());
416if (result == PP_ERROR_FILENOTFOUND) {
417  ShowStatusMessage(&quot;File/Directory not found&quot;);
418  return;
419} else if (result != PP_OK) {
420  ShowErrorMessage(&quot;Deletion failed&quot;, result);
421  return;
422}
423</pre>
424</section><section id="listing-files-in-a-directory">
425<h3 id="listing-files-in-a-directory">Listing files in a directory</h3>
426<p><code>FileIoInstance::List</code> is called when the <code>List Directory</code> button is
427pressed. Like all other operations, it checks whether the FileSystem has been
428opened and creates a new <code>FileRef</code>:</p>
429<pre class="prettyprint">
430if (!file_system_ready_) {
431  ShowErrorMessage(&quot;File system is not open&quot;, PP_ERROR_FAILED);
432  return;
433}
434
435pp::FileRef ref(file_system_, dir_name.c_str());
436</pre>
437<p>Unlike the other operations, it does not make a blocking call to
438<code>pp::FileRef::ReadDirectoryEntries</code>. Since <code>ReadDirectoryEntries</code> returns
439the resulting directory entries in its callback, a new callback object is
440created pointing to <code>FileIoInstance::ListCallback</code>.</p>
441<p>The <code>pp::CompletionCallbackFactory</code> template class is used to instantiate a
442new callback. Notice that the <code>FileRef</code> resource is passed as a parameter;
443this will add a reference count to the callback object, to keep the <code>FileRef</code>
444resource from being destroyed when the function finishes.</p>
445<pre class="prettyprint">
446// Pass ref along to keep it alive.
447ref.ReadDirectoryEntries(callback_factory_.NewCallbackWithOutput(
448    &amp;FileIoInstance::ListCallback, ref));
449</pre>
450<p><code>FileIoInstance::ListCallback</code> then gets the results passed as a
451<code>std::vector</code> of <code>pp::DirectoryEntry</code> objects, and sends them to
452JavaScript:</p>
453<pre class="prettyprint">
454void ListCallback(int32_t result,
455                  const std::vector&lt;pp::DirectoryEntry&gt;&amp; entries,
456                  pp::FileRef /*unused_ref*/) {
457  if (result != PP_OK) {
458    ShowErrorMessage(&quot;List failed&quot;, result);
459    return;
460  }
461
462  std::stringstream ss;
463  ss &lt;&lt; &quot;LIST&quot;;
464  for (size_t i = 0; i &lt; entries.size(); ++i) {
465    pp::Var name = entries[i].file_ref().GetName();
466    if (name.is_string()) {
467      ss &lt;&lt; &quot;|&quot; &lt;&lt; name.AsString();
468    }
469  }
470  PostMessage(ss.str());
471  ShowStatusMessage(&quot;List success&quot;);
472}
473</pre>
474</section><section id="making-a-new-directory">
475<h3 id="making-a-new-directory">Making a new directory</h3>
476<p><code>FileIoInstance::MakeDir</code> is called when the <code>Make Directory</code> button is
477pressed. Like all other operations, it checks whether the FileSystem has been
478opened and creates a new <code>FileRef</code>:</p>
479<pre class="prettyprint">
480if (!file_system_ready_) {
481  ShowErrorMessage(&quot;File system is not open&quot;, PP_ERROR_FAILED);
482  return;
483}
484pp::FileRef ref(file_system_, dir_name.c_str());
485</pre>
486<p>Then the <code>pp::FileRef::MakeDirectory</code> function is called.</p>
487<pre class="prettyprint">
488int32_t result = ref.MakeDirectory(
489    PP_MAKEDIRECTORYFLAG_NONE, pp::BlockUntilComplete());
490if (result != PP_OK) {
491  ShowErrorMessage(&quot;Make directory failed&quot;, result);
492  return;
493}
494ShowStatusMessage(&quot;Make directory success&quot;);
495</pre>
496</section></section></section>
497
498{{/partials.standard_nacl_article}}
499