void AudioRenderer::ResetBlockCount() { if (provider) { const size_t total_blocks = NumBlocks(provider->GetNumSamples()); for (auto& bmp : bitmaps) bmp.SetBlockCount(total_blocks); } }
bool disk_super_block::IsValid() const { if (Magic1() != (int32)SUPER_BLOCK_MAGIC1 || Magic2() != (int32)SUPER_BLOCK_MAGIC2 || Magic3() != (int32)SUPER_BLOCK_MAGIC3 || (int32)block_size != inode_size || ByteOrder() != SUPER_BLOCK_FS_LENDIAN || (1UL << BlockShift()) != BlockSize() || AllocationGroups() < 1 || AllocationGroupShift() < 1 || BlocksPerAllocationGroup() < 1 || NumBlocks() < 10 || AllocationGroups() != divide_roundup(NumBlocks(), 1L << AllocationGroupShift())) return false; return true; }
void AudioRenderer::Render(wxDC &dc, wxPoint origin, const int start, const int length, const AudioRenderingStyle style) { assert(start >= 0); if (!provider) return; if (!renderer) return; if (length <= 0) return; // One past last absolute pixel strip to render const int end = start + length; // One past last X coordinate to render on const int lastx = origin.x + length; // Figure out which range of bitmaps are required const int firstbitmap = start / cache_bitmap_width; // And the offset in it to start its use at const int firstbitmapoffset = start % cache_bitmap_width; // The last bitmap required const int lastbitmap = std::min<int>(end / cache_bitmap_width, NumBlocks(provider->GetDecodedSamples()) - 1); // Set a clipping region so that the first and last bitmaps don't draw // outside the requested range const wxDCClipper clipper(dc, wxRect(origin, wxSize(length, pixel_height))); origin.x -= firstbitmapoffset; for (int i = firstbitmap; i <= lastbitmap; ++i) { dc.DrawBitmap(GetCachedBitmap(i, style), origin); origin.x += cache_bitmap_width; } // Now render blank audio from origin to end if (origin.x < lastx) renderer->RenderBlank(dc, wxRect(origin.x-1, origin.y, lastx-origin.x+1, pixel_height), style); if (needs_age) { bitmaps[style].Age(cache_bitmap_maxsize); renderer->AgeCache(cache_renderer_maxsize); needs_age = false; } }
status_t Volume::Mount(const char* deviceName, uint32 flags) { // flags |= B_MOUNT_READ_ONLY; // we only support read-only for now if ((flags & B_MOUNT_READ_ONLY) != 0) { TRACE("Volume::Mount(): Read only\n"); } else { TRACE("Volume::Mount(): Read write\n"); } DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0 ? O_RDONLY : O_RDWR); fDevice = opener.Device(); if (fDevice < B_OK) { FATAL("Volume::Mount(): couldn't open device\n"); return fDevice; } if (opener.IsReadOnly()) fFlags |= VOLUME_READ_ONLY; TRACE("features %lx, incompatible features %lx, read-only features %lx\n", fSuperBlock.CompatibleFeatures(), fSuperBlock.IncompatibleFeatures(), fSuperBlock.ReadOnlyFeatures()); // read the super block status_t status = Identify(fDevice, &fSuperBlock); if (status != B_OK) { FATAL("Volume::Mount(): Identify() failed\n"); return status; } // check read-only features if mounting read-write if (!IsReadOnly() && _UnsupportedReadOnlyFeatures(fSuperBlock) != 0) return B_UNSUPPORTED; // initialize short hands to the super block (to save byte swapping) fBlockShift = fSuperBlock.BlockShift(); if (fBlockShift < 10 || fBlockShift > 16) return B_ERROR; fBlockSize = 1UL << fBlockShift; fFirstDataBlock = fSuperBlock.FirstDataBlock(); fFreeBlocks = fSuperBlock.FreeBlocks(Has64bitFeature()); fFreeInodes = fSuperBlock.FreeInodes(); off_t numBlocks = fSuperBlock.NumBlocks(Has64bitFeature()) - fFirstDataBlock; uint32 blocksPerGroup = fSuperBlock.BlocksPerGroup(); fNumGroups = numBlocks / blocksPerGroup; if (numBlocks % blocksPerGroup != 0) fNumGroups++; if (Has64bitFeature()) { fGroupDescriptorSize = fSuperBlock.GroupDescriptorSize(); if (fGroupDescriptorSize < sizeof(ext2_block_group)) return B_ERROR; } else fGroupDescriptorSize = EXT2_BLOCK_GROUP_NORMAL_SIZE; fGroupsPerBlock = fBlockSize / fGroupDescriptorSize; fNumInodes = fSuperBlock.NumInodes(); TRACE("block size %ld, num groups %ld, groups per block %ld, first %lu\n", fBlockSize, fNumGroups, fGroupsPerBlock, fFirstDataBlock); uint32 blockCount = (fNumGroups + fGroupsPerBlock - 1) / fGroupsPerBlock; fGroupBlocks = (uint8**)malloc(blockCount * sizeof(uint8*)); if (fGroupBlocks == NULL) return B_NO_MEMORY; memset(fGroupBlocks, 0, blockCount * sizeof(uint8*)); fInodesPerBlock = fBlockSize / InodeSize(); // check if the device size is large enough to hold the file system off_t diskSize; status = opener.GetSize(&diskSize); if (status != B_OK) return status; if (diskSize < ((off_t)NumBlocks() << BlockShift())) return B_BAD_VALUE; fBlockCache = opener.InitCache(NumBlocks(), fBlockSize); if (fBlockCache == NULL) return B_ERROR; TRACE("Volume::Mount(): Initialized block cache: %p\n", fBlockCache); // initialize journal if mounted read-write if (!IsReadOnly() && (fSuperBlock.CompatibleFeatures() & EXT2_FEATURE_HAS_JOURNAL) != 0) { // TODO: There should be a mount option to ignore the existent journal if (fSuperBlock.JournalInode() != 0) { fJournalInode = new(std::nothrow) Inode(this, fSuperBlock.JournalInode()); if (fJournalInode == NULL) return B_NO_MEMORY; TRACE("Opening an on disk, inode mapped journal.\n"); fJournal = new(std::nothrow) InodeJournal(fJournalInode); } else { // TODO: external journal TRACE("Can not open an external journal.\n"); return B_UNSUPPORTED; } } else { TRACE("Opening a fake journal (NoJournal).\n"); fJournal = new(std::nothrow) NoJournal(this); } if (fJournal == NULL) { TRACE("No memory to create the journal\n"); return B_NO_MEMORY; } TRACE("Volume::Mount(): Checking if journal was initialized\n"); status = fJournal->InitCheck(); if (status != B_OK) { FATAL("could not initialize journal!\n"); return status; } // TODO: Only recover if asked to TRACE("Volume::Mount(): Asking journal to recover\n"); status = fJournal->Recover(); if (status != B_OK) { FATAL("could not recover journal!\n"); return status; } TRACE("Volume::Mount(): Restart journal log\n"); status = fJournal->StartLog(); if (status != B_OK) { FATAL("could not initialize start journal!\n"); return status; } if (!IsReadOnly()) { // Initialize allocators fBlockAllocator = new(std::nothrow) BlockAllocator(this); if (fBlockAllocator != NULL) { TRACE("Volume::Mount(): Initialize block allocator\n"); status = fBlockAllocator->Initialize(); } if (fBlockAllocator == NULL || status != B_OK) { delete fBlockAllocator; fBlockAllocator = NULL; FATAL("could not initialize block allocator, going read-only!\n"); fFlags |= VOLUME_READ_ONLY; fJournal->Uninit(); delete fJournal; delete fJournalInode; fJournalInode = NULL; fJournal = new(std::nothrow) NoJournal(this); } } // ready status = get_vnode(fFSVolume, EXT2_ROOT_NODE, (void**)&fRootNode); if (status != B_OK) { FATAL("could not create root node: get_vnode() failed!\n"); return status; } // all went fine opener.Keep(); if (!fSuperBlock.name[0]) { // generate a more or less descriptive volume name off_t divisor = 1ULL << 40; char unit = 'T'; if (diskSize < divisor) { divisor = 1UL << 30; unit = 'G'; if (diskSize < divisor) { divisor = 1UL << 20; unit = 'M'; } } double size = double((10 * diskSize + divisor - 1) / divisor); // %g in the kernel does not support precision... snprintf(fName, sizeof(fName), "%g %cB Ext2 Volume", size / 10, unit); } return B_OK; }
status_t Volume::Initialize(int fd, const char* name, uint32 blockSize, uint32 flags) { // although there is no really good reason for it, we won't // accept '/' in disk names (mkbfs does this, too - and since // Tracker names mounted volumes like their name) if (strchr(name, '/') != NULL) return B_BAD_VALUE; if (blockSize != 1024 && blockSize != 2048 && blockSize != 4096 && blockSize != 8192) return B_BAD_VALUE; DeviceOpener opener(fd, O_RDWR); if (opener.Device() < B_OK) return B_BAD_VALUE; if (opener.IsReadOnly()) return B_READ_ONLY_DEVICE; fDevice = opener.Device(); uint32 deviceBlockSize; off_t deviceSize; if (opener.GetSize(&deviceSize, &deviceBlockSize) < B_OK) return B_ERROR; off_t numBlocks = deviceSize / blockSize; // create valid superblock fSuperBlock.Initialize(name, numBlocks, blockSize); // initialize short hands to the superblock (to save byte swapping) fBlockSize = fSuperBlock.BlockSize(); fBlockShift = fSuperBlock.BlockShift(); fAllocationGroupShift = fSuperBlock.AllocationGroupShift(); // determine log size depending on the size of the volume off_t logSize = 2048; if (numBlocks <= 20480) logSize = 512; if (deviceSize > 1LL * 1024 * 1024 * 1024) logSize = 4096; // since the allocator has not been initialized yet, we // cannot use BlockAllocator::BitmapSize() here off_t bitmapBlocks = (numBlocks + blockSize * 8 - 1) / (blockSize * 8); fSuperBlock.log_blocks = ToBlockRun(bitmapBlocks + 1); fSuperBlock.log_blocks.length = HOST_ENDIAN_TO_BFS_INT16(logSize); fSuperBlock.log_start = fSuperBlock.log_end = HOST_ENDIAN_TO_BFS_INT64( ToBlock(Log())); // set the current log pointers, so that journaling will work correctly fLogStart = fSuperBlock.LogStart(); fLogEnd = fSuperBlock.LogEnd(); if (!IsValidSuperBlock()) RETURN_ERROR(B_ERROR); if ((fBlockCache = opener.InitCache(NumBlocks(), fBlockSize)) == NULL) return B_ERROR; fJournal = new(std::nothrow) Journal(this); if (fJournal == NULL || fJournal->InitCheck() < B_OK) RETURN_ERROR(B_ERROR); // ready to write data to disk Transaction transaction(this, 0); if (fBlockAllocator.InitializeAndClearBitmap(transaction) < B_OK) RETURN_ERROR(B_ERROR); off_t id; status_t status = Inode::Create(transaction, NULL, NULL, S_DIRECTORY | 0755, 0, 0, NULL, &id, &fRootNode); if (status < B_OK) RETURN_ERROR(status); fSuperBlock.root_dir = ToBlockRun(id); if ((flags & VOLUME_NO_INDICES) == 0) { // The indices root directory will be created automatically // when the standard indices are created (or any other). Index index(this); status = index.Create(transaction, "name", B_STRING_TYPE); if (status < B_OK) return status; status = index.Create(transaction, "BEOS:APP_SIG", B_STRING_TYPE); if (status < B_OK) return status; status = index.Create(transaction, "last_modified", B_INT64_TYPE); if (status < B_OK) return status; status = index.Create(transaction, "size", B_INT64_TYPE); if (status < B_OK) return status; } status = CreateVolumeID(transaction); if (status < B_OK) return status; status = _EraseUnusedBootBlock(); if (status < B_OK) return status; status = WriteSuperBlock(); if (status < B_OK) return status; status = transaction.Done(); if (status < B_OK) return status; Sync(); opener.RemoveCache(true); return B_OK; }
status_t Volume::Mount(const char* deviceName, uint32 flags) { // TODO: validate the FS in write mode as well! #if (B_HOST_IS_LENDIAN && defined(BFS_BIG_ENDIAN_ONLY)) \ || (B_HOST_IS_BENDIAN && defined(BFS_LITTLE_ENDIAN_ONLY)) // in big endian mode, we only mount read-only for now flags |= B_MOUNT_READ_ONLY; #endif DeviceOpener opener(deviceName, (flags & B_MOUNT_READ_ONLY) != 0 ? O_RDONLY : O_RDWR); fDevice = opener.Device(); if (fDevice < B_OK) RETURN_ERROR(fDevice); if (opener.IsReadOnly()) fFlags |= VOLUME_READ_ONLY; // read the superblock if (Identify(fDevice, &fSuperBlock) != B_OK) { FATAL(("invalid superblock!\n")); return B_BAD_VALUE; } // initialize short hands to the superblock (to save byte swapping) fBlockSize = fSuperBlock.BlockSize(); fBlockShift = fSuperBlock.BlockShift(); fAllocationGroupShift = fSuperBlock.AllocationGroupShift(); // check if the device size is large enough to hold the file system off_t diskSize; if (opener.GetSize(&diskSize, &fDeviceBlockSize) != B_OK) RETURN_ERROR(B_ERROR); if (diskSize < (NumBlocks() << BlockShift())) RETURN_ERROR(B_BAD_VALUE); // set the current log pointers, so that journaling will work correctly fLogStart = fSuperBlock.LogStart(); fLogEnd = fSuperBlock.LogEnd(); if ((fBlockCache = opener.InitCache(NumBlocks(), fBlockSize)) == NULL) return B_ERROR; fJournal = new(std::nothrow) Journal(this); if (fJournal == NULL) return B_NO_MEMORY; status_t status = fJournal->InitCheck(); if (status < B_OK) { FATAL(("could not initialize journal: %s!\n", strerror(status))); return status; } // replaying the log is the first thing we will do on this disk status = fJournal->ReplayLog(); if (status != B_OK) { FATAL(("Replaying log failed, data may be corrupted, volume " "read-only.\n")); fFlags |= VOLUME_READ_ONLY; // TODO: if this is the boot volume, Bootscript will assume this // is a CD... // TODO: it would be nice to have a user visible alert instead // of letting him just find this in the syslog. } status = fBlockAllocator.Initialize(); if (status != B_OK) { FATAL(("could not initialize block bitmap allocator!\n")); return status; } fRootNode = new(std::nothrow) Inode(this, ToVnode(Root())); if (fRootNode != NULL && fRootNode->InitCheck() == B_OK) { status = publish_vnode(fVolume, ToVnode(Root()), (void*)fRootNode, &gBFSVnodeOps, fRootNode->Mode(), 0); if (status == B_OK) { // try to get indices root dir if (!Indices().IsZero()) { fIndicesNode = new(std::nothrow) Inode(this, ToVnode(Indices())); } if (fIndicesNode == NULL || fIndicesNode->InitCheck() < B_OK || !fIndicesNode->IsContainer()) { INFORM(("bfs: volume doesn't have indices!\n")); if (fIndicesNode) { // if this is the case, the index root node is gone bad, // and BFS switch to read-only mode fFlags |= VOLUME_READ_ONLY; delete fIndicesNode; fIndicesNode = NULL; } } else { // we don't use the vnode layer to access the indices node } } else { FATAL(("could not create root node: publish_vnode() failed!\n")); delete fRootNode; return status; } } else { status = B_BAD_VALUE; FATAL(("could not create root node!\n")); return status; } // all went fine opener.Keep(); return B_OK; }
/*! Checks whether the given block number may be the location of an inode block. */ bool Volume::IsValidInodeBlock(off_t block) const { return block > fSuperBlock.LogEnd() && block < NumBlocks(); }