File: DirectIOFile.h

package info (click to toggle)
dolphin-emu 2512%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 76,328 kB
  • sloc: cpp: 499,023; ansic: 119,674; python: 6,547; sh: 2,338; makefile: 1,093; asm: 726; pascal: 257; javascript: 183; perl: 97; objc: 75; xml: 30
file content (150 lines) | stat: -rw-r--r-- 3,952 bytes parent folder | download
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
// Copyright 2025 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <span>
#include <string>

#include "Common/CommonTypes.h"
#include "Common/IOFile.h"

namespace File
{
enum class AccessMode
{
  Read,
  Write,
  ReadAndWrite,
};

enum class OpenMode
{
  // Based on the provided `AccessMode`.
  // Read: Existing.
  // Write: Truncate.
  // ReadAndWrite: Existing.
  Default,

  // Either create a new file or open an existing file.
  Always,

  // Like `Always`, but also erase the contents of an existing file.
  Truncate,

  // Require a file to already exist. Fail otherwise.
  Existing,

  // Require a new file be created. Fail if one already exists.
  Create,
};

// This file wrapper avoids use of the underlying system file position.
// It keeps track of its own file position and read/write calls directly use it.
// This makes copied handles entirely thread safe.
class DirectIOFile final
{
public:
  DirectIOFile();
  ~DirectIOFile();

  // Copies and moves are allowed.
  DirectIOFile(const DirectIOFile&);
  DirectIOFile& operator=(const DirectIOFile&);
  DirectIOFile(DirectIOFile&&);
  DirectIOFile& operator=(DirectIOFile&&);

  explicit DirectIOFile(const std::string& path, AccessMode access_mode,
                        OpenMode open_mode = OpenMode::Default);

  bool Open(const std::string& path, AccessMode access_mode,
            OpenMode open_mode = OpenMode::Default);

  bool Close();

  bool IsOpen() const;

  // An offset from the start of the file may be specified directly.
  // These explicit offset versions entirely ignore the current file position.
  // They are thread safe, even when used on the same object.

  bool OffsetRead(u64 offset, u8* out_ptr, u64 size);
  bool OffsetRead(u64 offset, std::span<u8> out_data)
  {
    return OffsetRead(offset, out_data.data(), out_data.size());
  }
  bool OffsetWrite(u64 offset, const u8* in_ptr, u64 size);
  bool OffsetWrite(auto offset, std::span<const u8> in_data)
  {
    return OffsetWrite(offset, in_data.data(), in_data.size());
  }

  // These Read/Write functions advance the current position on success.

  bool Read(u8* out_ptr, u64 size)
  {
    if (!OffsetRead(m_current_offset, out_ptr, size))
      return false;
    m_current_offset += size;
    return true;
  }
  bool Read(std::span<u8> out_data) { return Read(out_data.data(), out_data.size()); }

  bool Write(const u8* in_ptr, u64 size)
  {
    if (!OffsetWrite(m_current_offset, in_ptr, size))
      return false;
    m_current_offset += size;
    return true;
  }
  bool Write(std::span<const u8> in_data) { return Write(in_data.data(), in_data.size()); }

  // Returns 0 on error.
  u64 GetSize() const;

  bool Seek(s64 offset, SeekOrigin origin);

  // Returns 0 when not open.
  u64 Tell() const { return m_current_offset; }

  bool Flush();

  auto GetHandle() const
  {
#if defined(_WIN32)
    return m_handle;
#else
    return m_fd;
#endif
  }

private:
  void Swap(DirectIOFile& other);
  DirectIOFile Duplicate() const;

#if defined(_WIN32)
  // A workaround to avoid including <windows.h> in this header.
  // HANDLE is just void* and INVALID_HANDLE_VALUE is -1.
  using HandleType = void*;
  HandleType m_handle{HandleType(-1)};
#else
  using HandleType = int;
  HandleType m_fd{-1};
#endif

  u64 m_current_offset{};
};

// These take an open file handle to avoid failures from other processes trying to open our files.
// This is mainly an issue on Windows.

bool Resize(DirectIOFile& file, u64 size);

// Attempts to replace a destination file if one already exists.
// Note: Windows uses `file`. Elsewhere uses `source_path`, but `file` is checked for openness.
bool Rename(DirectIOFile& file, const std::string& source_path,
            const std::string& destination_path);
// Note: Ditto, only Windows actually uses the file handle. Provide both.
bool Delete(DirectIOFile& file, const std::string& filename);

}  // namespace File