/* * Copyright 2001-2008, pinc Software. All Rights Reserved. * Released under the terms of the MIT license. */ //! handles the BFS block bitmap #include "Bitmap.h" #include "Disk.h" #include "Inode.h" #include #include #include Bitmap::Bitmap(Disk *disk) : fBitmap(NULL), fBackupBitmap(NULL) { SetTo(disk); } Bitmap::Bitmap() : fDisk(NULL), fBitmap(NULL), fBackupBitmap(NULL), fSize(0L), fByteSize(0L), fUsedBlocks(0LL) { } Bitmap::~Bitmap() { free(fBitmap); free(fBackupBitmap); } status_t Bitmap::SetTo(Disk *disk) { free(fBitmap); fDisk = disk; fSize = divide_roundup(disk->NumBlocks(),disk->BlockSize() * 8); fByteSize = disk->BlockSize() * disk->SuperBlock()->num_ags * disk->SuperBlock()->blocks_per_ag; fBitmap = (uint32 *)malloc(fByteSize); if (!fBitmap) return B_NO_MEMORY; fBackupBitmap = (uint32 *)malloc(fByteSize); if (fBackupBitmap == NULL) return B_NO_MEMORY; memset(fBackupBitmap, 0, fByteSize); // set root block, block bitmap, log as used off_t end = disk->ToBlock(disk->Log()) + disk->Log().length; for (off_t block = 0; block < end; block++) { if (!BackupSetAt(block, true)) break; } ssize_t size; if ((size = disk->ReadAt(disk->BlockSize(), fBitmap, fByteSize)) < B_OK) { free(fBitmap); fBitmap = NULL; free(fBackupBitmap); fBackupBitmap = NULL; return size; } // calculate used blocks fUsedBlocks = 0LL; for (uint32 i = fByteSize >> 2;i-- > 0;) { uint32 compare = 1; for (int16 j = 0;j < 32;j++,compare <<= 1) { if (compare & fBitmap[i]) fUsedBlocks++; } } return B_OK; } status_t Bitmap::InitCheck() { return fBitmap ? B_OK : B_ERROR; } off_t Bitmap::FreeBlocks() const { if (fDisk == NULL) return 0; return fDisk->NumBlocks() - fUsedBlocks; } bool Bitmap::UsedAt(off_t block) const { uint32 index = block / 32; // 32bit resolution, (beginning with block 1?) if (index > fByteSize / 4) return false; return fBitmap[index] & (1L << (block & 0x1f)); } bool Bitmap::BackupUsedAt(off_t block) const { uint32 index = block / 32; // 32bit resolution, (beginning with block 1?) if (index > fByteSize / 4) return false; return fBackupBitmap[index] & (1L << (block & 0x1f)); } bool Bitmap::BackupSetAt(off_t block, bool used) { uint32 index = block / 32; if (index > fByteSize / 4) { fprintf(stderr, "Bitmap::BackupSetAt(): Block %" B_PRIdOFF " outside " "bitmap!\n", block); return false; } int32 mask = 1L << (block & 0x1f); bool oldUsed = fBackupBitmap[index] & mask; if (used) fBackupBitmap[index] |= mask; else fBackupBitmap[index] &= ~mask; return oldUsed; } void Bitmap::BackupSet(Inode *inode, bool used) { // set inode and its data-stream // the attributes are ignored for now, because they will // be added anyway since all inodes from disk are collected. // printf("a: %lld\n",inode->Block()); BackupSetAt(inode->Block(),used); // the data stream of symlinks is no real data stream if (inode->IsSymlink() && (inode->Flags() & INODE_LONG_SYMLINK) == 0) return; // direct blocks const bfs_inode *node = inode->InodeBuffer(); for (int32 i = 0; i < NUM_DIRECT_BLOCKS; i++) { if (node->data.direct[i].IsZero()) break; off_t start = fDisk->ToBlock(node->data.direct[i]); off_t end = start + node->data.direct[i].length; for (off_t block = start; block < end; block++) { if (!BackupSetAt(block, used)) { //dump_inode(node); break; } } } // indirect blocks if (node->data.max_indirect_range == 0 || node->data.indirect.IsZero()) return; // printf("c: %lld\n",fDisk->ToBlock(node->data.indirect)); BackupSetAt(fDisk->ToBlock(node->data.indirect), used); DataStream *stream = dynamic_cast(inode); if (stream == NULL) return; // load indirect blocks int32 bytes = node->data.indirect.length << fDisk->BlockShift(); block_run *indirect = (block_run *)malloc(bytes); if (indirect == NULL) return; if (fDisk->ReadAt(fDisk->ToOffset(node->data.indirect), indirect, bytes) <= 0) return; int32 runs = bytes / sizeof(block_run); for (int32 i = 0; i < runs; i++) { if (indirect[i].IsZero()) break; off_t start = fDisk->ToBlock(indirect[i]); off_t end = start + indirect[i].length; for (off_t block = start; block < end; block++) { // printf("d: %lld\n", block); if (!BackupSetAt(block, used)) break; } } free(indirect); // double indirect blocks if (node->data.max_double_indirect_range == 0 || node->data.double_indirect.IsZero()) return; // printf("e: %lld\n",fDisk->ToBlock(node->data.double_indirect)); BackupSetAt(fDisk->ToBlock(node->data.double_indirect), used); // FIXME: to be implemented... puts("double indirect blocks to block bitmap requested..."); } status_t Bitmap::Validate() { return B_OK; } status_t Bitmap::CompareWithBackup() { for (int32 i = fByteSize / 4;i-- > 0;) { if (fBitmap[i] != fBackupBitmap[i]) { printf("differ at %" B_PRId32 " (block %" B_PRId32 ") -> bitmap = " "%08" B_PRIx32 ", backup = %08" B_PRIx32 "\n", i, i * 32, fBitmap[i], fBackupBitmap[i]); } } return B_OK; } bool Bitmap::TrustBlockContaining(off_t /*block*/) const { return true; }