Example #1
0
void AudioRenderer::ResetBlockCount()
{
	if (provider)
	{
		const size_t total_blocks = NumBlocks(provider->GetNumSamples());
		for (auto& bmp : bitmaps) bmp.SetBlockCount(total_blocks);
	}
}
Example #2
0
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;
}
Example #3
0
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;
	}
}
Example #4
0
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;
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #7
0
/*!	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();
}