1/*
2 * Copyright 2003-2013, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "Volume.h"
8#include "Directory.h"
9
10#include <boot/partitions.h>
11#include <boot/platform.h>
12
13#include <string.h>
14#include <unistd.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18
19
20using namespace FFS;
21using std::nothrow;
22
23
24Volume::Volume(boot::Partition *partition)
25	:
26	fRoot(NULL)
27{
28	if ((fDevice = open_node(partition, O_RDONLY)) < B_OK)
29		return;
30
31	if (read_pos(fDevice, 0, &fType, sizeof(int32)) < B_OK)
32		return;
33
34	fType = B_BENDIAN_TO_HOST_INT32(fType);
35
36	switch (fType) {
37		case DT_AMIGA_FFS:
38		case DT_AMIGA_FFS_INTL:
39		case DT_AMIGA_FFS_DCACHE:
40			break;
41
42		case DT_AMIGA_OFS:
43			printf("The Amiga OFS is not yet supported.\n");
44			return;
45		default:
46			// unsupported file system
47			//printf("amiga_ffs: unsupported: %08lx\n", fType);
48			return;
49	}
50
51	char *buffer = (char *)malloc(4096);
52	if (buffer == NULL)
53		return;
54
55	int32 blockSize = partition->block_size;
56	if (get_root_block(fDevice, buffer, blockSize, partition->size) != B_OK) {
57		// try to get the root block at different sizes, if the
58		// block size was incorrectly passed from the partitioning
59		// system
60		for (int32 size = 512; size <= 4096; size <<= 1) {
61			if (get_root_block(fDevice, buffer, size, partition->size) == B_OK) {
62				blockSize = size;
63				break;
64			} else if (size >= 4096) {
65				puts("Could not find root block\n");
66				free(buffer);
67				return;
68			}
69		}
70	}
71
72	char *newBuffer = (char *)realloc(buffer, blockSize);
73		// if reallocation fails, we keep the old buffer
74	if (newBuffer != NULL)
75		buffer = newBuffer;
76
77	fRootNode.SetTo(buffer, blockSize);
78	fRoot = new(nothrow) Directory(*this, fRootNode);
79		// fRoot will free the buffer for us upon destruction
80}
81
82
83Volume::~Volume()
84{
85	delete fRoot;
86	close(fDevice);
87}
88
89
90status_t
91Volume::InitCheck()
92{
93	if (fRoot != NULL)
94		return fRootNode.ValidateCheckSum();
95
96	return B_ERROR;
97}
98
99
100//	#pragma mark -
101
102
103float
104amiga_ffs_identify_file_system(boot::Partition *partition)
105{
106	Volume volume(partition);
107
108	return volume.InitCheck() < B_OK ? 0 : 0.8;
109}
110
111
112static status_t
113amiga_ffs_get_file_system(boot::Partition *partition, ::Directory **_root)
114{
115	Volume *volume = new(nothrow) Volume(partition);
116	if (volume == NULL)
117		return B_NO_MEMORY;
118
119	if (volume->InitCheck() < B_OK) {
120		delete volume;
121		return B_ERROR;
122	}
123
124	*_root = volume->Root();
125	return B_OK;
126}
127
128
129file_system_module_info gAmigaFFSFileSystemModule = {
130	"file_systems/amiga_ffs/v1",
131	kPartitionTypeAmigaFFS,
132	amiga_ffs_identify_file_system,
133	amiga_ffs_get_file_system
134};
135
136