438 lines
13 KiB
C++
438 lines
13 KiB
C++
/*
|
|
* Data of a FileInode stored on disk.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <common/storage/striping/StripePattern.h>
|
|
#include <common/storage/Metadata.h>
|
|
#include <common/storage/StatData.h>
|
|
#include <common/storage/PathInfo.h>
|
|
|
|
/* Note: Don't forget to update DiskMetaData::getSupportedFileInodeFeatureFlags() if you add new
|
|
* flags here. */
|
|
|
|
#define FILEINODE_FEATURE_MIRRORED 1 // indicate mirrored inodes
|
|
#define FILEINODE_FEATURE_BUDDYMIRRORED 8 // indicate mirrored inodes
|
|
|
|
// note: original parent-id and uid are required for the chunk-path calculation
|
|
#define FILEINODE_FEATURE_HAS_ORIG_PARENTID 16 // parent-id was updated
|
|
#define FILEINODE_FEATURE_HAS_ORIG_UID 32 // uid was updated
|
|
#define FILEINODE_FEATURE_HAS_STATFLAGS 64 // stat-data have their own flags
|
|
#define FILEINODE_FEATURE_HAS_VERSIONS 128 // file has a cto version counter
|
|
#define FILEINODE_FEATURE_HAS_RST 256 // file has remote targets
|
|
#define FILEINODE_FEATURE_HAS_STATE_FLAGS 512 // file has state flags (access state + data state)
|
|
|
|
enum FileInodeOrigFeature
|
|
{
|
|
FileInodeOrigFeature_UNSET = -1,
|
|
FileInodeOrigFeature_TRUE,
|
|
FileInodeOrigFeature_FALSE
|
|
};
|
|
|
|
// Access control flags (lower 5 bits)
|
|
// NOTE: The naming of access flags might seem counter-intuitive.
|
|
//
|
|
// - UNLOCKED means no access restrictions are in place
|
|
// - READ_LOCK means READ operations are BLOCKED, allowing only write operations.
|
|
// The file is effectively "write-only"
|
|
// - WRITE_LOCK means WRITE operations are BLOCKED, allowing only read operations.
|
|
// The file is effectively "read-only"
|
|
// - When both READ_LOCK and WRITE_LOCK are set, all access is blocked
|
|
namespace AccessFlags {
|
|
constexpr uint8_t UNLOCKED = 0x00; // No flags set (no restrictions)
|
|
constexpr uint8_t READ_LOCK = 0x01; // Bit 0 (1 << 0) - Block reads
|
|
constexpr uint8_t WRITE_LOCK = 0x02; // Bit 1 (1 << 1) - Block writes
|
|
constexpr uint8_t RESERVED3 = 0x04; // Bit 2 (1 << 2) - Reserved for future use
|
|
constexpr uint8_t RESERVED4 = 0x08; // Bit 3 (1 << 3) - Reserved for future use
|
|
constexpr uint8_t RESERVED5 = 0x10; // Bit 4 (1 << 4) - Reserved for future use
|
|
}
|
|
|
|
// Represents data state (HSM application defined) (0-7)
|
|
using DataState = uint8_t;
|
|
|
|
class FileState {
|
|
public:
|
|
static constexpr uint8_t ACCESS_FLAGS_MASK = 0x1F; // 0001 1111 (5 bits)
|
|
static constexpr uint8_t DATA_STATE_MASK = 0xE0; // 1110 0000 (3 bits)
|
|
static constexpr uint8_t DATA_STATE_SHIFT = 5; // Number of bits to shift
|
|
|
|
// Constructor taking a raw byte value
|
|
explicit FileState(uint8_t value = 0) : raw(value) {}
|
|
|
|
uint8_t getAccessFlags() const
|
|
{
|
|
return raw & ACCESS_FLAGS_MASK;
|
|
}
|
|
|
|
DataState getDataState() const
|
|
{
|
|
return (raw & DATA_STATE_MASK) >> DATA_STATE_SHIFT;
|
|
}
|
|
|
|
bool isReadLocked() const
|
|
{
|
|
return (raw & AccessFlags::READ_LOCK) != 0;
|
|
}
|
|
|
|
bool isWriteLocked() const
|
|
{
|
|
return (raw & AccessFlags::WRITE_LOCK) != 0;
|
|
}
|
|
|
|
bool isUnlocked() const
|
|
{
|
|
return (getAccessFlags() == 0);
|
|
}
|
|
|
|
bool isFullyLocked() const
|
|
{
|
|
return (isReadLocked() && isWriteLocked());
|
|
}
|
|
|
|
uint8_t getRawValue() const { return raw; }
|
|
|
|
private:
|
|
uint8_t raw; // Raw byte representing access flags + data state of a file
|
|
};
|
|
|
|
/* inode data inlined into a direntry, such as in DIRENTRY_STORAGE_FORMAT_VER3 */
|
|
class FileInodeStoreData
|
|
{
|
|
friend class FileInode;
|
|
friend class DirEntry;
|
|
friend class DirEntryStore;
|
|
friend class GenericDebugMsgEx;
|
|
friend class LookupIntentMsgEx; // just to avoid to copy two time statData
|
|
friend class RecreateDentriesMsgEx;
|
|
friend class RetrieveDirEntriesMsgEx;
|
|
friend class MetaStore;
|
|
friend class DiskMetaData;
|
|
|
|
friend class AdjustChunkPermissionsMsgEx;
|
|
|
|
friend class TestSerialization; // for testing
|
|
|
|
public:
|
|
|
|
FileInodeStoreData()
|
|
: inodeFeatureFlags(FILEINODE_FEATURE_HAS_VERSIONS),
|
|
stripePattern(NULL),
|
|
origFeature(FileInodeOrigFeature_UNSET),
|
|
fileVersion(0),
|
|
metaVersion(0),
|
|
rawFileState(0)
|
|
{ }
|
|
|
|
FileInodeStoreData(const std::string& entryID, StatData* statData,
|
|
StripePattern* stripePattern, unsigned featureFlags, unsigned origParentUID,
|
|
const std::string& origParentEntryID, FileInodeOrigFeature origFeature)
|
|
: inodeFeatureFlags(featureFlags),
|
|
inodeStatData(*statData),
|
|
entryID(entryID),
|
|
origFeature(origFeature),
|
|
origParentUID(origParentUID),
|
|
origParentEntryID(origParentEntryID),
|
|
fileVersion(0),
|
|
metaVersion(0), rawFileState(0)
|
|
{
|
|
this->stripePattern = stripePattern->clone();
|
|
|
|
if ((statData->getUserID() != origParentUID) &&
|
|
(origFeature == FileInodeOrigFeature_TRUE) )
|
|
this->inodeFeatureFlags |= FILEINODE_FEATURE_HAS_ORIG_UID;
|
|
}
|
|
|
|
bool operator==(const FileInodeStoreData& second) const;
|
|
|
|
bool operator!=(const FileInodeStoreData& other) const { return !(*this == other); }
|
|
|
|
/**
|
|
* Used to set the values from those read from disk
|
|
*/
|
|
FileInodeStoreData(std::string entryID, FileInodeStoreData* diskData) :
|
|
entryID(entryID)
|
|
{
|
|
// this->entryID = entryID; // set in initializer
|
|
this->stripePattern = NULL;
|
|
|
|
setFileInodeStoreData(diskData);
|
|
}
|
|
|
|
~FileInodeStoreData()
|
|
{
|
|
SAFE_DELETE_NOSET(this->stripePattern);
|
|
}
|
|
|
|
private:
|
|
uint32_t inodeFeatureFlags; // feature flags for the inode itself, e.g. for mirroring
|
|
|
|
StatData inodeStatData;
|
|
std::string entryID; // filesystem-wide unique string
|
|
StripePattern* stripePattern;
|
|
|
|
FileInodeOrigFeature origFeature; // indirectly determined via dentry-version
|
|
uint32_t origParentUID;
|
|
std::string origParentEntryID;
|
|
|
|
// version number for CTO cache consistency optimizations
|
|
uint32_t fileVersion;
|
|
uint32_t metaVersion;
|
|
|
|
// raw byte value representing access flags + data state
|
|
uint8_t rawFileState;
|
|
|
|
void getPathInfo(PathInfo* outPathInfo);
|
|
|
|
|
|
public:
|
|
StatData* getInodeStatData()
|
|
{
|
|
return &this->inodeStatData;
|
|
}
|
|
|
|
std::string getEntryID()
|
|
{
|
|
return this->entryID;
|
|
}
|
|
|
|
StripePattern* getStripePattern()
|
|
{
|
|
return this->stripePattern;
|
|
}
|
|
|
|
uint32_t getFileVersion() const { return fileVersion; }
|
|
uint32_t getMetaVersion() const { return metaVersion; }
|
|
|
|
void setFileVersion(uint32_t fileVersion)
|
|
{
|
|
this->fileVersion = fileVersion;
|
|
}
|
|
|
|
void setMetaVersion(uint32_t metaVersion)
|
|
{
|
|
this->metaVersion = metaVersion;
|
|
setMetaVersionStat(metaVersion); //update metadata version in StatData
|
|
}
|
|
|
|
protected:
|
|
|
|
/**
|
|
* Set all fileInodeStoreData
|
|
*
|
|
* Note: Might update existing values and if these are allocated, such as stripePattern,
|
|
* these need to be freed first.
|
|
*/
|
|
void setFileInodeStoreData(FileInodeStoreData* diskData)
|
|
{
|
|
SAFE_DELETE_NOSET(this->stripePattern);
|
|
this->stripePattern = diskData->getStripePattern()->clone();
|
|
|
|
this->inodeStatData = *(diskData->getInodeStatData() );
|
|
this->inodeFeatureFlags = diskData->getInodeFeatureFlags();
|
|
this->origFeature = diskData->origFeature;
|
|
this->origParentUID = diskData->origParentUID;
|
|
this->origParentEntryID = diskData->origParentEntryID;
|
|
this->fileVersion = diskData->fileVersion;
|
|
setMetaVersion(diskData->metaVersion);
|
|
this->rawFileState = diskData->rawFileState;
|
|
}
|
|
|
|
void setInodeFeatureFlags(unsigned flags)
|
|
{
|
|
this->inodeFeatureFlags = flags;
|
|
}
|
|
|
|
void addInodeFeatureFlag(unsigned flag)
|
|
{
|
|
this->inodeFeatureFlags |= flag;
|
|
}
|
|
|
|
void removeInodeFeatureFlag(unsigned flag)
|
|
{
|
|
this->inodeFeatureFlags &= ~flag;
|
|
}
|
|
|
|
void setBuddyMirrorFeatureFlag(bool mirrored)
|
|
{
|
|
if (mirrored)
|
|
addInodeFeatureFlag(FILEINODE_FEATURE_BUDDYMIRRORED);
|
|
else
|
|
removeInodeFeatureFlag(FILEINODE_FEATURE_BUDDYMIRRORED);
|
|
}
|
|
|
|
bool getIsBuddyMirrored() const
|
|
{
|
|
return (getInodeFeatureFlags() & FILEINODE_FEATURE_BUDDYMIRRORED);
|
|
}
|
|
|
|
void setIsRstAvailable(bool available)
|
|
{
|
|
if (available)
|
|
addInodeFeatureFlag(FILEINODE_FEATURE_HAS_RST);
|
|
else
|
|
removeInodeFeatureFlag(FILEINODE_FEATURE_HAS_RST);
|
|
}
|
|
|
|
bool getIsRstAvailable() const
|
|
{
|
|
return (getInodeFeatureFlags() & FILEINODE_FEATURE_HAS_RST);
|
|
}
|
|
|
|
void setFileState(uint8_t value)
|
|
{
|
|
this->rawFileState = value;
|
|
if (this->rawFileState == 0)
|
|
removeInodeFeatureFlag(FILEINODE_FEATURE_HAS_STATE_FLAGS);
|
|
else
|
|
addInodeFeatureFlag(FILEINODE_FEATURE_HAS_STATE_FLAGS);
|
|
}
|
|
|
|
uint8_t getFileState() const
|
|
{
|
|
// If FILEINODE_FEATURE_HAS_STATE_FLAGS is not set,
|
|
// return the default "unlocked + zero data state"
|
|
if (!(inodeFeatureFlags & FILEINODE_FEATURE_HAS_STATE_FLAGS))
|
|
{
|
|
constexpr uint8_t defaultAccessFlags = AccessFlags::UNLOCKED;
|
|
constexpr uint8_t defaultDataState = 0;
|
|
|
|
// Format: [dataState (upper 3 bits) | accessFlags (lower 5 bits)]
|
|
return (defaultAccessFlags & FileState::ACCESS_FLAGS_MASK) |
|
|
((defaultDataState << FileState::DATA_STATE_SHIFT) & FileState::DATA_STATE_MASK);
|
|
}
|
|
|
|
// Return the explicitly set state if feature is supported
|
|
return rawFileState;
|
|
}
|
|
|
|
void setInodeStatData(StatData& statData)
|
|
{
|
|
this->inodeStatData = statData;
|
|
}
|
|
|
|
void setEntryID(const std::string& entryID)
|
|
{
|
|
this->entryID = entryID;
|
|
}
|
|
|
|
void setPattern(StripePattern* pattern)
|
|
{
|
|
this->stripePattern = pattern;
|
|
}
|
|
|
|
void setOrigUID(unsigned origParentUID)
|
|
{
|
|
this->origParentUID = origParentUID;
|
|
}
|
|
|
|
/**
|
|
* Set the origParentEntryID based on the parentDir. Feature flag will not be updated.
|
|
* This is for inodes which are not de-inlined and not renamed between dirs.
|
|
*/
|
|
void setDynamicOrigParentEntryID(const std::string& origParentEntryID)
|
|
{
|
|
/* Never overwrite existing data! Callers do not check if they need to set it only we do
|
|
* that here. */
|
|
if (!(this->inodeFeatureFlags & FILEINODE_FEATURE_HAS_ORIG_PARENTID) )
|
|
this->origParentEntryID = origParentEntryID;
|
|
}
|
|
|
|
/**
|
|
* Set the origParentEntryID from disk, no feature flag test and
|
|
* feature flag will not be updated.
|
|
* Note: Use this for disk-deserialization.
|
|
*/
|
|
void setDiskOrigParentEntryID(const std::string& origParentEntryID)
|
|
{
|
|
this->origParentEntryID = origParentEntryID;
|
|
}
|
|
|
|
/**
|
|
* Set the origParentEntryID. Feature flag will be updated, origInformation will be stored
|
|
* to disk.
|
|
* Note: Use this on file renames between dirs and de-inlining.
|
|
*/
|
|
void setPersistentOrigParentEntryID(const std::string& origParentEntryID)
|
|
{
|
|
/* Never overwrite existing data! Callers do not check if they need to set it only we do
|
|
* that here. */
|
|
if ( (!(this->inodeFeatureFlags & FILEINODE_FEATURE_HAS_ORIG_PARENTID) ) &&
|
|
(this->getOrigFeature() == FileInodeOrigFeature_TRUE) )
|
|
{
|
|
this->origParentEntryID = origParentEntryID;
|
|
addInodeFeatureFlag(FILEINODE_FEATURE_HAS_ORIG_PARENTID);
|
|
}
|
|
}
|
|
|
|
uint32_t getInodeFeatureFlags() const
|
|
{
|
|
return this->inodeFeatureFlags;
|
|
}
|
|
|
|
StripePattern* getPattern()
|
|
{
|
|
return this->stripePattern;
|
|
}
|
|
|
|
void setOrigFeature(FileInodeOrigFeature value)
|
|
{
|
|
this->origFeature = value;
|
|
}
|
|
|
|
FileInodeOrigFeature getOrigFeature() const
|
|
{
|
|
return this->origFeature;
|
|
}
|
|
|
|
uint32_t getOrigUID() const
|
|
{
|
|
return this->origParentUID;
|
|
}
|
|
|
|
const std::string& getOrigParentEntryID() const
|
|
{
|
|
return this->origParentEntryID;
|
|
}
|
|
|
|
void incDecNumHardlinks(int value)
|
|
{
|
|
this->inodeStatData.incDecNumHardLinks(value);
|
|
}
|
|
|
|
void setNumHardlinks(unsigned numHardlinks)
|
|
{
|
|
this->inodeStatData.setNumHardLinks(numHardlinks);
|
|
}
|
|
|
|
void setMetaVersionStat(unsigned metaVersion)
|
|
{
|
|
this->inodeStatData.setMetaVersionStat(metaVersion);
|
|
}
|
|
|
|
unsigned getNumHardlinks() const
|
|
{
|
|
return this->inodeStatData.getNumHardlinks();
|
|
}
|
|
|
|
/**
|
|
* Return the pattern and set the internal pattern to NULL to make sure it does not get
|
|
* deleted on object destruction.
|
|
*/
|
|
StripePattern* getStripePatternAndSetToNull()
|
|
{
|
|
StripePattern* pattern = this->stripePattern;
|
|
this->stripePattern = NULL;
|
|
|
|
return pattern;
|
|
}
|
|
|
|
void setAttribChangeTimeSecs(int64_t attribChangeTimeSecs)
|
|
{
|
|
this->inodeStatData.setAttribChangeTimeSecs(attribChangeTimeSecs);
|
|
}
|
|
|
|
};
|
|
|
|
|