OXYGENHUB
◆ main openmsx / src / fdc / DirAsDSK.hh
6.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef DIRASDSK_HH
2
#define DIRASDSK_HH
3
4
#include "DiskImageUtils.hh"
5
#include "EmuTime.hh"
6
#include "FileOperations.hh"
7
#include "SectorBasedDisk.hh"
8
9
#include "hash_map.hh"
10
11
#include <utility>
12
13
namespace openmsx {
14
15
class DiskChanger;
16
class CliComm;
17
18
class DirAsDSK final : public SectorBasedDisk
19
{
20
public:
21
	enum class SyncMode : uint8_t { READONLY, FULL };
22
	enum class BootSectorType : uint8_t { DOS1, DOS2 };
23
24
public:
25
	DirAsDSK(DiskChanger& diskChanger, CliComm& cliComm,
26
	         const Filename& hostDir, SyncMode syncMode,
27
	         BootSectorType bootSectorType);
28
29
	// SectorBasedDisk
30
	void readSectorImpl (size_t sector,       SectorBuffer& buf) override;
31
	void writeSectorImpl(size_t sector, const SectorBuffer& buf) override;
32
	[[nodiscard]] bool isWriteProtectedImpl() const override;
33
	[[nodiscard]] bool hasChanged() const override;
34
	void checkCaches() override;
35
36
private:
37
	struct DirIndex {
38
		DirIndex() = default;
39
		DirIndex(unsigned sector_, unsigned idx_)
40
			: sector(sector_), idx(idx_) {}
41
		[[nodiscard]] constexpr bool operator==(const DirIndex&) const = default;
42
43
		unsigned sector;
44
		unsigned idx;
45
	};
46
	struct HashDirIndex {
47
		auto operator()(const DirIndex& d) const {
48
			std::hash<unsigned> subHasher;
49
			return 31 * subHasher(d.sector)
50
			          + subHasher(d.idx);
51
		}
52
	};
53
	struct MapDir {
54
		std::string hostName; // path relative to 'hostDir'
55
		// The following two are used to detect changes in the host
56
		// file compared to the last host->virtual-disk sync.
57
		time_t mtime; // Modification time of host file at the time of
58
		              // the last sync.
59
		size_t filesize; // Host file size, normally the same as msx
60
		                 // filesize, except when the host file was
61
		                 // truncated.
62
	};
63
64
	[[nodiscard]] std::span<SectorBuffer> fat();
65
	[[nodiscard]] std::span<SectorBuffer> fat2();
66
	[[nodiscard]] MSXDirEntry& msxDir(DirIndex dirIndex);
67
	void writeFATSector (unsigned sector, const SectorBuffer& buf);
68
	void writeDIRSector (unsigned sector, DirIndex dirDirIndex,
69
	                     const SectorBuffer& buf);
70
	void writeDataSector(unsigned sector, const SectorBuffer& buf);
71
	void writeDIREntry(DirIndex dirIndex, DirIndex dirDirIndex,
72
	                   const MSXDirEntry& newEntry);
73
	void syncWithHost();
74
	void checkDeletedHostFiles();
75
	void deleteMSXFile(DirIndex dirIndex);
76
	void deleteMSXFilesInDir(unsigned msxDirSector);
77
	void freeFATChain(unsigned cluster);
78
	void addNewHostFiles(const std::string& hostSubDir, unsigned msxDirSector);
79
	void addNewDirectory(const std::string& hostSubDir, const std::string& hostName,
80
	                     unsigned msxDirSector, const FileOperations::Stat& fst);
81
	void addNewHostFile(const std::string& hostSubDir, const std::string& hostName,
82
	                    unsigned msxDirSector, const FileOperations::Stat& fst);
83
	[[nodiscard]] DirIndex fillMSXDirEntry(
84
		const std::string& hostSubDir, const std::string& hostName,
85
		unsigned msxDirSector);
86
	[[nodiscard]] DirIndex getFreeDirEntry(unsigned msxDirSector);
87
	[[nodiscard]] DirIndex findHostFileInDSK(std::string_view hostName) const;
88
	[[nodiscard]] bool checkFileUsedInDSK(std::string_view hostName) const;
89
	[[nodiscard]] unsigned nextMsxDirSector(unsigned sector);
90
	[[nodiscard]] bool checkMSXFileExists(std::span<const char, 11> msxfilename,
91
	                                      unsigned msxDirSector);
92
	void checkModifiedHostFiles();
93
	void setMSXTimeStamp(DirIndex dirIndex, const FileOperations::Stat& fst);
94
	void importHostFile(DirIndex dirIndex, const FileOperations::Stat& fst);
95
	void exportToHost(DirIndex dirIndex, DirIndex dirDirIndex);
96
	void exportToHostDir (DirIndex dirIndex, const std::string& hostName);
97
	void exportToHostFile(DirIndex dirIndex, const std::string& hostName);
98
	[[nodiscard]] unsigned findNextFreeCluster(unsigned cluster);
99
	[[nodiscard]] unsigned findFirstFreeCluster();
100
	[[nodiscard]] unsigned getFreeCluster();
101
	[[nodiscard]] unsigned readFAT(unsigned cluster);
102
	void writeFAT12(unsigned cluster, unsigned val);
103
	void exportFileFromFATChange(unsigned cluster, std::span<SectorBuffer> oldFAT);
104
	std::pair<unsigned, unsigned> getChainStart(unsigned cluster);
105
	[[nodiscard]] std::optional<DirIndex> isDirSector(unsigned sector);
106
107
	struct DirEntryForClusterResult {
108
		DirIndex dirIndex;
109
		DirIndex dirDirIndex;
110
	};
111
	[[nodiscard]] std::optional<DirEntryForClusterResult> getDirEntryForCluster(unsigned cluster);
112
113
	void unmapHostFiles(unsigned msxDirSector);
114
	template<typename FUNC> bool scanMsxDirs(
115
		FUNC&& func, unsigned msxDirSector);
116
	friend struct NullScanner;
117
	friend struct DirScanner;
118
	friend struct IsDirSector;
119
	friend struct DirEntryForCluster;
120
	friend struct UnmapHostFiles;
121
122
	// internal helper functions
123
	[[nodiscard]] unsigned readFATHelper(std::span<const SectorBuffer> fat, unsigned cluster) const;
124
	void writeFATHelper(std::span<SectorBuffer> fat, unsigned cluster, unsigned val) const;
125
	[[nodiscard]] unsigned clusterToSector(unsigned cluster) const;
126
	[[nodiscard]] std::pair<unsigned, unsigned> sectorToClusterOffset(unsigned sector) const;
127
	[[nodiscard]] unsigned sectorToCluster(unsigned sector) const;
128
129
	// One of the standard 9-sectors/track MSX disk formats, selected from the
130
	// drive's track-count and number of sides (see getDiskFormat()).
131
	struct DiskFormat {
132
		uint8_t mediaDescriptor;
133
		unsigned sectorsPerCluster;
134
		unsigned sectorsPerDir; // number of sectors in the root directory
135
	};
136
	[[nodiscard]] static DiskFormat getDiskFormat(unsigned numTracks, bool doubleSided);
137
138
private:
139
	DiskChanger& diskChanger; // used to query time / report disk change
140
	CliComm& cliComm; // TODO don't use CliComm to report errors/warnings
141
	const std::string hostDir;
142
	const SyncMode syncMode;
143
144
	EmuTime lastAccess = EmuTime::zero(); // last time there was a sector read/write
145
146
	// For each directory entry that has a mapped host file/directory we
147
	// store the name, last modification time and size of the corresponding
148
	// host file/dir.
149
	using MapDirs = hash_map<DirIndex, MapDir, HashDirIndex>;
150
	MapDirs mapDirs;
151
152
	// Disk format/geometry, derived from the drive's track-count and #sides.
153
	const DiskFormat diskFormat;
154
	const unsigned sectorsPerCluster;
155
	const unsigned sectorsPerDir;
156
	// varying root parameters
157
	const unsigned nofSectors;
158
	const unsigned nofSectorsPerFat;
159
	// parameters that depend on these and thus also vary
160
	const unsigned firstSector2ndFAT;
161
	const unsigned firstDirSector;
162
	const unsigned firstDataSector;
163
	const unsigned maxCluster; // First cluster number that can NOT be used anymore.
164
165
	// Storage for the whole virtual disk.
166
	std::vector<SectorBuffer> sectors;
167
};
168
169
} // namespace openmsx
170
171
#endif