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