1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153

content / browser / file_system_access / file_system_access_file_writer_impl.h [blame]

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_FILE_WRITER_IMPL_H_
#define CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_FILE_WRITER_IMPL_H_

#include "base/memory/weak_ptr.h"
#include "base/thread_annotations.h"
#include "base/types/pass_key.h"
#include "components/services/filesystem/public/mojom/types.mojom.h"
#include "content/browser/file_system_access/file_system_access_file_handle_impl.h"
#include "content/browser/file_system_access/file_system_access_handle_base.h"
#include "content/browser/file_system_access/file_system_access_safe_move_helper.h"
#include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "storage/browser/file_system/file_system_url.h"
#include "third_party/blink/public/mojom/file_system_access/file_system_access_file_writer.mojom.h"

namespace content {

// This is the browser side implementation of the
// FileSystemAccessFileWriter mojom interface. Instances of this class are
// owned by the FileSystemAccessManagerImpl instance passed in to the
// constructor.
//
// This class is not thread safe, all methods must be called from the same
// sequence.
class CONTENT_EXPORT FileSystemAccessFileWriterImpl
    : public FileSystemAccessHandleBase,
      public blink::mojom::FileSystemAccessFileWriter {
 public:
  // Creates a FileWriter that writes in a swap file URL and
  // materializes the changes in the target file URL only after `Close`
  // is invoked and successfully completes. Assumes that swap_url represents a
  // file, and is valid.
  // If no `quarantine_connection_callback` is passed in no quarantine is done,
  // other than setting source information directly if on windows.
  // FileWriters should only be created via the FileSystemAccessManagerImpl.
  FileSystemAccessFileWriterImpl(
      FileSystemAccessManagerImpl* manager,
      base::PassKey<FileSystemAccessManagerImpl> pass_key,
      const BindingContext& context,
      const storage::FileSystemURL& url,
      const storage::FileSystemURL& swap_url,
      scoped_refptr<FileSystemAccessLockManager::LockHandle> lock,
      scoped_refptr<FileSystemAccessLockManager::LockHandle> swap_lock,
      const SharedHandleState& handle_state,
      mojo::PendingReceiver<blink::mojom::FileSystemAccessFileWriter> receiver,
      bool has_transient_user_activation,
      bool auto_close,
      download::QuarantineConnectionCallback quarantine_connection_callback);
  FileSystemAccessFileWriterImpl(const FileSystemAccessFileWriterImpl&) =
      delete;
  FileSystemAccessFileWriterImpl& operator=(
      const FileSystemAccessFileWriterImpl&) = delete;
  ~FileSystemAccessFileWriterImpl() override;

  const storage::FileSystemURL& swap_url() const { return swap_url_; }
  base::WeakPtr<FileSystemAccessFileWriterImpl> weak_ptr() {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    return weak_factory_.GetWeakPtr();
  }

  void Write(uint64_t offset,
             mojo::ScopedDataPipeConsumerHandle stream,
             WriteCallback callback) override;

  void Truncate(uint64_t length, TruncateCallback callback) override;
  // The writer will be destroyed upon completion.
  void Close(CloseCallback callback) override;
  // The writer will be destroyed upon completion.
  void Abort(AbortCallback callback) override;

 private:
  // State that is kept for the duration of a write operation, to keep track of
  // progress until the write completes.
  struct WriteState;

  mojo::Receiver<blink::mojom::FileSystemAccessFileWriter> receiver_;

  // If the mojo pipe is severed before either Close() or Abort() is invoked,
  // the transaction is aborted from the OnDisconnect method. Otherwise, the
  // writer will be destroyed upon completion of Close() or Abort().
  void OnDisconnect();

  // Destroys the file writer after calling the close callback.
  void CallCloseCallbackAndDeleteThis(
      blink::mojom::FileSystemAccessErrorPtr result);

  void WriteImpl(uint64_t offset,
                 mojo::ScopedDataPipeConsumerHandle stream,
                 WriteCallback callback);
  void DidWrite(WriteState* state,
                base::File::Error result,
                int64_t bytes,
                bool complete);
  void TruncateImpl(uint64_t length, TruncateCallback callback);
  void CloseImpl(CloseCallback callback);
  void AbortImpl(AbortCallback callback);
  void DidReplaceSwapFile(
      std::unique_ptr<content::FileSystemAccessSafeMoveHelper>
          file_system_access_safe_move_helper,
      blink::mojom::FileSystemAccessErrorPtr result);

  bool is_close_pending() const {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    return !close_callback_.is_null();
  }

  // We write using this file URL. When `Close()` is invoked, we
  // execute a move operation from the swap URL to the target URL at `url_`. In
  // most filesystems, this move operation is atomic.
  storage::FileSystemURL swap_url_ GUARDED_BY_CONTEXT(sequence_checker_);

  // Lock on the target file. It is released on destruction.
  scoped_refptr<FileSystemAccessLockManager::LockHandle> lock_
      GUARDED_BY_CONTEXT(sequence_checker_);
  // Exclusive lock on the swap file. It is released on destruction.
  scoped_refptr<FileSystemAccessLockManager::LockHandle> swap_lock_
      GUARDED_BY_CONTEXT(sequence_checker_);

  CloseCallback close_callback_ GUARDED_BY_CONTEXT(sequence_checker_);

  download::QuarantineConnectionCallback quarantine_connection_callback_
      GUARDED_BY_CONTEXT(sequence_checker_);

  // Keeps track of user activation state at creation time for after write
  // checks.
  bool has_transient_user_activation_ GUARDED_BY_CONTEXT(sequence_checker_) =
      false;

  // Changes will be written to the target file even if the stream isn't
  // explicitly closed.
  bool auto_close_ GUARDED_BY_CONTEXT(sequence_checker_) = false;

  // The writer should not attempt to purge the swap file if the move operation
  // to the target file is successful, since this may incidentally remove the
  // active swap file of a different writer.
  bool should_purge_swap_file_on_destruction_
      GUARDED_BY_CONTEXT(sequence_checker_) = true;

  base::WeakPtr<FileSystemAccessHandleBase> AsWeakPtr() override;

  base::WeakPtrFactory<FileSystemAccessFileWriterImpl> weak_factory_
      GUARDED_BY_CONTEXT(sequence_checker_){this};
};

}  // namespace content

#endif  // CONTENT_BROWSER_FILE_SYSTEM_ACCESS_FILE_SYSTEM_ACCESS_FILE_WRITER_IMPL_H_