近日有人求助,要寫一個UNIX檔案系統作為暑假作業。這種事情基本是學作業系統的必須要做的或者是做過的,畢竟檔案系統是作業系統課程的一個重要組成部分。要實作這個UNIX檔案系統,很多人就紮進了UNIX V6的的系統源碼,以及《萊昂氏UNIX源代碼分析》和《返璞歸真:UNIX技術内幕》這兩本書,很多人出來了,很多人在裡面迷失了...最終忘了自己隻是要實作一個UNIX檔案系統而已。
為何會迷失,因為代碼不是自己寫的,而且年代久遠,程式設計理念不同了,作者為何那樣寫不一定就能了解,實際上對于任何别人寫的代碼,總是會有一些不易了解的地方,當然,如果作者水準超級高,那麼代碼也就相對容易了解。是以,寫代碼永遠比讀代碼要容易!既然是要寫一個檔案系統,為何要用現成的UNIX V6代碼呢?如果了解了UNIX檔案的布局和結構,自己從零開始不參考任何現有的代碼做一個也不是什麼難事,最根本的是UNIX檔案系統本身,至于說代碼,僅僅是一個實作與使用者操作的一個接口而已。如果代碼是自己一點一點寫的,那麼你肯定能徹底明白每一行的每一個語句的精确含義,至于為何這麼寫,你當然及其明了!
本文留下我倉促間幾個小時寫的一個類UNIX檔案系統的代碼,不是讓别人看的,是為了自己留檔,因為本文已經說了,看别人的代嗎隻能學習經驗,不能了解本質,更何況,你看的還得是超級一流的代碼,而我寫的,則是超級垃圾的代碼。我隻想說,了解問題的本質要比代碼重要得多,代碼,碼,并不是很多人想象中的那般重要!本文的實作基于Linux系統,即在Linux系統上編寫一個使用者态程式,實作UNIX檔案的IO接口以及操作。
我一向堅持的原則,那就是任何東西的根本性的,本質上的原理以及背後的思想都是及其簡單的,所謂的複雜性都是優化與政策化的擴充帶來的,正如TCP一樣,UNIX的檔案系統也不例外!我們必須知道,什麼是最根本的,什麼是次要的。對于UNIX檔案系統,最根本的就是其布局以及其系統調用接口,一個處在最低層,一個在最上層開放給使用者,如下所示:
系統調用接口:open,write,read,close...
檔案系統布局:引導快,超級塊,inode區表,資料塊區
所有的在二者中間的部分都是次要的,也就是說那些東西不要也行,比如高速緩沖,高速緩存,VFS層,塊層...是以在我的實作代碼中,并沒有這些東西,我所做到的,僅僅是UNIX檔案系統所要求必須做到的最小集,那就是:
面對一個按照UNIX檔案系統标準布局的“塊裝置”,可以使用open,read,write等接口進行IO操作。
在實作中,我用一個标準的Linux大檔案來模拟磁盤塊,這樣塊的操作基本都映射到了Linux标準的write,read等系統調用了。
首先定義必要的結構體:
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
<code>//超級塊結構</code>
<code>struct</code> <code>filesys {</code>
<code> </code><code>unsigned </code><code>int</code> <code>s_size; </code><code>//總大小 </code>
<code> </code><code>unsigned </code><code>int</code> <code>s_itsize; </code><code>//inode表大小 </code>
<code> </code><code>unsigned </code><code>int</code> <code>s_freeinodesize; </code><code>//空閑i節點的數量 </code>
<code> </code><code>unsigned </code><code>int</code> <code>s_nextfreeinode; </code><code>//下一個空閑i節點</code>
<code> </code><code>unsigned </code><code>int</code> <code>s_freeinode[NUM]; </code><code>//空閑i節點數組</code>
<code> </code><code>unsigned </code><code>int</code> <code>s_freeblocksize; </code><code>//空閑塊的數量 </code>
<code> </code><code>unsigned </code><code>int</code> <code>s_nextfreeblock; </code><code>//下一個空閑塊</code>
<code> </code><code>unsigned </code><code>int</code> <code>s_freeblock[NUM]; </code><code>//空閑塊數組</code>
<code> </code><code>unsigned </code><code>int</code> <code>s_pad[]; </code><code>//填充到512位元組 </code>
<code>};</code>
<code>//磁盤inode結構</code>
<code>struct</code> <code>finode {</code>
<code> </code><code>int</code> <code>fi_mode; </code><code>//類型:檔案/目錄</code>
<code> </code><code>int</code> <code>fi_uid_unused; </code><code>//uid,由于和程序無關聯,僅僅是模拟一個FS,未使用,下同</code>
<code> </code><code>int</code> <code>fi_gid_unused;</code>
<code> </code><code>int</code> <code>fi_nlink; </code><code>//連結數,當連結數為0,意味着被删除</code>
<code> </code><code>long</code> <code>int</code> <code>fi_size; </code><code>//檔案大小</code>
<code> </code><code>long</code> <code>int</code> <code>fi_addr[BNUM]; </code><code>//檔案塊一級指針,并未實作多級指針</code>
<code> </code><code>time_t</code> <code>fi_atime_unused; </code><code>//未實作</code>
<code> </code><code>time_t</code> <code>fi_mtime_unused;</code>
<code>//記憶體inode結構</code>
<code>struct</code> <code>inode {</code>
<code> </code><code>struct</code> <code>finode i_finode;</code>
<code> </code><code>struct</code> <code>inode *i_parent; </code><code>//所屬的目錄i節點</code>
<code> </code><code>int</code> <code>i_ino; </code><code>//i節點号</code>
<code> </code><code>int</code> <code>i_users; </code><code>//引用計數</code>
<code>//目錄項結構(非Linux核心的目錄項)</code>
<code>struct</code> <code>direct</code>
<code>{</code>
<code> </code><code>char</code> <code>d_name[MAXLEN]; </code><code>//檔案或者目錄的名字</code>
<code> </code><code>unsigned </code><code>short</code> <code>d_ino; </code><code>//檔案或者目錄的i節點号</code>
<code>//目錄結構</code>
<code>struct</code> <code>dir</code>
<code> </code><code>struct</code> <code>direct direct[DIRNUM]; </code><code>//包含的目錄項數組</code>
<code> </code><code>unsigned </code><code>short</code> <code>size; </code><code>//包含的目錄項大小 </code>
<code>//抽象的檔案結構</code>
<code>struct</code> <code>file {</code>
<code> </code><code>struct</code> <code>inode *f_inode; </code><code>//檔案的i節點</code>
<code> </code><code>int</code> <code>f_curpos; </code><code>//檔案的目前讀寫指針</code>
之是以叫做類UNIX檔案系統,是因為我并沒有去精确确認當時的UNIX檔案系統的超級塊以及inode表的結構,隻是大緻的模仿其布局,比如超級塊中字段,以及字段的順序可能和标準的UNIX檔案系統并不完全一緻。但是不管怎麼說,當時的UNIX檔案系統基本就是這個一個樣子。另外,可以看到file結構體内容及其少,因為本質上,我隻是想表示“一個inode節點相對于一個讀寫者來說,就是一個file”,僅此而已。接下來就是具體的實作了,我的方式是自下而上的,這樣做的好處在于便于今後的擴充。那麼首先要完成的就是i節點的配置設定和釋放了,我的實作中,是将檔案i節點映射到了記憶體i節點,這樣或許違背了我的初衷,我不是說過不要那麼多“額外”的東西來擾亂視聽的嗎?是的,然而比起那些所謂的額外的優化,我更不喜歡頻繁的調用read和write。反正,隻要自己能控制住局面即可。
在實作中,還有一個大事就是記憶體的配置設定與釋放,這些也不是本質的,記住,要實作的僅僅是一個UNIX檔案系統,其它的能繞開則繞開!顯然malloc,free等也是我們要繞開的,于是我基本都使用預配置設定空間的東西-全局數組。以下是全局變量:
<code>//記憶體i節點數組,NUM為該檔案系統容納的檔案數</code>
<code>struct</code> <code>inode g_usedinode[NUM];</code>
<code>//ROOT的記憶體i節點</code>
<code>struct</code> <code>inode *g_root;</code>
<code>//已經打開檔案的數組</code>
<code>struct</code> <code>file* g_opened[OPENNUM];</code>
<code>//超級塊</code>
<code>struct</code> <code>filesys *g_super;</code>
<code>//模拟二級檔案系統的Linux大檔案的檔案描述符</code>
<code>int</code> <code>g_fake_disk = -1;</code>
在給出實作代碼之前,要說明的是,在删除檔案的時候,我并沒有實作檔案塊區以及i節點的清除操作,衆所周知,那樣很耗時,和很多實作一樣,我隻是記錄了一些資訊,表示這個檔案塊或者inode字段是可以随時覆寫的。
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
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
<code>//同步i節點,将其寫入“磁盤”</code>
<code>void</code> <code>syncinode(</code><code>struct</code> <code>inode *inode)</code>
<code> </code><code>int</code> <code>ino = -1, ipos = -1;</code>
<code> </code><code>ino = inode->i_ino;</code>
<code> </code><code>//ipos為inode節點表在檔案系統塊中的偏移</code>
<code> </code><code>ipos = IBPOS + ino*</code><code>sizeof</code><code>(</code><code>struct</code> <code>finode);</code>
<code> </code><code>//從模拟塊的指定偏移位置讀取inode資訊</code>
<code> </code><code>lseek(g_fake_disk, ipos, SEEK_SET);</code>
<code> </code><code>write(g_fake_disk, (</code><code>void</code> <code>*)&inode->i_finode, </code><code>sizeof</code><code>(</code><code>struct</code> <code>finode));</code>
<code>}</code>
<code>//同步超級塊資訊</code>
<code>int</code> <code>syncsuper(</code><code>struct</code> <code>filesys *super)</code>
<code> </code><code>int</code> <code>pos = -1, size = -1;</code>
<code> </code><code>struct</code> <code>dir dir = {0};</code>
<code> </code><code>pos = BOOTBSIZE;</code>
<code> </code><code>size = SUPERBSIZE;</code>
<code> </code><code>lseek(g_fake_disk, pos, SEEK_SET);</code>
<code> </code><code>write(g_fake_disk, (</code><code>void</code> <code>*)super, size);</code>
<code> </code><code>syncinode(g_root);</code>
<code> </code><code>breadwrite(g_root->i_finode.fi_addr[0], (</code><code>char</code> <code>*)&dir, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir), 0, 1);</code>
<code> </code><code>breadwrite(g_root->i_finode.fi_addr[0], (</code><code>char</code> <code>*)&dir, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir), 0, 0);</code>
<code>//關鍵的将路徑名轉換為i節點的函數,暫不支援相對路徑</code>
<code>struct</code> <code>inode *namei(</code><code>char</code> <code>*filepath, </code><code>char</code> <code>flag, </code><code>int</code> <code>*match, </code><code>char</code> <code>*ret_name)</code>
<code> </code><code>int</code> <code>in = 0;</code>
<code> </code><code>int</code> <code>repeat = 0;</code>
<code> </code><code>char</code> <code>*name = NULL;</code>
<code> </code><code>char</code> <code>*path = </code><code>calloc</code><code>(1, MAXLEN*10);</code>
<code> </code><code>char</code> <code>*back = path;</code>
<code> </code><code>struct</code> <code>inode *root = iget(0);</code>
<code> </code><code>struct</code> <code>inode *parent = root;</code>
<code> </code><code>strncpy</code><code>(path, filepath, MAXLEN*10);</code>
<code> </code><code>if</code> <code>(path[0] != </code><code>'/'</code><code>)</code>
<code> </code><code>return</code> <code>NULL;</code>
<code> </code><code>breadwrite(root->i_finode.fi_addr[0], &dir, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir), 0, 1);</code>
<code> </code><code>while</code><code>((name=</code><code>strtok</code><code>(path, </code><code>"/"</code><code>)) != NULL) {</code>
<code> </code><code>int</code> <code>i = 0;</code>
<code> </code><code>repeat = 0;</code>
<code> </code><code>*match = 0;</code>
<code> </code><code>path = NULL;</code>
<code> </code><code>if</code> <code>(ret_name) {</code>
<code> </code><code>strcpy</code><code>(ret_name, name);</code>
<code> </code><code>}</code>
<code> </code><code>for</code> <code>(; i<dir.size; i++) {</code>
<code> </code><code>if</code> <code>(!</code><code>strncmp</code><code>(name, dir.direct[i].d_name, </code><code>strlen</code><code>(name))) {</code>
<code> </code><code>parent = root;</code>
<code> </code><code>iput(root);</code>
<code> </code><code>root = iget(dir.direct[i].d_ino);</code>
<code> </code><code>root->i_parent = parent;</code>
<code> </code><code>*match = 1;</code>
<code> </code><code>if</code> <code>(root->i_finode.fi_mode == MODE_DIR) {</code>
<code> </code><code>memset</code><code>(&dir, 0, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir));</code>
<code> </code><code>breadwrite(root->i_finode.fi_addr[0], &dir, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir), 0, 1);</code>
<code> </code><code>} </code><code>else</code> <code>{</code>
<code> </code><code>free</code><code>(back);</code>
<code> </code><code>return</code> <code>root;</code>
<code> </code><code>}</code>
<code> </code><code>repeat = 1;</code>
<code> </code><code>}</code>
<code> </code><code>if</code> <code>(repeat == 0) {</code>
<code> </code><code>break</code><code>;</code>
<code> </code><code>}</code>
<code> </code><code>if</code> <code>(*match != 1) {</code>
<code> </code><code>if</code> <code>(*match == 0) {</code>
<code> </code><code>free</code><code>(back);</code>
<code> </code><code>return</code> <code>root;</code>
<code>//通過i節點号擷取記憶體i節點的函數</code>
<code>struct</code> <code>inode *iget(</code><code>int</code> <code>ino)</code>
<code> </code><code>int</code> <code>ibpos = 0;</code>
<code> </code><code>int</code> <code>ipos = 0;</code>
<code> </code><code>int</code> <code>ret = 0;</code>
<code> </code><code>//傾向于直接從記憶體i節點擷取</code>
<code> </code><code>if</code> <code>(g_usedinode[ino].i_users) {</code>
<code> </code><code>g_usedinode[ino].i_users ++;</code>
<code> </code><code>return</code> <code>&g_usedinode[ino];</code>
<code> </code><code>if</code> <code>(g_fake_disk < 0) {</code>
<code> </code><code>//實在不行則從模拟磁盤塊讀入</code>
<code> </code><code>ret = read(g_fake_disk, &g_usedinode[ino], </code><code>sizeof</code><code>(</code><code>struct</code> <code>finode));</code>
<code> </code><code>if</code> <code>(ret == -1) {</code>
<code> </code><code>if</code> <code>(g_super->s_freeinode[ino] == 0) {</code>
<code> </code><code>//如果是一個已經被删除的檔案或者從未被配置設定過的i節點,則初始化其link值以及size值</code>
<code> </code><code>if</code> <code>(g_usedinode[ino].i_finode.fi_nlink == 0) {</code>
<code> </code><code>g_usedinode[ino].i_finode.fi_nlink ++;</code>
<code> </code><code>g_usedinode[ino].i_finode.fi_size = 0;</code>
<code> </code><code>syncinode(&g_usedinode[ino]);</code>
<code> </code><code>g_usedinode[ino].i_users ++;</code>
<code> </code><code>g_usedinode[ino].i_ino = ino;</code>
<code> </code><code>return</code> <code>&g_usedinode[ino];</code>
<code>//釋放一個占有的記憶體i節點</code>
<code>void</code> <code>iput(</code><code>struct</code> <code>inode *ip)</code>
<code> </code><code>if</code> <code>(ip->i_users > 0)</code>
<code> </code><code>ip->i_users --;</code>
<code>//配置設定一個未使用的i節點。注意,我并沒有使用超級塊的s_freeinodesize字段,</code>
<code>//因為還會有一個更好更快的配置設定算法</code>
<code>struct</code> <code>inode* ialloc()</code>
<code> </code><code>int</code> <code>ino = -1, nowpos = -1;</code>
<code> </code><code>ino = g_super->s_nextfreeinode;</code>
<code> </code><code>if</code> <code>(ino == -1) {</code>
<code> </code><code>nowpos = ino + 1;</code>
<code> </code><code>g_super->s_nextfreeinode = -1;</code>
<code> </code><code>//尋找下一個空閑i節點,正如上述,這個算法并不好</code>
<code> </code><code>for</code> <code>(; nowpos < NUM; nowpos++) {</code>
<code> </code><code>if</code> <code>(g_super->s_freeinode[nowpos] == 0) {</code>
<code> </code><code>g_super->s_nextfreeinode = nowpos;</code>
<code> </code><code>g_super->s_freeinode[ino] = 1;</code>
<code> </code><code>return</code> <code>iget(ino);</code>
<code>//試圖删除一個檔案i節點</code>
<code>int</code> <code>itrunc(</code><code>struct</code> <code>inode *ip)</code>
<code> </code><code>iput(ip);</code>
<code> </code><code>if</code> <code>(ip->i_users == 0 && g_super) {</code>
<code> </code><code>syncinode(ip);</code>
<code> </code><code>g_super->s_freeinode[ip->i_ino] = 0;</code>
<code> </code><code>g_super->s_nextfreeinode = ip->i_ino;</code>
<code> </code><code>return</code> <code>0;</code>
<code> </code><code>return</code> <code>ERR_BUSY;</code>
<code>//配置設定一個未使用的磁盤塊</code>
<code>int</code> <code>balloc()</code>
<code> </code><code>int</code> <code>bno = -1, nowpos = -1;</code>
<code> </code><code>bno = g_super->s_nextfreeblock;</code>
<code> </code><code>if</code> <code>(bno == -1) {</code>
<code> </code><code>return</code> <code>bno;</code>
<code> </code><code>nowpos = bno + 1;</code>
<code> </code><code>g_super->s_nextfreeblock = -1;</code>
<code> </code><code>if</code> <code>(g_super->s_freeblock[nowpos] == 0) {</code>
<code> </code><code>g_super->s_nextfreeblock = nowpos;</code>
<code> </code><code>g_super->s_freeblock[bno] = 1;</code>
<code> </code><code>return</code> <code>bno;</code>
<code>//讀寫操作</code>
<code>int</code> <code>breadwrite(</code><code>int</code> <code>bno, </code><code>char</code> <code>*buf, </code><code>int</code> <code>size, </code><code>int</code> <code>offset, </code><code>int</code> <code>type)</code>
<code> </code><code>int</code> <code>pos = BOOTBSIZE+SUPERBSIZE+g_super->s_itsize + bno*BSIZE;</code>
<code> </code><code>int</code> <code>rs = -1;</code>
<code> </code><code>if</code> <code>(offset + size > BSIZE) {</code>
<code> </code><code>return</code> <code>ERR_EXCEED;</code>
<code> </code><code>lseek(g_fake_disk, pos + offset, SEEK_SET);</code>
<code> </code><code>rs = type ? read(g_fake_disk, buf, size):write(g_fake_disk, buf, size);</code>
<code> </code><code>return</code> <code>rs;</code>
<code>//IO讀接口</code>
<code>int</code> <code>mfread(</code><code>int</code> <code>fd, </code><code>char</code> <code>*buf, </code><code>int</code> <code>length)</code>
<code> </code><code>struct</code> <code>file *fs = g_opened[fd];</code>
<code> </code><code>struct</code> <code>inode *inode = fs->f_inode;</code>
<code> </code><code>int</code> <code>baddr = fs->f_curpos;</code>
<code> </code><code>int</code> <code>bondary = baddr%BSIZE;</code>
<code> </code><code>int</code> <code>max_block = (baddr+length)/BSIZE;</code>
<code> </code><code>int</code> <code>size = 0;</code>
<code> </code><code>int</code> <code>i = inode->i_finode.fi_addr[baddr/BSIZE+1];</code>
<code> </code><code>for</code> <code>(; i < max_block+1; i ++,bondary = size%BSIZE) {</code>
<code> </code><code>size += breadwrite(inode->i_finode.fi_addr[i], buf+size, (length-size)%BSIZE, bondary, 1);</code>
<code> </code><code>return</code> <code>size;</code>
<code>//IO寫接口</code>
<code>int</code> <code>mfwrite(</code><code>int</code> <code>fd, </code><code>char</code> <code>*buf, </code><code>int</code> <code>length)</code>
<code> </code><code>int</code> <code>curr_blocks = inode->i_finode.fi_size/BSIZE;</code>
<code> </code><code>int</code> <code>sync = 0;</code>
<code> </code><code>//如果第一次寫,先配置設定一個塊</code>
<code> </code><code>if</code> <code>(inode->i_finode.fi_size == 0) {</code>
<code> </code><code>int</code> <code>nbno = balloc();</code>
<code> </code><code>if</code> <code>(nbno == -1) {</code>
<code> </code><code>return</code> <code>-1;</code>
<code> </code><code>inode->i_finode.fi_addr[0] = nbno;</code>
<code> </code><code>sync = 1;</code>
<code> </code><code>//如果必須擴充,則再配置設定塊,可以和上面的合并優化</code>
<code> </code><code>if</code> <code>(max_block > curr_blocks) {</code>
<code> </code><code>int</code> <code>j = curr_blocks + 1;</code>
<code> </code><code>for</code> <code>(; j < max_block; j++) {</code>
<code> </code><code>int</code> <code>nbno = balloc();</code>
<code> </code><code>if</code> <code>(nbno == -1) {</code>
<code> </code><code>return</code> <code>-1;</code>
<code> </code><code>}</code>
<code> </code><code>inode->i_finode.fi_addr[j] = nbno;</code>
<code> </code><code>size += breadwrite(inode->i_finode.fi_addr[i], buf+size, (length-size)%BSIZE, bondary, 0);</code>
<code> </code><code>if</code> <code>(size) {</code>
<code> </code><code>inode->i_finode.fi_size += size;</code>
<code> </code><code>if</code> <code>(sync) {</code>
<code> </code><code>syncinode(inode);</code>
<code>//IO的seek接口</code>
<code>int</code> <code>mflseek(</code><code>int</code> <code>fd, </code><code>int</code> <code>pos)</code>
<code> </code><code>fs->f_curpos = pos;</code>
<code> </code><code>return</code> <code>pos;</code>
<code>//IO打開接口</code>
<code>int</code> <code>mfopen(</code><code>char</code> <code>*path, </code><code>int</code> <code>mode)</code>
<code> </code><code>struct</code> <code>inode *inode = NULL;</code>
<code> </code><code>struct</code> <code>file *file = NULL;</code>
<code> </code><code>int</code> <code>match = 0;</code>
<code> </code><code>inode = namei(path, 0, &match, NULL);</code>
<code> </code><code>if</code> <code>(match == 0) {</code>
<code> </code><code>return</code> <code>ERR_NOEXIST;</code>
<code> </code><code>file = (</code><code>struct</code> <code>file*)</code><code>calloc</code><code>(1, </code><code>sizeof</code><code>(</code><code>struct</code> <code>file));</code>
<code> </code><code>file->f_inode = inode;</code>
<code> </code><code>file->f_curpos = 0;</code>
<code> </code><code>g_opened[g_fd] = file;</code>
<code> </code><code>g_fd++;</code>
<code> </code><code>return</code> <code>g_fd-1;</code>
<code>//IO關閉接口</code>
<code>void</code> <code>mfclose(</code><code>int</code> <code>fd)</code>
<code> </code><code>file = g_opened[fd];</code>
<code> </code><code>inode = file->f_inode;</code>
<code> </code><code>iput(inode);</code>
<code> </code><code>free</code><code>(file);</code>
<code>//IO建立接口</code>
<code>int</code> <code>mfcreat(</code><code>char</code> <code>*path, </code><code>int</code> <code>mode)</code>
<code> </code><code>struct</code> <code>dir dir;</code>
<code> </code><code>struct</code> <code>inode *</code><code>new</code> <code>= NULL;</code>
<code> </code><code>char</code> <code>name[MAXLEN] = {0};;</code>
<code> </code><code>struct</code> <code>inode *inode = namei(path, 0, &match, name);</code>
<code> </code><code>if</code> <code>(match == 1) {</code>
<code> </code><code>return</code> <code>ERR_EXIST;</code>
<code> </code><code>breadwrite(inode->i_finode.fi_addr[0], (</code><code>char</code> <code>*)&dir, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir), 0, 1);</code>
<code> </code><code>strcpy</code><code>(dir.direct[dir.size].d_name, name);</code>
<code> </code><code>new</code> <code>= ialloc();</code>
<code> </code><code>if</code> <code>(</code><code>new</code> <code>== NULL) {</code>
<code> </code><code>return</code> <code>-1;</code>
<code> </code><code>dir.direct[dir.size].d_ino = </code><code>new</code><code>->i_ino;</code>
<code> </code><code>new</code><code>->i_finode.fi_mode = mode;</code>
<code> </code><code>if</code> <code>(mode == MODE_DIR) {</code>
<code> </code><code>//不允許延遲配置設定目錄項</code>
<code> </code><code>int</code> <code>nbno = balloc();</code>
<code> </code><code>new</code><code>->i_finode.fi_addr[0] = nbno;</code>
<code> </code><code>new</code><code>->i_parent = inode;</code>
<code> </code><code>syncinode(</code><code>new</code><code>);</code>
<code> </code><code>dir.size ++;</code>
<code> </code><code>breadwrite(inode->i_finode.fi_addr[0], (</code><code>char</code> <code>*)&dir, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir), 0, 0);</code>
<code> </code><code>syncinode(inode);</code>
<code> </code><code>iput(</code><code>new</code><code>);</code>
<code> </code><code>return</code> <code>ERR_OK;</code>
<code>//IO删除接口</code>
<code>int</code> <code>mfdelete(</code><code>char</code> <code>*path)</code>
<code> </code><code>struct</code> <code>inode *del = NULL;</code>
<code> </code><code>struct</code> <code>inode *parent = NULL;</code>
<code> </code><code>char</code> <code>name[MAXLEN];</code>
<code> </code><code>int</code> <code>i = 0;</code>
<code> </code><code>if</code> <code>(match == 0 || inode->i_ino == 0) {</code>
<code> </code><code>match = -1;</code>
<code> </code><code>parent = inode->i_parent;</code>
<code> </code><code>breadwrite(parent->i_finode.fi_addr[0], (</code><code>char</code> <code>*)&dir, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir), 0, 1);</code>
<code> </code><code>for</code> <code>(; i < dir.size; i++) {</code>
<code> </code><code>if</code> <code>(!</code><code>strncmp</code><code>(name, dir.direct[i].d_name, </code><code>strlen</code><code>(name))) {</code>
<code> </code><code>del = iget(dir.direct[i].d_ino);</code>
<code> </code><code>iput(del);</code>
<code> </code><code>if</code> <code>(itrunc(del) == 0) {</code>
<code> </code><code>memset</code><code>(dir.direct[i].d_name, 0, </code><code>strlen</code><code>(dir.direct[i].d_name));</code>
<code> </code><code>match = i;</code>
<code> </code><code>break</code><code>;</code>
<code> </code><code>} </code><code>else</code> <code>{</code>
<code> </code><code>return</code> <code>ERR_BUSY;</code>
<code> </code><code>for</code> <code>(i = match; i < dir.size - 1 && match != -1; i++) {</code>
<code> </code><code>strcpy</code><code>(dir.direct[i].d_name, dir.direct[i+1].d_name);</code>
<code> </code><code>dir.size--;</code>
<code> </code><code>breadwrite(parent->i_finode.fi_addr[0], (</code><code>char</code> <code>*)&dir, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir), 0, 0);</code>
<code>//序列初始化接口,從模拟塊裝置初始化記憶體結構</code>
<code>int</code> <code>initialize(</code><code>char</code> <code>*fake_disk_path)</code>
<code> </code><code>g_fake_disk = open(fake_disk_path, O_RDWR);</code>
<code> </code><code>if</code> <code>(g_fake_disk == -1) {</code>
<code> </code><code>g_super = (</code><code>struct</code> <code>filesys*)</code><code>calloc</code><code>(1, </code><code>sizeof</code><code>(</code><code>struct</code> <code>filesys));</code>
<code> </code><code>lseek(g_fake_disk, BOOTBSIZE, SEEK_SET);</code>
<code> </code><code>read(g_fake_disk, g_super, </code><code>sizeof</code><code>(</code><code>struct</code> <code>filesys));</code>
<code> </code><code>g_super->s_size = 1024*1024;</code>
<code> </code><code>g_super->s_itsize = INODEBSIZE;</code>
<code> </code><code>g_super->s_freeinodesize = NUM;</code>
<code> </code><code>g_super->s_freeblocksize = (g_super->s_size - (BOOTBSIZE+SUPERBSIZE+INODEBSIZE))/BSIZE;</code>
<code> </code><code>g_root = iget(0);</code>
<code> </code><code>//第一次的話要配置設定ROOT</code>
<code> </code><code>if</code> <code>(g_root == NULL) {</code>
<code> </code><code>g_root = ialloc();</code>
<code> </code><code>g_root->i_finode.fi_addr[0] = balloc();</code>
下面是一個測試程式:
<code>int</code> <code>main()</code>
<code> </code><code>int</code> <code>fd = -1,ws = -1;</code>
<code> </code><code>char</code> <code>buf[16] = {0};</code>
<code> </code><code>initialize(</code><code>"bigdisk"</code><code>);</code>
<code> </code><code>mfcreat(</code><code>"/aa"</code><code>, MODE_FILE);</code>
<code> </code><code>fd = mfopen(</code><code>"/aa"</code><code>, 0);</code>
<code> </code><code>ws = mfwrite(fd, </code><code>"abcde"</code><code>, 5);</code>
<code> </code><code>mfread(fd, buf, 5);</code>
<code> </code><code>mfcreat(</code><code>"/bb"</code><code>, MODE_DIR);</code>
<code> </code><code>mfcreat(</code><code>"/bb/cc"</code><code>, MODE_FILE);</code>
<code> </code><code>fd = mfopen(</code><code>"/bb/cc"</code><code>, 0);</code>
<code> </code><code>ws = mfwrite(fd, </code><code>"ABCDEFG"</code><code>, 6);</code>
<code> </code><code>mflseek(0, 4);</code>
<code> </code><code>ws = mfwrite(0, </code><code>"ABCDEFG"</code><code>, 6);</code>
<code> </code><code>mflseek(0, 0);</code>
<code> </code><code>mfread(0, buf, 10);</code>
<code> </code><code>mfclose(0);</code>
<code> </code><code>mfdelete(</code><code>"/aa"</code><code>);</code>
<code> </code><code>syncsuper(g_super);</code>
這個檔案系統實作得超級簡單,除去了很多額外的非本質的東西,并且也繞開了煩人的記憶體管理問題!于是,我的這個實作也就顯示了UNIX檔案系統的本質。那麼再看一下,還有什麼東西雖然是額外的,但是卻是必不可少或者起碼說是很有意思的?答案很顯然,那就是空閑塊或者空閑inode的組織以及配置設定算法,然而這個算法可以單獨抽象出來。
本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1282346