@Override
    public int allocateClusters(int tailCluster, int count) throws IOException {
        int headCluster = -1;
        int tailOffset = tailCluster;
        while (count > 0 && freeListHead >= 0) {
            int fatEntry = fs.getFatEntry(freeListHead);
            if ((fatEntry & CLUSTER_STATUS) == CLUSTER_FREE || fatEntry == CLUSTER_FREE_EOC) {
                if (headCluster == -1)
                    headCluster = freeListHead;

                // "God, save EOC on power down!"
                // mark as EOC
                --fs.freeClusterCount;
                fs.putFatEntry(freeListHead, CLUSTER_EOC);
                if (tailOffset != -1) {
                    // mark as ALLOCATED with forward index
                    fs.putFatEntry(tailOffset, CLUSTER_ALLOCATED | freeListHead);
                }
                tailOffset = freeListHead;
                freeListHead = (fatEntry == CLUSTER_FREE_EOC)
                    ? -1
                    : (fatEntry & CLUSTER_INDEX);
                --count;
                if (count == 0)
                    return headCluster;
            } else {
                fs.LogError("Wrong value in free list.");
                break;
            }
        }

        fs.setDirtyState("[freeClusterCount] has wrong value.", false);

        // rollback allocation.
        if (tailCluster == -1)
            freeClusters(headCluster, true);
        else
            freeClusters(tailCluster, false);

        throw new IOException("Disk full.");
    }