Home | History | Annotate | Download | only in nacl_io
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "nacl_io/mount_html5fs.h"
      6 
      7 #include <errno.h>
      8 #include <fcntl.h>
      9 #include <ppapi/c/pp_completion_callback.h>
     10 #include <ppapi/c/pp_errors.h>
     11 #include <stdlib.h>
     12 #include <string.h>
     13 #include <algorithm>
     14 #include "nacl_io/mount_node_html5fs.h"
     15 #include "sdk_util/auto_lock.h"
     16 
     17 namespace nacl_io {
     18 
     19 namespace {
     20 
     21 #if defined(WIN32)
     22 int64_t strtoull(const char* nptr, char** endptr, int base) {
     23   return _strtoui64(nptr, endptr, base);
     24 }
     25 #endif
     26 
     27 }  // namespace
     28 
     29 Error MountHtml5Fs::Access(const Path& path, int a_mode) {
     30   // a_mode is unused, since all files are readable, writable and executable.
     31   ScopedMountNode node;
     32   return Open(path, O_RDONLY, &node);
     33 }
     34 
     35 Error MountHtml5Fs::Open(const Path& path,
     36                          int mode,
     37                          ScopedMountNode* out_node) {
     38   out_node->reset(NULL);
     39   Error error = BlockUntilFilesystemOpen();
     40   if (error)
     41     return error;
     42 
     43   PP_Resource fileref = ppapi()->GetFileRefInterface()
     44       ->Create(filesystem_resource_, path.Join().c_str());
     45   if (!fileref)
     46     return ENOENT;
     47 
     48   ScopedMountNode node(new MountNodeHtml5Fs(this, fileref));
     49   error = node->Init(mode);
     50   if (error)
     51     return error;
     52 
     53   *out_node = node;
     54   return 0;
     55 }
     56 
     57 Error MountHtml5Fs::Unlink(const Path& path) { return Remove(path); }
     58 
     59 Error MountHtml5Fs::Mkdir(const Path& path, int permissions) {
     60   Error error = BlockUntilFilesystemOpen();
     61   if (error)
     62     return error;
     63 
     64   ScopedResource fileref_resource(
     65       ppapi(),
     66       ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
     67                                              path.Join().c_str()));
     68   if (!fileref_resource.pp_resource())
     69     return ENOENT;
     70 
     71   int32_t result = ppapi()->GetFileRefInterface()->MakeDirectory(
     72       fileref_resource.pp_resource(), PP_FALSE, PP_BlockUntilComplete());
     73   if (result != PP_OK)
     74     return PPErrorToErrno(result);
     75 
     76   return 0;
     77 }
     78 
     79 Error MountHtml5Fs::Rmdir(const Path& path) { return Remove(path); }
     80 
     81 Error MountHtml5Fs::Remove(const Path& path) {
     82   Error error = BlockUntilFilesystemOpen();
     83   if (error)
     84     return error;
     85 
     86   ScopedResource fileref_resource(
     87       ppapi(),
     88       ppapi()->GetFileRefInterface()->Create(filesystem_resource_,
     89                                              path.Join().c_str()));
     90   if (!fileref_resource.pp_resource())
     91     return ENOENT;
     92 
     93   int32_t result = ppapi()->GetFileRefInterface()
     94       ->Delete(fileref_resource.pp_resource(), PP_BlockUntilComplete());
     95   if (result != PP_OK)
     96     return PPErrorToErrno(result);
     97 
     98   return 0;
     99 }
    100 
    101 MountHtml5Fs::MountHtml5Fs()
    102     : filesystem_resource_(0),
    103       filesystem_open_has_result_(false),
    104       filesystem_open_error_(0) {}
    105 
    106 Error MountHtml5Fs::Init(int dev, StringMap_t& args, PepperInterface* ppapi) {
    107   Error error = Mount::Init(dev, args, ppapi);
    108   if (error)
    109     return error;
    110 
    111   if (!ppapi)
    112     return ENOSYS;
    113 
    114   pthread_cond_init(&filesystem_open_cond_, NULL);
    115 
    116   // Parse mount args.
    117   PP_FileSystemType filesystem_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
    118   int64_t expected_size = 0;
    119   for (StringMap_t::iterator iter = args.begin(), end = args.end(); iter != end;
    120        ++iter) {
    121     if (iter->first == "type") {
    122       if (iter->second == "PERSISTENT") {
    123         filesystem_type = PP_FILESYSTEMTYPE_LOCALPERSISTENT;
    124       } else if (iter->second == "TEMPORARY") {
    125         filesystem_type = PP_FILESYSTEMTYPE_LOCALTEMPORARY;
    126       }
    127     } else if (iter->first == "expected_size") {
    128       expected_size = strtoull(iter->second.c_str(), NULL, 10);
    129     }
    130   }
    131 
    132   // Initialize filesystem.
    133   filesystem_resource_ = ppapi->GetFileSystemInterface()
    134       ->Create(ppapi_->GetInstance(), filesystem_type);
    135   if (filesystem_resource_ == 0)
    136     return ENOSYS;
    137 
    138   // We can't block the main thread, so make an asynchronous call if on main
    139   // thread. If we are off-main-thread, then don't make an asynchronous call;
    140   // otherwise we require a message loop.
    141   bool main_thread = ppapi->IsMainThread();
    142   PP_CompletionCallback cc =
    143       main_thread ? PP_MakeCompletionCallback(
    144                         &MountHtml5Fs::FilesystemOpenCallbackThunk, this)
    145                   : PP_BlockUntilComplete();
    146 
    147   int32_t result = ppapi->GetFileSystemInterface()
    148       ->Open(filesystem_resource_, expected_size, cc);
    149 
    150   if (!main_thread) {
    151     filesystem_open_has_result_ = true;
    152     filesystem_open_error_ = PPErrorToErrno(result);
    153 
    154     return filesystem_open_error_;
    155   } else {
    156     // We have to assume the call to Open will succeed; there is no better
    157     // result to return here.
    158     return 0;
    159   }
    160 }
    161 
    162 void MountHtml5Fs::Destroy() {
    163   ppapi_->ReleaseResource(filesystem_resource_);
    164   pthread_cond_destroy(&filesystem_open_cond_);
    165 }
    166 
    167 Error MountHtml5Fs::BlockUntilFilesystemOpen() {
    168   AUTO_LOCK(filesysem_open_lock_);
    169   while (!filesystem_open_has_result_) {
    170     pthread_cond_wait(&filesystem_open_cond_, filesysem_open_lock_.mutex());
    171   }
    172   return filesystem_open_error_;
    173 }
    174 
    175 // static
    176 void MountHtml5Fs::FilesystemOpenCallbackThunk(void* user_data,
    177                                                int32_t result) {
    178   MountHtml5Fs* self = static_cast<MountHtml5Fs*>(user_data);
    179   self->FilesystemOpenCallback(result);
    180 }
    181 
    182 void MountHtml5Fs::FilesystemOpenCallback(int32_t result) {
    183   AUTO_LOCK(filesysem_open_lock_);
    184   filesystem_open_has_result_ = true;
    185   filesystem_open_error_ = PPErrorToErrno(result);
    186   pthread_cond_signal(&filesystem_open_cond_);
    187 }
    188 
    189 }  // namespace nacl_io
    190 
    191