summaryrefslogtreecommitdiff
path: root/src/unstable/myriadfs.h
blob: 5a79c390b058d825c07afa1b2ce804cca4e82724 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*
 * Copyright (C) 2007-2014 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 <sys/types.h>

#include "bu/myriad.h"
#include "bu/readwritemutex.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   = 0x44, ///< 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<Stat> 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<int32_t, int32_t> NodeIndex;

    private:
        int32_t lookupInode( const Bu::String &sPath, int32_t &iParent );
        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 );

        Bu::String filePart( const Bu::String &sPath );

    private:
        Bu::Stream &rStore;
        Bu::Myriad mStore;
        Bu::ReadWriteMutex mNodeIndex;
        NodeIndex hNodeIndex;
        int32_t iUser;
        int32_t iGroup;
    };
};

#endif