rev |
line source |
nuclear@96
|
1 /* This code is used by the kernel AND by userspace filesystem-related tools. */
|
nuclear@97
|
2
|
nuclear@97
|
3 /* XXX convention:
|
nuclear@97
|
4 * - functions that accept or return a struct inode, do not read/write it to disk
|
nuclear@97
|
5 * - functions that accept or return an int ino, do read/write it to disk
|
nuclear@97
|
6 * other kinds of blocks (data, indirect, etc) always hit the disk directly.
|
nuclear@97
|
7 */
|
nuclear@97
|
8
|
nuclear@88
|
9 #include <stdio.h>
|
nuclear@89
|
10 #include <stdlib.h>
|
nuclear@94
|
11 #include <string.h>
|
nuclear@90
|
12 #include <errno.h>
|
nuclear@94
|
13 #include <assert.h>
|
nuclear@88
|
14 #include "fs.h"
|
nuclear@93
|
15 #include "bdev.h"
|
nuclear@96
|
16 #include "kdef.h"
|
nuclear@96
|
17
|
nuclear@96
|
18 /* number of inodes in a block */
|
nuclear@96
|
19 #define BLK_INODES (BLKSZ / sizeof(struct inode))
|
nuclear@96
|
20 /* number of directory entries in a block */
|
nuclear@96
|
21 #define BLK_DIRENT (BLKSZ / sizeof(struct dir_entry))
|
nuclear@96
|
22
|
nuclear@96
|
23 #define BLKBITS (BLKSZ * 8)
|
nuclear@90
|
24
|
nuclear@95
|
25 #define BM_IDX(x) ((x) / 32)
|
nuclear@95
|
26 #define BM_BIT(x) ((x) & 0x1f)
|
nuclear@95
|
27
|
nuclear@95
|
28 #define BM_ISFREE(bm, x) (((bm)[BM_IDX(x)] & (1 << BM_BIT(x))) == 0)
|
nuclear@95
|
29 #define BM_SET(bm, x) ((bm)[BM_IDX(x)] |= (1 << BM_BIT(x)))
|
nuclear@95
|
30 #define BM_CLR(bm, x) ((bm)[BM_IDX(x)] &= ~(1 << BM_BIT(x)))
|
nuclear@95
|
31
|
nuclear@89
|
32
|
nuclear@96
|
33 static struct inode *newdir(struct filesys *fs, struct inode *parent);
|
nuclear@96
|
34 static int addlink(struct filesys *fs, struct inode *target, struct inode *node, const char *name);
|
nuclear@94
|
35 static int read_superblock(struct filesys *fs);
|
nuclear@94
|
36 static int write_superblock(struct filesys *fs);
|
nuclear@94
|
37 static int get_inode(struct filesys *fs, int ino, struct inode *inode);
|
nuclear@94
|
38 static int put_inode(struct filesys *fs, struct inode *inode);
|
nuclear@96
|
39 static int find_free(uint32_t *bm, int sz);
|
nuclear@96
|
40 static int alloc_inode(struct filesys *fs);
|
nuclear@97
|
41 #define free_inode(fs, ino) BM_CLR((fs)->sb->ibm, (ino))
|
nuclear@96
|
42 static int alloc_block(struct filesys *fs);
|
nuclear@97
|
43 #define free_block(fs, bno) BM_CLR((fs)->sb->bm, (bno))
|
nuclear@97
|
44 #define zero_block(fs, bno) \
|
nuclear@97
|
45 do { \
|
nuclear@97
|
46 assert(bno > 0); \
|
nuclear@97
|
47 blk_write((fs)->bdev, (bno), 1, (fs)->zeroblock); \
|
nuclear@97
|
48 } while(0)
|
nuclear@97
|
49
|
nuclear@97
|
50 static int file_block(struct filesys *fs, struct inode *node, int boffs, int allocate);
|
nuclear@97
|
51 #define get_file_block(fs, node, boffs) file_block(fs, node, boffs, 0)
|
nuclear@97
|
52 #define alloc_file_block(fs, node, boffs) file_block(fs, node, boffs, 1)
|
nuclear@97
|
53
|
nuclear@90
|
54
|
nuclear@93
|
55 int openfs(struct filesys *fs, dev_t dev)
|
nuclear@93
|
56 {
|
nuclear@93
|
57 int res;
|
nuclear@93
|
58 struct block_device *bdev;
|
nuclear@94
|
59
|
nuclear@94
|
60 assert(BLKSZ % sizeof(struct inode) == 0);
|
nuclear@89
|
61
|
nuclear@93
|
62 if(!(bdev = blk_open(dev))) {
|
nuclear@93
|
63 return -ENOENT;
|
nuclear@90
|
64 }
|
nuclear@94
|
65 fs->bdev = bdev;
|
nuclear@90
|
66
|
nuclear@93
|
67 /* read the superblock */
|
nuclear@94
|
68 if(!(fs->sb = malloc(BLKSZ))) {
|
nuclear@96
|
69 blk_close(bdev);
|
nuclear@96
|
70 return -ENOMEM;
|
nuclear@93
|
71 }
|
nuclear@94
|
72 if((res = read_superblock(fs)) != 0) {
|
nuclear@96
|
73 blk_close(bdev);
|
nuclear@96
|
74 return res;
|
nuclear@93
|
75 }
|
nuclear@90
|
76
|
nuclear@97
|
77 /* allocate the zero-block buffer written to zero-out blocks */
|
nuclear@97
|
78 if(!(fs->zeroblock = malloc(fs->sb->blksize))) {
|
nuclear@97
|
79 blk_close(bdev);
|
nuclear@97
|
80 free(fs->sb->ibm);
|
nuclear@97
|
81 free(fs->sb->bm);
|
nuclear@97
|
82 free(fs->sb->root);
|
nuclear@97
|
83 return -ENOMEM;
|
nuclear@97
|
84 }
|
nuclear@97
|
85 memset(fs->zeroblock, 0xff, fs->sb->blksize);
|
nuclear@97
|
86
|
nuclear@96
|
87 return 0;
|
nuclear@96
|
88 }
|
nuclear@93
|
89
|
nuclear@96
|
90 int mkfs(struct filesys *fs, dev_t dev)
|
nuclear@96
|
91 {
|
nuclear@96
|
92 struct superblock *sb;
|
nuclear@96
|
93 struct block_device *bdev;
|
nuclear@96
|
94 int i, bcount;
|
nuclear@96
|
95
|
nuclear@96
|
96 if(!(bdev = blk_open(dev))) {
|
nuclear@96
|
97 return -1;
|
nuclear@96
|
98 }
|
nuclear@96
|
99 fs->bdev = bdev;
|
nuclear@96
|
100
|
nuclear@96
|
101 if(!(sb = malloc(BLKSZ))) {
|
nuclear@96
|
102 blk_close(bdev);
|
nuclear@96
|
103 return -1;
|
nuclear@96
|
104 }
|
nuclear@96
|
105 fs->sb = sb;
|
nuclear@96
|
106
|
nuclear@96
|
107 /* populate the superblock */
|
nuclear@96
|
108 sb->magic = MAGIC;
|
nuclear@96
|
109 sb->ver = FS_VER;
|
nuclear@96
|
110 sb->blksize = BLKSZ;
|
nuclear@96
|
111
|
nuclear@96
|
112 sb->num_blocks = bdev->size;
|
nuclear@96
|
113 sb->num_inodes = sb->num_blocks / 4;
|
nuclear@96
|
114
|
nuclear@96
|
115 /* inode bitmap just after the superblock */
|
nuclear@96
|
116 sb->ibm_start = 2;
|
nuclear@96
|
117 sb->ibm_count = (sb->num_inodes + BLKBITS - 1) / BLKBITS;
|
nuclear@96
|
118 /* also allocate and initialize in-memory inode bitmap */
|
nuclear@96
|
119 sb->ibm = malloc(sb->ibm_count * BLKSZ);
|
nuclear@96
|
120 assert(sb->ibm);
|
nuclear@96
|
121 memset(sb->ibm, 0, sb->ibm_count * BLKSZ);
|
nuclear@96
|
122
|
nuclear@96
|
123 /* XXX mark inode 0 as used always */
|
nuclear@96
|
124 BM_SET(sb->ibm, 0);
|
nuclear@96
|
125
|
nuclear@96
|
126 /* block bitmap just after the inode bitmap */
|
nuclear@96
|
127 sb->bm_start = sb->ibm_start + sb->ibm_count;
|
nuclear@96
|
128 sb->bm_count = (sb->num_blocks + BLKBITS - 1) / BLKBITS;
|
nuclear@96
|
129 /* also allocate and initialize in-memory block bitmap */
|
nuclear@96
|
130 sb->bm = malloc(sb->bm_count * BLKSZ);
|
nuclear@96
|
131 assert(sb->bm);
|
nuclear@96
|
132 memset(sb->bm, 0, sb->bm_count * BLKSZ);
|
nuclear@96
|
133
|
nuclear@96
|
134 /* inode table, just after the block bitmap */
|
nuclear@96
|
135 sb->itbl_start = sb->bm_start + sb->bm_count;
|
nuclear@96
|
136 sb->itbl_count = (sb->num_inodes * sizeof(struct inode) + BLKSZ - 1) / BLKSZ;
|
nuclear@96
|
137
|
nuclear@96
|
138 /* mark all used blocks as used */
|
nuclear@96
|
139 bcount = sb->itbl_start + sb->itbl_count;
|
nuclear@96
|
140 memset(sb->bm, 0xff, bcount / 8);
|
nuclear@96
|
141 for(i=0; i<bcount % 8; i++) {
|
nuclear@96
|
142 int bit = bcount / 8 + i;
|
nuclear@96
|
143 BM_SET(sb->bm, bit);
|
nuclear@96
|
144 }
|
nuclear@96
|
145
|
nuclear@96
|
146 /* create the root directory */
|
nuclear@96
|
147 sb->root = newdir(fs, 0);
|
nuclear@96
|
148 sb->root_ino = sb->root->ino;
|
nuclear@97
|
149 /* and write the inode to disk */
|
nuclear@97
|
150 put_inode(fs, sb->root);
|
nuclear@97
|
151
|
nuclear@97
|
152 return 0;
|
nuclear@90
|
153 }
|
nuclear@88
|
154
|
nuclear@96
|
155 static struct inode *newdir(struct filesys *fs, struct inode *parent)
|
nuclear@96
|
156 {
|
nuclear@96
|
157 struct inode *dirnode;
|
nuclear@96
|
158
|
nuclear@96
|
159 /* allocate and initialize inode */
|
nuclear@96
|
160 if(!(dirnode = malloc(sizeof *dirnode))) {
|
nuclear@96
|
161 return 0;
|
nuclear@96
|
162 }
|
nuclear@96
|
163 memset(dirnode, 0, sizeof *dirnode);
|
nuclear@96
|
164
|
nuclear@96
|
165 if((dirnode->ino = alloc_inode(fs)) == -1) {
|
nuclear@96
|
166 printf("failed to allocate inode for a new directory\n");
|
nuclear@96
|
167 free(dirnode);
|
nuclear@96
|
168 return 0;
|
nuclear@96
|
169 }
|
nuclear@96
|
170 dirnode->mode = S_IFDIR;
|
nuclear@96
|
171
|
nuclear@96
|
172 /* add . and .. links */
|
nuclear@96
|
173 addlink(fs, dirnode, dirnode, ".");
|
nuclear@96
|
174 addlink(fs, dirnode, parent ? parent : dirnode, "..");
|
nuclear@96
|
175
|
nuclear@96
|
176 return dirnode;
|
nuclear@96
|
177 }
|
nuclear@96
|
178
|
nuclear@96
|
179 static int addlink(struct filesys *fs, struct inode *target, struct inode *node, const char *name)
|
nuclear@96
|
180 {
|
nuclear@96
|
181 struct dir_entry ent, *data;
|
nuclear@97
|
182 int i, boffs, bidx, len;
|
nuclear@96
|
183
|
nuclear@96
|
184 if(!(target->mode & S_IFDIR)) {
|
nuclear@96
|
185 return -ENOTDIR;
|
nuclear@96
|
186 }
|
nuclear@96
|
187 if(node->mode & S_IFDIR) {
|
nuclear@96
|
188 return -EPERM;
|
nuclear@96
|
189 }
|
nuclear@96
|
190 /* TODO check that the link does not already exist (EEXIST) */
|
nuclear@96
|
191
|
nuclear@97
|
192 if((len = strlen(name)) > NAME_MAX) {
|
nuclear@96
|
193 return -ENAMETOOLONG;
|
nuclear@96
|
194 }
|
nuclear@97
|
195 ent.ino = node->ino;
|
nuclear@97
|
196 memcpy(ent.name, name, len + 1);
|
nuclear@96
|
197
|
nuclear@96
|
198 /* find a place to put it */
|
nuclear@96
|
199 if(!(data = malloc(BLKSZ))) {
|
nuclear@96
|
200 return -ENOMEM;
|
nuclear@96
|
201 }
|
nuclear@96
|
202
|
nuclear@96
|
203 boffs = 0;
|
nuclear@97
|
204 while((bidx = get_file_block(fs, target, boffs)) > 0) {
|
nuclear@96
|
205 /* read the block, and search for an empty entry */
|
nuclear@96
|
206 blk_read(fs->bdev, bidx, 1, data);
|
nuclear@96
|
207
|
nuclear@96
|
208 /* for all directory entries in this block... */
|
nuclear@96
|
209 for(i=0; i<BLK_DIRENT; i++) {
|
nuclear@96
|
210 if(data[i].ino == 0) {
|
nuclear@96
|
211 /* found empty */
|
nuclear@96
|
212 memcpy(data + i, &ent, sizeof ent);
|
nuclear@96
|
213 goto success;
|
nuclear@96
|
214 }
|
nuclear@96
|
215 }
|
nuclear@96
|
216 boffs++;
|
nuclear@96
|
217 }
|
nuclear@96
|
218
|
nuclear@96
|
219 /* didn't find any free entries amongst our blocks, allocate a new one */
|
nuclear@96
|
220 if(!(bidx = alloc_file_block(fs, target, boffs))) {
|
nuclear@96
|
221 free(data);
|
nuclear@96
|
222 return -ENOSPC;
|
nuclear@96
|
223 }
|
nuclear@96
|
224 /* zero-fill the new block and add the first entry */
|
nuclear@96
|
225 memset(data, 0, BLKSZ);
|
nuclear@96
|
226 *data = ent;
|
nuclear@96
|
227
|
nuclear@96
|
228 success:
|
nuclear@96
|
229 /* write to disk */
|
nuclear@96
|
230 blk_write(fs->bdev, bidx, 1, data);
|
nuclear@96
|
231 node->nlink++; /* increase reference count */
|
nuclear@96
|
232
|
nuclear@96
|
233 free(data);
|
nuclear@96
|
234 return 0;
|
nuclear@96
|
235 }
|
nuclear@96
|
236
|
nuclear@96
|
237
|
nuclear@94
|
238 static int read_superblock(struct filesys *fs)
|
nuclear@88
|
239 {
|
nuclear@94
|
240 struct superblock *sb = fs->sb;
|
nuclear@94
|
241
|
nuclear@93
|
242 /* read superblock and verify */
|
nuclear@94
|
243 if(blk_read(fs->bdev, 1, 1, sb) == -1) {
|
nuclear@93
|
244 printf("failed to read superblock\n");
|
nuclear@93
|
245 return -EIO;
|
nuclear@93
|
246 }
|
nuclear@93
|
247 if(sb->magic != MAGIC) {
|
nuclear@93
|
248 printf("invalid magic\n");
|
nuclear@93
|
249 return -EINVAL;
|
nuclear@93
|
250 }
|
nuclear@93
|
251 if(sb->ver > FS_VER) {
|
nuclear@93
|
252 printf("invalid version: %d\n", sb->ver);
|
nuclear@93
|
253 return -EINVAL;
|
nuclear@93
|
254 }
|
nuclear@93
|
255 if(sb->blksize != BLKSZ) {
|
nuclear@93
|
256 printf("invalid block size: %d\n", sb->blksize);
|
nuclear@93
|
257 return -EINVAL;
|
nuclear@93
|
258 }
|
nuclear@89
|
259
|
nuclear@93
|
260 /* allocate and populate in-memory bitmaps */
|
nuclear@93
|
261 if(!(sb->ibm = malloc(sb->ibm_count * sb->blksize))) {
|
nuclear@93
|
262 return -ENOMEM;
|
nuclear@88
|
263 }
|
nuclear@94
|
264 if(blk_read(fs->bdev, sb->ibm_start, sb->ibm_count, sb->ibm) == -1) {
|
nuclear@93
|
265 printf("failed to read inode bitmap\n");
|
nuclear@93
|
266 free(sb->ibm);
|
nuclear@93
|
267 return -EIO;
|
nuclear@93
|
268 }
|
nuclear@93
|
269 if(!(sb->bm = malloc(sb->bm_count * sb->blksize))) {
|
nuclear@93
|
270 free(sb->ibm);
|
nuclear@93
|
271 return -ENOMEM;
|
nuclear@93
|
272 }
|
nuclear@94
|
273 if(blk_read(fs->bdev, sb->bm_start, sb->bm_count, sb->bm) == -1) {
|
nuclear@93
|
274 printf("failed to read block bitmap\n");
|
nuclear@93
|
275 free(sb->ibm);
|
nuclear@93
|
276 free(sb->bm);
|
nuclear@93
|
277 return -EIO;
|
nuclear@93
|
278 }
|
nuclear@93
|
279
|
nuclear@94
|
280 /* read the root inode */
|
nuclear@94
|
281 if(!(sb->root = malloc(sizeof *sb->root))) {
|
nuclear@94
|
282 free(sb->ibm);
|
nuclear@94
|
283 free(sb->bm);
|
nuclear@94
|
284 return -ENOMEM;
|
nuclear@94
|
285 }
|
nuclear@94
|
286 if(get_inode(fs, sb->root_ino, sb->root) == -1) {
|
nuclear@94
|
287 printf("failed to read root inode\n");
|
nuclear@94
|
288 return -1;
|
nuclear@94
|
289 }
|
nuclear@94
|
290
|
nuclear@93
|
291 return 0;
|
nuclear@88
|
292 }
|
nuclear@94
|
293
|
nuclear@94
|
294 static int write_superblock(struct filesys *fs)
|
nuclear@94
|
295 {
|
nuclear@94
|
296 struct superblock *sb = fs->sb;
|
nuclear@94
|
297
|
nuclear@94
|
298 /* write back any changes in the root inode */
|
nuclear@94
|
299 if(put_inode(fs, sb->root) == -1) {
|
nuclear@94
|
300 return -1;
|
nuclear@94
|
301 }
|
nuclear@94
|
302 /* write back the block bitmap */
|
nuclear@94
|
303 if(blk_write(fs->bdev, sb->bm_start, sb->bm_count, sb->bm) == -1) {
|
nuclear@94
|
304 return -1;
|
nuclear@94
|
305 }
|
nuclear@94
|
306 /* write back the inode bitmap */
|
nuclear@94
|
307 if(blk_write(fs->bdev, sb->ibm_start, sb->ibm_count, sb->ibm) == -1) {
|
nuclear@94
|
308 return -1;
|
nuclear@94
|
309 }
|
nuclear@96
|
310 /* write the superblock itself */
|
nuclear@96
|
311 if(blk_write(fs->bdev, 1, 1, sb) == -1) {
|
nuclear@96
|
312 return -1;
|
nuclear@96
|
313 }
|
nuclear@94
|
314 return 0;
|
nuclear@94
|
315 }
|
nuclear@94
|
316
|
nuclear@94
|
317 /* copy the requested inode from the disk, into the buffer passed in the last arg */
|
nuclear@94
|
318 static int get_inode(struct filesys *fs, int ino, struct inode *inode)
|
nuclear@94
|
319 {
|
nuclear@94
|
320 struct inode *buf = malloc(BLKSZ);
|
nuclear@94
|
321 assert(buf);
|
nuclear@94
|
322
|
nuclear@94
|
323 if(blk_read(fs->bdev, fs->sb->itbl_start + ino / BLK_INODES, 1, buf) == -1) {
|
nuclear@94
|
324 free(buf);
|
nuclear@94
|
325 return -1;
|
nuclear@94
|
326 }
|
nuclear@94
|
327 memcpy(inode, buf + ino % BLK_INODES, sizeof *inode);
|
nuclear@94
|
328 free(buf);
|
nuclear@94
|
329 return 0;
|
nuclear@94
|
330 }
|
nuclear@94
|
331
|
nuclear@94
|
332 /* write the inode to the disk */
|
nuclear@94
|
333 static int put_inode(struct filesys *fs, struct inode *inode)
|
nuclear@94
|
334 {
|
nuclear@94
|
335 struct inode *buf = malloc(BLKSZ);
|
nuclear@94
|
336 assert(buf);
|
nuclear@94
|
337
|
nuclear@94
|
338 if(blk_read(fs->bdev, fs->sb->itbl_start + inode->ino / BLK_INODES, 1, buf) == -1) {
|
nuclear@94
|
339 free(buf);
|
nuclear@94
|
340 return -1;
|
nuclear@94
|
341 }
|
nuclear@94
|
342 memcpy(buf + inode->ino % BLK_INODES, inode, sizeof *inode);
|
nuclear@94
|
343
|
nuclear@94
|
344 if(blk_write(fs->bdev, fs->sb->itbl_start + inode->ino / BLK_INODES, 1, buf) == -1) {
|
nuclear@94
|
345 free(buf);
|
nuclear@94
|
346 return -1;
|
nuclear@94
|
347 }
|
nuclear@94
|
348 free(buf);
|
nuclear@94
|
349 return 0;
|
nuclear@94
|
350 }
|
nuclear@95
|
351
|
nuclear@96
|
352 /* find a free element in the bitmap and return its number */
|
nuclear@96
|
353 static int find_free(uint32_t *bm, int nbits)
|
nuclear@95
|
354 {
|
nuclear@96
|
355 int i, j, nwords = nbits / 32;
|
nuclear@96
|
356 uint32_t ent = 0;
|
nuclear@95
|
357
|
nuclear@96
|
358 for(i=0; i<=nwords; i++) {
|
nuclear@95
|
359 if(bm[i] != 0xffffffff) {
|
nuclear@95
|
360 for(j=0; j<32; j++) {
|
nuclear@95
|
361 if(BM_ISFREE(bm, ent)) {
|
nuclear@95
|
362 return ent;
|
nuclear@95
|
363 }
|
nuclear@96
|
364 ent++;
|
nuclear@95
|
365 }
|
nuclear@95
|
366
|
nuclear@95
|
367 panic("shouldn't happen (in find_free:fs.c)");
|
nuclear@96
|
368 } else {
|
nuclear@96
|
369 ent += 32;
|
nuclear@95
|
370 }
|
nuclear@95
|
371 }
|
nuclear@95
|
372
|
nuclear@95
|
373 return -1;
|
nuclear@95
|
374 }
|
nuclear@95
|
375
|
nuclear@95
|
376 static int alloc_inode(struct filesys *fs)
|
nuclear@95
|
377 {
|
nuclear@95
|
378 int ino;
|
nuclear@95
|
379
|
nuclear@96
|
380 if((ino = find_free(fs->sb->ibm, fs->sb->num_inodes)) == -1) {
|
nuclear@95
|
381 return -1;
|
nuclear@95
|
382 }
|
nuclear@96
|
383 BM_SET(fs->sb->ibm, ino);
|
nuclear@95
|
384 return 0;
|
nuclear@95
|
385 }
|
nuclear@96
|
386
|
nuclear@96
|
387 static int alloc_block(struct filesys *fs)
|
nuclear@96
|
388 {
|
nuclear@97
|
389 int bno;
|
nuclear@96
|
390
|
nuclear@97
|
391 if((bno = find_free(fs->sb->bm, fs->sb->num_blocks)) == -1) {
|
nuclear@96
|
392 return -1;
|
nuclear@96
|
393 }
|
nuclear@97
|
394 BM_SET(fs->sb->bm, bno);
|
nuclear@96
|
395 return 0;
|
nuclear@96
|
396 }
|
nuclear@96
|
397
|
nuclear@96
|
398 #define BLK_BLKID (BLKSZ / sizeof(blkid))
|
nuclear@96
|
399 #define MAX_IND (NDIRBLK + BLK_BLKID)
|
nuclear@96
|
400 #define MAX_DIND (MAX_IND + BLK_BLKID * BLK_BLKID)
|
nuclear@96
|
401
|
nuclear@97
|
402 static int file_block(struct filesys *fs, struct inode *node, int boffs, int allocate)
|
nuclear@96
|
403 {
|
nuclear@97
|
404 int res, idx, node_dirty = 0;
|
nuclear@96
|
405 blkid *barr;
|
nuclear@96
|
406
|
nuclear@97
|
407 /* out of bounds */
|
nuclear@97
|
408 if(boffs < 0 || boffs >= MAX_DIND) {
|
nuclear@97
|
409 return 0;
|
nuclear@97
|
410 }
|
nuclear@97
|
411
|
nuclear@96
|
412 /* is it a direct block ? */
|
nuclear@96
|
413 if(boffs < NDIRBLK) {
|
nuclear@97
|
414 if(!(res = node->blk[boffs]) && allocate) {
|
nuclear@97
|
415 res = node->blk[boffs] = alloc_block(fs);
|
nuclear@97
|
416 if(res) {
|
nuclear@97
|
417 zero_block(fs, res);
|
nuclear@97
|
418 /* also write back the modified inode */
|
nuclear@97
|
419 put_inode(fs, node);
|
nuclear@97
|
420 }
|
nuclear@97
|
421 }
|
nuclear@97
|
422 return res;
|
nuclear@96
|
423 }
|
nuclear@96
|
424
|
nuclear@97
|
425 barr = malloc(fs->sb->blksize);
|
nuclear@96
|
426 assert(barr);
|
nuclear@96
|
427
|
nuclear@96
|
428 /* is it an indirect block ? */
|
nuclear@96
|
429 if(boffs < MAX_IND) {
|
nuclear@97
|
430 int ind_dirty = 0;
|
nuclear@97
|
431
|
nuclear@97
|
432 if(node->ind) {
|
nuclear@97
|
433 /* read the indirect block */
|
nuclear@97
|
434 blk_read(fs->bdev, node->ind, 1, barr);
|
nuclear@97
|
435 } else {
|
nuclear@97
|
436 /* does not exist... try to allocate if requested */
|
nuclear@97
|
437 if(!allocate || !(node->ind = alloc_block(fs))) {
|
nuclear@97
|
438 res = 0;
|
nuclear@97
|
439 goto end;
|
nuclear@97
|
440 }
|
nuclear@97
|
441
|
nuclear@97
|
442 /* allocated a block clear the buffer, and invalidate everything */
|
nuclear@97
|
443 memset(barr, 0, sizeof fs->sb->blksize);
|
nuclear@97
|
444 node_dirty = 1;
|
nuclear@97
|
445 ind_dirty = 1;
|
nuclear@96
|
446 }
|
nuclear@97
|
447
|
nuclear@97
|
448 idx = boffs - NDIRBLK;
|
nuclear@97
|
449
|
nuclear@97
|
450 if(!(res = barr[idx])) {
|
nuclear@97
|
451 if(allocate && (res = barr[idx] = alloc_block(fs))) {
|
nuclear@97
|
452 ind_dirty = 1;
|
nuclear@97
|
453 }
|
nuclear@97
|
454 }
|
nuclear@97
|
455
|
nuclear@97
|
456 /* write back the indirect block if needed */
|
nuclear@97
|
457 if(ind_dirty) {
|
nuclear@97
|
458 blk_write(fs->bdev, node->ind, 1, barr);
|
nuclear@97
|
459 }
|
nuclear@96
|
460 goto end;
|
nuclear@96
|
461 }
|
nuclear@96
|
462
|
nuclear@97
|
463 /* TODO check/rewrite this */
|
nuclear@97
|
464 #if 0
|
nuclear@96
|
465 /* is it a double-indirect block ? */
|
nuclear@96
|
466 if(boffs < MAX_DIND) {
|
nuclear@96
|
467 /* first read the dind block and find the index of the ind block */
|
nuclear@96
|
468 if(!node->dind) {
|
nuclear@97
|
469 if(allocate) {
|
nuclear@97
|
470 /* allocate and zero-out the double indirect block */
|
nuclear@97
|
471 res = node->dind = alloc_block(fs);
|
nuclear@97
|
472 if(res) {
|
nuclear@97
|
473 zero_block(fs, res);
|
nuclear@97
|
474 }
|
nuclear@97
|
475 } else {
|
nuclear@97
|
476 res = 0;
|
nuclear@97
|
477 goto end;
|
nuclear@97
|
478 }
|
nuclear@96
|
479 }
|
nuclear@96
|
480 blk_read(fd->bdev, node->dind, 1, barr);
|
nuclear@96
|
481 idx = (boffs - MAX_IND) / BLK_BLKID;
|
nuclear@96
|
482
|
nuclear@96
|
483 /* then read the ind block and find the index of the block */
|
nuclear@96
|
484 if(!barr[idx]) {
|
nuclear@96
|
485 res = 0;
|
nuclear@96
|
486 goto end;
|
nuclear@96
|
487 }
|
nuclear@96
|
488 blk_read(fd->bdev, barr[idx], 1, barr);
|
nuclear@96
|
489 res = barr[(boffs - MAX_IND) % BLK_BLKID];
|
nuclear@96
|
490 }
|
nuclear@97
|
491 #endif
|
nuclear@96
|
492
|
nuclear@96
|
493 end:
|
nuclear@97
|
494 if(node_dirty) {
|
nuclear@97
|
495 put_inode(fs, node);
|
nuclear@97
|
496 }
|
nuclear@96
|
497 free(barr);
|
nuclear@96
|
498 return res;
|
nuclear@96
|
499 }
|