diff options
Diffstat (limited to 'src/myriadfs.cpp')
-rw-r--r-- | src/myriadfs.cpp | 292 |
1 files changed, 281 insertions, 11 deletions
diff --git a/src/myriadfs.cpp b/src/myriadfs.cpp index c8d23b6..4e2a0f6 100644 --- a/src/myriadfs.cpp +++ b/src/myriadfs.cpp | |||
@@ -10,6 +10,11 @@ | |||
10 | 10 | ||
11 | #include <string.h> | 11 | #include <string.h> |
12 | #include <unistd.h> | 12 | #include <unistd.h> |
13 | #include <time.h> | ||
14 | |||
15 | #include "bu/sio.h" | ||
16 | using Bu::sio; | ||
17 | using Bu::Fmt; | ||
13 | 18 | ||
14 | namespace Bu { subExceptionDef( MyriadFsException ) } | 19 | namespace Bu { subExceptionDef( MyriadFsException ) } |
15 | 20 | ||
@@ -17,8 +22,15 @@ namespace Bu { subExceptionDef( MyriadFsException ) } | |||
17 | 22 | ||
18 | Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) : | 23 | Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) : |
19 | rStore( rStore ), | 24 | rStore( rStore ), |
20 | mStore( rStore, iBlockSize ) | 25 | mStore( rStore, iBlockSize ), |
26 | iUser( 0 ), | ||
27 | iGroup( 0 ) | ||
21 | { | 28 | { |
29 | #ifndef WIN32 | ||
30 | iUser = getuid(); | ||
31 | iGroup = getgid(); | ||
32 | #endif | ||
33 | |||
22 | if( mStore.hasStream( 1 ) ) | 34 | if( mStore.hasStream( 1 ) ) |
23 | { | 35 | { |
24 | // Check to see if this is a MyriadFs stream. | 36 | // Check to see if this is a MyriadFs stream. |
@@ -32,6 +44,8 @@ Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) : | |||
32 | "a MyriadFs stream."); | 44 | "a MyriadFs stream."); |
33 | 45 | ||
34 | int8_t iVer; | 46 | int8_t iVer; |
47 | ms.read( &iVer, 1 ); | ||
48 | throw MyriadFsException("You totally have a MyriadFs stream, version %d, but they can't be loaded yet.", iVer ); | ||
35 | } | 49 | } |
36 | else | 50 | else |
37 | { | 51 | { |
@@ -43,43 +57,299 @@ Bu::MyriadFs::MyriadFs( Bu::Stream &rStore, int iBlockSize ) : | |||
43 | int8_t iVer = 1; | 57 | int8_t iVer = 1; |
44 | int32_t iTmp = 1; | 58 | int32_t iTmp = 1; |
45 | ms.write( &iVer, 1 ); | 59 | ms.write( &iVer, 1 ); |
46 | ms.write( &iBlockSize, 4 ); | ||
47 | ms.write( &iTmp, 4 ); // iNumNodes | 60 | ms.write( &iTmp, 4 ); // iNumNodes |
48 | iTmp = 0; | 61 | iTmp = 0; |
49 | ms.write( &iTmp, 4 ); // iInode | 62 | ms.write( &iTmp, 4 ); // iInode |
50 | ms.write( &iTmp, 0 ); // iPosition | 63 | ms.write( &iTmp, 4 ); // iPosition |
64 | hNodeIndex.insert( 0, 0 ); | ||
51 | } | 65 | } |
52 | 66 | ||
53 | // Create initial inode stream, with one root node. | 67 | // Create initial inode stream, with one root node. |
54 | { | 68 | { |
55 | mStore.createStream( 2 ); | 69 | mStore.createStream( 2 ); |
56 | Bu::MyriadStream ms = mStore.openStream( 2 ); | 70 | Bu::MyriadStream ms = mStore.openStream( 2 ); |
57 | int32_t iUser = 0, iGroup = 0; | ||
58 | #ifndef WIN32 | ||
59 | iUser = getuid(); | ||
60 | iGroup = getgid(); | ||
61 | #endif | ||
62 | int32_t iTmp32 = 0; | 71 | int32_t iTmp32 = 0; |
63 | int16_t iTmp16 = 0; | 72 | int16_t iTmp16 = 0; |
73 | uint16_t uPerms = 775|typeDir; | ||
64 | ms.write( &iUser, 4 ); // User | 74 | ms.write( &iUser, 4 ); // User |
65 | ms.write( &iGroup, 4 ); // Group | 75 | ms.write( &iGroup, 4 ); // Group |
66 | ms.write( &iTmp16, 2 ); // Meta? I...don't remember this | 76 | ms.write( &uPerms, 2 ); // Permissions/types |
67 | ms.write( &iTmp16, 2 ); // Permissions/types | 77 | ms.write( &iTmp16, 2 ); // Link count |
68 | iTmp32 = 3; | 78 | iTmp32 = 3; |
69 | ms.write( &iTmp32, 4 ); // Stream index | 79 | ms.write( &iTmp32, 4 ); // Stream index |
70 | iTmp32 = 0; | 80 | iTmp32 = 0; |
71 | ms.write( &iTmp32, 4 ); // Parent inode | 81 | ms.write( &iTmp32, 4 ); // Parent inode (root's it's own parent) |
82 | int64_t iTime = time(NULL); | ||
83 | ms.write( &iTime, 8 ); // atime | ||
84 | ms.write( &iTime, 8 ); // mtime | ||
85 | ms.write( &iTime, 8 ); // ctime | ||
72 | ms.write( &iTmp16, 2 ); // Name size | 86 | ms.write( &iTmp16, 2 ); // Name size |
73 | } | 87 | } |
74 | 88 | ||
75 | // Create inode 0's storage stream. | 89 | // Create inode 0's storage stream. |
76 | { | 90 | { |
77 | mStore.createStream( 3 ); | 91 | mStore.createStream( 3 ); |
92 | Bu::MyriadStream ms = mStore.openStream( 3 ); | ||
93 | int32_t iTmp32 = 0; | ||
94 | ms.write( &iTmp32, 4 ); // iChildCount | ||
78 | } | 95 | } |
79 | } | 96 | } |
80 | } | 97 | } |
81 | 98 | ||
82 | Bu::MyriadFs::~MyriadFs() | 99 | Bu::MyriadFs::~MyriadFs() |
83 | { | 100 | { |
101 | writeHeader(); | ||
102 | } | ||
103 | |||
104 | void Bu::MyriadFs::stat( const Bu::String &sPath, Bu::MyriadFs::Stat &rBuf ) | ||
105 | { | ||
106 | int32_t iParent; | ||
107 | int32_t iNode = lookupInode( sPath, iParent ); | ||
108 | Bu::MyriadStream is = mStore.openStream( 2 ); | ||
109 | stat( iNode, rBuf, is ); | ||
110 | } | ||
111 | |||
112 | Bu::MyriadStream Bu::MyriadFs::open( const Bu::String &sPath, int iMode ) | ||
113 | { | ||
114 | int32_t iParent = -1; | ||
115 | int32_t iNode; | ||
116 | try | ||
117 | { | ||
118 | iNode = lookupInode( sPath, iParent ); | ||
119 | sio << "File found." << sio.nl; | ||
120 | // The file was found | ||
121 | return openByInode( iNode ); | ||
122 | } | ||
123 | catch( Bu::MyriadFsException &e ) | ||
124 | { | ||
125 | if( iParent < 0 ) | ||
126 | throw; | ||
127 | |||
128 | // The file wasn't found, but the path leading up to it was. | ||
129 | // first, figure out the final path element... | ||
130 | Bu::String::const_iterator iStart = sPath.begin(); | ||
131 | if( *iStart == '/' ) | ||
132 | iStart++; | ||
133 | sio << "Scanning for filename:" << sio.nl; | ||
134 | for( Bu::String::const_iterator iEnd = iStart.find('/')+1; iEnd; iStart = iEnd ) { } | ||
135 | Bu::String sName( iStart, sPath.end() ); | ||
136 | sio << "End filename: " << sName << sio.nl; | ||
137 | sio << "Parent inode: " << iParent << sio.nl; | ||
138 | iNode = create( iParent, sName, 0664|typeRegFile ); | ||
139 | sio << "New iNode: " << iNode << sio.nl; | ||
140 | return openByInode( iNode ); | ||
141 | } | ||
142 | |||
143 | return mStore.openStream( 2 ); | ||
144 | } | ||
145 | |||
146 | int32_t Bu::MyriadFs::lookupInode( const Bu::String &sPath, int32_t &iParent ) | ||
147 | { | ||
148 | if( sPath[0] == '/' ) | ||
149 | { | ||
150 | // Absolute lookup | ||
151 | return lookupInode( sPath.begin()+1, 0, iParent ); | ||
152 | } | ||
153 | else | ||
154 | { | ||
155 | // Relative lookup | ||
156 | throw Bu::ExceptionBase( | ||
157 | "Relative lookups in MyriadFs are not working yet."); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | int32_t Bu::MyriadFs::lookupInode( Bu::String::const_iterator iStart, | ||
162 | int32_t iNode, int32_t &iParent ) | ||
163 | { | ||
164 | iParent = iNode; | ||
165 | |||
166 | Bu::String::const_iterator iEnd = iStart.find('/'); | ||
167 | Bu::String sTok( iStart, iEnd ); | ||
168 | |||
169 | sio << "Direcotry component: " << sTok << sio.nl; | ||
170 | |||
171 | Dir lDir = readDir( iNode ); | ||
172 | |||
173 | for( Dir::iterator i = lDir.begin(); i; i++ ) | ||
174 | { | ||
175 | if( (*i).sName == sTok ) | ||
176 | { | ||
177 | // We found an item | ||
178 | if( !iEnd ) | ||
179 | { | ||
180 | // It's the last one in the requested path, return it | ||
181 | return (*i).iNode; | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | // Not the last one in our path, double check it's a dir | ||
186 | if( ((*i).uPerms&typeMask) == typeDir ) | ||
187 | { | ||
188 | return lookupInode( iEnd+1, (*i).iNode ); | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | iParent = -1; | ||
193 | throw Bu::MyriadFsException( | ||
194 | "Element '%s' in given path is not a directory.", | ||
195 | sTok.getStr() ); | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | throw Bu::MyriadFsException( 1, "Path not found"); | ||
202 | } | ||
203 | |||
204 | Bu::MyriadFs::Dir Bu::MyriadFs::readDir( int32_t iNode ) | ||
205 | { | ||
206 | Bu::MyriadStream ms = openByInode( iNode ); | ||
207 | int32_t iNumChildren; | ||
208 | ms.read( &iNumChildren, 4 ); | ||
209 | |||
210 | Bu::MyriadStream is = mStore.openStream( 2 ); | ||
211 | Dir lDir; | ||
212 | sio << "Reading dir, " << iNumChildren << " entries:" << sio.nl; | ||
213 | for( int32_t j = 0; j < iNumChildren; j++ ) | ||
214 | { | ||
215 | int32_t iChildNode; | ||
216 | ms.read( &iChildNode, 4 ); | ||
217 | Stat s; | ||
218 | stat( iChildNode, s, is ); | ||
219 | lDir.append( s ); | ||
220 | |||
221 | sio << " " << s.sName << sio.nl; | ||
222 | } | ||
223 | |||
224 | return lDir; | ||
225 | } | ||
226 | |||
227 | Bu::MyriadStream Bu::MyriadFs::openByInode( int32_t iNode ) | ||
228 | { | ||
229 | int32_t iIndex = hNodeIndex.get( iNode ); | ||
230 | Bu::MyriadStream ms = mStore.openStream( 2 ); | ||
231 | ms.setPos( mStore.getBlockSize()*iIndex ); | ||
232 | RawStat rs; | ||
233 | ms.read( &rs, sizeof(RawStat) ); | ||
234 | switch( (rs.uPerms&typeMask) ) | ||
235 | { | ||
236 | case typeDir: | ||
237 | case typeSymLink: | ||
238 | case typeRegFile: | ||
239 | return mStore.openStream( rs.iStreamIndex ); | ||
240 | |||
241 | default: | ||
242 | throw Bu::MyriadFsException( | ||
243 | "inode incorrect type for low-level openByInode."); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | int32_t Bu::MyriadFs::create( int32_t iParent, const Bu::String &sName, | ||
248 | uint16_t uPerms ) | ||
249 | { | ||
250 | Bu::MyriadStream ms = openByInode( iParent ); | ||
251 | int32_t iNumChildren; | ||
252 | ms.read( &iNumChildren, 4 ); | ||
253 | iNumChildren++; | ||
254 | ms.setPos( 0 ); | ||
255 | ms.write( &iNumChildren, 4 ); | ||
256 | ms.setPos( iNumChildren*4 ); // Actually 4+(iNumChildren-1)*4 :-P | ||
257 | int32_t iNode = allocInode( sName, iParent, uPerms ); | ||
258 | ms.write( &iNode, 4 ); | ||
259 | return iNode; | ||
260 | } | ||
261 | |||
262 | int32_t Bu::MyriadFs::allocInode( const Bu::String &sName, int32_t iParent, | ||
263 | uint16_t uPerms ) | ||
264 | { | ||
265 | int32_t iNode = 0; | ||
266 | for(; iNode < 0xfffffff; iNode++ ) | ||
267 | { | ||
268 | if( !hNodeIndex.has( iNode ) ) | ||
269 | { | ||
270 | Bu::MyriadStream is = mStore.openStream( 2 ); | ||
271 | is.setSize( (hNodeIndex.getSize()+1)*mStore.getBlockSize() ); | ||
272 | is.setPos( hNodeIndex.getSize()*mStore.getBlockSize() ); | ||
273 | |||
274 | hNodeIndex.insert( iNode, hNodeIndex.getSize() ); | ||
275 | RawStat rs; | ||
276 | rs.iUser = iUser; | ||
277 | rs.iGroup = iGroup; | ||
278 | rs.uPerms = uPerms; | ||
279 | rs.iLinks = 1; | ||
280 | switch( (uPerms&typeMask) ) | ||
281 | { | ||
282 | case typeDir: | ||
283 | case typeRegFile: | ||
284 | case typeSymLink: | ||
285 | rs.iStreamIndex = mStore.createStream(); | ||
286 | break; | ||
287 | |||
288 | default: | ||
289 | rs.iStreamIndex = 0; | ||
290 | break; | ||
291 | } | ||
292 | rs.iParentNode = iParent; | ||
293 | rs.iATime = time(NULL); | ||
294 | rs.iMTime = time(NULL); | ||
295 | rs.iCTime = time(NULL); | ||
296 | rs.iNameSize = sName.getSize(); | ||
297 | is.write( &rs, sizeof(RawStat) ); | ||
298 | is.write( sName.getStr(), sName.getSize() ); | ||
299 | |||
300 | return iNode; | ||
301 | } | ||
302 | } | ||
303 | |||
304 | throw Bu::MyriadFsException( | ||
305 | "No inode could be allocated. You've run out!"); | ||
306 | } | ||
307 | |||
308 | void Bu::MyriadFs::stat( int32_t iNode, Stat &rBuf, MyriadStream &rIs ) | ||
309 | { | ||
310 | rIs.setPos( hNodeIndex.get( iNode )*mStore.getBlockSize() ); | ||
311 | RawStat rs; | ||
312 | rIs.read( &rs, sizeof(RawStat) ); | ||
313 | rBuf.sName.setSize( rs.iNameSize ); | ||
314 | rIs.read( rBuf.sName.getStr(), rs.iNameSize ); | ||
315 | rBuf.iNode = iNode; | ||
316 | rBuf.iUser = rs.iUser; | ||
317 | rBuf.iGroup = rs.iGroup; | ||
318 | rBuf.uPerms = rs.uPerms; | ||
319 | rBuf.iLinks = rs.iLinks; | ||
320 | rBuf.iATime = rs.iATime; | ||
321 | rBuf.iMTime = rs.iMTime; | ||
322 | rBuf.iCTime = rs.iCTime; | ||
323 | switch( (rBuf.uPerms&typeMask) ) | ||
324 | { | ||
325 | case typeRegFile: | ||
326 | case typeSymLink: | ||
327 | rBuf.iSize = mStore.getStreamSize( rs.iStreamIndex ); | ||
328 | break; | ||
329 | |||
330 | default: | ||
331 | rBuf.iSize = 0; | ||
332 | break; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | void Bu::MyriadFs::writeHeader() | ||
337 | { | ||
338 | Bu::MyriadStream ms = mStore.openStream( 1 ); | ||
339 | ms.write( Myriad_Fs_MAGIC_CODE, 4 ); | ||
340 | int8_t iVer = 1; | ||
341 | int32_t iNumNodes = hNodeIndex.getSize(); | ||
342 | ms.write( &iVer, 1 ); | ||
343 | ms.write( &iNumNodes, 4 ); // iNumNodes | ||
344 | for( NodeIndex::iterator i = hNodeIndex.begin(); i; i++ ) | ||
345 | { | ||
346 | int32_t iNode = i.getKey(); | ||
347 | int32_t iPosition = i.getValue(); | ||
348 | ms.write( &iNode, 4 ); | ||
349 | ms.write( &iPosition, 4 ); | ||
350 | } | ||
351 | |||
352 | // Truncate the stream afterwards so we don't use up too much space. | ||
353 | ms.setSize( ms.tell() ); | ||
84 | } | 354 | } |
85 | 355 | ||