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