SCXFileSystem::Attributes SCXFileSystem::GetAttributes()

in source/code/scxcorelib/pal/scxfilesystem.cpp [787:986]


    SCXFileSystem::Attributes SCXFileSystem::GetAttributes(SCXStatStruct* pStat)
    {
        SCXFileSystem::Attributes attributes;
        if (0 == pStat)
        {
            throw SCXInvalidArgumentException(L"pstat", L"Argument is NULL", SCXSRCLOCATION);
        }
#if defined(S_ISDIR)
        if (S_ISDIR(pStat->st_mode)) { // Do not check the directory bit alone since some sys files have the directory bit set too.
#else
        if (pStat->st_mode & _S_IFDIR) {
#endif
            attributes.insert(SCXFileSystem::eDirectory);
        }
        if (pStat->st_mode & S_IREAD) {
            attributes.insert(SCXFileSystem::eReadable);
        }
        if (pStat->st_mode & S_IWRITE) {
            attributes.insert(SCXFileSystem::eWritable);
        }
#if defined(SCX_UNIX)
        if (pStat->st_mode & S_IRUSR) {
            attributes.insert(SCXFileSystem::eUserRead);
        }
        if (pStat->st_mode & S_IWUSR) {
            attributes.insert(SCXFileSystem::eUserWrite);
        }
        if (pStat->st_mode & S_IXUSR) {
            attributes.insert(SCXFileSystem::eUserExecute);
        }
        if (pStat->st_mode & S_IRGRP) {
            attributes.insert(SCXFileSystem::eGroupRead);
        }
        if (pStat->st_mode & S_IWGRP) {
            attributes.insert(SCXFileSystem::eGroupWrite);
        }
        if (pStat->st_mode & S_IXGRP) {
            attributes.insert(SCXFileSystem::eGroupExecute);
        }
        if (pStat->st_mode & S_IROTH) {
            attributes.insert(SCXFileSystem::eOtherRead);
        }
        if (pStat->st_mode & S_IWOTH) {
            attributes.insert(SCXFileSystem::eOtherWrite);
        }
        if (pStat->st_mode & S_IXOTH) {
            attributes.insert(SCXFileSystem::eOtherExecute);
        }
#endif
        return attributes;
    }

    /*--------------------------------------------------------------*/
    /**
        Sets the specified FileAttributes of the file or directory on the specified path

        \param[in]  path            The path to the file or directory.
        \param[in]  attributes      The desired FileAttributes, such as Readable and Writable
        \throws     SCXUnauthorizedFileSystemAccessException    The caller does not have the required permission
        \throws     SCXFilePathNotFoundException                If no file or directory is found at path

        The path parameter is permitted to specify relative or absolute path information.
        Relative path information is interpreted as relative to the current working directory.
        To obtain the current working directory, see GetCurrentDirectory.

        It is not possible to change the compression status of a File object using the
        SetAttributes method

     */
    void SCXFileSystem::SetAttributes(const SCXFilePath& path, const SCXFileSystem::Attributes& attributes) {
        int permissions = 0;
        if (attributes.count(SCXFileSystem::eWritable) > 0) {
            permissions |= S_IWRITE;
        }
        if (attributes.count(SCXFileSystem::eReadable) > 0) {
            permissions |= S_IREAD;
        }
#if defined(SCX_UNIX)
        if (attributes.count(SCXFileSystem::eUserRead) > 0) {
            permissions |= S_IRUSR;
        }
        if (attributes.count(SCXFileSystem::eUserWrite) > 0) {
            permissions |= S_IWUSR;
        }
        if (attributes.count(SCXFileSystem::eUserExecute) > 0) {
            permissions |= S_IXUSR;
        }
        if (attributes.count(SCXFileSystem::eGroupRead) > 0) {
            permissions |= S_IRGRP;
        }
        if (attributes.count(SCXFileSystem::eGroupWrite) > 0) {
            permissions |= S_IWGRP;
        }
        if (attributes.count(SCXFileSystem::eGroupExecute) > 0) {
            permissions |= S_IXGRP;
        }
        if (attributes.count(SCXFileSystem::eOtherRead) > 0) {
            permissions |= S_IROTH;
        }
        if (attributes.count(SCXFileSystem::eOtherWrite) > 0) {
            permissions |= S_IWOTH;
        }
        if (attributes.count(SCXFileSystem::eOtherExecute) > 0) {
            permissions |= S_IXOTH;
        }
#endif
#if defined(WIN32)
        int failure = _wchmod(path.Get().c_str(), permissions);
#elif defined(SCX_UNIX)
        std::string localizedPath = SCXFileSystem::EncodePath(path);
        int failure = chmod(localizedPath.c_str(), permissions);
#else
#error
#endif

        if (failure) {
            switch (errno)
            {
            case EACCES:
            case EPERM:
            case EROFS:
                throw SCXUnauthorizedFileSystemAccessException(path, GetAttributes(path), SCXSRCLOCATION);
            case ENAMETOOLONG:
            case EINVAL:
                throw SCXInvalidArgumentException(L"path", path.Get(), SCXSRCLOCATION);
#if defined(SCX_UNIX)
            case ELOOP:
#endif
            case ENOENT:
            case ENOTDIR:
                throw SCXFilePathNotFoundException(path, SCXSRCLOCATION);
            default:
                wstring problem(L"Failed to set attributes for " + path.Get());
                throw SCXInternalErrorException(UnexpectedErrno(problem, errno), SCXSRCLOCATION);
            }
        }
    }

    /*--------------------------------------------------------------*/
    /**
        Moves a specified file or directory to a new location, providing the option to specify a
        new file name.

        \param[in]  oldPath     Existing file or directory to be moved
        \param[in]  newPath     New path, directory or file

        \throws     SCXUnauthorizedFileSystemAccessException    If oldPath specifies a directory and
                                                                newPath specifies a file
        \throws     SCXFilePathNotFoundException                If no file is found at oldPath

        If oldPath is a path to a file and newPath is a path not to a file but to an existing
        directory, the file is moved to that directory using the old name.

        This method works across disk volumes, and it does not throw an exception if the
        source and destination are the same. Note that if you attempt to replace a file by
        moving a file of the same name into that directory, you get an IOException. You
        cannot use the Move method to overwrite an existing file.

        The oldPath and newPath arguments are permitted to specify relative or
        absolute path information. Relative path information is interpreted as relative
        to the current working directory.

        \note The current implementation is restricted by the underlying API and requires newName to be complete
     */
    void SCXFileSystem::Move(const SCXFilePath& oldPath, const SCXFilePath &newPath) {
#if defined(WIN32)
        int failure = _wrename(oldPath.Get().c_str(), newPath.Get().c_str());
#elif defined(SCX_UNIX)
        std::string oldLocalizedPath = SCXFileSystem::EncodePath(oldPath);
        std::string newLocalizedPath = SCXFileSystem::EncodePath(newPath);
        int failure = rename(oldLocalizedPath.c_str(), newLocalizedPath.c_str());
#else
#error
#endif
        if (failure) {
            if (errno == EINVAL) {
                throw SCXInvalidArgumentException(L"path",
                    oldPath.Get() + L" or " + newPath.Get(), SCXSRCLOCATION);
            } else if (errno == EACCES || errno == EBUSY || errno == EROFS ||
                        errno == EISDIR || errno == EEXIST || errno == ENOTEMPTY ||
                        errno == ENOTDIR)  {
                throw SCXUnauthorizedFileSystemAccessException(newPath, SCXFileSystem::GetAttributes(newPath), SCXSRCLOCATION);
            } else if (errno == ENOENT) {
                throw SCXFilePathNotFoundException(oldPath, SCXSRCLOCATION);
            } else if (errno == EMLINK) {
                throw SCXFileSystemExhaustedException(L"directory entry", newPath, SCXSRCLOCATION);
            } else if (errno == ENOSPC) {
                throw SCXFileSystemExhaustedException(L"filesystem space", newPath, SCXSRCLOCATION);
            } else if (errno == EXDEV) {
                // May perhaps be implemented as copy and delete
                throw SCXNotSupportedException(L"Move files between file systems", SCXSRCLOCATION);
            } else {
                wstring problem(L"Failed to move " + oldPath.Get());
                throw SCXInternalErrorException(UnexpectedErrno(problem, errno), SCXSRCLOCATION);
            }
        }

    }

}