1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4 
5     hardisk.c
6 
7     Generic MAME hard disk implementation, with differencing files
8 
9 ***************************************************************************/
10 
11 #include <cassert>
12 #include "harddisk.h"
13 #include "osdcore.h"
14 #include <cstdlib>
15 
16 /***************************************************************************
17     TYPE DEFINITIONS
18 ***************************************************************************/
19 
20 struct hard_disk_file
21 {
22 	chd_file *          chd;                /* CHD file */
23 	util::core_file     *fhandle;           /* core_file if not a CHD */
24 	hard_disk_info      info;               /* hard disk info */
25 };
26 
27 
28 
29 /***************************************************************************
30     CORE IMPLEMENTATION
31 ***************************************************************************/
32 
33 /*-------------------------------------------------
34     hard_disk_open - open a hard disk handle,
35     given a chd_file
36 -------------------------------------------------*/
37 
hard_disk_open(chd_file * chd)38 hard_disk_file *hard_disk_open(chd_file *chd)
39 {
40 	int cylinders, heads, sectors, sectorbytes;
41 	hard_disk_file *file;
42 	std::string metadata;
43 	chd_error err;
44 
45 	/* punt if no CHD */
46 	if (chd == nullptr)
47 		return nullptr;
48 
49 	/* read the hard disk metadata */
50 	err = chd->read_metadata(HARD_DISK_METADATA_TAG, 0, metadata);
51 	if (err != CHDERR_NONE)
52 		return nullptr;
53 
54 	/* parse the metadata */
55 	if (sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, &cylinders, &heads, &sectors, &sectorbytes) != 4)
56 		return nullptr;
57 
58 	/* allocate memory for the hard disk file */
59 	file = (hard_disk_file *)malloc(sizeof(hard_disk_file));
60 	if (file == nullptr)
61 		return nullptr;
62 
63 	/* fill in the data */
64 	file->chd = chd;
65 	file->fhandle = nullptr;
66 	file->info.cylinders = cylinders;
67 	file->info.heads = heads;
68 	file->info.sectors = sectors;
69 	file->info.sectorbytes = sectorbytes;
70 	file->info.fileoffset = 0;
71 	return file;
72 }
73 
hard_disk_open(util::core_file & corefile,uint32_t skipoffs)74 hard_disk_file *hard_disk_open(util::core_file &corefile, uint32_t skipoffs)
75 {
76 	hard_disk_file *file;
77 
78 	/* allocate memory for the hard disk file */
79 	file = (hard_disk_file *)malloc(sizeof(hard_disk_file));
80 	if (file == nullptr)
81 		return nullptr;
82 
83 	file->chd = nullptr;
84 	file->fhandle = &corefile;
85 	file->info.sectorbytes = 512;
86 	file->info.cylinders = 0;
87 	file->info.heads = 0;
88 	file->info.sectors = 0;
89 	file->info.fileoffset = skipoffs;
90 
91 	// attempt to guess geometry in case this is an ATA situation
92 	for (uint32_t totalsectors = (corefile.size() - skipoffs) / file->info.sectorbytes; ; totalsectors++)
93 		for (uint32_t cursectors = 63; cursectors > 1; cursectors--)
94 			if (totalsectors % cursectors == 0)
95 			{
96 				uint32_t totalheads = totalsectors / cursectors;
97 				for (uint32_t curheads = 16; curheads > 1; curheads--)
98 					if (totalheads % curheads == 0)
99 					{
100 						file->info.cylinders = totalheads / curheads;
101 						file->info.heads = curheads;
102 						file->info.sectors = cursectors;
103 						osd_printf_verbose("Guessed CHS of %d/%d/%d\n", file->info.cylinders, file->info.heads, file->info.sectors);
104 						return file;
105 					}
106 			}
107 
108 	return file;
109 }
110 
111 
112 /*-------------------------------------------------
113     hard_disk_close - close a hard disk handle
114 -------------------------------------------------*/
115 
hard_disk_close(hard_disk_file * file)116 void hard_disk_close(hard_disk_file *file)
117 {
118 	if (file->fhandle)
119 	{
120 		file->fhandle->flush();
121 	}
122 
123 	free(file);
124 }
125 
126 
127 /*-------------------------------------------------
128     hard_disk_get_chd - get a handle to a CHD
129     from a hard disk
130 -------------------------------------------------*/
131 
hard_disk_get_chd(hard_disk_file * file)132 chd_file *hard_disk_get_chd(hard_disk_file *file)
133 {
134 	return file->chd;
135 }
136 
137 
138 /*-------------------------------------------------
139     hard_disk_get_info - return information about
140     a hard disk
141 -------------------------------------------------*/
142 
143 /**
144  * @fn  hard_disk_info *hard_disk_get_info(hard_disk_file *file)
145  *
146  * @brief   Hard disk get information.
147  *
148  * @param [in,out]  file    If non-null, the file.
149  *
150  * @return  null if it fails, else a hard_disk_info*.
151  */
152 
hard_disk_get_info(hard_disk_file * file)153 hard_disk_info *hard_disk_get_info(hard_disk_file *file)
154 {
155 	return &file->info;
156 }
157 
158 
159 /*-------------------------------------------------
160     hard_disk_read - read sectors from a hard
161     disk
162 -------------------------------------------------*/
163 
164 /**
165  * @fn  uint32_t hard_disk_read(hard_disk_file *file, uint32_t lbasector, void *buffer)
166  *
167  * @brief   Hard disk read.
168  *
169  * @param [in,out]  file    If non-null, the file.
170  * @param   lbasector       The lbasector.
171  * @param [in,out]  buffer  If non-null, the buffer.
172  *
173  * @return  An uint32_t.
174  */
175 
hard_disk_read(hard_disk_file * file,uint32_t lbasector,void * buffer)176 uint32_t hard_disk_read(hard_disk_file *file, uint32_t lbasector, void *buffer)
177 {
178 	if (file->chd)
179 	{
180 		chd_error err = file->chd->read_units(lbasector, buffer);
181 		return (err == CHDERR_NONE);
182 	}
183 	else
184 	{
185 		uint32_t actual = 0;
186 		file->fhandle->seek(file->info.fileoffset + (lbasector * file->info.sectorbytes), SEEK_SET);
187 		actual = file->fhandle->read(buffer, file->info.sectorbytes);
188 		return (actual == file->info.sectorbytes);
189 	}
190 }
191 
192 
193 /*-------------------------------------------------
194     hard_disk_write - write  sectors to a hard
195     disk
196 -------------------------------------------------*/
197 
198 /**
199  * @fn  uint32_t hard_disk_write(hard_disk_file *file, uint32_t lbasector, const void *buffer)
200  *
201  * @brief   Hard disk write.
202  *
203  * @param [in,out]  file    If non-null, the file.
204  * @param   lbasector       The lbasector.
205  * @param   buffer          The buffer.
206  *
207  * @return  An uint32_t.
208  */
209 
hard_disk_write(hard_disk_file * file,uint32_t lbasector,const void * buffer)210 uint32_t hard_disk_write(hard_disk_file *file, uint32_t lbasector, const void *buffer)
211 {
212 	if (file->chd)
213 	{
214 		chd_error err = file->chd->write_units(lbasector, buffer);
215 		return (err == CHDERR_NONE);
216 	}
217 	else
218 	{
219 		uint32_t actual = 0;
220 		file->fhandle->seek(file->info.fileoffset + (lbasector * file->info.sectorbytes), SEEK_SET);
221 		actual = file->fhandle->write(buffer, file->info.sectorbytes);
222 		return (actual == file->info.sectorbytes);
223 	}
224 }
225