private SizeSet calcSizes(long maxFreeBlocks, long chunkSize) throws Exception { long dataSize = chunkSize; SizeSet last = new SizeSet(); log.debug("maxFreeBlocks=%d, chunkSize=%d", maxFreeBlocks, chunkSize); /* Find optimal size set. Logic: assume data size is 1 chunk - it will check for minimum required space calculate descriptor partition size to represent all data blocks check if size set is valid - fits the free space (for first run it will not obviously) if it is not valid - recalculate data size that is guaranteed to fit - i.e. free space minus calculated descriptor partition size note that after descriptor size is recalculated using this new (smaller) data size, it can only be the same or smaller if it is valid - check if it makes sense to continue - stop if 1. data size is less or equal than previous known from valid size set 2. unclaimed space (free - descriptor - data) is less than one data chunk if continue - remember valid size set */ while (true) { long descriptorSize = Zone64.calculateDescriptorSize(dataSize / chunkSize) / AppleDisk.BLOCK_SIZE; // account for backup as well and round up long descriptorPartitionSize = Utils.roundUp(descriptorSize * 2, MfsView.VOLUME_SIZE_ROUNDING); long unclaimedBlocks = maxFreeBlocks - (descriptorPartitionSize + dataSize); if (unclaimedBlocks < 0) { // combined size does not fit into free space if (dataSize <= chunkSize) { log.debug( "unclaimedBlocks=%d, descriptorSize=%d, descriptorPartitionSize=%d, dataSize=%d", unclaimedBlocks, descriptorSize, descriptorPartitionSize, dataSize); throw new Exception( "Free space is to small to accomodate necessary data - extension is impossible"); } } else { // combined size fits - it is a valid size set if (last == null) last = new SizeSet(); else { if (dataSize <= last.data) break; } last.partition = descriptorPartitionSize; last.data = dataSize; last.descriptor = descriptorSize; if (unclaimedBlocks < chunkSize) break; } dataSize = maxFreeBlocks - descriptorPartitionSize; } return last; }
private Zone addZone(Mfs mfs, long logicalStartBlock, SizeSet sizes, long chunkSize) throws Exception { if ((mfs == null) || (mfs.getMfs() == null)) throw new Exception("No MFS - MFS has not been initialized"); List<Zone> zones = mfs.getZones(); if ((zones == null) || zones.isEmpty()) throw new Exception("No Zones - MFS has not been initialized"); Zone lastZone = zones.get(zones.size() - 1); int baseFsPointer = lastZone.getInts()[0] - (int) lastZone.getNum() * Utils.SIZEOF_INT + (int) Utils.blocksToBytes(lastZone.getDescriptorSize() + 1) + 160; Zone64 z = new Zone64( logicalStartBlock, // descriptor start logicalStartBlock + sizes.partition, // data start sizes.data, // data size chunkSize, baseFsPointer); z.setType(ZoneType.MEDIA); ZoneHeader lastNext = lastZone.getNext(); /* just put the next pointer indicating the end into the new zone and fill the previous next with pointers to the new zone */ z.setNext(lastNext); lastZone.setNext(z.getHeader()); mfs.addZone(z); return z; }