#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;
}