// StatItem.h
//
// Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can alternatively use *this file* under the terms of the the MIT
// license included in this package.
 
#ifndef STAT_ITEM_H
#define STAT_ITEM_H
 
#include <sys/stat.h>
 
#include <SupportDefs.h>
 
#include "Block.h"
#include "Debug.h"
#include "endianess.h"
#include "Item.h"
#include "reiserfs.h"
 
// StatData
/*!
	\class StatData
	\brief Represents the on-disk structure for stat data (stat item contents).
 
	There are two different formats for stat data. This class hides this
	fact and provides convenient access to the fields.
*/
class StatData {
public:
	StatData() : fCurrentData(NULL), fVersion(STAT_DATA_V2) {}
	StatData(const StatData &data)
		: fCurrentData(NULL), fVersion(STAT_DATA_V2) { *this = data; }
	StatData(stat_data_v1 *data, bool clone = false)
		: fCurrentData(NULL), fVersion(STAT_DATA_V2) { SetTo(data, clone); }
	StatData(stat_data *data, bool clone = false)
		: fCurrentData(NULL), fVersion(STAT_DATA_V2) { SetTo(data, clone); }
	~StatData() { Unset(); }
 
	status_t SetTo(stat_data_v1 *data, bool clone = false)
	{
		Unset();
		status_t error = B_OK;
		fVersion = STAT_DATA_V1;
		if (clone && data) {
			fOldData = new(nothrow) stat_data_v1;
			if (fOldData) {
				*fOldData = *data;
				fVersion |= ALLOCATED;
			} else
				error = B_NO_MEMORY;
		} else
			fOldData = data;
		return error;
	}
 
	status_t SetTo(stat_data *data, bool clone = false)
	{
		Unset();
		status_t error = B_OK;
		fVersion = STAT_DATA_V2;
		if (clone && data) {
			fCurrentData = new(nothrow) stat_data;
			if (fCurrentData) {
				*fCurrentData = *data;
				fVersion |= ALLOCATED;
			} else
				error = B_NO_MEMORY;
		} else
			fCurrentData = data;
		return error;
	}
 
	void Unset()
	{
		if (fVersion & ALLOCATED) {
			if (GetVersion() == STAT_DATA_V2) {
				delete fCurrentData;
				fCurrentData = NULL;
			} else {
				delete fOldData;
				fOldData = NULL;
			}
		}
	}
 
	uint32 GetVersion() const { return (fVersion & VERSION_MASK); }
 
	uint16 GetMode() const
	{
		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_mode)
											 : le2h(fOldData->sd_mode));
	}
 
	uint32 GetNLink() const
	{
		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_nlink)
											 : le2h(fOldData->sd_nlink));
	}
 
	uint32 GetUID() const
	{
		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_uid)
											 : le2h(fOldData->sd_uid));
	}
 
	uint32 GetGID() const
	{
		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_gid)
											 : le2h(fOldData->sd_gid));
	}
 
	uint64 GetSize() const
	{
		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_size)
											 : le2h(fOldData->sd_size));
	}
 
	uint32 GetATime() const
	{
		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_atime)
											 : le2h(fOldData->sd_atime));
	}
 
	uint32 GetMTime() const
	{
		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_mtime)
											 : le2h(fOldData->sd_mtime));
	}
 
	uint32 GetCTime() const
	{
		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_ctime)
											 : le2h(fOldData->sd_ctime));
	}
 
	uint32 GetBlocks() const
	{
		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->sd_blocks)
											 : le2h(fOldData->u.sd_blocks));
	}
 
	uint32 GetRDev() const
	{
		return (GetVersion() == STAT_DATA_V2 ? le2h(fCurrentData->u.sd_rdev)
											 : le2h(fOldData->u.sd_rdev));
	}
 
	uint32 GetGeneration() const
	{
		return (GetVersion() == STAT_DATA_V2
			? le2h(fCurrentData->u.sd_generation) : 0);
	}
 
	bool IsDir() const { return S_ISDIR(GetMode()); }
	bool IsFile() const { return S_ISREG(GetMode()); }
	bool IsSymlink() const { return S_ISLNK(GetMode()); }
	bool IsEsoteric() const { return (!IsDir() && !IsFile() && !IsSymlink()); }
 
 
	void Dump()
	{
		PRINT(("StatData:\n"));
		PRINT(("  mode:       %hx\n", GetMode()));
		PRINT(("  nlink:      %lu\n", GetNLink()));
		PRINT(("  uid:        %lx\n", GetUID()));
		PRINT(("  gid:        %lx\n", GetGID()));
		PRINT(("  size:       %Lu\n", GetSize()));
		PRINT(("  atime:      %lu\n", GetATime()));
		PRINT(("  mtime:      %lu\n", GetMTime()));
		PRINT(("  ctime:      %lu\n", GetCTime()));
		PRINT(("  blocks:     %lu\n", GetBlocks()));
		PRINT(("  rdev:       %lu\n", GetRDev()));
		PRINT(("  generation: %lu\n", GetGeneration()));
	}
 
	StatData &operator=(const StatData &data)
	{
		if (&data != this) {
			if (data.GetVersion() == STAT_DATA_V2)
				SetTo(data.fCurrentData, true);
			else
				SetTo(data.fOldData, true);
		}
		return *this;
	}
 
private:
	enum {
		VERSION_MASK	= STAT_DATA_V1 | STAT_DATA_V2,
		ALLOCATED		= 0x8000
	};
 
private:
	union {
		stat_data_v1	*fOldData;
		stat_data		*fCurrentData;
	};
	uint16	fVersion;
};
 
// StatItem
/*!
	\class StatItem
	\brief Provides access to the on-disk stat item structure.
 
	A stat item simply consists of StatData. This is only a convenience
	class to get hold of it.
*/
class StatItem : public Item {
public:
	StatItem() : Item() {}
	StatItem(LeafNode *node, ItemHeader *header)
		: Item(node, header) {}
 
	status_t GetStatData(StatData *statData, bool clone = false) const
	{
		status_t error = B_OK;
		if (GetLen() == sizeof(stat_data)) {
			stat_data *data = (stat_data*)GetData();
			statData->SetTo(data, clone);
		} else if (GetLen() == sizeof(stat_data_v1)) {
			stat_data_v1 *data = (stat_data_v1*)GetData();
			statData->SetTo(data, clone);
		} else {
			FATAL(("WARNING: bad stat item %ld on node %Ld: the item len "
				   "(%u) does not match the len of any stat data format!\n",
				   GetIndex(), fNode->GetNumber(), GetLen()));
			error = B_BAD_DATA;
		}
		return error;
	}
};
 
#endif	// STAT_ITEM_H

V576 Incorrect format. Consider checking the second actual argument of the 'dprintf' function. The memsize type argument is expected.

V576 Potentially incorrect format string is passed to the 'dprintf' function. Prefix 'L' is not applicable to conversion specifier 'd'.