The Pedigree Project 0.1
msdos.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "msdos.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/Spinlock.h"
24#include "pedigree/kernel/machine/Disk.h"
25#include "pedigree/kernel/utilities/StaticString.h"
26#include "pedigree/kernel/utilities/String.h"
27#include "pedigree/kernel/utilities/utility.h"
28
29#include "Partition.h"
30
31class Device;
32
33static Spinlock g_Lock;
34
35static const char* g_pPartitionTypes[256] = {"Empty",
36 "FAT12",
37 "XENIX root",
38 "XENIX usr",
39 "FAT16 <32M",
40 "Extended",
41 "FAT16",
42 "HPFS/NTFS",
43 "AIX",
44 "AIX bootable",
45 "OS/2 Boot Manag",
46 "W95 FAT32",
47 "W95 FAT32 (LBA)",
48 "",
49 "W95 FAT16 (LBA)",
50 "W95 Ext",
51 "OPUS",
52 "Hidden FAT12",
53 "Compaq diagnost",
54 "",
55 "Hidden FAT16 <3",
56 "",
57 "Hidden FAT16",
58 "Hidden HPFS/NTF",
59 "AST SmartSleep",
60 "",
61 "",
62 "Hidden W95 FAT3",
63 "Hidden W95 FAT3",
64 "",
65 "Hidden W95 FAT1",
66 "",
67 "",
68 "",
69 "",
70 "",
71 "NEC DOS",
72 "",
73 "",
74 "",
75 "",
76 "",
77 "",
78 "",
79 "",
80 "",
81 "",
82 "",
83 "",
84 "",
85 "",
86 "",
87 "",
88 "",
89 "",
90 "",
91 "",
92 "Plan 9",
93 "",
94 "",
95 "PartitionMagic",
96 "",
97 "",
98 "",
99 "Venix 80286",
100 "PPC PReP Boot",
101 "SFS",
102 "",
103 "",
104 "",
105 "",
106 "",
107 "",
108 "",
109 "",
110 "",
111 "",
112 "QNX4.x",
113 "QNX4.x 2nd part",
114 "QNX4.x 3rd part",
115 "OnTrack DM",
116 "OnTrack DM6 Aux",
117 "CP/M",
118 "OnTrack DM6 Aux",
119 "OnTrackDM6",
120 "EZ-Drive",
121 "Golden Bow",
122 "",
123 "",
124 "",
125 "",
126 "",
127 "Priam Edisk",
128 "",
129 "",
130 "",
131 "",
132 "SpeedStor",
133 "",
134 "GNU HURD or Sys",
135 "Novell Netware",
136 "Novell Netware",
137 "",
138 "",
139 "",
140 "",
141 "",
142 "",
143 "",
144 "",
145 "",
146 "",
147 "DiskSecure Mult",
148 "",
149 "",
150 "",
151 "",
152 "PC/IX",
153 "",
154 "",
155 "",
156 "",
157 "",
158 "",
159 "",
160 "",
161 "",
162 "",
163 "Old Minix",
164 "Minix / old Lin",
165 "Linux swap / So",
166 "Linux",
167 "OS/2 hidden C:",
168 "Linux extended",
169 "NTFS volume set",
170 "NTFS volume set",
171 "Linux plaintext",
172 "",
173 "",
174 "",
175 "",
176 "",
177 "Linux LVM",
178 "",
179 "",
180 "",
181 "",
182 "Amoeba",
183 "Amoeba BBT",
184 "",
185 "",
186 "",
187 "",
188 "",
189 "",
190 "",
191 "",
192 "",
193 "",
194 "BSD/OS",
195 "IBM Thinkpad hi",
196 "",
197 "",
198 "",
199 "",
200 "FreeBSD",
201 "OpenBSD",
202 "NeXTSTEP",
203 "Darwin UFS",
204 "NetBSD",
205 "",
206 "Darwin boot",
207 "",
208 "",
209 "",
210 "",
211 "",
212 "",
213 "",
214 "",
215 "",
216 "",
217 "",
218 "BSDI fs",
219 "BSDI swap",
220 "",
221 "",
222 "Boot Wizard hid",
223 "",
224 "",
225 "Solaris boot",
226 "Solaris",
227 "",
228 "DRDOS/sec (FAT-",
229 "",
230 "",
231 "DRDOS/sec (FAT-",
232 "",
233 "DRDOS/sec (FAT-",
234 "Syrinx",
235 "",
236 "",
237 "",
238 "",
239 "",
240 "",
241 "",
242 "",
243 "",
244 "",
245 "",
246 "",
247 "",
248 "",
249 "",
250 "",
251 "",
252 "",
253 "Non-FS data",
254 "CP/M / CTOS / .",
255 "",
256 "",
257 "Dell Utility",
258 "BootIt",
259 "",
260 "DOS access",
261 "",
262 "DOS R/O",
263 "SpeedStor",
264 "",
265 "",
266 "",
267 "",
268 "",
269 "",
270 "BeOS fs",
271 "",
272 "",
273 "EFI GPT",
274 "EFI (FAT-12/16/",
275 "Linux/PA-RISC b",
276 "SpeedStor",
277 "DOS secondary",
278 "",
279 "SpeedStor",
280 "",
281 "",
282 "",
283 "",
284 "",
285 "",
286 "",
287 "",
288 "Linux RAID auto",
289 "LANstep",
290 "BBT"};
291
293static int gNextPartition = 0;
294
295static bool extended(uint8_t type) {
296 return type == 5 || type == 0x0f || type == 0x85;
297}
298
299static bool sectorRange(Disk* disk, uint64_t start, uint64_t count) {
300 const size_t sectorBytes = disk->getNativeBlockSize();
301 const uint64_t sectors = sectorBytes ? disk->getSize() / sectorBytes : 0;
302 return count && start < sectors && count <= sectors - start;
303}
304
305static void registerPartition(const MsdosPartitionInfo& entry, Disk* disk, uint64_t start) {
306 const uint64_t count = LITTLE_TO_HOST32(entry.size);
307 if (!sectorRange(disk, start, count) || !start) {
308 WARNING("MS-DOS: partition outside disk");
309 return;
310 }
311 int number;
312 {
313 LockGuard<Spinlock> guard(g_Lock);
314 number = gNextPartition++;
315 }
316 NormalStaticString label("(");
317 label += number;
318 label += ") ";
319 label += g_pPartitionTypes[entry.type];
320 const size_t bytes = disk->getNativeBlockSize();
321 auto* partition = new Partition(String(label), start * bytes, count * bytes);
322 partition->setParent(disk);
323 disk->addChild(partition);
324}
325
326static bool readEntries(Disk* disk, uint64_t lba, MsdosPartitionInfo* entries) {
327 if (!sectorRange(disk, lba, 1))
328 return false;
329 const uint64_t offset = lba * disk->getNativeBlockSize();
330 const BufferView view = disk->read(offset);
331 if (!view)
332 return false;
333 const bool valid = view.size() >= 512 && view[510] == MSDOS_IDENT_1 && view[511] == MSDOS_IDENT_2;
334 if (valid)
335 MemoryCopy(entries, view.as<uint8_t>(MSDOS_PARTTAB_START), sizeof(MsdosPartitionInfo) * 4);
336 disk->unpin(offset);
337 return valid;
338}
339
340static void readExtended(Disk* disk, uint64_t base, uint64_t count) {
341 if (!sectorRange(disk, base, count) || !base)
342 return;
343 uint64_t visited[128];
344 size_t depth = 0;
345 uint64_t current = base;
346 while (depth < 128) {
347 for (size_t i = 0; i < depth; ++i)
348 if (visited[i] == current)
349 return;
350 visited[depth++] = current;
351 MsdosPartitionInfo entries[4];
352 if (!readEntries(disk, current, entries))
353 return;
354 const auto& data = entries[0];
355 const uint64_t start = current + LITTLE_TO_HOST32(data.start_lba);
356 const uint64_t length = LITTLE_TO_HOST32(data.size);
357 if ((data.active == 0 || data.active == 0x80) && data.type && !extended(data.type) &&
358 data.type != 0xee && start > current && start >= base && start < base + count &&
359 length <= base + count - start)
360 registerPartition(data, disk, start);
361 const auto& link = entries[1];
362 if (!extended(link.type) || (link.active != 0 && link.active != 0x80))
363 return;
364 const uint64_t relative = LITTLE_TO_HOST32(link.start_lba);
365 if (!relative || relative >= count)
366 return;
367 current = base + relative;
368 }
369 WARNING("MS-DOS: extended partition chain exceeds 128 records");
370}
371
372bool msdosReadTable(MsdosPartitionInfo* entries, Disk* disk) {
373 // A corrupt GPT must not expose its protective container as a filesystem.
374 for (size_t i = 0; i < 4; ++i)
375 if (entries[i].type == 0xee)
376 return true;
377 for (size_t i = 0; i < 4; ++i) {
378 const auto& entry = entries[i];
379 if (entry.active != 0 && entry.active != 0x80)
380 continue;
381 const uint64_t start = LITTLE_TO_HOST32(entry.start_lba);
382 if (extended(entry.type))
383 readExtended(disk, start, LITTLE_TO_HOST32(entry.size));
384 else if (entry.type)
385 registerPartition(entry, disk, start);
386 }
387 return true;
388}
389
390bool msdosProbeDisk(Disk* disk) {
391 const size_t bytes = disk->getNativeBlockSize();
392 if (bytes < 512 || bytes > 4096 || (bytes & (bytes - 1)))
393 return false;
394 MsdosPartitionInfo entries[4];
395 return readEntries(disk, 0, entries) && msdosReadTable(entries, disk);
396}
void addChild(Device *pDevice)
Definition Device.cc:123
Definition Disk.h:35
virtual BufferView read(uint64_t location)
Definition Disk.cc:163
virtual size_t getSize() const
Gets the size of the disk.
Definition Disk.cc:344
virtual void unpin(uint64_t location)=0
virtual size_t getNativeBlockSize() const
Definition Disk.cc:383