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