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, "---> %s %llu", __func__, 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 (unsigned long)block);
63 befs_debug(sb, "<--- %s ERROR", __func__);
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 (unsigned long)block);
70 return NULL;
71 }
72
73 befs_debug(sb, "<--- %s read data, starting at %llu", __func__, pos);
74
75 return bh;
76}
77
78
79
80
81
82
83
84
85
86
87
88
89int
90befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
91 befs_blocknr_t fblock, befs_block_run * run)
92{
93 int err;
94 befs_off_t pos = fblock << BEFS_SB(sb)->block_shift;
95
96 if (pos < data->max_direct_range) {
97 err = befs_find_brun_direct(sb, data, fblock, run);
98
99 } else if (pos < data->max_indirect_range) {
100 err = befs_find_brun_indirect(sb, data, fblock, run);
101
102 } else if (pos < data->max_double_indirect_range) {
103 err = befs_find_brun_dblindirect(sb, data, fblock, run);
104
105 } else {
106 befs_error(sb,
107 "befs_fblock2brun() was asked to find block %lu, "
108 "which is not mapped by the datastream\n",
109 (unsigned long)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, "---> %s length: %llu", __func__, 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 %llu", bytes_read);
138 befs_debug(sb, "<--- %s ERROR", __func__);
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, "<--- %s read %u bytes", __func__, (unsigned int)
150 bytes_read);
151 return bytes_read;
152}
153
154
155
156
157
158
159
160
161
162
163
164
165befs_blocknr_t
166befs_count_blocks(struct super_block * sb, befs_data_stream * ds)
167{
168 befs_blocknr_t blocks;
169 befs_blocknr_t datablocks;
170 befs_blocknr_t metablocks;
171 befs_sb_info *befs_sb = BEFS_SB(sb);
172
173 befs_debug(sb, "---> %s", __func__);
174
175 datablocks = ds->size >> befs_sb->block_shift;
176 if (ds->size & (befs_sb->block_size - 1))
177 datablocks += 1;
178
179 metablocks = 1;
180
181
182 if (ds->size > ds->max_direct_range)
183 metablocks += ds->indirect.len;
184
185
186
187
188
189
190
191
192
193
194 if (ds->size > ds->max_indirect_range && ds->max_indirect_range != 0) {
195 uint dbl_bytes;
196 uint dbl_bruns;
197 uint indirblocks;
198
199 dbl_bytes =
200 ds->max_double_indirect_range - ds->max_indirect_range;
201 dbl_bruns =
202 dbl_bytes / (befs_sb->block_size * BEFS_DBLINDIR_BRUN_LEN);
203 indirblocks = dbl_bruns / befs_iaddrs_per_block(sb);
204
205 metablocks += ds->double_indirect.len;
206 metablocks += indirblocks;
207 }
208
209 blocks = datablocks + metablocks;
210 befs_debug(sb, "<--- %s %u blocks", __func__, (unsigned int)blocks);
211
212 return blocks;
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
245static int
246befs_find_brun_direct(struct super_block *sb, befs_data_stream * data,
247 befs_blocknr_t blockno, befs_block_run * run)
248{
249 int i;
250 befs_block_run *array = data->direct;
251 befs_blocknr_t sum;
252 befs_blocknr_t max_block =
253 data->max_direct_range >> BEFS_SB(sb)->block_shift;
254
255 befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno);
256
257 if (blockno > max_block) {
258 befs_error(sb, "%s passed block outside of direct region",
259 __func__);
260 return BEFS_ERR;
261 }
262
263 for (i = 0, sum = 0; i < BEFS_NUM_DIRECT_BLOCKS;
264 sum += array[i].len, i++) {
265 if (blockno >= sum && blockno < sum + (array[i].len)) {
266 int offset = blockno - sum;
267 run->allocation_group = array[i].allocation_group;
268 run->start = array[i].start + offset;
269 run->len = array[i].len - offset;
270
271 befs_debug(sb, "---> %s, "
272 "found %lu at direct[%d]", __func__,
273 (unsigned long)blockno, i);
274 return BEFS_OK;
275 }
276 }
277
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
304
305static int
306befs_find_brun_indirect(struct super_block *sb,
307 befs_data_stream * data, 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 = befs_bread(sb, indirblockno + i);
329 if (indirblock == NULL) {
330 befs_debug(sb, "---> %s failed to read "
331 "disk block %lu from the indirect brun",
332 __func__, (unsigned long)indirblockno + i);
333 return BEFS_ERR;
334 }
335
336 array = (befs_disk_block_run *) indirblock->b_data;
337
338 for (j = 0; j < arraylen; ++j) {
339 int len = fs16_to_cpu(sb, array[j].len);
340
341 if (search_blk >= sum && search_blk < sum + len) {
342 int offset = search_blk - sum;
343 run->allocation_group =
344 fs32_to_cpu(sb, array[j].allocation_group);
345 run->start =
346 fs16_to_cpu(sb, array[j].start) + offset;
347 run->len =
348 fs16_to_cpu(sb, array[j].len) - offset;
349
350 brelse(indirblock);
351 befs_debug(sb,
352 "<--- %s found file block "
353 "%lu at indirect[%d]", __func__,
354 (unsigned long)blockno,
355 j + (i * arraylen));
356 return BEFS_OK;
357 }
358 sum += len;
359 }
360
361 brelse(indirblock);
362 }
363
364
365 befs_error(sb, "BeFS: %s failed to find "
366 "file block %lu", __func__, (unsigned long)blockno);
367
368 befs_debug(sb, "<--- %s ERROR", __func__);
369 return BEFS_ERR;
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
411
412
413static int
414befs_find_brun_dblindirect(struct super_block *sb,
415 befs_data_stream * data, befs_blocknr_t blockno,
416 befs_block_run * run)
417{
418 int dblindir_indx;
419 int indir_indx;
420 int offset;
421 int dbl_which_block;
422 int which_block;
423 int dbl_block_indx;
424 int block_indx;
425 off_t dblindir_leftover;
426 befs_blocknr_t blockno_at_run_start;
427 struct buffer_head *dbl_indir_block;
428 struct buffer_head *indir_block;
429 befs_block_run indir_run;
430 befs_disk_inode_addr *iaddr_array = NULL;
431 befs_sb_info *befs_sb = BEFS_SB(sb);
432
433 befs_blocknr_t indir_start_blk =
434 data->max_indirect_range >> befs_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 befs_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 brelse(dbl_indir_block);
481 return BEFS_ERR;
482 }
483
484 dbl_block_indx =
485 dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb));
486 iaddr_array = (befs_disk_inode_addr *) dbl_indir_block->b_data;
487 indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]);
488 brelse(dbl_indir_block);
489 iaddr_array = NULL;
490
491
492 which_block = indir_indx / befs_iaddrs_per_block(sb);
493 if (which_block > indir_run.len) {
494 befs_error(sb, "The indirect index calculated by "
495 "%s, %d, is outside the range "
496 "of the indirect block", __func__, indir_indx);
497 return BEFS_ERR;
498 }
499
500 indir_block =
501 befs_bread(sb, iaddr2blockno(sb, &indir_run) + which_block);
502 if (indir_block == NULL) {
503 befs_error(sb, "%s couldn't read the indirect block "
504 "at blockno %lu", __func__, (unsigned long)
505 iaddr2blockno(sb, &indir_run) + which_block);
506 brelse(indir_block);
507 return BEFS_ERR;
508 }
509
510 block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb));
511 iaddr_array = (befs_disk_inode_addr *) indir_block->b_data;
512 *run = fsrun_to_cpu(sb, iaddr_array[block_indx]);
513 brelse(indir_block);
514 iaddr_array = NULL;
515
516 blockno_at_run_start = indir_start_blk;
517 blockno_at_run_start += diblklen * dblindir_indx;
518 blockno_at_run_start += iblklen * indir_indx;
519 offset = blockno - blockno_at_run_start;
520
521 run->start += offset;
522 run->len -= offset;
523
524 befs_debug(sb, "Found file block %lu in double_indirect[%d][%d],"
525 " double_indirect_leftover = %lu", (unsigned long)
526 blockno, dblindir_indx, indir_indx, dblindir_leftover);
527
528 return BEFS_OK;
529}
530