0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/kernel.h>
0015 #include <linux/buffer_head.h>
0016 #include <linux/string.h>
0017
0018 #include "befs.h"
0019 #include "datastream.h"
0020 #include "io.h"
0021
0022 const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
0023
0024 static int befs_find_brun_direct(struct super_block *sb,
0025 const befs_data_stream *data,
0026 befs_blocknr_t blockno, befs_block_run *run);
0027
0028 static int befs_find_brun_indirect(struct super_block *sb,
0029 const befs_data_stream *data,
0030 befs_blocknr_t blockno,
0031 befs_block_run *run);
0032
0033 static int befs_find_brun_dblindirect(struct super_block *sb,
0034 const befs_data_stream *data,
0035 befs_blocknr_t blockno,
0036 befs_block_run *run);
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 struct buffer_head *
0049 befs_read_datastream(struct super_block *sb, const befs_data_stream *ds,
0050 befs_off_t pos, uint *off)
0051 {
0052 struct buffer_head *bh;
0053 befs_block_run run;
0054 befs_blocknr_t block;
0055
0056 befs_debug(sb, "---> %s %llu", __func__, pos);
0057 block = pos >> BEFS_SB(sb)->block_shift;
0058 if (off)
0059 *off = pos - (block << BEFS_SB(sb)->block_shift);
0060
0061 if (befs_fblock2brun(sb, ds, block, &run) != BEFS_OK) {
0062 befs_error(sb, "BeFS: Error finding disk addr of block %lu",
0063 (unsigned long)block);
0064 befs_debug(sb, "<--- %s ERROR", __func__);
0065 return NULL;
0066 }
0067 bh = befs_bread_iaddr(sb, run);
0068 if (!bh) {
0069 befs_error(sb, "BeFS: Error reading block %lu from datastream",
0070 (unsigned long)block);
0071 return NULL;
0072 }
0073
0074 befs_debug(sb, "<--- %s read data, starting at %llu", __func__, pos);
0075
0076 return bh;
0077 }
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094 int
0095 befs_fblock2brun(struct super_block *sb, const befs_data_stream *data,
0096 befs_blocknr_t fblock, befs_block_run *run)
0097 {
0098 int err;
0099 befs_off_t pos = fblock << BEFS_SB(sb)->block_shift;
0100
0101 if (pos < data->max_direct_range) {
0102 err = befs_find_brun_direct(sb, data, fblock, run);
0103
0104 } else if (pos < data->max_indirect_range) {
0105 err = befs_find_brun_indirect(sb, data, fblock, run);
0106
0107 } else if (pos < data->max_double_indirect_range) {
0108 err = befs_find_brun_dblindirect(sb, data, fblock, run);
0109
0110 } else {
0111 befs_error(sb,
0112 "befs_fblock2brun() was asked to find block %lu, "
0113 "which is not mapped by the datastream\n",
0114 (unsigned long)fblock);
0115 err = BEFS_ERR;
0116 }
0117 return err;
0118 }
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129 size_t
0130 befs_read_lsymlink(struct super_block *sb, const befs_data_stream *ds,
0131 void *buff, befs_off_t len)
0132 {
0133 befs_off_t bytes_read = 0;
0134 u16 plen;
0135 struct buffer_head *bh;
0136
0137 befs_debug(sb, "---> %s length: %llu", __func__, len);
0138
0139 while (bytes_read < len) {
0140 bh = befs_read_datastream(sb, ds, bytes_read, NULL);
0141 if (!bh) {
0142 befs_error(sb, "BeFS: Error reading datastream block "
0143 "starting from %llu", bytes_read);
0144 befs_debug(sb, "<--- %s ERROR", __func__);
0145 return bytes_read;
0146
0147 }
0148 plen = ((bytes_read + BEFS_SB(sb)->block_size) < len) ?
0149 BEFS_SB(sb)->block_size : len - bytes_read;
0150 memcpy(buff + bytes_read, bh->b_data, plen);
0151 brelse(bh);
0152 bytes_read += plen;
0153 }
0154
0155 befs_debug(sb, "<--- %s read %u bytes", __func__, (unsigned int)
0156 bytes_read);
0157 return bytes_read;
0158 }
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171 befs_blocknr_t
0172 befs_count_blocks(struct super_block *sb, const befs_data_stream *ds)
0173 {
0174 befs_blocknr_t blocks;
0175 befs_blocknr_t datablocks;
0176 befs_blocknr_t metablocks;
0177 struct befs_sb_info *befs_sb = BEFS_SB(sb);
0178
0179 befs_debug(sb, "---> %s", __func__);
0180
0181 datablocks = ds->size >> befs_sb->block_shift;
0182 if (ds->size & (befs_sb->block_size - 1))
0183 datablocks += 1;
0184
0185 metablocks = 1;
0186
0187
0188 if (ds->size > ds->max_direct_range)
0189 metablocks += ds->indirect.len;
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200 if (ds->size > ds->max_indirect_range && ds->max_indirect_range != 0) {
0201 uint dbl_bytes;
0202 uint dbl_bruns;
0203 uint indirblocks;
0204
0205 dbl_bytes =
0206 ds->max_double_indirect_range - ds->max_indirect_range;
0207 dbl_bruns =
0208 dbl_bytes / (befs_sb->block_size * BEFS_DBLINDIR_BRUN_LEN);
0209 indirblocks = dbl_bruns / befs_iaddrs_per_block(sb);
0210
0211 metablocks += ds->double_indirect.len;
0212 metablocks += indirblocks;
0213 }
0214
0215 blocks = datablocks + metablocks;
0216 befs_debug(sb, "<--- %s %u blocks", __func__, (unsigned int)blocks);
0217
0218 return blocks;
0219 }
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 static int
0251 befs_find_brun_direct(struct super_block *sb, const befs_data_stream *data,
0252 befs_blocknr_t blockno, befs_block_run *run)
0253 {
0254 int i;
0255 const befs_block_run *array = data->direct;
0256 befs_blocknr_t sum;
0257
0258 befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno);
0259
0260 for (i = 0, sum = 0; i < BEFS_NUM_DIRECT_BLOCKS;
0261 sum += array[i].len, i++) {
0262 if (blockno >= sum && blockno < sum + (array[i].len)) {
0263 int offset = blockno - sum;
0264
0265 run->allocation_group = array[i].allocation_group;
0266 run->start = array[i].start + offset;
0267 run->len = array[i].len - offset;
0268
0269 befs_debug(sb, "---> %s, "
0270 "found %lu at direct[%d]", __func__,
0271 (unsigned long)blockno, i);
0272 return BEFS_OK;
0273 }
0274 }
0275
0276 befs_error(sb, "%s failed to find file block %lu", __func__,
0277 (unsigned long)blockno);
0278 befs_debug(sb, "---> %s ERROR", __func__);
0279 return BEFS_ERR;
0280 }
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304 static int
0305 befs_find_brun_indirect(struct super_block *sb,
0306 const befs_data_stream *data,
0307 befs_blocknr_t blockno,
0308 befs_block_run *run)
0309 {
0310 int i, j;
0311 befs_blocknr_t sum = 0;
0312 befs_blocknr_t indir_start_blk;
0313 befs_blocknr_t search_blk;
0314 struct buffer_head *indirblock;
0315 befs_disk_block_run *array;
0316
0317 befs_block_run indirect = data->indirect;
0318 befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect);
0319 int arraylen = befs_iaddrs_per_block(sb);
0320
0321 befs_debug(sb, "---> %s, find %lu", __func__, (unsigned long)blockno);
0322
0323 indir_start_blk = data->max_direct_range >> BEFS_SB(sb)->block_shift;
0324 search_blk = blockno - indir_start_blk;
0325
0326
0327 for (i = 0; i < indirect.len; i++) {
0328 indirblock = sb_bread(sb, indirblockno + i);
0329 if (indirblock == NULL) {
0330 befs_error(sb, "---> %s failed to read "
0331 "disk block %lu from the indirect brun",
0332 __func__, (unsigned long)indirblockno + i);
0333 befs_debug(sb, "<--- %s ERROR", __func__);
0334 return BEFS_ERR;
0335 }
0336
0337 array = (befs_disk_block_run *) indirblock->b_data;
0338
0339 for (j = 0; j < arraylen; ++j) {
0340 int len = fs16_to_cpu(sb, array[j].len);
0341
0342 if (search_blk >= sum && search_blk < sum + len) {
0343 int offset = search_blk - sum;
0344 run->allocation_group =
0345 fs32_to_cpu(sb, array[j].allocation_group);
0346 run->start =
0347 fs16_to_cpu(sb, array[j].start) + offset;
0348 run->len =
0349 fs16_to_cpu(sb, array[j].len) - offset;
0350
0351 brelse(indirblock);
0352 befs_debug(sb,
0353 "<--- %s found file block "
0354 "%lu at indirect[%d]", __func__,
0355 (unsigned long)blockno,
0356 j + (i * arraylen));
0357 return BEFS_OK;
0358 }
0359 sum += len;
0360 }
0361
0362 brelse(indirblock);
0363 }
0364
0365
0366 befs_error(sb, "BeFS: %s failed to find "
0367 "file block %lu", __func__, (unsigned long)blockno);
0368
0369 befs_debug(sb, "<--- %s ERROR", __func__);
0370 return BEFS_ERR;
0371 }
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413 static int
0414 befs_find_brun_dblindirect(struct super_block *sb,
0415 const befs_data_stream *data,
0416 befs_blocknr_t blockno,
0417 befs_block_run *run)
0418 {
0419 int dblindir_indx;
0420 int indir_indx;
0421 int offset;
0422 int dbl_which_block;
0423 int which_block;
0424 int dbl_block_indx;
0425 int block_indx;
0426 off_t dblindir_leftover;
0427 befs_blocknr_t blockno_at_run_start;
0428 struct buffer_head *dbl_indir_block;
0429 struct buffer_head *indir_block;
0430 befs_block_run indir_run;
0431 befs_disk_inode_addr *iaddr_array;
0432
0433 befs_blocknr_t indir_start_blk =
0434 data->max_indirect_range >> BEFS_SB(sb)->block_shift;
0435
0436 off_t dbl_indir_off = blockno - indir_start_blk;
0437
0438
0439
0440
0441 size_t iblklen = BEFS_DBLINDIR_BRUN_LEN;
0442
0443
0444
0445
0446 size_t diblklen = iblklen * befs_iaddrs_per_block(sb)
0447 * BEFS_DBLINDIR_BRUN_LEN;
0448
0449 befs_debug(sb, "---> %s find %lu", __func__, (unsigned long)blockno);
0450
0451
0452
0453
0454
0455
0456
0457 dblindir_indx = dbl_indir_off / diblklen;
0458 dblindir_leftover = dbl_indir_off % diblklen;
0459 indir_indx = dblindir_leftover / diblklen;
0460
0461
0462 dbl_which_block = dblindir_indx / befs_iaddrs_per_block(sb);
0463 if (dbl_which_block > data->double_indirect.len) {
0464 befs_error(sb, "The double-indirect index calculated by "
0465 "%s, %d, is outside the range "
0466 "of the double-indirect block", __func__,
0467 dblindir_indx);
0468 return BEFS_ERR;
0469 }
0470
0471 dbl_indir_block =
0472 sb_bread(sb, iaddr2blockno(sb, &data->double_indirect) +
0473 dbl_which_block);
0474 if (dbl_indir_block == NULL) {
0475 befs_error(sb, "%s couldn't read the "
0476 "double-indirect block at blockno %lu", __func__,
0477 (unsigned long)
0478 iaddr2blockno(sb, &data->double_indirect) +
0479 dbl_which_block);
0480 return BEFS_ERR;
0481 }
0482
0483 dbl_block_indx =
0484 dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb));
0485 iaddr_array = (befs_disk_inode_addr *) dbl_indir_block->b_data;
0486 indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]);
0487 brelse(dbl_indir_block);
0488
0489
0490 which_block = indir_indx / befs_iaddrs_per_block(sb);
0491 if (which_block > indir_run.len) {
0492 befs_error(sb, "The indirect index calculated by "
0493 "%s, %d, is outside the range "
0494 "of the indirect block", __func__, indir_indx);
0495 return BEFS_ERR;
0496 }
0497
0498 indir_block =
0499 sb_bread(sb, iaddr2blockno(sb, &indir_run) + which_block);
0500 if (indir_block == NULL) {
0501 befs_error(sb, "%s couldn't read the indirect block "
0502 "at blockno %lu", __func__, (unsigned long)
0503 iaddr2blockno(sb, &indir_run) + which_block);
0504 return BEFS_ERR;
0505 }
0506
0507 block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb));
0508 iaddr_array = (befs_disk_inode_addr *) indir_block->b_data;
0509 *run = fsrun_to_cpu(sb, iaddr_array[block_indx]);
0510 brelse(indir_block);
0511
0512 blockno_at_run_start = indir_start_blk;
0513 blockno_at_run_start += diblklen * dblindir_indx;
0514 blockno_at_run_start += iblklen * indir_indx;
0515 offset = blockno - blockno_at_run_start;
0516
0517 run->start += offset;
0518 run->len -= offset;
0519
0520 befs_debug(sb, "Found file block %lu in double_indirect[%d][%d],"
0521 " double_indirect_leftover = %lu", (unsigned long)
0522 blockno, dblindir_indx, indir_indx, dblindir_leftover);
0523
0524 return BEFS_OK;
0525 }