root/src/tools/fs_shell/stat_util.cpp
/*
 * Copyright 2005-2007, Ingo Weinhold, bonefish@users.sf.net.
 * Distributed under the terms of the MIT License.
 */

#include "compatibility.h"

#include "stat_util.h"

#include <fcntl.h>
#include <sys/stat.h>

#include "fssh_fcntl.h"
#include "fssh_stat.h"


namespace FSShell {

// Haiku only mode_t flags
#ifndef HAIKU_HOST_PLATFORM_HAIKU
#       define S_LINK_SELF_HEALING      0
#       define S_LINK_AUTO_DELETE       0
#endif


fssh_mode_t
from_platform_mode(mode_t mode)
{
        #define SET_ST_MODE_BIT(flag, fsshFlag) \
                if (mode & flag)                        \
                        fsshMode |= fsshFlag;

        fssh_mode_t fsshMode = 0;

        // BeOS/Haiku only
        #if (defined(__BEOS__) || defined(__HAIKU__))
                SET_ST_MODE_BIT(FSSH_S_ATTR_DIR, S_ATTR_DIR);
                SET_ST_MODE_BIT(FSSH_S_ATTR, S_ATTR);
                SET_ST_MODE_BIT(FSSH_S_INDEX_DIR, S_INDEX_DIR);
                SET_ST_MODE_BIT(FSSH_S_INT_INDEX, S_INT_INDEX);
                SET_ST_MODE_BIT(FSSH_S_UINT_INDEX, S_UINT_INDEX);
                SET_ST_MODE_BIT(FSSH_S_LONG_LONG_INDEX, S_LONG_LONG_INDEX);
                SET_ST_MODE_BIT(FSSH_S_ULONG_LONG_INDEX, S_ULONG_LONG_INDEX);
                SET_ST_MODE_BIT(FSSH_S_FLOAT_INDEX, S_FLOAT_INDEX);
                SET_ST_MODE_BIT(FSSH_S_DOUBLE_INDEX, S_DOUBLE_INDEX);
                SET_ST_MODE_BIT(FSSH_S_ALLOW_DUPS, S_ALLOW_DUPS);
                SET_ST_MODE_BIT(FSSH_S_LINK_SELF_HEALING, S_LINK_SELF_HEALING);
                SET_ST_MODE_BIT(FSSH_S_LINK_AUTO_DELETE, S_LINK_AUTO_DELETE);
        #endif

        switch (mode & S_IFMT) {
                case S_IFLNK:
                        fsshMode |= FSSH_S_IFLNK;
                        break;
                case S_IFREG:
                        fsshMode |= FSSH_S_IFREG;
                        break;
                case S_IFBLK:
                        fsshMode |= FSSH_S_IFBLK;
                        break;
                case S_IFDIR:
                        fsshMode |= FSSH_S_IFDIR;
                        break;
                case S_IFIFO:
                        fsshMode |= FSSH_S_IFIFO;
                        break;
        }

        SET_ST_MODE_BIT(FSSH_S_ISUID, S_ISUID);
        SET_ST_MODE_BIT(FSSH_S_ISGID, S_ISGID);
        SET_ST_MODE_BIT(FSSH_S_ISVTX, S_ISVTX);
        SET_ST_MODE_BIT(FSSH_S_IRUSR, S_IRUSR);
        SET_ST_MODE_BIT(FSSH_S_IWUSR, S_IWUSR);
        SET_ST_MODE_BIT(FSSH_S_IXUSR, S_IXUSR);
        SET_ST_MODE_BIT(FSSH_S_IRGRP, S_IRGRP);
        SET_ST_MODE_BIT(FSSH_S_IWGRP, S_IWGRP);
        SET_ST_MODE_BIT(FSSH_S_IXGRP, S_IXGRP);
        SET_ST_MODE_BIT(FSSH_S_IROTH, S_IROTH);
        SET_ST_MODE_BIT(FSSH_S_IWOTH, S_IWOTH);
        SET_ST_MODE_BIT(FSSH_S_IXOTH, S_IXOTH);

        #undef SET_ST_MODE_BIT

        return fsshMode;
}


mode_t
to_platform_mode(fssh_mode_t fsshMode)
{
        #define SET_ST_MODE_BIT(flag, fsshFlag) \
                if (fsshMode & fsshFlag)                                \
                        mode |= flag;

        mode_t mode = 0;

        // BeOS/Haiku only
        #if (defined(__BEOS__) || defined(__HAIKU__))
                SET_ST_MODE_BIT(FSSH_S_ATTR_DIR, S_ATTR_DIR);
                SET_ST_MODE_BIT(FSSH_S_ATTR, S_ATTR);
                SET_ST_MODE_BIT(FSSH_S_INDEX_DIR, S_INDEX_DIR);
                SET_ST_MODE_BIT(FSSH_S_INT_INDEX, S_INT_INDEX);
                SET_ST_MODE_BIT(FSSH_S_UINT_INDEX, S_UINT_INDEX);
                SET_ST_MODE_BIT(FSSH_S_LONG_LONG_INDEX, S_LONG_LONG_INDEX);
                SET_ST_MODE_BIT(FSSH_S_ULONG_LONG_INDEX, S_ULONG_LONG_INDEX);
                SET_ST_MODE_BIT(FSSH_S_FLOAT_INDEX, S_FLOAT_INDEX);
                SET_ST_MODE_BIT(FSSH_S_DOUBLE_INDEX, S_DOUBLE_INDEX);
                SET_ST_MODE_BIT(FSSH_S_ALLOW_DUPS, S_ALLOW_DUPS);
                SET_ST_MODE_BIT(FSSH_S_LINK_SELF_HEALING, S_LINK_SELF_HEALING);
                SET_ST_MODE_BIT(FSSH_S_LINK_AUTO_DELETE, S_LINK_AUTO_DELETE);
        #endif

        switch (fsshMode & FSSH_S_IFMT) {
                case FSSH_S_IFLNK:
                        mode |= S_IFLNK;
                        break;
                case FSSH_S_IFREG:
                        mode |= S_IFREG;
                        break;
                case FSSH_S_IFBLK:
                        mode |= S_IFBLK;
                        break;
                case FSSH_S_IFDIR:
                        mode |= S_IFDIR;
                        break;
                case FSSH_S_IFIFO:
                        mode |= S_IFIFO;
                        break;
        }

        SET_ST_MODE_BIT(FSSH_S_ISUID, S_ISUID);
        SET_ST_MODE_BIT(FSSH_S_ISGID, S_ISGID);
        SET_ST_MODE_BIT(FSSH_S_ISVTX, S_ISVTX);
        SET_ST_MODE_BIT(FSSH_S_IRUSR, S_IRUSR);
        SET_ST_MODE_BIT(FSSH_S_IWUSR, S_IWUSR);
        SET_ST_MODE_BIT(FSSH_S_IXUSR, S_IXUSR);
        SET_ST_MODE_BIT(FSSH_S_IRGRP, S_IRGRP);
        SET_ST_MODE_BIT(FSSH_S_IWGRP, S_IWGRP);
        SET_ST_MODE_BIT(FSSH_S_IXGRP, S_IXGRP);
        SET_ST_MODE_BIT(FSSH_S_IROTH, S_IROTH);
        SET_ST_MODE_BIT(FSSH_S_IWOTH, S_IWOTH);
        SET_ST_MODE_BIT(FSSH_S_IXOTH, S_IXOTH);

        #undef SET_ST_MODE_BIT

        return mode;
}


void
from_platform_stat(const struct stat *st, struct fssh_stat *fsshStat)
{
        fsshStat->fssh_st_dev = st->st_dev;
        fsshStat->fssh_st_ino = st->st_ino;
        fsshStat->fssh_st_mode = from_platform_mode(st->st_mode);
        fsshStat->fssh_st_nlink = st->st_nlink;
        fsshStat->fssh_st_uid = st->st_uid;
        fsshStat->fssh_st_gid = st->st_gid;
        fsshStat->fssh_st_size = st->st_size;
        fsshStat->fssh_st_blksize = st->st_blksize;
        fsshStat->fssh_st_atime = st->st_atime;
        fsshStat->fssh_st_mtime = st->st_mtime;
        fsshStat->fssh_st_ctime = st->st_ctime;
        fsshStat->fssh_st_crtime = st->st_ctime;
        fsshStat->fssh_st_type = 0;
}


void
to_platform_stat(const struct fssh_stat *fsshStat, struct stat *st)
{
        st->st_dev = fsshStat->fssh_st_dev;
        st->st_ino = fsshStat->fssh_st_ino;
        st->st_mode = to_platform_mode(fsshStat->fssh_st_mode);
        st->st_nlink = fsshStat->fssh_st_nlink;
        st->st_uid = fsshStat->fssh_st_uid;
        st->st_gid = fsshStat->fssh_st_gid;
        st->st_size = fsshStat->fssh_st_size;
        st->st_blksize = fsshStat->fssh_st_blksize;
        st->st_atime = fsshStat->fssh_st_atime;
        st->st_mtime = fsshStat->fssh_st_mtime;
        st->st_ctime = fsshStat->fssh_st_ctime;
//      st->st_crtime = fsshStat->fssh_st_crtime;
//      st->st_type = fsshStat->fssh_st_type;
}


int
to_platform_open_mode(int fsshMode)
{
        #define SET_OPEN_MODE_FLAG(flag, fsshFlag)      \
                if (fsshMode & fsshFlag)                                \
                        mode |= flag;

        int mode = 0;

        // the r/w mode
        switch (fsshMode & FSSH_O_RWMASK) {
                case FSSH_O_RDONLY:
                        mode |= O_RDONLY;
                        break;
                case FSSH_O_WRONLY:
                        mode |= O_WRONLY;
                        break;
                case FSSH_O_RDWR:
                        mode |= O_RDWR;
                        break;
        }

        // the flags
        //SET_OPEN_MODE_FLAG(O_CLOEXEC, FSSH_O_CLOEXEC)
        SET_OPEN_MODE_FLAG(O_NONBLOCK, FSSH_O_NONBLOCK)
        SET_OPEN_MODE_FLAG(O_EXCL, FSSH_O_EXCL)
        SET_OPEN_MODE_FLAG(O_CREAT, FSSH_O_CREAT)
        SET_OPEN_MODE_FLAG(O_TRUNC, FSSH_O_TRUNC)
        SET_OPEN_MODE_FLAG(O_APPEND, FSSH_O_APPEND)
        SET_OPEN_MODE_FLAG(O_NOCTTY, FSSH_O_NOCTTY)
        SET_OPEN_MODE_FLAG(O_NOTRAVERSE, FSSH_O_NOTRAVERSE)
        //SET_OPEN_MODE_FLAG(O_TEXT, FSSH_O_TEXT)
        //SET_OPEN_MODE_FLAG(O_BINARY, FSSH_O_BINARY)

        #undef SET_OPEN_MODE_FLAG

        return mode;
}

}       // namespace FSShell