1 /*
2  *  Copyright (C) 2002-2021  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #ifndef DOSBOX_DRIVES_H
20 #define DOSBOX_DRIVES_H
21 
22 #include "dosbox.h"
23 
24 #include <memory>
25 #include <unordered_set>
26 #include <string>
27 #include <vector>
28 
29 #include "dos_inc.h"
30 #include "dos_system.h"
31 
32 bool WildFileCmp(const char * file, const char * wild);
33 void Set_Label(char const * const input, char * const output, bool cdrom);
34 std::string To_Label(const char* name);
35 
36 class DriveManager {
37 public:
38 	static void AppendDisk(int drive, DOS_Drive* disk);
39 	static void InitializeDrive(int drive);
40 	static int UnmountDrive(int drive);
41 //	static void CycleDrive(bool pressed);
42 //	static void CycleDisk(bool pressed);
43 	static void CycleDisks(int drive, bool notify);
44 	static void CycleAllDisks(void);
45 	static void Init(Section* sec);
46 
47 private:
48 	static struct DriveInfo {
49 		std::vector<DOS_Drive*> disks = {};
50 		int currentDisk = 0;
51 	} driveInfos[DOS_DRIVES];
52 
53 	static int currentDrive;
54 };
55 
56 class localDrive : public DOS_Drive {
57 public:
58 	localDrive(const char * startdir,Bit16u _bytes_sector,Bit8u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid);
59 	virtual bool FileOpen(DOS_File * * file,char * name,Bit32u flags);
60 	virtual FILE *GetSystemFilePtr(char const * const name, char const * const type);
61 	virtual bool GetSystemFilename(char* sysName, char const * const dosName);
62 	virtual bool FileCreate(DOS_File * * file,char * name,Bit16u attributes);
63 	virtual bool FileUnlink(char * name);
64 	virtual bool RemoveDir(char * dir);
65 	virtual bool MakeDir(char * dir);
66 	virtual bool TestDir(char * dir);
67 	virtual bool FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst=false);
68 	virtual bool FindNext(DOS_DTA & dta);
69 	virtual bool GetFileAttr(char * name,Bit16u * attr);
70 	virtual bool Rename(char * oldname,char * newname);
71 	virtual bool AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters);
72 	virtual bool FileExists(const char* name);
73 	virtual bool FileStat(const char* name, FileStat_Block * const stat_block);
74 	virtual Bit8u GetMediaByte(void);
75 	virtual bool isRemote(void);
76 	virtual bool isRemovable(void);
77 	virtual Bits UnMount(void);
GetBasedir()78 	const char *GetBasedir() const { return basedir; }
79 
80 protected:
81 	char basedir[CROSS_LEN] = "";
82 	struct {
83 		char srch_dir[CROSS_LEN] = "";
84 	} srchInfo[MAX_OPENDIRS];
85 
86 private:
87 	bool IsFirstEncounter(const std::string& filename);
88 	std::unordered_set<std::string> write_protected_files;
89 	struct {
90 		Bit16u bytes_sector;
91 		Bit8u sectors_cluster;
92 		Bit16u total_clusters;
93 		Bit16u free_clusters;
94 		Bit8u mediaid;
95 	} allocation;
96 };
97 
98 #ifdef _MSC_VER
99 #pragma pack (1)
100 #endif
101 struct bootstrap {
102 	Bit8u  nearjmp[3];
103 	Bit8u  oemname[8];
104 	Bit16u bytespersector;
105 	Bit8u  sectorspercluster;
106 	Bit16u reservedsectors;
107 	Bit8u  fatcopies;
108 	Bit16u rootdirentries;
109 	Bit16u totalsectorcount;
110 	Bit8u  mediadescriptor;
111 	Bit16u sectorsperfat;
112 	Bit16u sectorspertrack;
113 	Bit16u headcount;
114 	/* 32-bit FAT extensions */
115 	Bit32u hiddensectorcount;
116 	Bit32u totalsecdword;
117 	Bit8u  bootcode[474];
118 	Bit8u  magic1; /* 0x55 */
119 	Bit8u  magic2; /* 0xaa */
120 } GCC_ATTRIBUTE(packed);
121 
122 struct direntry {
123 	Bit8u entryname[11];
124 	Bit8u attrib;
125 	Bit8u NTRes;
126 	Bit8u milliSecondStamp;
127 	Bit16u crtTime;
128 	Bit16u crtDate;
129 	Bit16u accessDate;
130 	Bit16u hiFirstClust;
131 	Bit16u modTime;
132 	Bit16u modDate;
133 	Bit16u loFirstClust;
134 	Bit32u entrysize;
135 } GCC_ATTRIBUTE(packed);
136 
137 struct partTable {
138 	Bit8u booter[446];
139 	struct {
140 		Bit8u bootflag;
141 		Bit8u beginchs[3];
142 		Bit8u parttype;
143 		Bit8u endchs[3];
144 		Bit32u absSectStart;
145 		Bit32u partSize;
146 	} pentry[4];
147 	Bit8u  magic1; /* 0x55 */
148 	Bit8u  magic2; /* 0xaa */
149 } GCC_ATTRIBUTE(packed);
150 
151 #ifdef _MSC_VER
152 #pragma pack ()
153 #endif
154 //Forward
155 class imageDisk;
156 class fatDrive final : public DOS_Drive {
157 public:
158 	fatDrive(const char * sysFilename, Bit32u bytesector, Bit32u cylsector, Bit32u headscyl, Bit32u cylinders, Bit32u startSector);
159 	fatDrive(const fatDrive&) = delete; // prevent copying
160 	fatDrive& operator= (const fatDrive&) = delete; // prevent assignment
161 	virtual bool FileOpen(DOS_File * * file,char * name,Bit32u flags);
162 	virtual bool FileCreate(DOS_File * * file,char * name,Bit16u attributes);
163 	virtual bool FileUnlink(char * name);
164 	virtual bool RemoveDir(char * dir);
165 	virtual bool MakeDir(char * dir);
166 	virtual bool TestDir(char * dir);
167 	virtual bool FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst=false);
168 	virtual bool FindNext(DOS_DTA & dta);
169 	virtual bool GetFileAttr(char * name,Bit16u * attr);
170 	virtual bool Rename(char * oldname,char * newname);
171 	virtual bool AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters);
172 	virtual bool FileExists(const char* name);
173 	virtual bool FileStat(const char* name, FileStat_Block * const stat_block);
174 	virtual Bit8u GetMediaByte(void);
175 	virtual bool isRemote(void);
176 	virtual bool isRemovable(void);
177 	virtual Bits UnMount(void);
EmptyCache(void)178 	virtual void EmptyCache(void){}
179 public:
180 	Bit8u readSector(Bit32u sectnum, void * data);
181 	Bit8u writeSector(Bit32u sectnum, void * data);
182 	Bit32u getAbsoluteSectFromBytePos(Bit32u startClustNum, Bit32u bytePos);
183 	Bit32u getSectorSize(void);
184 	Bit32u getClusterSize(void);
185 	Bit32u getAbsoluteSectFromChain(Bit32u startClustNum, Bit32u logicalSector);
186 	bool allocateCluster(Bit32u useCluster, Bit32u prevCluster);
187 	Bit32u appendCluster(Bit32u startCluster);
188 	void deleteClustChain(Bit32u startCluster, Bit32u bytePos);
189 	Bit32u getFirstFreeClust(void);
190 	bool directoryBrowse(Bit32u dirClustNumber, direntry *useEntry, Bit32s entNum, Bit32s start=0);
191 	bool directoryChange(Bit32u dirClustNumber, direntry *useEntry, Bit32s entNum);
192 	std::shared_ptr<imageDisk> loadedDisk;
193 	bool created_successfully;
194 private:
195 	Bit32u getClusterValue(Bit32u clustNum);
196 	void setClusterValue(Bit32u clustNum, Bit32u clustValue);
197 	Bit32u getClustFirstSect(Bit32u clustNum);
198 	bool FindNextInternal(Bit32u dirClustNumber, DOS_DTA & dta, direntry *foundEntry);
199 	bool getDirClustNum(char * dir, Bit32u * clustNum, bool parDir);
200 	bool getFileDirEntry(char const * const filename, direntry * useEntry, Bit32u * dirClust, Bit32u * subEntry);
201 	bool addDirectoryEntry(Bit32u dirClustNumber, direntry useEntry);
202 	void zeroOutCluster(Bit32u clustNumber);
203 	bool getEntryName(char *fullname, char *entname);
204 
205 	bootstrap bootbuffer;
206 	bool absolute;
207 	Bit8u fattype;
208 	Bit32u CountOfClusters;
209 	Bit32u partSectOff;
210 	Bit32u firstDataSector;
211 	Bit32u firstRootDirSect;
212 
213 	Bit32u cwdDirCluster;
214 
215 	Bit8u fatSectBuffer[1024];
216 	Bit32u curFatSect;
217 };
218 
219 class cdromDrive final : public localDrive
220 {
221 public:
222 	cdromDrive(const char _driveLetter, const char * startdir,Bit16u _bytes_sector,Bit8u _sectors_cluster,Bit16u _total_clusters,Bit16u _free_clusters,Bit8u _mediaid, int& error);
223 	virtual bool FileOpen(DOS_File * * file,char * name,Bit32u flags);
224 	virtual bool FileCreate(DOS_File * * file,char * name,Bit16u attributes);
225 	virtual bool FileUnlink(char * name);
226 	virtual bool RemoveDir(char * dir);
227 	virtual bool MakeDir(char * dir);
228 	virtual bool Rename(char * oldname,char * newname);
229 	virtual bool GetFileAttr(char * name,Bit16u * attr);
230 	virtual bool FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst=false);
231 	virtual void SetDir(const char* path);
232 	virtual bool isRemote(void);
233 	virtual bool isRemovable(void);
234 	virtual Bits UnMount(void);
235 private:
236 	Bit8u subUnit;
237 	char driveLetter;
238 };
239 
240 #ifdef _MSC_VER
241 #pragma pack (1)
242 #endif
243 struct isoPVD {
244 	Bit8u type;
245 	Bit8u standardIdent[5];
246 	Bit8u version;
247 	Bit8u unused1;
248 	Bit8u systemIdent[32];
249 	Bit8u volumeIdent[32];
250 	Bit8u unused2[8];
251 	Bit32u volumeSpaceSizeL;
252 	Bit32u volumeSpaceSizeM;
253 	Bit8u unused3[32];
254 	Bit16u volumeSetSizeL;
255 	Bit16u volumeSetSizeM;
256 	Bit16u volumeSeqNumberL;
257 	Bit16u volumeSeqNumberM;
258 	Bit16u logicBlockSizeL;
259 	Bit16u logicBlockSizeM;
260 	Bit32u pathTableSizeL;
261 	Bit32u pathTableSizeM;
262 	Bit32u locationPathTableL;
263 	Bit32u locationOptPathTableL;
264 	Bit32u locationPathTableM;
265 	Bit32u locationOptPathTableM;
266 	Bit8u rootEntry[34];
267 	Bit32u unused4[1858];
268 } GCC_ATTRIBUTE(packed);
269 
270 struct isoDirEntry {
271 	Bit8u length;
272 	Bit8u extAttrLength;
273 	Bit32u extentLocationL;
274 	Bit32u extentLocationM;
275 	Bit32u dataLengthL;
276 	Bit32u dataLengthM;
277 	Bit8u dateYear;
278 	Bit8u dateMonth;
279 	Bit8u dateDay;
280 	Bit8u timeHour;
281 	Bit8u timeMin;
282 	Bit8u timeSec;
283 	Bit8u timeZone;
284 	Bit8u fileFlags;
285 	Bit8u fileUnitSize;
286 	Bit8u interleaveGapSize;
287 	Bit16u VolumeSeqNumberL;
288 	Bit16u VolumeSeqNumberM;
289 	Bit8u fileIdentLength;
290 	Bit8u ident[222];
291 } GCC_ATTRIBUTE(packed);
292 
293 #ifdef _MSC_VER
294 #pragma pack ()
295 #endif
296 
297 #if defined (WORDS_BIGENDIAN)
298 #define EXTENT_LOCATION(de)	((de).extentLocationM)
299 #define DATA_LENGTH(de)		((de).dataLengthM)
300 #else
301 #define EXTENT_LOCATION(de)	((de).extentLocationL)
302 #define DATA_LENGTH(de)		((de).dataLengthL)
303 #endif
304 
305 #define ISO_FRAMESIZE		2048
306 #define ISO_ASSOCIATED		4
307 #define ISO_DIRECTORY		2
308 #define ISO_HIDDEN		1
309 #define ISO_MAX_FILENAME_LENGTH 37
310 #define ISO_MAXPATHNAME		256
311 #define ISO_FIRST_VD		16
312 #define IS_ASSOC(fileFlags)	(fileFlags & ISO_ASSOCIATED)
313 #define IS_DIR(fileFlags)	(fileFlags & ISO_DIRECTORY)
314 #define IS_HIDDEN(fileFlags)	(fileFlags & ISO_HIDDEN)
315 #define ISO_MAX_HASH_TABLE_SIZE 	100
316 
317 class isoDrive final : public DOS_Drive {
318 public:
319 	isoDrive(char driveLetter, const char* device_name, Bit8u mediaid, int &error);
320 	~isoDrive();
321 	virtual bool FileOpen(DOS_File **file, char *name, Bit32u flags);
322 	virtual bool FileCreate(DOS_File **file, char *name, Bit16u attributes);
323 	virtual bool FileUnlink(char *name);
324 	virtual bool RemoveDir(char *dir);
325 	virtual bool MakeDir(char *dir);
326 	virtual bool TestDir(char *dir);
327 	virtual bool FindFirst(char *_dir, DOS_DTA &dta, bool fcb_findfirst);
328 	virtual bool FindNext(DOS_DTA &dta);
329 	virtual bool GetFileAttr(char *name, Bit16u *attr);
330 	virtual bool Rename(char * oldname,char * newname);
331 	virtual bool AllocationInfo(Bit16u *bytes_sector, Bit8u *sectors_cluster, Bit16u *total_clusters, Bit16u *free_clusters);
332 	virtual bool FileExists(const char *name);
333    	virtual bool FileStat(const char *name, FileStat_Block *const stat_block);
334 	virtual Bit8u GetMediaByte(void);
EmptyCache(void)335 	virtual void EmptyCache(void){}
336 	virtual bool isRemote(void);
337 	virtual bool isRemovable(void);
338 	virtual Bits UnMount(void);
339 	bool readSector(Bit8u *buffer, Bit32u sector);
GetLabel()340 	virtual const char *GetLabel() { return discLabel; }
341 	virtual void Activate(void);
342 private:
343 	int  readDirEntry(isoDirEntry *de, Bit8u *data);
344 	bool loadImage();
345 	bool lookupSingle(isoDirEntry *de, const char *name, Bit32u sectorStart, Bit32u length);
346 	bool lookup(isoDirEntry *de, const char *path);
347 	int  UpdateMscdex(char driveLetter, const char* physicalPath, Bit8u& subUnit);
348 	int  GetDirIterator(const isoDirEntry* de);
349 	bool GetNextDirEntry(const int dirIterator, isoDirEntry* de);
350 	void FreeDirIterator(const int dirIterator);
351 	bool ReadCachedSector(Bit8u** buffer, const Bit32u sector);
352 
353 	struct DirIterator {
354 		bool valid;
355 		bool root;
356 		Bit32u currentSector;
357 		Bit32u endSector;
358 		Bit32u pos;
359 	} dirIterators[MAX_OPENDIRS];
360 
361 	int nextFreeDirIterator;
362 
363 	struct SectorHashEntry {
364 		bool valid;
365 		Bit32u sector;
366 		Bit8u data[ISO_FRAMESIZE];
367 	} sectorHashEntries[ISO_MAX_HASH_TABLE_SIZE];
368 
369 	bool iso;
370 	bool dataCD;
371 	isoDirEntry rootEntry;
372 	Bit8u mediaid;
373 	char fileName[CROSS_LEN];
374 	Bit8u subUnit;
375 	char driveLetter;
376 	char discLabel[32];
377 };
378 
379 struct VFILE_Block;
380 
381 class Virtual_Drive final : public DOS_Drive {
382 public:
383 	Virtual_Drive();
384 	bool FileOpen(DOS_File * * file,char * name,Bit32u flags);
385 	bool FileCreate(DOS_File * * file,char * name,Bit16u attributes);
386 	bool FileUnlink(char * name);
387 	bool RemoveDir(char * dir);
388 	bool MakeDir(char * dir);
389 	bool TestDir(char * dir);
390 	bool FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst);
391 	bool FindNext(DOS_DTA & dta);
392 	bool GetFileAttr(char * name,Bit16u * attr);
393 	bool Rename(char * oldname,char * newname);
394 	bool AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters);
395 	bool FileExists(const char* name);
396 	bool FileStat(const char* name, FileStat_Block* const stat_block);
397 	Bit8u GetMediaByte(void);
EmptyCache(void)398 	void EmptyCache(void){}
399 	bool isRemote(void);
400 	virtual bool isRemovable(void);
401 	virtual Bits UnMount(void);
402 	virtual char const* GetLabel(void);
403 private:
404 	Virtual_Drive(const Virtual_Drive&); // prevent copying
405 	Virtual_Drive& operator= (const Virtual_Drive&); // prevent assignment
406 	VFILE_Block * search_file;
407 };
408 
409 class Overlay_Drive final : public localDrive {
410 public:
411 	Overlay_Drive(const char *startdir,
412 	              const char *overlay,
413 	              uint16_t _bytes_sector,
414 	              uint8_t _sectors_cluster,
415 	              uint16_t _total_clusters,
416 	              uint16_t _free_clusters,
417 	              uint8_t _mediaid,
418 	              uint8_t &error);
419 
420 	virtual bool FileOpen(DOS_File **file, char *name, uint32_t flags);
421 	virtual bool FileCreate(DOS_File * * file,char * name,Bit16u /*attributes*/);
422 	virtual bool FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst);
423 	virtual bool FindNext(DOS_DTA & dta);
424 	virtual bool FileUnlink(char * name);
425 	virtual bool GetFileAttr(char * name,Bit16u * attr);
426 	virtual bool FileExists(const char* name);
427 	virtual bool Rename(char * oldname,char * newname);
428 	virtual bool FileStat(const char* name, FileStat_Block * const stat_block);
429 	virtual void EmptyCache(void);
430 
431 	FILE *create_file_in_overlay(const char *dos_filename, char const *mode);
432 
433 	virtual Bits UnMount(void);
434 	virtual bool TestDir(char * dir);
435 	virtual bool RemoveDir(char * dir);
436 	virtual bool MakeDir(char * dir);
437 private:
438 	char overlaydir[CROSS_LEN];
439 	bool Sync_leading_dirs(const char* dos_filename);
440 	void add_DOSname_to_cache(const char* name);
441 	void remove_DOSname_from_cache(const char* name);
442 	void add_DOSdir_to_cache(const char* name);
443 	void remove_DOSdir_from_cache(const char* name);
444 	void update_cache(bool read_directory_contents = false);
445 
446 	std::vector<std::string> deleted_files_in_base; //Set is probably better, or some other solution (involving the disk).
447 	std::vector<std::string> deleted_paths_in_base; //Currently only used to hide the overlay folder.
448 	std::string overlap_folder;
449 	void add_deleted_file(const char* name, bool create_on_disk);
450 	void remove_deleted_file(const char* name, bool create_on_disk);
451 	bool is_deleted_file(const char* name);
452 	void add_deleted_path(const char* name, bool create_on_disk);
453 	void remove_deleted_path(const char* name, bool create_on_disk);
454 	bool is_deleted_path(const char* name);
455 	bool check_if_leading_is_deleted(const char* name);
456 
457 	bool is_dir_only_in_overlay(const char* name); //cached
458 
459 
460 	void remove_special_file_from_disk(const char* dosname, const char* operation);
461 	void add_special_file_to_disk(const char* dosname, const char* operation);
462 	std::string create_filename_of_special_operation(const char* dosname, const char* operation);
463 	void convert_overlay_to_DOSname_in_base(char* dirname );
464 	//For caching the update_cache routine.
465 	std::vector<std::string> DOSnames_cache; //Also set is probably better.
466 	std::vector<std::string> DOSdirs_cache; //Can not blindly change its type. it is important that subdirs come after the parent directory.
467 	const std::string special_prefix;
468 };
469 
470 #endif
471