NListtree.mcc: fix sorted insert
[AROS.git] / rom / partition / partitionebr.c
blob29786d09fd16ecf641d4e0f30dc4bd94ec7d4ab3
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 */
7 #include <exec/memory.h>
8 #include <exec/types.h>
9 #include <libraries/partition.h>
10 #include <proto/exec.h>
11 #include <proto/partition.h>
12 #include <proto/utility.h>
14 #include "partition_types.h"
15 #include "partition_support.h"
16 #include "partitionmbr.h"
17 #include "platform.h"
18 #include "debug.h"
20 struct EBRData
22 UBYTE type;
23 ULONG ebr_block_no; /* Home block of the record itself */
24 ULONG block_no; /* Start partition block */
25 ULONG block_count; /* Length of partition in blocks */
28 static LONG PartitionEBRCheckPartitionTable
30 struct Library *PartitionBase,
31 struct PartitionHandle *root
34 union {
35 struct MBR mbr;
36 UBYTE space[4096];
37 } sector;
39 struct PartitionType type;
40 struct TagItem tags[] = {{PT_TYPE, (IPTR)&type}, {TAG_DONE, 0}};
42 if ((root->de.de_SizeBlock << 2) > sizeof(sector))
43 return 0;
45 if (readBlock(PartitionBase, root, 0, &sector.mbr) == 0)
47 if (AROS_LE2WORD(sector.mbr.magic) == 0xAA55)
49 if (root->root != NULL)
51 GetPartitionAttrs(root, tags);
52 if (
53 (root->root->table->type == PHPTT_MBR) &&
54 (type.id[0] == MBRT_EXTENDED
55 || type.id[0] == MBRT_EXTENDED2)
58 return 1;
63 return 0;
66 static struct PartitionHandle *PartitionEBRNewHandle(struct Library *PartitionBase, struct PartitionHandle *root,
67 UBYTE type, ULONG block_no, ULONG block_count, ULONG ebr_block_no)
69 struct PartitionHandle *ph;
71 ph = AllocMem(sizeof(struct PartitionHandle), MEMF_PUBLIC | MEMF_CLEAR);
72 if (ph != NULL)
74 struct EBRData *data;
76 data = AllocMem(sizeof(struct EBRData), MEMF_PUBLIC);
77 if (data != NULL)
79 data->type = type;
80 data->ebr_block_no = ebr_block_no;
81 data->block_no = block_no;
82 data->block_count = block_count;
84 ph->data = data;
86 /* Initialize DosEnvec and DriveGeometry */
87 initPartitionHandle(root, ph, block_no, block_count);
89 /* Map type ID to a DOSType */
90 setDosType(&ph->de, MBR_FindDosType(data->type));
92 return ph;
94 FreeMem(ph, sizeof(struct PartitionHandle));
96 return NULL;
99 static LONG PartitionEBROpenPartitionTable
101 struct Library *PartitionBase,
102 struct PartitionHandle *root
105 LONG error = 0;
106 struct PartitionHandle *ph;
107 struct MBR *ebr;
108 UBYTE i;
109 ULONG block_no = 0;
110 BOOL atEnd = FALSE;
112 ebr = AllocMem(root->de.de_SizeBlock<<2, MEMF_PUBLIC);
113 if (ebr != NULL)
115 NEWLIST(&root->table->list);
116 for (i = 0; !atEnd && error == 0; i++)
118 if (readBlock(PartitionBase, root, block_no, ebr) == 0)
120 if (AROS_LE2WORD(ebr->magic) == 0xAA55)
122 /* Create handle for current EBR's logical partition */
124 if (AROS_LE2LONG(ebr->pcpt[0].count_sector) != 0)
126 ph = PartitionEBRNewHandle(PartitionBase, root,
127 ebr->pcpt[0].type,
128 block_no + AROS_LE2LONG(ebr->pcpt[0].first_sector),
129 AROS_LE2LONG(ebr->pcpt[0].count_sector),
130 block_no);
131 if (ph != NULL)
133 Enqueue(&root->table->list, &ph->ln);
135 else
136 error = 1;
139 /* Get location of next EBR in chain */
141 block_no = AROS_LE2LONG(ebr->pcpt[1].first_sector);
142 if (block_no == 0)
143 atEnd = TRUE;
145 else
146 error = 1;
148 else
149 error = 1;
151 FreeMem(ebr, root->de.de_SizeBlock<<2);
153 else
154 error = 1;
155 return error;
158 static void PartitionEBRFreeHandle
160 struct Library *PartitionBase,
161 struct PartitionHandle *ph
164 ClosePartitionTable(ph);
165 FreeMem(ph->data, sizeof(struct EBRData));
166 FreeMem(ph, sizeof(struct PartitionHandle));
169 static void PartitionEBRClosePartitionTable
171 struct Library *PartitionBase,
172 struct PartitionHandle *root
175 struct PartitionHandle *ph;
177 while ((ph = (struct PartitionHandle *)RemTail(&root->table->list)))
178 PartitionEBRFreeHandle(PartitionBase, ph);
181 static LONG PartitionEBRWritePartitionTable
183 struct Library *PartitionBase,
184 struct PartitionHandle *root
187 ULONG block_no, block_count;
188 struct PartitionHandle *ph, *next_ph, *tail;
189 struct EBRData *data, *next_data;
190 struct DosEnvec *de;
191 struct MBR *ebr;
192 LONG error = 0;
194 ebr = AllocMem(root->de.de_SizeBlock << 2, MEMF_PUBLIC | MEMF_CLEAR);
195 if (ebr != NULL)
197 ph = (struct PartitionHandle *)root->table->list.lh_Head;
198 tail = (struct PartitionHandle *)&root->table->list.lh_Tail;
200 if (ph == tail)
202 /* Write an empty EBR block for empty partition table */
204 ebr->magic = AROS_WORD2LE(0xAA55);
205 if (writeBlock(PartitionBase, root, 0, ebr))
206 error = 1;
209 else
211 /* First EBR must be at extended partition's first block */
212 data = (struct EBRData *)ph->data;
213 data->ebr_block_no = 0;
215 /* Write an EBR block for every partition in the list */
217 while (ph != tail)
219 data = (struct EBRData *)ph->data;
220 next_ph = (struct PartitionHandle *)ph->ln.ln_Succ;
222 /* Write table entry for current EBR's logical partition */
224 de = &ph->de;
225 block_no = de->de_LowCyl * de->de_Surfaces * de->de_BlocksPerTrack;
226 block_count = (de->de_HighCyl - de->de_LowCyl + 1) *
227 de->de_Surfaces * de->de_BlocksPerTrack;
229 PartitionMBRSetGeometry(root, &ebr->pcpt[0], block_no,
230 block_count, data->ebr_block_no);
231 ebr->pcpt[0].status = 0;
232 ebr->pcpt[0].type = data->type;
234 /* Write table entry that points to next EBR in chain */
236 if (next_ph != tail)
238 de = &root->de;
239 next_data = (struct EBRData *)next_ph->data;
240 block_no = next_data->ebr_block_no;
241 block_count = (de->de_HighCyl - de->de_LowCyl + 1) *
242 de->de_Surfaces * de->de_BlocksPerTrack - block_no;
243 ebr->pcpt[1].type = MBRT_EXTENDED;
245 else
247 block_no = 0;
248 block_count = 0;
249 ebr->pcpt[1].type = 0;
251 PartitionMBRSetGeometry(root, &ebr->pcpt[1], block_no, block_count, 0);
252 ebr->pcpt[1].status = 0;
254 /* Write EBR */
256 ebr->magic = AROS_WORD2LE(0xAA55);
257 if (writeBlock(PartitionBase, root, data->ebr_block_no, ebr))
258 error = 1;
260 ph = next_ph;
264 FreeMem(ebr, root->de.de_SizeBlock << 2);
266 else
267 error = 1;
269 return error;
272 static LONG PartitionEBRCreatePartitionTable
274 struct Library *PartitionBase,
275 struct PartitionHandle *ph
278 NEWLIST(&ph->table->list);
279 return 0;
282 static struct PartitionHandle *PartitionEBRAddPartition(struct Library *PartitionBase, struct PartitionHandle *root, struct TagItem *taglist)
284 struct TagItem *tag;
285 ULONG block_no = 0, new_block_no, new_block_count, ebr_track_no, ebr_block_no;
286 struct PartitionHandle *ph, *new_ph, *head;
287 struct DosEnvec *de;
288 BOOL found = FALSE;
289 struct PartitionType *ptype;
290 LONG error = 0;
292 tag = FindTagItem(PT_DOSENVEC, taglist);
293 if (tag == NULL)
294 error = 1;
296 if (error == 0)
298 de = (struct DosEnvec *)tag->ti_Data;
300 tag = FindTagItem(PT_TYPE, taglist);
301 if (tag == NULL)
302 error = 1;
305 if (error == 0)
307 ptype = (struct PartitionType *)tag->ti_Data;
309 new_block_no =
310 de->de_LowCyl * de->de_Surfaces * de->de_BlocksPerTrack;
311 new_block_count = (de->de_HighCyl - de->de_LowCyl + 1) *
312 de->de_Surfaces * de->de_BlocksPerTrack;
314 /* Find the position in the chain/list of EBRs at which to insert
315 new EBR */
317 ph = (struct PartitionHandle *)root->table->list.lh_TailPred;
318 head = (struct PartitionHandle *)&root->table->list;
320 while (ph != head && !found)
322 de = &ph->de;
323 block_no = de->de_LowCyl * de->de_Surfaces * de->de_BlocksPerTrack;
324 if (block_no < new_block_no)
325 found = TRUE;
326 else
327 ph = (struct PartitionHandle *)ph->ln.ln_Pred;
330 /* Calculate appropriate location for new EBR */
332 de = &root->de;
333 ebr_track_no = (new_block_no - 1) / de->de_BlocksPerTrack;
334 ebr_block_no = ebr_track_no * de->de_BlocksPerTrack;
336 /* Create new handle and add it to list */
338 new_ph = PartitionEBRNewHandle(PartitionBase, root, ptype->id[0],
339 new_block_no, new_block_count, ebr_block_no);
340 Insert(&root->table->list, &new_ph->ln, &ph->ln);
342 return new_ph;
344 return NULL;
347 static void PartitionEBRDeletePartition
349 struct Library *PartitionBase,
350 struct PartitionHandle *ph
353 Remove(&ph->ln);
354 PartitionEBRFreeHandle(PartitionBase, ph);
357 static LONG PartitionEBRGetPartitionTableAttr(struct Library *PartitionBase, struct PartitionHandle *root, struct TagItem *tag)
359 switch (tag->ti_Tag)
361 case PTT_MAXLEADIN:
362 *((LONG *)tag->ti_Data) = root->de.de_BlocksPerTrack;
363 return TRUE;
366 return 0;
369 static LONG PartitionEBRGetPartitionAttr(struct Library *PartitionBase, struct PartitionHandle *ph, struct TagItem *tag)
371 struct EBRData *data = (struct EBRData *)ph->data;
373 switch (tag->ti_Tag)
375 case PT_TYPE:
376 PTYPE(tag->ti_Data)->id[0] = data->type;
377 PTYPE(tag->ti_Data)->id_len = 1;
378 return TRUE;
380 case PT_STARTBLOCK:
381 *((UQUAD *)tag->ti_Data) = data->block_no;
382 return TRUE;
384 case PT_ENDBLOCK:
385 *((UQUAD *)tag->ti_Data) = data->block_no + data->block_count - 1;
386 return TRUE;
389 return 0;
392 static LONG PartitionEBRSetPartitionAttrs(struct Library *PartitionBase, struct PartitionHandle *ph, const struct TagItem *taglist)
394 struct EBRData *data = (struct EBRData *)ph->data;
395 struct TagItem *tag;
397 while ((tag = NextTagItem((struct TagItem **)&taglist)))
399 switch (tag->ti_Tag)
401 case PT_DOSENVEC:
402 // TO DO: move handle to new position in list
403 CopyMem((struct DosEnvec *)tag->ti_Data, &ph->de, sizeof(struct DosEnvec));
404 break;
405 case PT_TYPE:
406 data->type = PTYPE(tag->ti_Data)->id[0]; // fix
407 /* Update DOSType according to a new type ID */
408 setDosType(&ph->de, MBR_FindDosType(data->type));
409 break;
413 return 0;
416 static const struct PartitionAttribute PartitionEBRPartitionTableAttrs[]=
418 {PTT_TYPE, PLAM_READ},
419 {PTT_RESERVED, PLAM_READ},
420 {PTT_MAXLEADIN, PLAM_READ},
421 {TAG_DONE, 0}
424 static const struct PartitionAttribute PartitionEBRPartitionAttrs[]=
426 {PT_GEOMETRY, PLAM_READ},
427 {PT_TYPE, PLAM_READ | PLAM_WRITE},
428 {PT_DOSENVEC, PLAM_READ | PLAM_WRITE},
429 {PT_POSITION, PLAM_READ},
430 {PT_LEADIN, PLAM_READ},
431 {PT_STARTBLOCK, PLAM_READ},
432 {PT_ENDBLOCK, PLAM_READ},
433 {TAG_DONE, 0}
436 static ULONG PartitionEBRDestroyPartitionTable
438 struct Library *PartitionBase,
439 struct PartitionHandle *root
442 struct PartitionHandle *ph;
445 while ((ph = (struct PartitionHandle *)RemHead(&root->table->list))
446 != NULL)
448 PartitionEBRDeletePartition(PartitionBase, ph);
450 PartitionEBRWritePartitionTable(PartitionBase, root);
452 return 0;
455 const struct PTFunctionTable PartitionEBR =
457 PHPTT_EBR,
458 "PC-EBR",
459 PartitionEBRCheckPartitionTable,
460 PartitionEBROpenPartitionTable,
461 PartitionEBRClosePartitionTable,
462 PartitionEBRWritePartitionTable,
463 PartitionEBRCreatePartitionTable,
464 PartitionEBRAddPartition,
465 PartitionEBRDeletePartition,
466 PartitionEBRGetPartitionTableAttr,
467 NULL,
468 PartitionEBRGetPartitionAttr,
469 PartitionEBRSetPartitionAttrs,
470 PartitionEBRPartitionTableAttrs,
471 PartitionEBRPartitionAttrs,
472 PartitionEBRDestroyPartitionTable,
473 NULL