#help_index "Info;File/Cmd Line (Typically);Cmd Line (Typically)"
Bool CheckDiskConfirm(Bool *_fix, Bool *_confirm)
{
    if (*_fix && *_confirm)
    {
        "Fix ";
        if (!YorN)
            *_fix = FALSE;
        *_confirm = FALSE;
    }
    return *_fix;
}

I64 RedSeaCheckDiskList(CDrive *drive, CDirEntry *tmpde1, U8 *bits, U8 *bits2, I64 size, I64 bpc)
{
    CDirEntry   *tmpde2;
    I64          i, j, errs = 0;

    while (tmpde1)
    {
        tmpde2 = tmpde1->next;
        if (tmpde1->attr & RS_ATTR_DIR && tmpde1->sub)
            errs += RedSeaCheckDiskList(drive, tmpde1->sub, bits, bits2, size, bpc);
        j = (tmpde1->size + bpc - 1) / bpc;
        for (i = 0; i < j; i++)
        {
            if (i + tmpde1->clus-drive->data_area > size)
            {
                PrintErr("Invalid Clus:%s Clus:%X\n", tmpde1->full_name, i + tmpde1->clus);
                errs++;
                break;
            }
            if (LBts(bits, i + tmpde1->clus-drive->data_area))
            {
                PrintErr("Dbl Alloc:%s Clus:%X\n", tmpde1->full_name, i + tmpde1->clus);
                errs++;
            }
            if (!LBtr(bits2, i + tmpde1->clus-drive->data_area))
            {
                PrintErr("UnAlloc:%s Clus:%X\n", tmpde1->full_name, i + tmpde1->clus);
                errs++;
            }
        }
        DirEntryDel(tmpde1);
        tmpde1 = tmpde2;
    }

    return errs;
}

I64 RedSeaCheckDisk(U8 drv_let, Bool *_fix, Bool *_confirm)
{
    I64          i, j, bpc, size, errs = 0;
    CDrive      *drive = Letter2Drive(drv_let), *old_dv = Fs->cur_dv;
    U8          *files_find_mask = MStrPrint("%c:/*", Drive2Letter(drive)),
                *old_dir = StrNew(Fs->cur_dir),
                *bits, *bits2;
    CDirEntry   *ptr,*ptr2;

    Drive(drv_let);
    "Scanning...\n";
    size = (drive->size - (drive->data_area - drive->drv_offset)) / drive->spc;
    bpc = drive->spc << BLK_SIZE_BITS;
    bits = CAlloc((size + 7) >> 3);
    bits2 = CAlloc((size + 7) >> 3 + BLK_SIZE);
    BlkRead(drive, bits2, drive->fat1, ((size + 7) >> 3 + BLK_SIZE - 1) >> BLK_SIZE_BITS);

    //Get Root Dir size
    ptr2 = MAlloc(bpc);
    BlkRead(drive, ptr2, drive->root_clus, 1);
    ptr = ptr2(U8 *) - offset(CDirEntry.start);
    j = (ptr->size + bpc - 1) / bpc;
    Free(ptr2);

    for (i = 0; i < j; i++)
    {
        if (i + drive->root_clus - drive->data_area > size)
        {
            PrintErr("Invalid Clus: RootDir Clus:%X\n", i + drive->root_clus);
            errs++;
            break;
        }
        if (LBts(bits, i + drive->root_clus - drive->data_area))
        {
            PrintErr("Dbl Alloc: RootDir Clus:%X\n", i + drive->root_clus);
            errs++;
        }
        if (!LBtr(bits2, i + drive->root_clus - drive->data_area))
        {
            PrintErr("UnAlloc: RootDir Clus:%X\n", i + drive->root_clus);
            errs++;
        }
    }

    errs += RedSeaCheckDiskList(drive, FilesFind(files_find_mask, FUF_RECURSE), bits, bits2, size, bpc);
    for (i = 1; i < size; i++)
        if (Bt(bits2, i))
        {
            PrintWarn("Shouldn't Alloc Clus:%0X\n", i + drive->data_area);
            errs++;
            if (CheckDiskConfirm(_fix, _confirm))
                RedSeaFreeClus(drive, i + drive->data_area, 1);
        }

    Free(files_find_mask);
    Free(bits);
    Free(bits2);
    Drive(Drive2Letter(old_dv));
    Cd(old_dir);
    Free(old_dir);

    return errs;
}

I64 FAT32CheckDiskList(CDrive *drive, CDirEntry *tmpde1, U8 *bits, U32 *bits2, I64 size, I64 bpc)
{
    CDirEntry   *tmpde2;
    I64          i, c, errs = 0;

    while (tmpde1)
    {
        tmpde2 = tmpde1->next;
        if (tmpde1->attr & RS_ATTR_DIR && tmpde1->sub)
            errs += FAT32CheckDiskList(drive, tmpde1->sub, bits, bits2, size, bpc);
        i = 0;
        c = tmpde1->clus;
        while (0 < c < 0x0FFFFFF8)
        {
            if (c > size)
            {
                PrintErr("Invalid Clus:%s Clus:%X\n", tmpde1->full_name, c);
                errs++;
                break;
            }
            if (LBts(bits, c))
            {
                PrintErr("Dbl Alloc:%s Clus:%X\n", tmpde1->full_name, c);
                errs++;
            }
            if (!bits2[c])
            {
                PrintErr("UnAlloc:%s Clus:%X\n", tmpde1->full_name, c);
                errs++;
            }
            else
                bits2[c] = 0;
            c = ClusNumNext(drive, c);
            i++;
        }
        if (!(tmpde1->attr & RS_ATTR_DIR))
        {
            i *= bpc;
            if (tmpde1->size>i)
            {
                PrintErr("Alloced File Too Short:%s\n", tmpde1->full_name);
                errs++;
            }
            if (i > tmpde1->size + bpc - 1)
            {
                PrintWarn("Alloced File Too Long:%s\n", tmpde1->full_name);
                errs++;
            }
        }
        DirEntryDel(tmpde1);
        tmpde1 = tmpde2;
    }
    return errs;
}

I64 FAT32CheckDisk(U8 drv_let, Bool *_fix, Bool *_confirm)
{
    I64      i, bpc, size, c, errs = 0;
    CDrive  *drive = Letter2Drive(drv_let), *old_dv = Fs->cur_dv;
    U8      *files_find_mask = MStrPrint("%c:/*", Drive2Letter(drive)),
            *old_dir = StrNew(Fs->cur_dir),
            *bits;
    U32     *bits2;

    Drive(drv_let);
    "Scanning...\n";
    size = (drive->size - (drive->data_area - drive->drv_offset)) / drive->spc;
    bpc = drive->spc << BLK_SIZE_BITS;
    bits = CAlloc((size + 7) >> 3);
    bits2 = CAlloc(size * 4 + BLK_SIZE);
    BlkRead(drive, bits2, drive->fat1, (size * 4 + BLK_SIZE - 1) >> BLK_SIZE_BITS);

    c = drive->root_clus;
    while (0 < c < 0x0FFFFFF8)
    {
        if (c > size)
        {
            PrintErr("Invalid Clus: RootDir Clus:%X\n", c);
            errs++;
            break;
        }
        if (LBts(bits, c))
        {
            PrintErr("Dbl Alloc: RootDir Clus:%X\n", c);
            errs++;
        }
        if (!bits2[c])
        {
            PrintErr("UnAlloc: RootDir Clus:%X\n", c);
            errs++;
        }
        else
            bits2[c] = 0;
        c = ClusNumNext(drive, c);
    }

    errs += FAT32CheckDiskList(drive, FilesFind(files_find_mask, FUF_RECURSE), bits, bits2, size, bpc);

    bits2[1] = 0; //See FAT32Format()
    for (i = 1; i < size; i++)
        if (bits2[i])
        {
            PrintWarn("Shouldn't Alloc Clus:%0X\n", i);
            errs++;
            if (CheckDiskConfirm(_fix, _confirm))
                FAT32FreeClus(drive, i);
        }
    Free(files_find_mask);
    Free(bits);
    Free(bits2);
    Drive(Drive2Letter(old_dv));
    Cd(old_dir);
    Free(old_dir);

    return errs;
}

public I64 DiskCheck(U8 drv_let=0, Bool fix=FALSE, Bool confirm=TRUE)
{//Check disk for allocation errors and, optionally, fix.
//You probably want to reformat and reinstall.
    I64      errs = 0;
    CDrive  *drive = Letter2Drive(drv_let);

    switch (drive->fs_type)
    {
        case FSt_REDSEA:
            errs = RedSeaCheckDisk(drv_let, &fix, &confirm);
            break;

        case FSt_FAT32:
            errs = FAT32CheckDisk(drv_let, &fix, &confirm);
            break;

        default:
            PrintErr("File System Not Supported\n");
    }
    if (errs)
    {
        if (fix)
            "It might be a little better.  ";
        "Copy files to another partition or CD/DVD, "
            "reformat, and copy back.  "
            "Or, copy from a back-up.\n";
    }

    return errs;
}

U0 RedSeaDriveView(U8 drv_let=0)
{
    CDrive  *drive = Letter2Drive(drv_let);
    I64      lohi, c1, i, x, y,
             l = (GR_HEIGHT - 3 * FONT_HEIGHT) * (GR_WIDTH - FONT_WIDTH << 1),
             s = drive->size + drive->drv_offset - drive->data_area;
    U8      *bitmap;
    CDC     *dc = DCAlias;

    SettingsPush; //See SettingsPush
    WinMax;
    WinBorder(ON);
    DocCursor;
    DocClear;
    DCFill;
    try
    {
        i = ((s + 7) >> 3 + BLK_SIZE - 1) >> BLK_SIZE_BITS;
        bitmap = MAlloc(i << BLK_SIZE_BITS);
        BlkRead(drive, bitmap, drive->fat1, i);
        i = 0;
        for (y = 0; y < GR_HEIGHT - 3 * FONT_HEIGHT; y++)
        {
            if (KeyScan)
                break;
            for (x = 0; x < GR_WIDTH - FONT_WIDTH << 1; x++)
            {
                lohi = i * s;
                c1 = lohi / l;
                if (Bt(bitmap, c1))
                    dc->color = ROP_XOR + BLUE ^ TRANSPARENT;
                else
                    dc->color = ROP_XOR + WHITE ^ TRANSPARENT;
                GrPlot(dc, x, y);
                i++;
            }
        }
        Free(bitmap);
    }
    catch
        DriveUnlock(drive);
    CharGet;

    SettingsPop;
    DCFill;
    DCDel(dc);
}
U0 FAT32DriveView(U8 drv_let=0)
{
    CDrive  *drive = Letter2Drive(drv_let);
    I64      lohi, c1, i, x, y,
             l = (GR_HEIGHT - 3 * FONT_HEIGHT) * (GR_WIDTH - FONT_WIDTH << 1),
             s = (drive->size + drive->spc - 1) / drive->spc - (2 + drive->data_area - drive->drv_offset);
    U32     *bitmap;
    CDC     *dc = DCAlias;

    SettingsPush; //See SettingsPush
    WinMax;
    WinBorder(ON);
    DocCursor;
    DocClear;
    DCFill;
    try
    {
        i = (s * 4 + BLK_SIZE - 1) >> BLK_SIZE_BITS;
        bitmap = MAlloc(i << BLK_SIZE_BITS);
        BlkRead(drive, bitmap, drive->fat1, i);
        i = 0;
        for (y = 0; y < GR_HEIGHT - 3 * FONT_HEIGHT; y++)
        {
            if (KeyScan)
                break;
            for (x = 0; x < GR_WIDTH - FONT_WIDTH << 1; x++)
            {
                lohi = i * s;
                c1 = lohi / l;
                if (bitmap[c1])
                    dc->color = ROP_XOR + BLUE ^ TRANSPARENT;
                else
                    dc->color = ROP_XOR + WHITE ^ TRANSPARENT;
                GrPlot(dc, x, y);
                i++;
            }
        }
        Free(bitmap);
    }
    catch
        DriveUnlock(drive);
    CharGet;

    SettingsPop;
    DCFill;
    DCDel(dc);
}

public U0 DriveView(U8 drv_let=0)
{//Drive view. Graph the allocation map's fragmentation.
    CDrive *drive = Letter2Drive(drv_let), *old_dv = Fs->cur_dv;

    Drive(drv_let);
    switch (drive->fs_type)
    {
        case FSt_REDSEA:
            RedSeaDriveView(drv_let);
            break;

        case FSt_FAT32:
            FAT32DriveView(drv_let);
            break;

        default:
            PrintErr("File System Not Supported\n");
    }
    Drive(Drive2Letter(old_dv));
}

public U0 DiskView(U8 drv_let=0)
{//Disk view. Pie chart of partition sizes.
    I64      i, j, attr,
             h = Fs->pix_width,
             v = Fs->pix_height,
             radius;
    CDrive  *drive;
    CBlkDev *bd = Letter2BlkDev(drv_let);
    CDC     *dc = DCAlias;
    F64      sect_start, sect_end;

    SettingsPush; //See SettingsPush
    DocCursor;
    DocClear;
    DCFill;
    if (h < v)
        radius = 0.4 * h;
    else
        radius = 0.4 * v;
    dc->color = BLACK;
    GrCircle(dc, h >> 1, v >> 1, radius);

    j = 1;
    for (i = 0; i < DRIVES_NUM; i++)
    {
        drive = &blkdev.drvs[i];
        if (bd == drive->bd && drive->fs_type)
        {
            sect_start  = -(drive->drv_offset * 2 * pi / (bd->max_blk + 1));
            sect_end    = -((drive->drv_offset + drive->size) * 2 * pi / (bd->max_blk + 1));
            dc->color = BLACK;
            GrLine(dc, h >> 1, v >> 1,
                    h >> 1 + radius * Cos(sect_start),
                    v >> 1 + radius * Sin(sect_start));

            GrLine(dc, h >> 1, v >> 1,
                    h >> 1 + radius * Cos(sect_end),
                    v >> 1 + radius * Sin(sect_end));

            attr = DriveTextAttrGet(Drive2Letter(drive));
            dc->color = attr & 15;
            GrPrint(dc, 0, v - FONT_HEIGHT * j, "%C %-8Z", Drive2Letter(drive), drive->fs_type, "ST_DRIVE_TYPES");
            dc->color.c1 = attr >> 4;
            dc->color |= ROPF_DITHER;
            GrFloodFill(dc,
                        h >> 1 + (radius - 4) * Cos((sect_start + sect_end) / 2),
                        v >> 1 + (radius - 4) * Sin((sect_start + sect_end) / 2), FALSE);
            j++;
        }
    }

    CharGet(,FALSE);
    SettingsPop;
    DCFill;
    DCDel(dc);
}

I64 RedSeaUnusedDriveSpace(U8 drv_let=0)
{
    CDrive  *drive = Letter2Drive(drv_let);
    I64      res = 0, i, l;
    U8      *bitmap;

    try
    {
        l = drive->size + drive->drv_offset - drive->data_area;
        i = ((l + 7) >> 3 + BLK_SIZE - 1) >> BLK_SIZE_BITS;
        bitmap = MAlloc(i << BLK_SIZE_BITS);
        BlkRead(drive, bitmap, drive->fat1, i);
        for (i = 0; i < l; i++)
            if (!Bt(bitmap, i))
                res++;
        Free(bitmap);
    }
    catch
        DriveUnlock(drive);

    return res * BLK_SIZE * drive->spc;
}
I64 FAT32UnusedDriveSpace(U8 drv_let=0)
{
    CDrive  *drive = Letter2Drive(drv_let);
    I64      res = 0, i, l;
    U32     *bitmap;

    try
    {
        l = (drive->size + drive->spc - 1) / drive->spc - (2 + drive->data_area - drive->drv_offset);
        i = (l * 4 + BLK_SIZE - 1) >> BLK_SIZE_BITS;
        bitmap = MAlloc(i << BLK_SIZE_BITS);
        BlkRead(drive, bitmap, drive->fat1, i);
        for (i = 0; i < l; i++)
            if (!bitmap[i])
                res++;
        Free(bitmap);
    }
    catch
        DriveUnlock(drive);

    return res * BLK_SIZE * drive->spc;
}
public I64 DriveUnused(U8 drv_let=0)
{//Returns unused size in bytes.
    CDrive  *drive = Letter2Drive(drv_let), *old_dv = Fs->cur_dv;
    U8      *old_dir = StrNew(Fs->cur_dir);
    I64      res = 0;

    Drive(drv_let);
    switch (drive->fs_type)
    {
        case FSt_REDSEA:
            res = RedSeaUnusedDriveSpace(drv_let);
            break;

        case FSt_FAT32:
            res = FAT32UnusedDriveSpace(drv_let);
            break;

        default:
            PrintErr("File System Not Supported\n");
    }
    Drive(Drive2Letter(old_dv));
    Cd(old_dir);
    Free(old_dir);

    return res;
}