天天看點

編寫一個UNIX檔案系統

近日有人求助,要寫一個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-&gt;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>*)&amp;inode-&gt;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-&gt;i_finode.fi_addr[0], (</code><code>char</code> <code>*)&amp;dir, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir), 0, 1);</code>

<code>        </code><code>breadwrite(g_root-&gt;i_finode.fi_addr[0], (</code><code>char</code> <code>*)&amp;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-&gt;i_finode.fi_addr[0], &amp;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&lt;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-&gt;i_parent = parent;</code>

<code>                                </code><code>*match = 1;</code>

<code>                                </code><code>if</code> <code>(root-&gt;i_finode.fi_mode == MODE_DIR) {</code>

<code>                                        </code><code>memset</code><code>(&amp;dir, 0, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir));</code>

<code>                                        </code><code>breadwrite(root-&gt;i_finode.fi_addr[0], &amp;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>&amp;g_usedinode[ino];</code>

<code>        </code><code>if</code> <code>(g_fake_disk &lt; 0) {</code>

<code>    </code><code>//實在不行則從模拟磁盤塊讀入</code>

<code>        </code><code>ret = read(g_fake_disk, &amp;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-&gt;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(&amp;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>&amp;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-&gt;i_users &gt; 0)</code>

<code>                </code><code>ip-&gt;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-&gt;s_nextfreeinode;</code>

<code>        </code><code>if</code> <code>(ino == -1) {</code>

<code>        </code><code>nowpos = ino + 1;</code>

<code>        </code><code>g_super-&gt;s_nextfreeinode = -1;</code>

<code>    </code><code>//尋找下一個空閑i節點,正如上述,這個算法并不好</code>

<code>        </code><code>for</code> <code>(; nowpos &lt; NUM; nowpos++) {</code>

<code>                </code><code>if</code> <code>(g_super-&gt;s_freeinode[nowpos] == 0) {</code>

<code>                        </code><code>g_super-&gt;s_nextfreeinode = nowpos;</code>

<code>        </code><code>g_super-&gt;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-&gt;i_users == 0 &amp;&amp; g_super) {</code>

<code>                </code><code>syncinode(ip);</code>

<code>                </code><code>g_super-&gt;s_freeinode[ip-&gt;i_ino] = 0;</code>

<code>                </code><code>g_super-&gt;s_nextfreeinode = ip-&gt;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-&gt;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-&gt;s_nextfreeblock = -1;</code>

<code>                </code><code>if</code> <code>(g_super-&gt;s_freeblock[nowpos] == 0) {</code>

<code>                        </code><code>g_super-&gt;s_nextfreeblock = nowpos;</code>

<code>        </code><code>g_super-&gt;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-&gt;s_itsize + bno*BSIZE;</code>

<code>        </code><code>int</code> <code>rs = -1;</code>

<code>        </code><code>if</code> <code>(offset + size &gt; 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-&gt;f_inode;</code>

<code>        </code><code>int</code> <code>baddr = fs-&gt;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-&gt;i_finode.fi_addr[baddr/BSIZE+1];</code>

<code>        </code><code>for</code> <code>(; i &lt; max_block+1; i ++,bondary = size%BSIZE) {</code>

<code>                </code><code>size += breadwrite(inode-&gt;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-&gt;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-&gt;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-&gt;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 &gt; curr_blocks) {</code>

<code>                </code><code>int</code> <code>j = curr_blocks + 1;</code>

<code>                </code><code>for</code> <code>(; j &lt; 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-&gt;i_finode.fi_addr[j] = nbno;</code>

<code>                </code><code>size += breadwrite(inode-&gt;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-&gt;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-&gt;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, &amp;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-&gt;f_inode = inode;</code>

<code>        </code><code>file-&gt;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-&gt;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, &amp;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-&gt;i_finode.fi_addr[0], (</code><code>char</code> <code>*)&amp;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>-&gt;i_ino;</code>

<code>        </code><code>new</code><code>-&gt;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>-&gt;i_finode.fi_addr[0] = nbno;</code>

<code>        </code><code>new</code><code>-&gt;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-&gt;i_finode.fi_addr[0], (</code><code>char</code> <code>*)&amp;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-&gt;i_ino == 0) {</code>

<code>        </code><code>match = -1;</code>

<code>        </code><code>parent = inode-&gt;i_parent;</code>

<code>        </code><code>breadwrite(parent-&gt;i_finode.fi_addr[0], (</code><code>char</code> <code>*)&amp;dir, </code><code>sizeof</code><code>(</code><code>struct</code> <code>dir), 0, 1);</code>

<code>        </code><code>for</code> <code>(; i &lt; 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 &lt; dir.size - 1 &amp;&amp; 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-&gt;i_finode.fi_addr[0], (</code><code>char</code> <code>*)&amp;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-&gt;s_size = 1024*1024;</code>

<code>        </code><code>g_super-&gt;s_itsize = INODEBSIZE;</code>

<code>        </code><code>g_super-&gt;s_freeinodesize = NUM;</code>

<code>        </code><code>g_super-&gt;s_freeblocksize = (g_super-&gt;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-&gt;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

繼續閱讀