1// SuperBlock.cpp
2//
3// Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de)
4//
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
17// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18//
19// You can alternatively use *this file* under the terms of the the MIT
20// license included in this package.
21
22#include <new>
23#include <string.h>
24#include <unistd.h>
25
26#include "Debug.h"
27#include "SuperBlock.h"
28
29using std::nothrow;
30
31/*!
32	\class DirEntry
33	\brief Represents the on-disk structure for superblock of the FS.
34
35	There exist two versions of the structure and this class can deal with both
36	of them. This class can also handle a very old layout that puts the super
37	block in a different location. The Init() methods tries to find and read
38	the superblock from disk.
39*/
40
41// read_super_block
42template<typename super_block_t>
43static
44status_t
45read_super_block(int device, off_t offset, const char *magic,
46				 super_block_t **_superBlock)
47{
48	super_block_t *superBlock = NULL;
49	status_t error = B_OK;
50	// allocate memory for the superblock
51	if (error == B_OK) {
52		superBlock = new(nothrow) super_block_t;
53		if (!superBlock)
54			error = B_NO_MEMORY;
55	}
56	// read the superblock
57	if (error == B_OK) {
58		size_t size = sizeof(super_block_t);
59		if (read_pos(device, offset, superBlock, size) != (int32)size)
60			error = B_IO_ERROR;
61	}
62	// check magic
63	if (error == B_OK) {
64		size_t len = strlen(magic);
65		if (strncmp(superBlock->s_magic, magic, len))
66			error = B_ERROR;
67	}
68	// set result / cleanup on failure
69	if (error == B_OK)
70		*_superBlock = superBlock;
71	else if (superBlock)
72		delete superBlock;
73	return error;
74}
75
76// constructor
77SuperBlock::SuperBlock()
78	: fFormatVersion(REISERFS_3_6),
79	  fCurrentData(NULL)
80{
81}
82
83// destructor
84SuperBlock::~SuperBlock()
85{
86	if (GetFormatVersion() == REISERFS_3_6) {
87		if (fCurrentData)
88			delete fCurrentData;
89	} else {
90		if (fOldData)
91			delete fOldData;
92	}
93}
94
95// Init
96status_t
97SuperBlock::Init(int device, off_t offset)
98{
99	status_t error = B_OK;
100	// try old version and old layout
101	if (read_super_block(device, REISERFS_OLD_DISK_OFFSET_IN_BYTES + offset,
102						 REISERFS_SUPER_MAGIC_STRING, &fOldData) == B_OK) {
103PRINT(("SuperBlock: ReiserFS 3.5 (old layout)\n"));
104		fFormatVersion = REISERFS_3_5;
105	// try old version and new layout
106	} else if (read_super_block(device, REISERFS_DISK_OFFSET_IN_BYTES + offset,
107			REISERFS_SUPER_MAGIC_STRING, &fOldData) == B_OK) {
108PRINT(("SuperBlock: ReiserFS 3.5\n"));
109		fFormatVersion = REISERFS_3_5;
110	// try new version and new layout
111	} else if (read_super_block(device, REISERFS_DISK_OFFSET_IN_BYTES + offset,
112			REISER2FS_SUPER_MAGIC_STRING, &fCurrentData) == B_OK) {
113PRINT(("SuperBlock: ReiserFS 3.6\n"));
114		fFormatVersion = REISERFS_3_6;
115	// failure
116	} else
117		error = B_ERROR;
118	// TODO: checks...
119	return error;
120}
121
122
123// GetLabel
124status_t
125SuperBlock::GetLabel(char* buffer, size_t bufferSize) const
126{
127	if (GetFormatVersion() == REISERFS_3_6 && fCurrentData->s_label[0]) {
128		size_t len = MIN(sizeof(fCurrentData->s_label), bufferSize - 1);
129		memcpy(buffer, fCurrentData->s_label, len);
130		buffer[len] = '\0';
131		return B_OK;
132	}
133	return B_ENTRY_NOT_FOUND;
134}
135