Home | History | Annotate | Download | only in plugin
      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 "ppapi/native_client/src/trusted/plugin/local_temp_file.h"
      6 
      7 #include "native_client/src/include/portability_io.h"
      8 #include "native_client/src/shared/platform/nacl_check.h"
      9 
     10 #include "ppapi/c/ppb_file_io.h"
     11 #include "ppapi/cpp/file_io.h"
     12 #include "ppapi/cpp/file_ref.h"
     13 #include "ppapi/cpp/file_system.h"
     14 
     15 #include "ppapi/native_client/src/trusted/plugin/plugin.h"
     16 #include "ppapi/native_client/src/trusted/plugin/utility.h"
     17 
     18 //////////////////////////////////////////////////////////////////////
     19 //  Local temporary file access.
     20 //////////////////////////////////////////////////////////////////////
     21 namespace plugin {
     22 
     23 namespace {
     24 nacl::string Random32CharHexString(struct NaClDescRng* rng) {
     25   struct NaClDesc* desc = reinterpret_cast<struct NaClDesc*>(rng);
     26   const struct NaClDescVtbl* vtbl =
     27       reinterpret_cast<const struct NaClDescVtbl*>(desc->base.vtbl);
     28 
     29   nacl::string hex_string;
     30   const int32_t kTempFileNameWords = 4;
     31   for (int32_t i = 0; i < kTempFileNameWords; ++i) {
     32     int32_t num;
     33     CHECK(sizeof num == vtbl->Read(desc,
     34                                    reinterpret_cast<char*>(&num),
     35                                    sizeof num));
     36     char frag[16];
     37     SNPRINTF(frag, sizeof frag, "%08x", num);
     38     hex_string += nacl::string(frag);
     39   }
     40   return hex_string;
     41 }
     42 
     43 // Some constants for LocalTempFile::GetFD readability.
     44 const bool kReadOnly = false;
     45 const bool kWriteable = true;
     46 } // namespace
     47 
     48 uint32_t LocalTempFile::next_identifier = 0;
     49 
     50 LocalTempFile::LocalTempFile(Plugin* plugin,
     51                              pp::FileSystem* file_system,
     52                              const nacl::string &base_dir)
     53     : plugin_(plugin),
     54       file_system_(file_system),
     55       base_dir_(base_dir) {
     56   PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, "
     57                  "file_system=%p)\n",
     58                  static_cast<void*>(plugin), static_cast<void*>(file_system)));
     59   Initialize();
     60 }
     61 
     62 LocalTempFile::LocalTempFile(Plugin* plugin,
     63                              pp::FileSystem* file_system,
     64                              const nacl::string &base_dir,
     65                              const nacl::string &filename)
     66     : plugin_(plugin),
     67       file_system_(file_system),
     68       base_dir_(base_dir),
     69       filename_(base_dir + "/" + filename) {
     70   PLUGIN_PRINTF(("LocalTempFile::LocalTempFile (plugin=%p, "
     71                  "file_system=%p, filename=%s)\n",
     72                  static_cast<void*>(plugin), static_cast<void*>(file_system),
     73                  filename.c_str()));
     74   file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str()));
     75   Initialize();
     76 }
     77 
     78 void LocalTempFile::Initialize() {
     79   callback_factory_.Initialize(this);
     80   rng_desc_ = (struct NaClDescRng *) malloc(sizeof *rng_desc_);
     81   CHECK(rng_desc_ != NULL);
     82   CHECK(NaClDescRngCtor(rng_desc_));
     83   file_io_trusted_ = static_cast<const PPB_FileIOTrusted*>(
     84       pp::Module::Get()->GetBrowserInterface(PPB_FILEIOTRUSTED_INTERFACE));
     85   ++next_identifier;
     86   SNPRINTF(reinterpret_cast<char *>(identifier_), sizeof identifier_,
     87            "%" NACL_PRIu32, next_identifier);
     88 }
     89 
     90 LocalTempFile::~LocalTempFile() {
     91   PLUGIN_PRINTF(("LocalTempFile::~LocalTempFile\n"));
     92   NaClDescUnref(reinterpret_cast<NaClDesc*>(rng_desc_));
     93 }
     94 
     95 void LocalTempFile::OpenWrite(const pp::CompletionCallback& cb) {
     96   done_callback_ = cb;
     97   // If we don't already have a filename, generate one.
     98   if (filename_ == "") {
     99     // Get a random temp file name.
    100     filename_ = base_dir_ + "/" + Random32CharHexString(rng_desc_);
    101     // Remember the ref used to open for writing and reading.
    102     file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str()));
    103   }
    104   PLUGIN_PRINTF(("LocalTempFile::OpenWrite: %s\n", filename_.c_str()));
    105   // Open the writeable file.
    106   write_io_.reset(new pp::FileIO(plugin_));
    107   pp::CompletionCallback open_write_cb =
    108       callback_factory_.NewCallback(&LocalTempFile::WriteFileDidOpen);
    109   write_io_->Open(*file_ref_,
    110                   PP_FILEOPENFLAG_WRITE |
    111                   PP_FILEOPENFLAG_CREATE |
    112                   PP_FILEOPENFLAG_EXCLUSIVE,
    113                   open_write_cb);
    114 }
    115 
    116 int32_t LocalTempFile::GetFD(int32_t pp_error,
    117                              const pp::Resource& resource,
    118                              bool is_writable) {
    119   PLUGIN_PRINTF(("LocalTempFile::GetFD (pp_error=%" NACL_PRId32
    120                  ", is_writable=%d)\n", pp_error, is_writable));
    121   if (pp_error != PP_OK) {
    122     PLUGIN_PRINTF(("LocalTempFile::GetFD pp_error != PP_OK\n"));
    123     return -1;
    124   }
    125   int32_t file_desc =
    126       file_io_trusted_->GetOSFileDescriptor(resource.pp_resource());
    127 #if NACL_WINDOWS
    128   // Convert the Windows HANDLE from Pepper to a POSIX file descriptor.
    129   int32_t open_flags = ((is_writable ? _O_RDWR : _O_RDONLY) | _O_BINARY);
    130   int32_t posix_desc = _open_osfhandle(file_desc, open_flags);
    131   if (posix_desc == -1) {
    132     // Close the Windows HANDLE if it can't be converted.
    133     CloseHandle(reinterpret_cast<HANDLE>(file_desc));
    134     PLUGIN_PRINTF(("LocalTempFile::GetFD _open_osfhandle failed.\n"));
    135     return NACL_NO_FILE_DESC;
    136   }
    137   file_desc = posix_desc;
    138 #endif
    139   int32_t file_desc_ok_to_close = DUP(file_desc);
    140   if (file_desc_ok_to_close == NACL_NO_FILE_DESC) {
    141     PLUGIN_PRINTF(("LocalTempFile::GetFD dup failed.\n"));
    142     return -1;
    143   }
    144   return file_desc_ok_to_close;
    145 }
    146 
    147 void LocalTempFile::WriteFileDidOpen(int32_t pp_error) {
    148   PLUGIN_PRINTF(("LocalTempFile::WriteFileDidOpen (pp_error=%"
    149                  NACL_PRId32")\n", pp_error));
    150   if (pp_error == PP_ERROR_FILEEXISTS) {
    151     // Filenames clashed, retry.
    152     filename_ = "";
    153     OpenWrite(done_callback_);
    154   }
    155   // Run the client's completion callback.
    156   pp::Core* core = pp::Module::Get()->core();
    157   if (pp_error != PP_OK) {
    158     core->CallOnMainThread(0, done_callback_, pp_error);
    159     return;
    160   }
    161   // Remember the object temporary file descriptor.
    162   int32_t fd = GetFD(pp_error, *write_io_, kWriteable);
    163   if (fd < 0) {
    164     core->CallOnMainThread(0, done_callback_, pp_error);
    165     return;
    166   }
    167   // The descriptor for a writeable file needs to have quota management.
    168   write_wrapper_.reset(
    169       plugin_->wrapper_factory()->MakeFileDescQuota(fd, O_RDWR, identifier_));
    170   core->CallOnMainThread(0, done_callback_, PP_OK);
    171 }
    172 
    173 void LocalTempFile::OpenRead(const pp::CompletionCallback& cb) {
    174   PLUGIN_PRINTF(("LocalTempFile::OpenRead: %s\n", filename_.c_str()));
    175   done_callback_ = cb;
    176   // Open the read only file.
    177   read_io_.reset(new pp::FileIO(plugin_));
    178   pp::CompletionCallback open_read_cb =
    179       callback_factory_.NewCallback(&LocalTempFile::ReadFileDidOpen);
    180   read_io_->Open(*file_ref_, PP_FILEOPENFLAG_READ, open_read_cb);
    181 }
    182 
    183 void LocalTempFile::ReadFileDidOpen(int32_t pp_error) {
    184   PLUGIN_PRINTF(("LocalTempFile::ReadFileDidOpen (pp_error=%"
    185                  NACL_PRId32")\n", pp_error));
    186   // Run the client's completion callback.
    187   pp::Core* core = pp::Module::Get()->core();
    188   if (pp_error != PP_OK) {
    189     core->CallOnMainThread(0, done_callback_, pp_error);
    190     return;
    191   }
    192   // Remember the object temporary file descriptor.
    193   int32_t fd = GetFD(pp_error, *read_io_, kReadOnly);
    194   if (fd < 0) {
    195     core->CallOnMainThread(0, done_callback_, PP_ERROR_FAILED);
    196     return;
    197   }
    198   read_wrapper_.reset(plugin_->wrapper_factory()->MakeFileDesc(fd, O_RDONLY));
    199   core->CallOnMainThread(0, done_callback_, PP_OK);
    200 }
    201 
    202 void LocalTempFile::Close(const pp::CompletionCallback& cb) {
    203   PLUGIN_PRINTF(("LocalTempFile::Close: %s\n", filename_.c_str()));
    204   // Close the open DescWrappers and FileIOs.
    205   if (write_io_.get() != NULL) {
    206     write_io_->Close();
    207   }
    208   write_wrapper_.reset(NULL);
    209   write_io_.reset(NULL);
    210   if (read_io_.get() != NULL) {
    211     read_io_->Close();
    212   }
    213   read_wrapper_.reset(NULL);
    214   read_io_.reset(NULL);
    215   // Run the client's completion callback.
    216   pp::Core* core = pp::Module::Get()->core();
    217   core->CallOnMainThread(0, cb, PP_OK);
    218 }
    219 
    220 void LocalTempFile::Delete(const pp::CompletionCallback& cb) {
    221   PLUGIN_PRINTF(("LocalTempFile::Delete: %s\n", filename_.c_str()));
    222   file_ref_->Delete(cb);
    223 }
    224 
    225 void LocalTempFile::Rename(const nacl::string& new_name,
    226                            const pp::CompletionCallback& cb) {
    227   // Rename the temporary file.
    228   filename_ = base_dir_ + "/" + new_name;
    229   PLUGIN_PRINTF(("LocalTempFile::Rename %s to %s\n",
    230                  file_ref_->GetName().AsString().c_str(),
    231                  filename_.c_str()));
    232   // Remember the old ref until the rename is complete.
    233   old_ref_.reset(file_ref_.release());
    234   file_ref_.reset(new pp::FileRef(*file_system_, filename_.c_str()));
    235   old_ref_->Rename(*file_ref_, cb);
    236 }
    237 
    238 void LocalTempFile::FinishRename() {
    239   // Now we can release the old ref.
    240   old_ref_.reset(NULL);
    241 }
    242 
    243 }  // namespace plugin
    244