File: scoped_file_opener.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (146 lines) | stat: -rw-r--r-- 5,395 bytes parent folder | download | duplicates (6)
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
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/file_system_provider/scoped_file_opener.h"

#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/file_system_provider/abort_callback.h"

namespace ash::file_system_provider {

using OpenFileCallback = ProvidedFileSystemInterface::OpenFileCallback;

// Opens and closes files automatically. Extracted from ScopedFileOpener to
// be able to make ScopedFileOpener *not* ref counted.
class ScopedFileOpener::Runner
    : public base::RefCounted<ScopedFileOpener::Runner> {
 public:
  static scoped_refptr<Runner> Create(ProvidedFileSystemInterface* file_system,
                                      const base::FilePath& file_path,
                                      OpenFileMode mode,
                                      OpenFileCallback callback) {
    auto runner =
        base::WrapRefCounted(new Runner(file_system, std::move(callback)));
    runner->abort_callback_ = file_system->OpenFile(
        file_path, mode,
        base::BindOnce(&ScopedFileOpener::Runner::OnOpenFileCompleted, runner));
    return runner;
  }

  // Aborts pending open operation, or closes a file if it's already opened.
  // Called from ScopedFileOpener::~ScopedFileOpener.
  void AbortOrClose() {
    if (!open_completed_) {
      aborting_requested_ = true;
      std::move(abort_callback_).Run();
      return;
    }

    if (open_completed_ && file_handle_ != 0) {
      if (file_system_.get()) {
        file_system_->CloseFile(
            file_handle_,
            base::BindOnce(
                &ScopedFileOpener::Runner::OnCloseFileAfterAbortCompleted, this,
                file_handle_));
      }
      return;
    }

    // Otherwise nothing to abort nor to close - the opening process has
    // completed, but the file failed to open, so there is no need to close it.
    DCHECK(open_completed_ && file_handle_ == 0);
  }

 private:
  friend class base::RefCounted<ScopedFileOpener::Runner>;

  Runner(ProvidedFileSystemInterface* file_system, OpenFileCallback callback)
      : file_system_(file_system->GetWeakPtr()),
        open_callback_(std::move(callback)),
        aborting_requested_(false),
        open_completed_(false),
        file_handle_(0) {}

  ~Runner() = default;

  // Called when opening is completed with either a success or an error.
  void OnOpenFileCompleted(int file_handle,
                           base::File::Error result,
                           std::unique_ptr<EntryMetadata> metadata) {
    open_completed_ = true;

    if (result != base::File::FILE_OK) {
      CallOpenCallbackOnce(file_handle, result);
      return;
    }

    file_handle_ = file_handle;
    if (aborting_requested_ && file_system_.get()) {
      // The opening request has been aborted earlier, but the abort request
      // either hasn't arrived yet the extension, or it abort request events are
      // not handled by the extension. In either case, close the file now.
      file_system_->CloseFile(
          file_handle,
          base::BindOnce(
              &ScopedFileOpener::Runner::OnCloseFileAfterAbortCompleted, this,
              file_handle_));
      return;
    }

    DCHECK_EQ(base::File::FILE_OK, result);
    CallOpenCallbackOnce(file_handle, base::File::FILE_OK);
  }

  // Called when automatic closing a file is completed. It's performed when
  // a file is opened successfully after the abort callback is called.
  void OnCloseFileAfterAbortCompleted(int file_handle,
                                      base::File::Error result) {
    if (result == base::File::FILE_ERROR_ABORT) {
      // Closing is aborted, so the file is still open. Call the OpenFile
      // callback with a success error code and mark the file as opened.
      //
      // This is not good, as callers, such as file stream readers may expect
      // aborting to *always* work, and leave the file opened permanently.
      // The problem will go away once we remove the dialog to abort slow
      // operations. See: crbug.com/475355.
      CallOpenCallbackOnce(file_handle, base::File::FILE_OK);
      return;
    }

    // Call the OpenFile callback with the ABORT error code, as the file is not
    // opened anymore.
    CallOpenCallbackOnce(file_handle, base::File::FILE_ERROR_ABORT);
  }

  // Calls the |open_callback_| only once with a result for opening a file.
  void CallOpenCallbackOnce(int file_handle, base::File::Error result) {
    if (open_callback_.is_null())
      return;

    std::move(open_callback_)
        .Run(file_handle, result, /*cloud_file_info=*/nullptr);
  }

  base::WeakPtr<ProvidedFileSystemInterface> file_system_;
  OpenFileCallback open_callback_;
  AbortCallback abort_callback_;
  bool aborting_requested_;
  bool open_completed_;
  int file_handle_;
};

ScopedFileOpener::ScopedFileOpener(ProvidedFileSystemInterface* file_system,
                                   const base::FilePath& file_path,
                                   OpenFileMode mode,
                                   OpenFileCallback callback)
    : runner_(
          Runner::Create(file_system, file_path, mode, std::move(callback))) {}

ScopedFileOpener::~ScopedFileOpener() {
  runner_->AbortOrClose();
}

}  // namespace ash::file_system_provider