-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmkfs.java
More file actions
294 lines (248 loc) · 9.41 KB
/
mkfs.java
File metadata and controls
294 lines (248 loc) · 9.41 KB
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/*
* $Id: mkfs.java,v 1.11 2001/10/07 23:48:55 rayo Exp $
*/
import java.io.* ;
/*
* $Log: mkfs.java,v $
* Revision 1.11 2001/10/07 23:48:55 rayo
* added author javadoc tag
*
* Revision 1.10 2001/09/29 20:57:12 rayo
* added code to deal with conditions where an extra block causes
* the number of inodes and free list bits to get too big.
*
* Revision 1.9 2001/09/25 12:53:15 rayo
* fixed absolute block number problem.
*
* Revision 1.8 2001/09/24 06:13:09 rayo
* all data block numbers are now relative to the beginning of the
* file system file
*
* Revision 1.7 2001/09/22 22:03:31 rayo
* many changes related to getting readdir() working, and adding FileSystem
*
* Revision 1.6 2001/09/18 03:08:40 rayo
* added various corrections, including better inode for root
* file.
*
* Revision 1.5 2001/09/17 03:19:22 rayo
* fixed superblock, added support for root inode
*
* Revision 1.4 2001/09/17 01:44:07 rayo
* added support for bit blocks, inodes, direntries
* added boot block at beginning.
*
* Revision 1.3 2001/09/10 20:32:52 rayo
* added @exception
*
* Revision 1.2 2001/09/09 23:12:50 rayo
* added more documentation
*
* Revision 1.1 2001/09/02 22:09:12 rayo
* Initial revision
*
*/
/**
* A MOSS File System Simulator program which uses the simulator
* classes to create a "file system".
* @author Ray Ontko
*/
public class mkfs
{
/**
* Creates a "file system" in the named file with the specified
* blocksize and number of blocks.
* @exception java.lang.Exception if any exception occurs
*/
public static void main( String[] argv ) throws Exception
{
if( argv.length != 3 )
{
System.err.println(
"mkfs: usage: java mkfs <filename> <block-size> <blocks>" ) ;
System.exit( 1 ) ;
}
String filename = argv[0] ;
short block_size = Short.parseShort( argv[1] ) ;
int blocks = Integer.parseInt( argv[2] ) ;
int block_total = 0 ;
/*
blocks =
super_blocks +
free_list_blocks +
inode_blocks +
data_blocks
We need one block for the superblock.
super_blocks = 1
We need one bit in the free list map for each data block.
free_list_blocks =
( data_blocks + block_size * 8 - 1 ) /
( block_size * 8 )
??? Is this the correct number of inodes?
At worse, there will be only directory entries and empty files.
In other words, we might need as many inodes as we have blocks.
inode_blocks =
( data_blocks + block_size / inode_size - 1 ) /
( block_size / inode_size )
Then:
blocks =
super_blocks +
( data_blocks + block_size * 8 - 1 ) /
( block_size * 8 ) +
( data_blocks + block_size / inode_size - 1 ) /
( block_size / inode_size ) +
data_blocks
We then seek the maximum number of data blocks where the total number
of blocks is less than or equal to the number of blocks available.
We use a binary searching technique in the following algorithm.
*/
int inode_size = IndexNode.INDEX_NODE_SIZE ;
int super_blocks = 1 ;
int free_list_blocks = 0 ;
int inode_blocks = 0 ;
int data_blocks = 0 ;
int lo = 0 ;
int hi = blocks ;
while( lo <= hi )
{
data_blocks = ( lo + hi + 1 ) / 2 ;
free_list_blocks =
( data_blocks + block_size * 8 - 1 ) /
( block_size * 8 ) ;
inode_blocks =
( data_blocks + block_size / inode_size - 1 ) /
( block_size / inode_size ) ;
block_total = super_blocks + free_list_blocks +
inode_blocks + data_blocks ;
/*
Just in case you want to see it converge...
System.out.println( "lo: " + lo + " hi: " + hi ) ;
System.out.println( "block_size: " + block_size ) ;
System.out.println( "blocks: " + blocks ) ;
System.out.println( "free_list_blocks: " + free_list_blocks ) ;
System.out.println( "inode_blocks: " + inode_blocks ) ;
System.out.println( "data_blocks: " + data_blocks ) ;
System.out.println( "block_total: " + block_total ) ;
System.out.println() ;
*/
if ( block_total < blocks )
lo = data_blocks + 1 ;
else if ( block_total > blocks )
hi = data_blocks - 1 ;
else
break ;
}
// if the last block causes free_list_blocks or inode_blocks to
// cross a block boundary, we "give" the extra space to the free
// list and/or inodes and use whatever remains for the data blocks
if( block_total > blocks )
{
// System.out.println( "adjusting data blocks..." ) ;
// System.out.println() ;
data_blocks -- ;
}
// calculate inode and free list blocks based on the final
// count of data blocks
free_list_blocks =
( data_blocks + block_size * 8 - 1 ) /
( block_size * 8 ) ;
inode_blocks = blocks - super_blocks - free_list_blocks - data_blocks ;
block_total = super_blocks + free_list_blocks +
inode_blocks + data_blocks ;
if ( data_blocks <= 0 )
{
System.err.println(
"mkfs: parameters resulted in data block count less than one" ) ;
System.exit( 2 ) ;
}
System.out.println( "block_size: " + block_size ) ;
System.out.println( "blocks: " + blocks ) ;
System.out.println( "super_blocks: " + super_blocks ) ;
System.out.println( "free_list_blocks: " + free_list_blocks ) ;
System.out.println( "inode_blocks: " + inode_blocks ) ;
System.out.println( "data_blocks: " + data_blocks ) ;
System.out.println( "block_total: " + block_total ) ;
// If the file already exists, we delete it.
// Under jdk 1.2 we can use setLength() to truncate, but
// for now we must delete and re-create.
File deleteFile = new File( filename ) ;
deleteFile.delete() ;
RandomAccessFile file = new RandomAccessFile( filename , "rw" ) ;
int superBlockOffset = 0 ;
int freeListBlockOffset = superBlockOffset + 1 ;
int inodeBlockOffset = freeListBlockOffset + free_list_blocks ;
int dataBlockOffset = inodeBlockOffset + inode_blocks ;
/*
System.out.println( "free list block offset: " + freeListBlockOffset ) ;
System.out.println( "inode block offset: " + inodeBlockOffset ) ;
System.out.println( "data block offset: " + dataBlockOffset ) ;
*/
// create the superblock
SuperBlock superBlock = new SuperBlock() ;
superBlock.setBlockSize( block_size ) ;
superBlock.setBlocks( blocks ) ;
superBlock.setFreeListBlockOffset( freeListBlockOffset ) ;
superBlock.setInodeBlockOffset( inodeBlockOffset ) ;
superBlock.setDataBlockOffset( dataBlockOffset ) ;
// write the superblock
file.seek( superBlockOffset * block_size ) ;
superBlock.write( file ) ;
// create the free list bitmap block
BitBlock freeListBlock = new BitBlock( block_size ) ;
// all blocks are free except the first block, which contains
// the directory block for the root directory.
freeListBlock.setBit( 0 ) ;
// write the free list bitmap blocks
file.seek( freeListBlockOffset * block_size ) ;
freeListBlock.write( file ) ;
// write the rest of the free list blocks which should be empty
BitBlock emptyFreeListBlock = new BitBlock( block_size ) ;
for( int i = freeListBlockOffset + 1 ; i < inodeBlockOffset ; i ++ )
{
file.seek( i * block_size ) ;
emptyFreeListBlock.write( file ) ;
}
// create the root inode block
Block rootInodeBlock = new Block( block_size ) ;
// create the inode for the root directory
IndexNode rootIndexNode = new IndexNode() ;
// set the first block address to the the
// address of the first available data block.
rootIndexNode.setBlockAddress( 0 , 0 ) ;
// the root inode is a directory inode
rootIndexNode.setMode( Kernel.S_IFDIR ) ;
// there are two directory entries in the root file system,
// so we set the file size accordingly.
rootIndexNode.setSize( DirectoryEntry.DIRECTORY_ENTRY_SIZE * 2 ) ;
// set the link count: itself, dot, dot-dot
rootIndexNode.setNlink( (short)3 ) ;
// write the rootIndexNode to the rootInodeBlock
rootIndexNode.write( rootInodeBlock.bytes ,
( FileSystem.ROOT_INDEX_NODE_NUMBER * IndexNode.INDEX_NODE_SIZE ) % block_size ) ;
// ??? write the rest of the inodes in the first block
// write the first inode block
file.seek( inodeBlockOffset * block_size +
FileSystem.ROOT_INDEX_NODE_NUMBER * IndexNode.INDEX_NODE_SIZE ) ;
rootInodeBlock.write( file ) ;
// ??? write the rest of the inode blocks
// create the root directory block
Block rootDirectoryBlock = new Block( block_size ) ;
// the root directory block contains two directory entries:
// one for itself ("."), and one for its parent ("..").
// Both of these reference the root inode.
DirectoryEntry itself =
new DirectoryEntry( FileSystem.ROOT_INDEX_NODE_NUMBER , "." ) ;
DirectoryEntry parent =
new DirectoryEntry( FileSystem.ROOT_INDEX_NODE_NUMBER , ".." ) ;
// write the root directory entries to the root directory block
itself.write( rootDirectoryBlock.bytes , 0 ) ;
parent.write( rootDirectoryBlock.bytes , DirectoryEntry.DIRECTORY_ENTRY_SIZE ) ;
// write the root directory block to the file
file.seek( dataBlockOffset * block_size ) ;
rootDirectoryBlock.write( file ) ;
// write a zero byte to the last byte of the file system file
file.seek( blocks * block_size - 1 ) ;
file.write( 0 ) ;
file.close() ;
}
}