// 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 #include #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: %" B_PRIu32 "\n", GetNLink())); PRINT((" uid: %" B_PRIx32 "\n", GetUID())); PRINT((" gid: %" B_PRIx32 "\n", GetGID())); PRINT((" size: %" B_PRIu64 "\n", GetSize())); PRINT((" atime: %" B_PRIu32 "\n", GetATime())); PRINT((" mtime: %" B_PRIu32 "\n", GetMTime())); PRINT((" ctime: %" B_PRIu32 "\n", GetCTime())); PRINT((" blocks: %" B_PRIu32 "\n", GetBlocks())); PRINT((" rdev: %" B_PRIu32 "\n", GetRDev())); PRINT((" generation: %" B_PRIu32 "\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 %" B_PRId32 " " "on node %" B_PRIu64 ": 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