xref: /haiku/src/add-ons/kernel/partitioning_systems/intel/intel.cpp (revision 51978af14a173e7fae0563b562be5603bc652aeb)
1 //----------------------------------------------------------------------
2 //  This software is part of the OpenBeOS distribution and is covered
3 //  by the OpenBeOS license.
4 //---------------------------------------------------------------------
5 /*!
6 	\file intel.cpp
7 	\brief disk_scanner partition module for "intel" style partitions.
8 */
9 
10 // TODO: The implementation is very strict right now. It rejects a partition
11 // completely, if it finds an error in its partition tables. We should see,
12 // what error can be handled gracefully, e.g. by ignoring the partition
13 // descriptor or the whole partition table sector.
14 
15 #include <errno.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 
21 #include <util/kernel_cpp.h>
22 #include <ddm_modules.h>
23 #ifndef _BOOT_MODE
24 #	include <DiskDeviceTypes.h>
25 #else
26 #	include <boot/partitions.h>
27 #endif
28 #include <KernelExport.h>
29 
30 #include "PartitionMap.h"
31 
32 #define TRACE(x) ;
33 //#define TRACE(x) dprintf x
34 
35 // module names
36 static const char *kPartitionMapModuleName
37 	= "partitioning_systems/intel/map/v1";
38 static const char *kExtendedPartitionModuleName
39 	= "partitioning_systems/intel/extended/v1";
40 
41 // Maximal number of logical partitions per extended partition we allow.
42 static const int32 kMaxLogicalPartitionCount = 128;
43 
44 
45 // AutoDeleter
46 
47 template<typename C>
48 class AutoDeleter {
49 public:
50 	AutoDeleter(C *object) : fObject(object)	{}
51 	~AutoDeleter()								{ delete fObject; }
52 	void SetObject(C *object)					{ fObject = object; }
53 
54 private:
55 	C	*fObject;
56 };
57 
58 
59 // PartitionMapParser
60 
61 class PartitionMapParser {
62 public:
63 	PartitionMapParser(int deviceFD, off_t sessionOffset, off_t sessionSize,
64 					   int32 blockSize);
65 	~PartitionMapParser();
66 
67 	status_t Parse(const uint8 *block, PartitionMap *map);
68 
69 	int32 CountPartitions() const;
70 	const Partition *PartitionAt(int32 index) const;
71 
72 private:
73 	status_t _ParsePrimary(const partition_table_sector *pts);
74 	status_t _ParseExtended(PrimaryPartition *primary, off_t offset);
75 	status_t _ReadPTS(off_t offset, partition_table_sector *pts = NULL);
76 
77 private:
78 	int						fDeviceFD;
79 	off_t					fSessionOffset;
80 	off_t					fSessionSize;
81 	int32					fBlockSize;
82 	partition_table_sector	*fPTS;	// while parsing
83 	PartitionMap			*fMap;	//
84 };
85 
86 // constructor
87 PartitionMapParser::PartitionMapParser(int deviceFD, off_t sessionOffset,
88 									   off_t sessionSize, int32 blockSize)
89 	: fDeviceFD(deviceFD),
90 	  fSessionOffset(sessionOffset),
91 	  fSessionSize(sessionSize),
92 	  fBlockSize(blockSize),
93 	  fPTS(NULL),
94 	  fMap(NULL)
95 {
96 }
97 
98 // destructor
99 PartitionMapParser::~PartitionMapParser()
100 {
101 }
102 
103 // Parse
104 status_t
105 PartitionMapParser::Parse(const uint8 *block, PartitionMap *map)
106 {
107 	status_t error = (map ? B_OK : B_BAD_VALUE);
108 	if (error == B_OK) {
109 		fMap = map;
110 		fMap->Unset();
111 		if (block) {
112 			const partition_table_sector *pts
113 				= (const partition_table_sector*)block;
114 			error = _ParsePrimary(pts);
115 		} else {
116 			partition_table_sector pts;
117 			error = _ReadPTS(0, &pts);
118 			if (error == B_OK)
119 				error = _ParsePrimary(&pts);
120 		}
121 		if (error == B_OK && !fMap->Check(fSessionSize, fBlockSize))
122 			error = B_BAD_DATA;
123 		fMap = NULL;
124 	}
125 	return error;
126 }
127 
128 // _ParsePrimary
129 status_t
130 PartitionMapParser::_ParsePrimary(const partition_table_sector *pts)
131 {
132 	status_t error = (pts ? B_OK : B_BAD_VALUE);
133 	// check the signature
134 	if (error == B_OK && pts->signature != kPartitionTableSectorSignature) {
135 		TRACE(("intel: _ParsePrimary(): invalid PTS signature\n"));
136 		error = B_BAD_DATA;
137 	}
138 	// examine the table
139 	if (error == B_OK) {
140 		for (int32 i = 0; i < 4; i++) {
141 			const partition_descriptor *descriptor = &pts->table[i];
142 			PrimaryPartition *partition = fMap->PrimaryPartitionAt(i);
143 			partition->SetTo(descriptor, 0, fBlockSize);
144 			// fail, if location is bad
145 			if (!partition->CheckLocation(fSessionSize, fBlockSize)) {
146 				error = B_BAD_DATA;
147 				break;
148 			}
149 		}
150 	}
151 	// allocate a PTS buffer
152 	if (error == B_OK) {
153 		fPTS = new(nothrow) partition_table_sector;
154 		if (!fPTS)
155 			error = B_NO_MEMORY;
156 	}
157 	// parse extended partitions
158 	if (error == B_OK) {
159 		for (int32 i = 0; error == B_OK && i < 4; i++) {
160 			PrimaryPartition *primary = fMap->PrimaryPartitionAt(i);
161 			if (primary->IsExtended())
162 				error = _ParseExtended(primary, primary->Offset());
163 		}
164 	}
165 	// cleanup
166 	if (fPTS) {
167 		delete fPTS;
168 		fPTS = NULL;
169 	}
170 	return error;
171 }
172 
173 // _ParseExtended
174 status_t
175 PartitionMapParser::_ParseExtended(PrimaryPartition *primary, off_t offset)
176 {
177 	status_t error = B_OK;
178 	int32 partitionCount = 0;
179 	while (error == B_OK) {
180 		// check for cycles
181 		if (++partitionCount > kMaxLogicalPartitionCount) {
182 			TRACE(("intel: _ParseExtended(): Maximal number of logical "
183 				   "partitions for extended partition reached. Cycle?\n"));
184 			error = B_BAD_DATA;
185 		}
186 		// read the PTS
187 		if (error == B_OK)
188 			error = _ReadPTS(offset);
189 		// check the signature
190 		if (error == B_OK
191 			&& fPTS->signature != kPartitionTableSectorSignature) {
192 			TRACE(("intel: _ParseExtended(): invalid PTS signature\n"));
193 			error = B_BAD_DATA;
194 		}
195 		// ignore the PTS, if any error occured till now
196 		if (error != B_OK) {
197 			TRACE(("intel: _ParseExtended(): ignoring this PTS\n"));
198 			error = B_OK;
199 			break;
200 		}
201 		// examine the table
202 		LogicalPartition extended;
203 		LogicalPartition nonExtended;
204 		if (error == B_OK) {
205 			for (int32 i = 0; error == B_OK && i < 4; i++) {
206 				const partition_descriptor *descriptor = &fPTS->table[i];
207 				LogicalPartition *partition = NULL;
208 				if (!descriptor->is_empty()) {
209 					if (descriptor->is_extended()) {
210 						if (extended.IsEmpty()) {
211 							extended.SetTo(descriptor, offset, fBlockSize,
212 										   primary);
213 							partition = &extended;
214 						} else {
215 							// only one extended partition allowed
216 							error = B_BAD_DATA;
217 							TRACE(("intel: _ParseExtended(): "
218 								   "only one extended partition allowed\n"));
219 						}
220 					} else {
221 						if (nonExtended.IsEmpty()) {
222 							nonExtended.SetTo(descriptor, offset, fBlockSize,
223 											  primary);
224 							partition = &nonExtended;
225 						} else {
226 							// only one non-extended partition allowed
227 							error = B_BAD_DATA;
228 							TRACE(("intel: _ParseExtended(): only one "
229 								   "non-extended partition allowed\n"));
230 						}
231 					}
232 					// check the partition's location
233 					if (partition && !partition->CheckLocation(fSessionSize,
234 															   fBlockSize)) {
235 						error = B_BAD_DATA;
236 					}
237 				}
238 			}
239 		}
240 		// add non-extended partition to list
241 		if (error == B_OK && !nonExtended.IsEmpty()) {
242 			LogicalPartition *partition
243 				= new(nothrow) LogicalPartition(nonExtended);
244 			if (partition)
245 				primary->AddLogicalPartition(partition);
246 			else
247 				error = B_NO_MEMORY;
248 		}
249 		// prepare to parse next extended partition
250 		if (error == B_OK && !extended.IsEmpty())
251 			offset = extended.Offset();
252 		else
253 			break;
254 	}
255 	return error;
256 }
257 
258 // _ReadPTS
259 status_t
260 PartitionMapParser::_ReadPTS(off_t offset, partition_table_sector *pts)
261 {
262 	status_t error = B_OK;
263 	if (!pts)
264 		pts = fPTS;
265 	int32 toRead = sizeof(partition_table_sector);
266 	// check the offset
267 	if (offset < 0 || offset + toRead > fSessionSize) {
268 		error = B_BAD_VALUE;
269 		TRACE(("intel: _ReadPTS(): bad offset: %Ld\n", offset));
270 	// read
271 	} else if (read_pos(fDeviceFD, fSessionOffset + offset, pts, toRead)
272 						!= toRead) {
273 #ifndef _BOOT_MODE
274 		error = errno;
275 		if (error == B_OK)
276 			error = B_IO_ERROR;
277 #else
278 		error = B_IO_ERROR;
279 #endif
280 		TRACE(("intel: _ReadPTS(): reading the PTS failed: %s\n",
281 			   strerror(error)));
282 	}
283 	return error;
284 }
285 
286 
287 // intel partition map module
288 
289 // module
290 static status_t pm_std_ops(int32 op, ...);
291 
292 // scanning
293 static float pm_identify_partition(int fd, partition_data *partition,
294 		void **cookie);
295 static status_t pm_scan_partition(int fd, partition_data *partition,
296 		void *cookie);
297 static void pm_free_identify_partition_cookie(partition_data *partition,
298 		void *cookie);
299 static void pm_free_partition_cookie(partition_data *partition);
300 static void pm_free_partition_content_cookie(partition_data *partition);
301 
302 #ifndef _BOOT_MODE
303 // querying
304 static bool pm_supports_resizing_child(partition_data *partition,
305 									   partition_data *child);
306 
307 static bool pm_validate_resize_child(partition_data *partition,
308 									 partition_data *child, off_t *size);
309 #endif
310 
311 #ifdef _BOOT_MODE
312 partition_module_info gIntelPartitionMapModule = {
313 #else
314 static partition_module_info intel_partition_map_module = {
315 #endif
316 	{
317 		kPartitionMapModuleName,
318 		0,
319 		pm_std_ops
320 	},
321 	kPartitionTypeIntel,				// pretty_name
322 	0,									// flags
323 
324 	// scanning
325 	pm_identify_partition,				// identify_partition
326 	pm_scan_partition,					// scan_partition
327 	pm_free_identify_partition_cookie,	// free_identify_partition_cookie
328 	pm_free_partition_cookie,			// free_partition_cookie
329 	pm_free_partition_content_cookie,	// free_partition_content_cookie
330 
331 #ifndef _BOOT_MODE
332 	// querying
333 	NULL,								// supports_repairing
334 	NULL,								// supports_resizing
335 	pm_supports_resizing_child,			// supports_resizing_child
336 	NULL,								// supports_moving
337 	NULL,								// supports_moving_child
338 	NULL,								// supports_setting_name
339 	NULL,								// supports_setting_content_name
340 	NULL,								// supports_setting_type
341 	NULL,								// supports_setting_parameters
342 	NULL,								// supports_setting_content_parameters
343 	NULL,								// supports_initializing
344 	NULL,								// supports_initializing_child
345 	NULL,								// supports_creating_child
346 	NULL,								// supports_deleting_child
347 	NULL,								// is_sub_system_for
348 
349 	NULL,								// validate_resize
350 	pm_validate_resize_child,			// validate_resize_child
351 	NULL,								// validate_move
352 	NULL,								// validate_move_child
353 	NULL,								// validate_set_name
354 	NULL,								// validate_set_content_name
355 	NULL,								// validate_set_type
356 	NULL,								// validate_set_parameters
357 	NULL,								// validate_set_content_parameters
358 	NULL,								// validate_initialize
359 	NULL,								// validate_create_child
360 	NULL,								// get_partitionable_spaces
361 	NULL,								// get_next_supported_type
362 	NULL,								// get_type_for_content_type
363 
364 	// shadow partition modification
365 	NULL,								// shadow_changed
366 
367 	// writing
368 	NULL,								// repair
369 	NULL,								// resize
370 	NULL,								// resize_child
371 	NULL,								// move
372 	NULL,								// move_child
373 	NULL,								// set_name
374 	NULL,								// set_content_name
375 	NULL,								// set_type
376 	NULL,								// set_parameters
377 	NULL,								// set_content_parameters
378 	NULL,								// initialize
379 	NULL,								// create_child
380 	NULL,								// delete_child
381 #else
382 	NULL
383 #endif	// _BOOT_MODE
384 };
385 
386 
387 // intel extended partition module
388 
389 // module
390 static status_t ep_std_ops(int32 op, ...);
391 
392 // scanning
393 static float ep_identify_partition(int fd, partition_data *partition,
394 		void **cookie);
395 static status_t ep_scan_partition(int fd, partition_data *partition,
396 		void *cookie);
397 static void ep_free_identify_partition_cookie(partition_data *partition,
398 		void *cookie);
399 static void ep_free_partition_cookie(partition_data *partition);
400 static void ep_free_partition_content_cookie(partition_data *partition);
401 
402 #ifdef _BOOT_MODE
403 partition_module_info gIntelExtendedPartitionModule = {
404 #else
405 static partition_module_info intel_extended_partition_module = {
406 #endif
407 	{
408 		kExtendedPartitionModuleName,
409 		0,
410 		ep_std_ops
411 	},
412 	kPartitionTypeIntelExtended,		// pretty_name
413 	0,									// flags
414 
415 	// scanning
416 	ep_identify_partition,				// identify_partition
417 	ep_scan_partition,					// scan_partition
418 	ep_free_identify_partition_cookie,	// free_identify_partition_cookie
419 	ep_free_partition_cookie,			// free_partition_cookie
420 	ep_free_partition_content_cookie,	// free_partition_content_cookie
421 
422 #ifndef _BOOT_MODE
423 	// querying
424 	NULL,								// supports_repairing
425 	NULL,								// supports_resizing
426 	NULL,								// supports_resizing_child
427 	NULL,								// supports_moving
428 	NULL,								// supports_moving_child
429 	NULL,								// supports_setting_name
430 	NULL,								// supports_setting_content_name
431 	NULL,								// supports_setting_type
432 	NULL,								// supports_setting_parameters
433 	NULL,								// supports_setting_content_parameters
434 	NULL,								// supports_initializing
435 	NULL,								// supports_initializing_child
436 	NULL,								// supports_creating_child
437 	NULL,								// supports_deleting_child
438 	NULL,								// is_sub_system_for
439 
440 	NULL,								// validate_resize
441 	NULL,								// validate_resize_child
442 	NULL,								// validate_move
443 	NULL,								// validate_move_child
444 	NULL,								// validate_set_name
445 	NULL,								// validate_set_content_name
446 	NULL,								// validate_set_type
447 	NULL,								// validate_set_parameters
448 	NULL,								// validate_set_content_parameters
449 	NULL,								// validate_initialize
450 	NULL,								// validate_create_child
451 	NULL,								// get_partitionable_spaces
452 	NULL,								// get_next_supported_type
453 	NULL,								// get_type_for_content_type
454 
455 	// shadow partition modification
456 	NULL,								// shadow_changed
457 
458 	// writing
459 	NULL,								// repair
460 	NULL,								// resize
461 	NULL,								// resize_child
462 	NULL,								// move
463 	NULL,								// move_child
464 	NULL,								// set_name
465 	NULL,								// set_content_name
466 	NULL,								// set_type
467 	NULL,								// set_parameters
468 	NULL,								// set_content_parameters
469 	NULL,								// initialize
470 	NULL,								// create_child
471 	NULL,								// delete_child
472 #else
473 	NULL
474 #endif	// _BOOT_MODE
475 };
476 
477 
478 #ifndef _BOOT_MODE
479 extern "C" partition_module_info *modules[];
480 _EXPORT partition_module_info *modules[] =
481 {
482 	&intel_partition_map_module,
483 	&intel_extended_partition_module,
484 	NULL
485 };
486 #endif
487 
488 
489 // intel partition map module
490 
491 // pm_std_ops
492 static
493 status_t
494 pm_std_ops(int32 op, ...)
495 {
496 	TRACE(("intel: pm_std_ops(0x%lx)\n", op));
497 	switch(op) {
498 		case B_MODULE_INIT:
499 		case B_MODULE_UNINIT:
500 			return B_OK;
501 	}
502 	return B_ERROR;
503 }
504 
505 // pm_identify_partition
506 static
507 float
508 pm_identify_partition(int fd, partition_data *partition, void **cookie)
509 {
510 	// check parameters
511 	if (fd < 0 || !partition || !cookie)
512 		return -1;
513 	TRACE(("intel: pm_identify_partition(%d, %ld: %lld, %lld, %ld)\n", fd,
514 		   partition->id, partition->offset, partition->size,
515 		   partition->block_size));
516 	// reject extended partitions
517 	if (partition->type
518 		&& !strcmp(partition->type, kPartitionTypeIntelExtended)) {
519 		return -1;
520 	}
521 	// check block size
522 	uint32 blockSize = partition->block_size;
523 	if (blockSize < sizeof(partition_table_sector)) {
524 		TRACE(("intel: read_partition_map: bad block size: %ld, should be "
525 			   ">= %ld\n", blockSize, sizeof(partition_table_sector)));
526 		return -1;
527 	}
528 	// allocate a PartitionMap
529 	PartitionMap *map = new(nothrow) PartitionMap;
530 	if (!map)
531 		return -1;
532 	// read the partition structure
533 	PartitionMapParser parser(fd, 0, partition->size, blockSize);
534 	status_t error = parser.Parse(NULL, map);
535 	if (error == B_OK) {
536 		*cookie = map;
537 		return 0.5;
538 	}
539 	// cleanup, if not detected
540 	delete map;
541 	return -1;
542 }
543 
544 // pm_scan_partition
545 static
546 status_t
547 pm_scan_partition(int fd, partition_data *partition, void *cookie)
548 {
549 	AutoDeleter<PartitionMap> deleter((PartitionMap*)cookie);
550 	// check parameters
551 	if (fd < 0 || !partition || !cookie)
552 		return B_ERROR;
553 	TRACE(("intel: pm_scan_partition(%d, %ld: %lld, %lld, %ld)\n", fd,
554 		   partition->id, partition->offset, partition->size,
555 		   partition->block_size));
556 	PartitionMap *map = (PartitionMap*)cookie;
557 	// fill in the partition_data structure
558 	partition->status = B_PARTITION_VALID;
559 	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM
560 						| B_PARTITION_READ_ONLY
561 						| B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD;
562 		// TODO: Update when write functionality is implemented.
563 	partition->content_size = partition->size;
564 	// (no content_name and content_parameters)
565 	// (content_type is set by the system)
566 	partition->content_cookie = map;
567 	// children
568 	status_t error = B_OK;
569 	int32 index = 0;
570 	for (int32 i = 0; i < 4; i++) {
571 		PrimaryPartition *primary = map->PrimaryPartitionAt(i);
572 		if (!primary->IsEmpty()) {
573 			partition_data *child = create_child_partition(partition->id,
574 														   index, -1);
575 			index++;
576 			if (!child) {
577 TRACE(("Creating child at index %ld failed\n", index - 1));
578 				// something went wrong
579 				error = B_ERROR;
580 				break;
581 			}
582 			child->offset = partition->offset + primary->Offset();
583 			child->size = primary->Size();
584 			child->block_size = partition->block_size;
585 			// (no name)
586 			char type[B_FILE_NAME_LENGTH];
587 			primary->GetTypeString(type);
588 			child->type = strdup(type);
589 			// parameters
590 			char buffer[128];
591 			sprintf(buffer, "type = %u ; active = %d", primary->Type(),
592 					primary->Active());
593 			child->parameters = strdup(buffer);
594 			child->cookie = primary;
595 			// check for allocation problems
596 			if (!child->type || !child->parameters) {
597 				error = B_NO_MEMORY;
598 				break;
599 			}
600 		}
601 	}
602 	// keep map on success or cleanup on error
603 	if (error == B_OK) {
604 		deleter.SetObject(NULL);
605 	} else {
606 		partition->content_cookie = NULL;
607 		for (int32 i = 0; i < partition->child_count; i++) {
608 			if (partition_data *child = get_child_partition(partition->id, i))
609 				child->cookie = NULL;
610 		}
611 	}
612 	return error;
613 }
614 
615 // pm_free_identify_partition_cookie
616 static
617 void
618 pm_free_identify_partition_cookie(partition_data */*partition*/, void *cookie)
619 {
620 	if (cookie)
621 		delete (PartitionMap*)cookie;
622 }
623 
624 // pm_free_partition_cookie
625 static
626 void
627 pm_free_partition_cookie(partition_data *partition)
628 {
629 	// called for the primary partitions: the PrimaryPartition is allocated
630 	// by the partition containing the partition map
631 	if (partition)
632 		partition->cookie = NULL;
633 }
634 
635 // pm_free_partition_content_cookie
636 static
637 void
638 pm_free_partition_content_cookie(partition_data *partition)
639 {
640 	if (partition && partition->content_cookie) {
641 		delete (PartitionMap*)partition->content_cookie;
642 		partition->content_cookie = NULL;
643 	}
644 }
645 
646 #ifndef _BOOT_MODE
647 // pm_supports_resizing_child
648 static
649 bool
650 pm_supports_resizing_child(partition_data *partition, partition_data *child)
651 {
652 	return (partition && child && partition->content_type
653 			&& !strcmp(partition->content_type, kPartitionTypeIntel));
654 }
655 
656 // pm_validate_resize_child
657 static
658 bool
659 pm_validate_resize_child(partition_data *partition, partition_data *child,
660 						 off_t *size)
661 {
662 	if (!partition || !child || !partition->content_type
663 		|| strcmp(partition->content_type, kPartitionTypeIntel)
664 		|| !size) {
665 		return false;
666 	}
667 	// size remains the same?
668 	if (*size == child->size)
669 		return true;
670 	// shrink partition?
671 	if (*size < child->size) {
672 		if (*size < 0)
673 			*size = 0;
674 		// make the size a multiple of the block size
675 		*size = *size / partition->block_size * partition->block_size;
676 		return true;
677 	}
678 	// grow partition
679 	// child must completely lie within the parent partition
680 	if (child->offset + *size > partition->offset + partition->size)
681 		*size = partition->offset + partition->size - child->offset;
682 	// child must not intersect with sibling partitions
683 	for (int32 i = 0; i < partition->child_count; i++) {
684 		partition_data *sibling = get_child_partition(partition->id, i);
685 		if (sibling && sibling != child && sibling->offset > child->offset) {
686 			if (child->offset + *size > sibling->offset)
687 				*size = sibling->offset - child->offset;
688 		}
689 	}
690 	// make the size a multiple of the block size
691 	*size = *size / partition->block_size * partition->block_size;
692 	return true;
693 }
694 #endif	// _BOOT_MODE
695 
696 
697 // intel extended partition module
698 
699 // ep_std_ops
700 static
701 status_t
702 ep_std_ops(int32 op, ...)
703 {
704 	TRACE(("intel: ep_std_ops(0x%lx)\n", op));
705 	switch(op) {
706 		case B_MODULE_INIT:
707 		case B_MODULE_UNINIT:
708 			return B_OK;
709 	}
710 	return B_ERROR;
711 }
712 
713 // ep_identify_partition
714 static
715 float
716 ep_identify_partition(int fd, partition_data *partition, void **cookie)
717 {
718 	// check parameters
719 	if (fd < 0 || !partition || !cookie || !partition->cookie)
720 		return -1;
721 	TRACE(("intel: ep_identify_partition(%d, %lld, %lld, %ld)\n", fd,
722 		   partition->offset, partition->size, partition->block_size));
723 	// our parent must be a intel partition map partition and we must have
724 	// extended partition type
725 	if (!partition->type
726 		|| strcmp(partition->type, kPartitionTypeIntelExtended)) {
727 		return -1;
728 	}
729 	partition_data *parent = get_parent_partition(partition->id);
730 	if (!parent || !parent->content_type
731 		|| strcmp(parent->content_type, kPartitionTypeIntel)) {
732 		return -1;
733 	}
734 	// things seem to be in order
735 	return 0.5;
736 }
737 
738 // ep_scan_partition
739 static
740 status_t
741 ep_scan_partition(int fd, partition_data *partition, void *cookie)
742 {
743 	// check parameters
744 	if (fd < 0 || !partition || !partition->cookie)
745 		return B_ERROR;
746 	partition_data *parent = get_parent_partition(partition->id);
747 	if (!parent)
748 		return B_ERROR;
749 	PrimaryPartition *primary = (PrimaryPartition*)partition->cookie;
750 	// fill in the partition_data structure
751 	partition->status = B_PARTITION_VALID;
752 	partition->flags |= B_PARTITION_PARTITIONING_SYSTEM
753 						| B_PARTITION_READ_ONLY;
754 		// TODO: Update when write functionality is implemented.
755 	partition->content_size = partition->size;
756 	// (no content_name and content_parameters)
757 	// (content_type is set by the system)
758 	partition->content_cookie = primary;
759 	// children
760 	status_t error = B_OK;
761 	int32 index = 0;
762 	for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) {
763 		LogicalPartition *logical = primary->LogicalPartitionAt(i);
764 		partition_data *child = create_child_partition(partition->id,
765 													   index, -1);
766 		index++;
767 		if (!child) {
768 			// something went wrong
769 			error = B_ERROR;
770 			break;
771 		}
772 		child->offset = parent->offset + logical->Offset();
773 		child->size = logical->Size();
774 		child->block_size = partition->block_size;
775 		// (no name)
776 		char type[B_FILE_NAME_LENGTH];
777 		logical->GetTypeString(type);
778 		child->type = strdup(type);
779 		// parameters
780 		char buffer[128];
781 		sprintf(buffer, "type = %u ; active = %d", logical->Type(),
782 				logical->Active());
783 		child->parameters = strdup(buffer);
784 		child->cookie = logical;
785 		// check for allocation problems
786 		if (!child->type || !child->parameters) {
787 			error = B_NO_MEMORY;
788 			break;
789 		}
790 	}
791 	// cleanup on error
792 	if (error != B_OK) {
793 		partition->content_cookie = NULL;
794 		for (int32 i = 0; i < partition->child_count; i++) {
795 			if (partition_data *child = get_child_partition(partition->id, i))
796 				child->cookie = NULL;
797 		}
798 	}
799 	return error;
800 }
801 
802 // ep_free_identify_partition_cookie
803 static
804 void
805 ep_free_identify_partition_cookie(partition_data *partition, void *cookie)
806 {
807 	// nothing to do
808 }
809 
810 // ep_free_partition_cookie
811 static
812 void
813 ep_free_partition_cookie(partition_data *partition)
814 {
815 	// the logical partition's cookie belongs to the partition map partition
816 	if (partition)
817 		partition->cookie = NULL;
818 }
819 
820 // ep_free_partition_content_cookie
821 static
822 void
823 ep_free_partition_content_cookie(partition_data *partition)
824 {
825 	// the extended partition's cookie belongs to the partition map partition
826 	if (partition)
827 		partition->content_cookie = NULL;
828 }
829 
830