| 332 | } |
| 333 | |
| 334 | Bytes getFile(const Path& path) override |
| 335 | { |
| 336 | mount(); |
| 337 | if (path.size() != 1) |
| 338 | throw BadPathException(); |
| 339 | |
| 340 | Bytes data; |
| 341 | ByteWriter bw(data); |
| 342 | int logicalExtent = 0; |
| 343 | for (;;) |
| 344 | { |
| 345 | /* Find a directory entry for this logical extent. */ |
| 346 | |
| 347 | std::unique_ptr<Entry> entry; |
| 348 | for (int d = 0; d < _config.dir_entries(); d++) |
| 349 | { |
| 350 | entry = getEntry(d); |
| 351 | if (entry->deleted) |
| 352 | continue; |
| 353 | if (path[0] != entry->combinedFilename()) |
| 354 | continue; |
| 355 | if (entry->extent < logicalExtent) |
| 356 | continue; |
| 357 | if ((entry->extent & ~_logicalExtentMask) == |
| 358 | (logicalExtent & ~_logicalExtentMask)) |
| 359 | break; |
| 360 | } |
| 361 | |
| 362 | if (entry->deleted) |
| 363 | { |
| 364 | if (logicalExtent == 0) |
| 365 | throw FileNotFoundException(); |
| 366 | break; |
| 367 | } |
| 368 | |
| 369 | /* Copy the data out. */ |
| 370 | |
| 371 | int i = |
| 372 | (logicalExtent & _logicalExtentMask) * _blocksPerLogicalExtent; |
| 373 | unsigned records = |
| 374 | (entry->extent == logicalExtent) ? entry->records : 128; |
| 375 | while (records != 0) |
| 376 | { |
| 377 | Bytes block; |
| 378 | unsigned blockid = entry->allocation_map[i]; |
| 379 | if (blockid != 0) |
| 380 | block = getCpmBlock(entry->allocation_map[i]); |
| 381 | else |
| 382 | block.resize(_config.block_size()); |
| 383 | |
| 384 | unsigned r = std::min(records, _recordsPerBlock); |
| 385 | bw += block.slice(0, r * 128); |
| 386 | |
| 387 | records -= r; |
| 388 | i++; |
| 389 | } |
| 390 | |
| 391 | logicalExtent++; |
nothing calls this directly
no test coverage detected