/* * Copyright (C) 2007-2023 Xagasoft, All rights reserved. * * This file is part of the libbu++ library and is released under the * terms of the license contained in the file LICENSE. */ #ifndef MYRIAD_FS_H #define MYRIAD_FS_H #include #include "bu/myriad.h" #include "bu/debugmutex.h" namespace Bu { class Stream; subExceptionDecl( MyriadFsException ); /** * A POSIX compliant, node based filesystem built on top of Myriad. * * A header is placed into stream 1. * Header format: * int32_t iMagicHeader (A7188B39) * int8_t iVersion (1) * int32_t iNumNodes * NodeLookup[iNumNodes] nNode * * Node lookup: * int32_t iInode * int32_t iPosition * * The node headers or inode structures have a base size of 44 bytes. * The name is stored in the directory format. * Basic node header format: * int32_t iNode * int32_t iUser * int32_t iGroup * uint16_t uPerms * int16_t iLinks * uint32_t uStreamIndex * int64_t iATime * int64_t iMTime * int64_t iCTime * * Some types get special formats for their assosiated data stream, or * other special considerations, here's a list: * * - typeFifo: No stream, uStreamIndex unused (probably) * - typeChrDev: No stream, uStreamIndex is device hi/lo * - typeDir: The stream contains a directory contents listing, described * below * - typeBlkDev: No stream, uStreamIndex is device hi/lo * - typeRegFile: The stream is the file data * - typeSymLink: The stream is the destination of the symlink * - typeSocket: No steram, uStreamIndex unused (probably) * * Directory streams have this simple listing format. They contain a list * of all child elements, with no particular order at the moment. The . and * .. entries are not listed, they are implicit: * int32_t iNumNodes * NodeTable[iNumNodes] nChildren * * NodeTable: * int32_t iInode * uint8_t uNameSize * char[uNameSize] sName */ class MyriadFs { public: MyriadFs( Bu::Stream &rStore, int iBlockSize=512 ); virtual ~MyriadFs(); enum { permOthX = 0000001, permOthW = 0000002, permOthR = 0000004, permGrpX = 0000010, permGrpW = 0000020, permGrpR = 0000040, permUsrX = 0000100, permUsrW = 0000200, permUsrR = 0000400, permSticky = 0001000, permSetGid = 0002000, permSetUid = 0004000, permMask = 0007777, typeFifo = 0010000, typeChrDev = 0020000, typeDir = 0040000, typeBlkDev = 0060000, typeRegFile = 0100000, typeSymLink = 0120000, typeSocket = 0140000, typeMask = 0170000 }; enum { Read = 0x01, ///< Open file for reading Write = 0x02, ///< Open file for writing Create = 0x04, ///< Create file if it doesn't exist Truncate = 0x08, ///< Truncate file if it does exist Append = 0x10, ///< Always append on every write NonBlock = 0x20, ///< Open file in non-blocking mode Exclusive = 0x40, ///< Create file, if it exists then fail // Helpful mixes ReadWrite = 0x03, ///< Open for reading and writing WriteNew = 0x0E ///< Create a file (or truncate) for writing. /// Same as Write|Create|Truncate }; class Stat { public: int32_t iNode; int32_t iUser; int32_t iGroup; uint16_t uPerms; int16_t iLinks; int64_t iATime; int64_t iMTime; int64_t iCTime; int32_t iSize; uint32_t uDev; Bu::String sName; }; typedef Bu::List Dir; void stat( const Bu::String &sPath, Stat &rBuf ); MyriadStream open( const Bu::String &sPath, int iMode, uint16_t uPerms=0664 ); void create( const Bu::String &sPath, uint16_t iPerms ); void create( const Bu::String &sPath, uint16_t iPerms, uint16_t iDevHi, uint16_t iDevLo ); void create( const Bu::String &sPath, uint16_t iPerms, uint32_t uSpecial ); void mkDir( const Bu::String &sPath, uint16_t iPerms ); void mkSymLink( const Bu::String &sTarget, const Bu::String &sPath ); void mkHardLink( const Bu::String &sTarget, const Bu::String &sPath ); Bu::String readSymLink( const Bu::String &sPath ); Dir readDir( const Bu::String &sPath ); void setTimes( const Bu::String &sPath, int64_t iATime, int64_t iMTime ); void unlink( const Bu::String &sPath ); void setFileSize( const Bu::String &sPath, int32_t iSize ); void rename( const Bu::String &sFrom, const Bu::String &sTo ); static dev_t devToSys( uint32_t uDev ); static uint32_t sysToDev( dev_t uDev ); private: class RawStat { public: int32_t iNode; int32_t iUser; int32_t iGroup; uint16_t uPerms; int16_t iLinks; uint32_t uStreamIndex; int64_t iATime; int64_t iMTime; int64_t iCTime; }; typedef Bu::Hash NodeIndex; private: /** * Lookup inode. */ int32_t lookupInode( const Bu::String &sPath, int32_t &iParent ); /** * Lookup inode. */ int32_t lookupInode( Bu::String::const_iterator iStart, int32_t iNode, int32_t &iParent ); void readInode( int32_t iNode, RawStat &rs, MyriadStream &rIs ); void readInode( int32_t iNode, RawStat &rs ); void writeInode( const RawStat &rs ); void writeInode( const RawStat &rs, MyriadStream &rOs ); Dir readDir( int32_t iNode ); MyriadStream openByInode( int32_t iNode ); void addToDir( int32_t iDir, int32_t iNode, const Bu::String &sName ); int32_t create( int32_t iParent, const Bu::String &sName, uint16_t uPerms, uint32_t uSpecial ); int32_t allocInode( uint16_t uPerms, uint32_t uSpecial ); void stat( int32_t iNode, Stat &rBuf, MyriadStream &rIs ); void writeHeader(); void setTimes( int32_t iNode, int64_t iATime, int64_t iMTime ); void destroyNode( int32_t iNode ); static Bu::String filePart( const Bu::String &sPath ); private: Bu::Stream &rStore; Bu::Myriad mStore; Bu::DebugMutex mAccess; NodeIndex hNodeIndex; int32_t iUser; int32_t iGroup; }; }; #endif