Home | History | Annotate | Download | only in proxy
      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 #ifndef PPAPI_PROXY_FILE_IO_RESOURCE_H_
      6 #define PPAPI_PROXY_FILE_IO_RESOURCE_H_
      7 
      8 #include <string>
      9 
     10 #include "base/files/file.h"
     11 #include "base/memory/ref_counted.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "ppapi/c/private/pp_file_handle.h"
     14 #include "ppapi/proxy/connection.h"
     15 #include "ppapi/proxy/plugin_resource.h"
     16 #include "ppapi/proxy/ppapi_proxy_export.h"
     17 #include "ppapi/shared_impl/file_io_state_manager.h"
     18 #include "ppapi/shared_impl/resource.h"
     19 #include "ppapi/shared_impl/scoped_pp_resource.h"
     20 #include "ppapi/thunk/ppb_file_io_api.h"
     21 
     22 namespace ppapi {
     23 
     24 class TrackedCallback;
     25 
     26 namespace proxy {
     27 
     28 class PPAPI_PROXY_EXPORT FileIOResource
     29     : public PluginResource,
     30       public thunk::PPB_FileIO_API {
     31  public:
     32   FileIOResource(Connection connection, PP_Instance instance);
     33   virtual ~FileIOResource();
     34 
     35   // Resource overrides.
     36   virtual thunk::PPB_FileIO_API* AsPPB_FileIO_API() OVERRIDE;
     37 
     38   // PPB_FileIO_API implementation.
     39   virtual int32_t Open(PP_Resource file_ref,
     40                        int32_t open_flags,
     41                        scoped_refptr<TrackedCallback> callback) OVERRIDE;
     42   virtual int32_t Query(PP_FileInfo* info,
     43                         scoped_refptr<TrackedCallback> callback) OVERRIDE;
     44   virtual int32_t Touch(PP_Time last_access_time,
     45                         PP_Time last_modified_time,
     46                         scoped_refptr<TrackedCallback> callback) OVERRIDE;
     47   virtual int32_t Read(int64_t offset,
     48                        char* buffer,
     49                        int32_t bytes_to_read,
     50                        scoped_refptr<TrackedCallback> callback) OVERRIDE;
     51   virtual int32_t ReadToArray(int64_t offset,
     52                               int32_t max_read_length,
     53                               PP_ArrayOutput* array_output,
     54                               scoped_refptr<TrackedCallback> callback) OVERRIDE;
     55   virtual int32_t Write(int64_t offset,
     56                         const char* buffer,
     57                         int32_t bytes_to_write,
     58                         scoped_refptr<TrackedCallback> callback) OVERRIDE;
     59   virtual int32_t SetLength(int64_t length,
     60                             scoped_refptr<TrackedCallback> callback) OVERRIDE;
     61   virtual int64_t GetMaxWrittenOffset() const OVERRIDE;
     62   virtual int64_t GetAppendModeWriteAmount() const OVERRIDE;
     63   virtual void SetMaxWrittenOffset(int64_t max_written_offset) OVERRIDE;
     64   virtual void SetAppendModeWriteAmount(
     65       int64_t append_mode_write_amount) OVERRIDE;
     66   virtual int32_t Flush(scoped_refptr<TrackedCallback> callback) OVERRIDE;
     67   virtual void Close() OVERRIDE;
     68   virtual int32_t RequestOSFileHandle(
     69       PP_FileHandle* handle,
     70       scoped_refptr<TrackedCallback> callback) OVERRIDE;
     71 
     72   // FileHolder is used to guarantee that file operations will have a valid FD
     73   // to operate on, even if they're in a different thread.
     74   // If instead we just passed the raw FD, the FD could be closed before the
     75   // file operation has a chance to run. It could interact with an invalid FD,
     76   // or worse, the FD value could be reused if another file is opened quickly
     77   // (POSIX is required to provide the lowest available value when opening a
     78   // file). This could result in strange problems such as writing data to the
     79   // wrong file.
     80   //
     81   // Operations that run on a background thread should hold one of these to
     82   // ensure they have a valid file descriptor. The file handle is only closed
     83   // when the last reference to the FileHolder is removed, so we are guaranteed
     84   // to operate on the correct file descriptor. It *is* still possible that the
     85   // FileIOResource will be destroyed and "Abort" callbacks just before the
     86   // operation does its task (e.g., Reading). In that case, we might for example
     87   // Read from a file even though the FileIO has been destroyed and the plugin's
     88   // callback got a PP_ERROR_ABORTED result. In the case of a write, we could
     89   // write some data to the file despite the plugin receiving a
     90   // PP_ERROR_ABORTED instead of a successful result.
     91   class FileHolder : public base::RefCountedThreadSafe<FileHolder> {
     92    public:
     93     explicit FileHolder(PP_FileHandle file_handle);
     94     base::File* file() {
     95       return &file_;
     96     }
     97     static bool IsValid(
     98         const scoped_refptr<FileIOResource::FileHolder>& handle);
     99    private:
    100     friend class base::RefCountedThreadSafe<FileHolder>;
    101     ~FileHolder();
    102     base::File file_;
    103   };
    104 
    105   scoped_refptr<FileHolder> file_holder() {
    106     return file_holder_;
    107   }
    108 
    109  private:
    110   // Class to perform file query operations across multiple threads.
    111   class QueryOp : public base::RefCountedThreadSafe<QueryOp> {
    112    public:
    113     explicit QueryOp(scoped_refptr<FileHolder> file_holder);
    114 
    115     // Queries the file. Called on the file thread (non-blocking) or the plugin
    116     // thread (blocking). This should not be called when we hold the proxy lock.
    117     int32_t DoWork();
    118 
    119     const base::File::Info& file_info() const { return file_info_; }
    120 
    121    private:
    122     friend class base::RefCountedThreadSafe<QueryOp>;
    123     ~QueryOp();
    124 
    125     scoped_refptr<FileHolder> file_holder_;
    126     base::File::Info file_info_;
    127   };
    128 
    129   // Class to perform file read operations across multiple threads.
    130   class ReadOp : public base::RefCountedThreadSafe<ReadOp> {
    131    public:
    132     ReadOp(scoped_refptr<FileHolder> file_holder,
    133            int64_t offset,
    134            int32_t bytes_to_read);
    135 
    136     // Reads the file. Called on the file thread (non-blocking) or the plugin
    137     // thread (blocking). This should not be called when we hold the proxy lock.
    138     int32_t DoWork();
    139 
    140     char* buffer() const { return buffer_.get(); }
    141 
    142    private:
    143     friend class base::RefCountedThreadSafe<ReadOp>;
    144     ~ReadOp();
    145 
    146     scoped_refptr<FileHolder> file_holder_;
    147     int64_t offset_;
    148     int32_t bytes_to_read_;
    149     scoped_ptr<char[]> buffer_;
    150   };
    151 
    152   // Class to perform file write operations across multiple threads.
    153   class WriteOp : public base::RefCountedThreadSafe<WriteOp> {
    154    public:
    155     WriteOp(scoped_refptr<FileHolder> file_holder,
    156             int64_t offset,
    157             scoped_ptr<char[]> buffer,
    158             int32_t bytes_to_write,
    159             bool append);
    160 
    161     // Writes the file. Called on the file thread (non-blocking) or the plugin
    162     // thread (blocking). This should not be called when we hold the proxy lock.
    163     int32_t DoWork();
    164 
    165    private:
    166     friend class base::RefCountedThreadSafe<WriteOp>;
    167     ~WriteOp();
    168 
    169     scoped_refptr<FileHolder> file_holder_;
    170     int64_t offset_;
    171     scoped_ptr<char[]> buffer_;
    172     int32_t bytes_to_write_;
    173     bool append_;
    174   };
    175 
    176   void OnRequestWriteQuotaComplete(int64_t offset,
    177                                    scoped_ptr<char[]> buffer,
    178                                    int32_t bytes_to_write,
    179                                    scoped_refptr<TrackedCallback> callback,
    180                                    int64_t granted);
    181   void OnRequestSetLengthQuotaComplete(int64_t length,
    182                                        scoped_refptr<TrackedCallback> callback,
    183                                        int64_t granted);
    184 
    185   int32_t ReadValidated(int64_t offset,
    186                         int32_t bytes_to_read,
    187                         const PP_ArrayOutput& array_output,
    188                         scoped_refptr<TrackedCallback> callback);
    189   int32_t WriteValidated(int64_t offset,
    190                          const char* buffer,
    191                          int32_t bytes_to_write,
    192                          scoped_refptr<TrackedCallback> callback);
    193   void SetLengthValidated(int64_t length,
    194                           scoped_refptr<TrackedCallback> callback);
    195 
    196   // Completion tasks for file operations that are done in the plugin.
    197   int32_t OnQueryComplete(scoped_refptr<QueryOp> query_op,
    198                           PP_FileInfo* info,
    199                           int32_t result);
    200   int32_t OnReadComplete(scoped_refptr<ReadOp> read_op,
    201                          PP_ArrayOutput array_output,
    202                          int32_t result);
    203   int32_t OnWriteComplete(int32_t result);
    204 
    205   // Reply message handlers for operations that are done in the host.
    206   void OnPluginMsgGeneralComplete(scoped_refptr<TrackedCallback> callback,
    207                                   const ResourceMessageReplyParams& params);
    208   void OnPluginMsgOpenFileComplete(scoped_refptr<TrackedCallback> callback,
    209                                    const ResourceMessageReplyParams& params,
    210                                    PP_Resource quota_file_system,
    211                                    int64_t max_written_offset);
    212   void OnPluginMsgRequestOSFileHandleComplete(
    213       scoped_refptr<TrackedCallback> callback,
    214       PP_FileHandle* output_handle,
    215       const ResourceMessageReplyParams& params);
    216 
    217   scoped_refptr<FileHolder> file_holder_;
    218   PP_FileSystemType file_system_type_;
    219   scoped_refptr<Resource> file_system_resource_;
    220   FileIOStateManager state_manager_;
    221 
    222   scoped_refptr<Resource> file_ref_;
    223 
    224   int32_t open_flags_;
    225   int64_t max_written_offset_;
    226   int64_t append_mode_write_amount_;
    227   bool check_quota_;
    228   bool called_close_;
    229 
    230   DISALLOW_COPY_AND_ASSIGN(FileIOResource);
    231 };
    232 
    233 }  // namespace proxy
    234 }  // namespace ppapi
    235 
    236 #endif  // PPAPI_PROXY_FILE_IO_RESOURCE_H_
    237