1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/kernel.h>
14#include <linux/buffer_head.h>
15#include <linux/string.h>
16
17#include "befs.h"
18#include "datastream.h"
19#include "io.h"
20
21const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
22
23static int befs_find_brun_direct(struct super_block *sb,
24 befs_data_stream * data,
25 befs_blocknr_t blockno, befs_block_run * run);
26
27static int befs_find_brun_indirect(struct super_block *sb,
28 befs_data_stream * data,
29 befs_blocknr_t blockno,
30 befs_block_run * run);
31
32static int befs_find_brun_dblindirect(struct super_block *sb,
33 befs_data_stream * data,
34 befs_blocknr_t blockno,
35 befs_block_run * run);
36
37
38
39
40
41
42
43
44
45
46
47struct buffer_head *
48befs_read_datastream(struct super_block *sb, befs_data_stream * ds,
49 befs_off_t pos, uint * off)
50{
51 struct buffer_head *bh = NULL;
52 befs_block_run run;
53 befs_blocknr_t block;
54
55 befs_debug(sb, "---> befs_read_datastream() %Lu", pos);
56 block = pos >> BEFS_SB(sb)->block_shift;
57 if (off)
58 *off = pos - (block << BEFS_SB(sb)->block_shift);
59
60 if (befs_fblock2brun(sb, ds, block, &run) != BEFS_OK) {
61 befs_error(sb, "BeFS: Error finding disk addr of block %lu",
62 block);
63 befs_debug(sb, "<--- befs_read_datastream() ERROR");
64 return NULL;
65 }
66 bh = befs_bread_iaddr(sb, run);
67 if (!bh) {
68 befs_error(sb, "BeFS: Error reading block %lu from datastream",
69 block);
70 return NULL;
71 }
72
73 befs_debug(sb, "<--- befs_read_datastream() read data, starting at %Lu",
74 pos);
75
76 return bh;
77}
78
79
80
81
82
83
84
85
86
87
88
89
90int
91befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
92 befs_blocknr_t fblock, befs_block_run * run)
93{
94 int err;
95 befs_off_t pos = fblock << BEFS_SB(sb)->block_shift;
96
97 if (pos < data->max_direct_range) {
98 err = befs_find_brun_direct(sb, data, fblock, run);
99
100 } else if (pos < data->max_indirect_range) {
101 err = befs_find_brun_indirect(sb, data, fblock, run);
102
103 } else if (pos < data->max_double_indirect_range) {
104 err = befs_find_brun_dblindirect(sb, data, fblock, run);
105
106 } else {
107 befs_error(sb,
108 "befs_fblock2brun() was asked to find block %lu, "
109 "which is not mapped by the datastream\n", fblock);
110 err = BEFS_ERR;
111 }
112 return err;
113}
114
115
116
117
118
119
120
121
122
123
124size_t
125befs_read_lsymlink(struct super_block * sb, befs_data_stream * ds, void *buff,
126 befs_off_t len)
127{
128 befs_off_t bytes_read = 0;
129 u16 plen;
130 struct buffer_head *bh = NULL;
131 befs_debug(sb, "---> befs_read_lsymlink() length: %Lu", len);
132
133 while (bytes_read < len) {
134 bh = befs_read_datastream(sb, ds, bytes_read, NULL);
135 if (!bh) {
136 befs_error(sb, "BeFS: Error reading datastream block "
137 "starting from %Lu", bytes_read);
138 befs_debug(sb, "<--- befs_read_lsymlink() ERROR");
139 return bytes_read;
140
141 }
142 plen = ((bytes_read + BEFS_SB(sb)->block_size) < len) ?
143 BEFS_SB(sb)->block_size : len - bytes_read;
144 memcpy(buff + bytes_read, bh->b_data, plen);
145 brelse(bh);
146 bytes_read += plen;
147 }
148
149 befs_debug(sb, "<--- befs_read_lsymlink() read %u bytes", bytes_read);
150 return bytes_read;
151}
152
153
154
155
156
157
158
159
160
161
162
163
164befs_blocknr_t
165befs_count_blocks(struct super_block * sb, befs_data_stream * ds)
166{
167 befs_blocknr_t blocks;
168 befs_blocknr_t datablocks;
169 befs_blocknr_t metablocks;
170 befs_sb_info *befs_sb = BEFS_SB(sb);
171
172 befs_debug(sb, "---> befs_count_blocks()");
173
174 datablocks = ds->size >> befs_sb->block_shift;
175 if (ds->size & (befs_sb->block_size - 1))
176 datablocks += 1;
177
178 metablocks = 1;
179
180
181 if (ds->size > ds->max_direct_range)
182 metablocks += ds->indirect.len;
183
184
185
186
187
188
189
190
191
192
193 if (ds->size > ds->max_indirect_range && ds->max_indirect_range != 0) {
194 uint dbl_bytes;
195 uint dbl_bruns;
196 uint indirblocks;
197
198 dbl_bytes =
199 ds->max_double_indirect_range - ds->max_indirect_range;
200 dbl_bruns =
201 dbl_bytes / (befs_sb->block_size * BEFS_DBLINDIR_BRUN_LEN);
202 indirblocks = dbl_bruns / befs_iaddrs_per_block(sb);
203
204 metablocks += ds->double_indirect.len;
205 metablocks += indirblocks;
206 }
207
208 blocks = datablocks + metablocks;
209 befs_debug(sb, "<--- befs_count_blocks() %u blocks", blocks);
210
211 return blocks;
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
244static int
245befs_find_brun_direct(struct super_block *sb, befs_data_stream * data,
246 befs_blocknr_t blockno, befs_block_run * run)
247{
248 int i;
249 befs_block_run *array = data->direct;
250 befs_blocknr_t sum;
251 befs_blocknr_t max_block =
252 data->max_direct_range >> BEFS_SB(sb)->block_shift;
253
254 befs_debug(sb, "---> befs_find_brun_direct(), find %lu", blockno);
255
256 if (blockno > max_block) {
257 befs_error(sb, "befs_find_brun_direct() passed block outside of"
258 "direct region");
259 return BEFS_ERR;
260 }
261
262 for (i = 0, sum = 0; i < BEFS_NUM_DIRECT_BLOCKS;
263 sum += array[i].len, i++) {
264 if (blockno >= sum && blockno < sum + (array[i].len)) {
265 int offset = blockno - sum;
266 run->allocation_group = array[i].allocation_group;
267 run->start = array[i].start + offset;
268 run->len = array[i].len - offset;
269
270 befs_debug(sb, "---> befs_find_brun_direct(), "
271 "found %lu at direct[%d]", blockno, i);
272 return BEFS_OK;
273 }
274 }
275
276 befs_debug(sb, "---> befs_find_brun_direct() ERROR");
277 return BEFS_ERR;
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
303static int
304befs_find_brun_indirect(struct super_block *sb,
305 befs_data_stream * data, befs_blocknr_t blockno,
306 befs_block_run * run)
307{
308 int i, j;
309 befs_blocknr_t sum = 0;
310 befs_blocknr_t indir_start_blk;
311 befs_blocknr_t search_blk;
312 struct buffer_head *indirblock;
313 befs_disk_block_run *array;
314
315 befs_block_run indirect = data->indirect;
316 befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect);
317 int arraylen = befs_iaddrs_per_block(sb);
318
319 befs_debug(sb, "---> befs_find_brun_indirect(), find %lu", blockno);
320
321 indir_start_blk = data->max_direct_range >> BEFS_SB(sb)->block_shift;
322 search_blk = blockno - indir_start_blk;
323
324
325 for (i = 0; i < indirect.len; i++) {
326 indirblock = befs_bread(sb, indirblockno + i);
327 if (indirblock == NULL) {
328 befs_debug(sb,
329 "---> befs_find_brun_indirect() failed to "
330 "read disk block %lu from the indirect brun",
331 indirblockno + i);
332 return BEFS_ERR;
333 }
334
335 array = (befs_disk_block_run *) indirblock->b_data;
336
337 for (j = 0; j < arraylen; ++j) {
338 int len = fs16_to_cpu(sb, array[j].len);
339
340 if (search_blk >= sum && search_blk < sum + len) {
341 int offset = search_blk - sum;
342 run->allocation_group =
343 fs32_to_cpu(sb, array[j].allocation_group);
344 run->start =
345 fs16_to_cpu(sb, array[j].start) + offset;
346 run->len =
347 fs16_to_cpu(sb, array[j].len) - offset;
348
349 brelse(indirblock);
350 befs_debug(sb,
351 "<--- befs_find_brun_indirect() found "
352 "file block %lu at indirect[%d]",
353 blockno, j + (i * arraylen));
354 return BEFS_OK;
355 }
356 sum += len;
357 }
358
359 brelse(indirblock);
360 }
361
362
363 befs_error(sb, "BeFS: befs_find_brun_indirect() failed to find "
364 "file block %lu", blockno);
365
366 befs_debug(sb, "<--- befs_find_brun_indirect() ERROR");
367 return BEFS_ERR;
368}
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411static int
412befs_find_brun_dblindirect(struct super_block *sb,
413 befs_data_stream * data, befs_blocknr_t blockno,
414 befs_block_run * run)
415{
416 int dblindir_indx;
417 int indir_indx;
418 int offset;
419 int dbl_which_block;
420 int which_block;
421 int dbl_block_indx;
422 int block_indx;
423 off_t dblindir_leftover;
424 befs_blocknr_t blockno_at_run_start;
425 struct buffer_head *dbl_indir_block;
426 struct buffer_head *indir_block;
427 befs_block_run indir_run;
428 befs_disk_inode_addr *iaddr_array = NULL;
429 befs_sb_info *befs_sb = BEFS_SB(sb);
430
431 befs_blocknr_t indir_start_blk =
432 data->max_indirect_range >> befs_sb->block_shift;
433
434 off_t dbl_indir_off = blockno - indir_start_blk;
435
436
437
438
439 size_t iblklen = BEFS_DBLINDIR_BRUN_LEN;
440
441
442
443
444 size_t diblklen = iblklen * befs_iaddrs_per_block(sb)
445 * BEFS_DBLINDIR_BRUN_LEN;
446
447 befs_debug(sb, "---> befs_find_brun_dblindirect() find %lu", blockno);
448
449
450
451
452
453
454
455 dblindir_indx = dbl_indir_off / diblklen;
456 dblindir_leftover = dbl_indir_off % diblklen;
457 indir_indx = dblindir_leftover / diblklen;
458
459
460 dbl_which_block = dblindir_indx / befs_iaddrs_per_block(sb);
461 if (dbl_which_block > data->double_indirect.len) {
462 befs_error(sb, "The double-indirect index calculated by "
463 "befs_read_brun_dblindirect(), %d, is outside the range "
464 "of the double-indirect block", dblindir_indx);
465 return BEFS_ERR;
466 }
467
468 dbl_indir_block =
469 befs_bread(sb, iaddr2blockno(sb, &data->double_indirect) +
470 dbl_which_block);
471 if (dbl_indir_block == NULL) {
472 befs_error(sb, "befs_read_brun_dblindirect() couldn't read the "
473 "double-indirect block at blockno %lu",
474 iaddr2blockno(sb,
475 &data->double_indirect) +
476 dbl_which_block);
477 brelse(dbl_indir_block);
478 return BEFS_ERR;
479 }
480
481 dbl_block_indx =
482 dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb));
483 iaddr_array = (befs_disk_inode_addr *) dbl_indir_block->b_data;
484 indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]);
485 brelse(dbl_indir_block);
486 iaddr_array = NULL;
487
488
489 which_block = indir_indx / befs_iaddrs_per_block(sb);
490 if (which_block > indir_run.len) {
491 befs_error(sb, "The indirect index calculated by "
492 "befs_read_brun_dblindirect(), %d, is outside the range "
493 "of the indirect block", indir_indx);
494 return BEFS_ERR;
495 }
496
497 indir_block =
498 befs_bread(sb, iaddr2blockno(sb, &indir_run) + which_block);
499 if (indir_block == NULL) {
500 befs_error(sb, "befs_read_brun_dblindirect() couldn't read the "
501 "indirect block at blockno %lu",
502 iaddr2blockno(sb, &indir_run) + which_block);
503 brelse(indir_block);
504 return BEFS_ERR;
505 }
506
507 block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb));
508 iaddr_array = (befs_disk_inode_addr *) indir_block->b_data;
509 *run = fsrun_to_cpu(sb, iaddr_array[block_indx]);
510 brelse(indir_block);
511 iaddr_array = NULL;
512
513 blockno_at_run_start = indir_start_blk;
514 blockno_at_run_start += diblklen * dblindir_indx;
515 blockno_at_run_start += iblklen * indir_indx;
516 offset = blockno - blockno_at_run_start;
517
518 run->start += offset;
519 run->len -= offset;
520
521 befs_debug(sb, "Found file block %lu in double_indirect[%d][%d],"
522 " double_indirect_leftover = %lu",
523 blockno, dblindir_indx, indir_indx, dblindir_leftover);
524
525 return BEFS_OK;
526}
527