1// StatItem.h
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#ifndef STAT_ITEM_H
23#define STAT_ITEM_H
24
25#include <sys/stat.h>
26
27#include <SupportDefs.h>
28
29#include "Block.h"
30#include "Debug.h"
31#include "endianess.h"
32#include "Item.h"
33#include "reiserfs.h"
34
35// StatData
36/*!
37	\class StatData
38	\brief Represents the on-disk structure for stat data (stat item contents).
39
40	There are two different formats for stat data. This class hides this
41	fact and provides convenient access to the fields.
42*/
43class StatData {
44public:
45	StatData() : fCurrentData(NULL), fVersion(STAT_DATA_V2) {}
46	StatData(const StatData &data)
47		: fCurrentData(NULL), fVersion(STAT_DATA_V2) { *this = data; }
48	StatData(stat_data_v1 *data, bool clone = false)
49		: fCurrentData(NULL), fVersion(STAT_DATA_V2) { SetTo(data, clone); }
50	StatData(stat_data *data, bool clone = false)
51		: fCurrentData(NULL), fVersion(STAT_DATA_V2) { SetTo(data, clone); }
52	~StatData() { Unset(); }
53
54	status_t SetTo(stat_data_v1 *data, bool clone = false)
55	{
56		Unset();
57		status_t error = B_OK;
58		fVersion = STAT_DATA_V1;
59		if (clone && data) {
60			fOldData = new(nothrow) stat_data_v1;
61			if (fOldData) {
62				*fOldData = *data;
63				fVersion |= ALLOCATED;
64			} else
65				error = B_NO_MEMORY;
66		} else
67			fOldData = data;
68		return error;
69	}
70
71	status_t SetTo(stat_data *data, bool clone = false)
72	{
73		Unset();
74		status_t error = B_OK;
75		fVersion = STAT_DATA_V2;
76		if (clone && data) {
77			fCurrentData = new(nothrow) stat_data;
78			if (fCurrentData) {
79				*fCurrentData = *data;
80				fVersion |= ALLOCATED;
81			} else
82				error = B_NO_MEMORY;
83		} else
84			fCurrentData = data;
85		return error;
86	}
87
88	void Unset()
89	{
90		if (fVersion & ALLOCATED) {
91			if (GetVersion() == STAT_DATA_V2) {
92				delete fCurrentData;
93				fCurrentData = NULL;
94			} else {
95				delete fOldData;
96				fOldData = NULL;
97			}
98		}
99	}
100
101	uint32 GetVersion() const { return (fVersion & VERSION_MASK); }
102
103	uint16 GetMode() const
104	{
105		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_mode)
106											: le2h(fOldData->sd_mode));
107	}
108
109	uint32 GetNLink() const
110	{
111		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_nlink)
112											: le2h(fOldData->sd_nlink));
113	}
114
115	uint32 GetUID() const
116	{
117		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_uid)
118											: le2h(fOldData->sd_uid));
119	}
120
121	uint32 GetGID() const
122	{
123		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_gid)
124											: le2h(fOldData->sd_gid));
125	}
126
127	uint64 GetSize() const
128	{
129		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_size)
130											: le2h(fOldData->sd_size));
131	}
132
133	uint32 GetATime() const
134	{
135		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_atime)
136											: le2h(fOldData->sd_atime));
137	}
138
139	uint32 GetMTime() const
140	{
141		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_mtime)
142											: le2h(fOldData->sd_mtime));
143	}
144
145	uint32 GetCTime() const
146	{
147		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_ctime)
148											: le2h(fOldData->sd_ctime));
149	}
150
151	uint32 GetBlocks() const
152	{
153		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_blocks)
154											: le2h(fOldData->u.sd_blocks));
155	}
156
157	uint32 GetRDev() const
158	{
159		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->u.sd_rdev)
160											: le2h(fOldData->u.sd_rdev));
161	}
162
163	uint32 GetGeneration() const
164	{
165		return (GetVersion() == STAT_DATA_V2
166			? le2h(fCurrentData->u.sd_generation) : 0);
167	}
168
169	bool IsDir() const { return S_ISDIR(GetMode()); }
170	bool IsFile() const { return S_ISREG(GetMode()); }
171	bool IsSymlink() const { return S_ISLNK(GetMode()); }
172	bool IsEsoteric() const { return (!IsDir() && !IsFile() && !IsSymlink()); }
173
174
175	void Dump()
176	{
177		PRINT(("StatData:\n"));
178		PRINT(("  mode:       %hx\n", GetMode()));
179		PRINT(("  nlink:      %" B_PRIu32 "\n", GetNLink()));
180		PRINT(("  uid:        %" B_PRIx32 "\n", GetUID()));
181		PRINT(("  gid:        %" B_PRIx32 "\n", GetGID()));
182		PRINT(("  size:       %" B_PRIu64 "\n", GetSize()));
183		PRINT(("  atime:      %" B_PRIu32 "\n", GetATime()));
184		PRINT(("  mtime:      %" B_PRIu32 "\n", GetMTime()));
185		PRINT(("  ctime:      %" B_PRIu32 "\n", GetCTime()));
186		PRINT(("  blocks:     %" B_PRIu32 "\n", GetBlocks()));
187		PRINT(("  rdev:       %" B_PRIu32 "\n", GetRDev()));
188		PRINT(("  generation: %" B_PRIu32 "\n", GetGeneration()));
189	}
190
191	StatData &operator=(const StatData &data)
192	{
193		if (&data != this) {
194			if (data.GetVersion() == STAT_DATA_V2)
195				SetTo(data.fCurrentData, true);
196			else
197				SetTo(data.fOldData, true);
198		}
199		return *this;
200	}
201
202private:
203	enum {
204		VERSION_MASK	= STAT_DATA_V1 | STAT_DATA_V2,
205		ALLOCATED		= 0x8000
206	};
207
208private:
209	union {
210		stat_data_v1	*fOldData;
211		stat_data		*fCurrentData;
212	};
213	uint16	fVersion;
214};
215
216// StatItem
217/*!
218	\class StatItem
219	\brief Provides access to the on-disk stat item structure.
220
221	A stat item simply consists of StatData. This is only a convenience
222	class to get hold of it.
223*/
224class StatItem : public Item {
225public:
226	StatItem() : Item() {}
227	StatItem(LeafNode *node, ItemHeader *header)
228		: Item(node, header) {}
229
230	status_t GetStatData(StatData *statData, bool clone = false) const
231	{
232		status_t error = B_OK;
233		if (GetLen() == sizeof(stat_data)) {
234			stat_data *data = (stat_data*)GetData();
235			statData->SetTo(data, clone);
236		} else if (GetLen() == sizeof(stat_data_v1)) {
237			stat_data_v1 *data = (stat_data_v1*)GetData();
238			statData->SetTo(data, clone);
239		} else {
240			FATAL(("WARNING: bad stat item %" B_PRId32 " "
241				"on node %" B_PRIu64 ": the item len "
242				"(%u) does not match the len of any stat data format!\n",
243				GetIndex(), fNode->GetNumber(), GetLen()));
244			error = B_BAD_DATA;
245		}
246		return error;
247	}
248};
249
250#endif	// STAT_ITEM_H
251