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 const 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 const 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 const 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, const befs_data_stream *ds,
49 befs_off_t pos, uint *off)
50{
51 struct buffer_head *bh;
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
89
90
91
92
93int
94befs_fblock2brun(struct super_block *sb, const befs_data_stream *data,
95 befs_blocknr_t fblock, befs_block_run *run)
96{
97 int err;
98 befs_off_t pos = fblock << BEFS_SB(sb)->block_shift;
99
100 if (pos < data->max_direct_range) {
101 err = befs_find_brun_direct(sb, data, fblock, run);
102
103 } else if (pos < data->max_indirect_range) {
104 err = befs_find_brun_indirect(sb, data, fblock, run);
105
106 } else if (pos < data->max_double_indirect_range) {
107 err = befs_find_brun_dblindirect(sb, data, fblock, run);
108
109 } else {
110 befs_error(sb,
111 "befs_fblock2brun() was asked to find block %lu, "
112 "which is not mapped by the datastream\n",
113 (unsigned long)fblock);
114 err = BEFS_ERR;
115 }
116 return err;
117}
118
119
120
121
122
123
124
125
126
127
128size_t
129befs_read_lsymlink(struct super_block *sb, const befs_data_stream *ds,
130 void *buff, befs_off_t len)
131{
132 befs_off_t bytes_read = 0;
133 u16 plen;
134 struct buffer_head *bh;
135
136 befs_debug(sb, "---> %s length: %llu", __func__, len);
137
138 while (bytes_read < len) {
139 bh = befs_read_datastream(sb, ds, bytes_read, NULL);
140 if (!bh) {
141 befs_error(sb, "BeFS: Error reading datastream block "
142 "starting from %llu", bytes_read);
143 befs_debug(sb, "<--- %s ERROR", __func__);
144 return bytes_read;
145
146 }
147 plen = ((bytes_read + BEFS_SB(sb)->block_size) < len) ?
148 BEFS_SB(sb)->block_size : len - bytes_read;
149 memcpy(buff + bytes_read, bh->b_data, plen);
150 brelse(bh);
151 bytes_read += plen;
152 }
153
154 befs_debug(sb, "<--- %s read %u bytes", __func__, (unsigned int)
155 bytes_read);
156 return bytes_read;
157}
158
159
160
161
162
163
164
165
166
167
168
169
170befs_blocknr_t
171befs_count_blocks(struct super_block *sb, const befs_data_stream *ds)
172{
173 befs_blocknr_t blocks;
174 befs_blocknr_t datablocks;
175 befs_blocknr_t metablocks;
176 struct befs_sb_info *befs_sb = BEFS_SB(sb);
177
178 befs_debug(sb, "---> %s", __func__);
179
180 datablocks = ds->size >> befs_sb->block_shift;
181 if (ds->size & (befs_sb->block_size - 1))
182 datablocks += 1;
183
184 metablocks = 1;
185
186
187 if (ds->size > ds->max_direct_range)
188 metablocks += ds->indirect.len;
189
190
191
192
193
194
195
196
197
198
199 if (ds->size > ds->max_indirect_range && ds->max_indirect_range != 0) {
200 uint dbl_bytes;
201 uint dbl_bruns;
202 uint indirblocks;
203
204 dbl_bytes =
205 ds->max_double_indirect_range - ds->max_indirect_range;
206 dbl_bruns =
207 dbl_bytes / (befs_sb->block_size * BEFS_DBLINDIR_BRUN_LEN);
208 indirblocks = dbl_bruns / befs_iaddrs_per_block(sb);
209
210 metablocks += ds->double_indirect.len;
211 metablocks += indirblocks;
212 }
213
214 blocks = datablocks + metablocks;
215 befs_debug(sb, "<--- %s %u blocks", __func__, (unsigned int)blocks);
216
217 return blocks;
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
249static int
250befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data,
251 befs_blocknr_t blockno, befs_block_run *run)
252{
253 int i;
254 const befs_block_run *array = data->direct;
255 befs_blocknr_t sum;
256
257 befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno);
258
259 for (i = 0, sum = 0; i < BEFS_NUM_DIRECT_BLOCKS;
260 sum += array[i].len, i++) {
261 if (blockno >= sum && blockno < sum + (array[i].len)) {
262 int offset = blockno - sum;
263
264 run->allocation_group = array[i].allocation_group;
265 run->start = array[i].start + offset;
266 run->len = array[i].len - offset;
267
268 befs_debug(sb, "---> %s, "
269 "found %lu at direct[%d]", __func__,
270 (unsigned long)blockno, i);
271 return BEFS_OK;
272 }
273 }
274
275 befs_error(sb, "%s failed to find file block %lu", __func__,
276 (unsigned long)blockno);
277 befs_debug(sb, "---> %s ERROR", __func__);
278 return BEFS_ERR;
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 const befs_data_stream *data,
306 befs_blocknr_t blockno,
307 befs_block_run *run)
308{
309 int i, j;
310 befs_blocknr_t sum = 0;
311 befs_blocknr_t indir_start_blk;
312 befs_blocknr_t search_blk;
313 struct buffer_head *indirblock;
314 befs_disk_block_run *array;
315
316 befs_block_run indirect = data->indirect;
317 befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect);
318 int arraylen = befs_iaddrs_per_block(sb);
319
320 befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno);
321
322 indir_start_blk = data->max_direct_range >> BEFS_SB(sb)->block_shift;
323 search_blk = blockno - indir_start_blk;
324
325
326 for (i = 0; i < indirect.len; i++) {
327 indirblock = sb_bread(sb, indirblockno + i);
328 if (indirblock == NULL) {
329 befs_error(sb, "---> %s failed to read "
330 "disk block %lu from the indirect brun",
331 __func__, (unsigned long)indirblockno + i);
332 befs_debug(sb, "<--- %s ERROR", __func__);
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
412static int
413befs_find_brun_dblindirect(struct super_block *sb,
414 const befs_data_stream *data,
415 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;
431
432 befs_blocknr_t indir_start_blk =
433 data->max_indirect_range >> BEFS_SB(sb)->block_shift;
434
435 off_t dbl_indir_off = blockno - indir_start_blk;
436
437
438
439
440 size_t iblklen = BEFS_DBLINDIR_BRUN_LEN;
441
442
443
444
445 size_t diblklen = iblklen * befs_iaddrs_per_block(sb)
446 * BEFS_DBLINDIR_BRUN_LEN;
447
448 befs_debug(sb, "---> %s find %lu", __func__, (unsigned long)blockno);
449
450
451
452
453
454
455
456 dblindir_indx = dbl_indir_off / diblklen;
457 dblindir_leftover = dbl_indir_off % diblklen;
458 indir_indx = dblindir_leftover / diblklen;
459
460
461 dbl_which_block = dblindir_indx / befs_iaddrs_per_block(sb);
462 if (dbl_which_block > data->double_indirect.len) {
463 befs_error(sb, "The double-indirect index calculated by "
464 "%s, %d, is outside the range "
465 "of the double-indirect block", __func__,
466 dblindir_indx);
467 return BEFS_ERR;
468 }
469
470 dbl_indir_block =
471 sb_bread(sb, iaddr2blockno(sb, &data->double_indirect) +
472 dbl_which_block);
473 if (dbl_indir_block == NULL) {
474 befs_error(sb, "%s couldn't read the "
475 "double-indirect block at blockno %lu", __func__,
476 (unsigned long)
477 iaddr2blockno(sb, &data->double_indirect) +
478 dbl_which_block);
479 return BEFS_ERR;
480 }
481
482 dbl_block_indx =
483 dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb));
484 iaddr_array = (befs_disk_inode_addr *) dbl_indir_block->b_data;
485 indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]);
486 brelse(dbl_indir_block);
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 "%s, %d, is outside the range "
493 "of the indirect block", __func__, indir_indx);
494 return BEFS_ERR;
495 }
496
497 indir_block =
498 sb_bread(sb, iaddr2blockno(sb, &indir_run) + which_block);
499 if (indir_block == NULL) {
500 befs_error(sb, "%s couldn't read the indirect block "
501 "at blockno %lu", __func__, (unsigned long)
502 iaddr2blockno(sb, &indir_run) + which_block);
503 return BEFS_ERR;
504 }
505
506 block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb));
507 iaddr_array = (befs_disk_inode_addr *) indir_block->b_data;
508 *run = fsrun_to_cpu(sb, iaddr_array[block_indx]);
509 brelse(indir_block);
510
511 blockno_at_run_start = indir_start_blk;
512 blockno_at_run_start += diblklen * dblindir_indx;
513 blockno_at_run_start += iblklen * indir_indx;
514 offset = blockno - blockno_at_run_start;
515
516 run->start += offset;
517 run->len -= offset;
518
519 befs_debug(sb, "Found file block %lu in double_indirect[%d][%d],"
520 " double_indirect_leftover = %lu", (unsigned long)
521 blockno, dblindir_indx, indir_indx, dblindir_leftover);
522
523 return BEFS_OK;
524}
525