root/src/kits/storage/Statable.cpp
/*
 * Copyright 2002-2014 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Tyler Dauwalder
 *              Ingo Weinhold, bonefish@users.sf.net
 */


#include <Statable.h>

#include <sys/stat.h>

#include <compat/sys/stat.h>

#include <Node.h>
#include <NodeMonitor.h>
#include <Volume.h>


class BStatable::Private {
public:
        Private(const BStatable* object)
                :
                fObject(object)
        {
        }

        status_t GetStatBeOS(struct stat_beos* stat)
        {
                return fObject->_GetStat(stat);
        }

private:
        const BStatable*        fObject;
};


#if __GNUC__ > 3
BStatable::~BStatable()
{
}
#endif


// Returns whether or not the current node is a file.
bool
BStatable::IsFile() const
{
        struct stat stat;
        if (GetStat(&stat) == B_OK)
                return S_ISREG(stat.st_mode);
        else
                return false;
}


// Returns whether or not the current node is a directory.
bool
BStatable::IsDirectory() const
{
        struct stat stat;
        if (GetStat(&stat) == B_OK)
                return S_ISDIR(stat.st_mode);
        else
                return false;
}


// Returns whether or not the current node is a symbolic link.
bool
BStatable::IsSymLink() const
{
        struct stat stat;
        if (GetStat(&stat) == B_OK)
                return S_ISLNK(stat.st_mode);
        else
                return false;
}


// Fills out ref with the node_ref of the node.
status_t
BStatable::GetNodeRef(node_ref* ref) const
{
        status_t result = (ref ? B_OK : B_BAD_VALUE);
        struct stat stat = {};

        if (result == B_OK)
                result = GetStat(&stat);

        if (result == B_OK) {
                ref->device  = stat.st_dev;
                ref->node = stat.st_ino;
        }

        return result;
}


// Fills out the node's UID into owner.
status_t
BStatable::GetOwner(uid_t* owner) const
{
        status_t result = (owner ? B_OK : B_BAD_VALUE);
        struct stat stat = {};

        if (result == B_OK)
                result = GetStat(&stat);

        if (result == B_OK)
                *owner = stat.st_uid;

        return result;
}


// Sets the node's UID to owner.
status_t
BStatable::SetOwner(uid_t owner)
{
        struct stat stat = {};
        stat.st_uid = owner;

        return set_stat(stat, B_STAT_UID);
}


// Fills out the node's GID into group.
status_t
BStatable::GetGroup(gid_t* group) const
{
        status_t result = (group ? B_OK : B_BAD_VALUE);
        struct stat stat = {};

        if (result == B_OK)
                result = GetStat(&stat);

        if (result == B_OK)
                *group = stat.st_gid;

        return result;
}


// Sets the node's GID to group.
status_t
BStatable::SetGroup(gid_t group)
{
        struct stat stat = {};
        stat.st_gid = group;

        return set_stat(stat, B_STAT_GID);
}


// Fills out permissions with the node's permissions.
status_t
BStatable::GetPermissions(mode_t* permissions) const
{
        status_t result = (permissions ? B_OK : B_BAD_VALUE);
        struct stat stat = {};

        if (result == B_OK)
                result = GetStat(&stat);

        if (result == B_OK)
                *permissions = (stat.st_mode & S_IUMSK);

        return result;
}


// Sets the node's permissions to permissions.
status_t
BStatable::SetPermissions(mode_t permissions)
{
        struct stat stat = {};
        // the FS should do the correct masking -- only the S_IUMSK part is
        // modifiable
        stat.st_mode = permissions;

        return set_stat(stat, B_STAT_MODE);
}


// Fills out the size of the node's data (not counting attributes) into size.
status_t
BStatable::GetSize(off_t* size) const
{
        status_t result = (size ? B_OK : B_BAD_VALUE);
        struct stat stat = {};

        if (result == B_OK)
                result = GetStat(&stat);

        if (result == B_OK)
                *size = stat.st_size;

        return result;
}


// Fills out mtime with the last modification time of the node.
status_t
BStatable::GetModificationTime(time_t* mtime) const
{
        status_t result = (mtime ? B_OK : B_BAD_VALUE);
        struct stat stat = {};

        if (result == B_OK)
                result = GetStat(&stat);

        if (result == B_OK)
                *mtime = stat.st_mtime;

        return result;
}


// Sets the node's last modification time to mtime.
status_t
BStatable::SetModificationTime(time_t mtime)
{
        struct stat stat = {};
        stat.st_mtime = mtime;

        return set_stat(stat, B_STAT_MODIFICATION_TIME);
}


// Fills out ctime with the creation time of the node
status_t
BStatable::GetCreationTime(time_t* ctime) const
{
        status_t result = (ctime ? B_OK : B_BAD_VALUE);
        struct stat stat = {};

        if (result == B_OK)
                result = GetStat(&stat);

        if (result == B_OK)
                *ctime = stat.st_crtime;

        return result;
}


// Sets the node's creation time to ctime.
status_t
BStatable::SetCreationTime(time_t ctime)
{
        struct stat stat = {};
        stat.st_crtime = ctime;

        return set_stat(stat, B_STAT_CREATION_TIME);
}


// Fills out atime with the access time of the node.
status_t
BStatable::GetAccessTime(time_t* atime) const
{
        status_t result = (atime ? B_OK : B_BAD_VALUE);
        struct stat stat = {};

        if (result == B_OK)
                result = GetStat(&stat);

        if (result == B_OK)
                *atime = stat.st_atime;

        return result;
}


// Sets the node's access time to atime.
status_t
BStatable::SetAccessTime(time_t atime)
{
        struct stat stat = {};
        stat.st_atime = atime;

        return set_stat(stat, B_STAT_ACCESS_TIME);
}


// Fills out vol with the the volume that the node lives on.
status_t
BStatable::GetVolume(BVolume* volume) const
{
        status_t result = (volume ? B_OK : B_BAD_VALUE);
        struct stat stat = {};
        if (result == B_OK)
                result = GetStat(&stat);

        if (result == B_OK)
                result = volume->SetTo(stat.st_dev);

        return result;
}


// _OhSoStatable1() -> GetStat()
extern "C" status_t
#if __GNUC__ == 2
_OhSoStatable1__9BStatable(const BStatable* self, struct stat* stat)
#else
_ZN9BStatable14_OhSoStatable1Ev(const BStatable* self, struct stat* stat)
#endif
{
        // No Perform() method -- we have to use the old GetStat() method instead.
        struct stat_beos oldStat = {};
        status_t result = BStatable::Private(self).GetStatBeOS(&oldStat);
        if (result != B_OK)
                return result;

        convert_from_stat_beos(&oldStat, stat);

        return B_OK;
}


void BStatable::_OhSoStatable2() {}
void BStatable::_OhSoStatable3() {}