/*
    Copyright (C) 1995-2026, The AROS Development Team. All rights reserved.
*/
/*
 * -date------ -name------------------- -description-----------------------------
 * 02-jan-2008 [Tomasz Wiszkowski]      added disk validation
 * 04-jan-2008 [Tomasz Wiszkowski]      corrected tabulation
 */


#ifndef DEBUG
#define DEBUG 0
#endif

#include "os.h"
#include "misc.h"
#include "afsblocks.h"
#include "bitmap.h"
#include "cache.h"
#include "checksums.h"
#include "extstrings.h"
#include "baseredef.h"
#include "validator.h"

/**********************************************
 Name  : writeHeader
 Descr.: update header information (time)
 Input : volume      -
         blockbuffer - pointer to struct BlockCache
                       containing the headerblock
 Output: 0 for success; error code otherwise
***********************************************/
ULONG writeHeader
        (
                struct AFSBase *afsbase,
                struct Volume *volume,
                struct BlockCache *blockbuffer
        )
{
struct DateStamp ds;

        /* store current time as modification date for this object and all its ancestors */
        DateStamp(&ds);
        for (;;)
        {
                blockbuffer->buffer[BLK_DAYS(volume)] = OS_LONG2BE(ds.ds_Days);
                blockbuffer->buffer[BLK_MINS(volume)] = OS_LONG2BE(ds.ds_Minute);
                blockbuffer->buffer[BLK_TICKS(volume)] = OS_LONG2BE(ds.ds_Tick);
                if (blockbuffer->buffer[BLK_PARENT(volume)] == 0)
                        break;
                writeBlockDeferred(afsbase, volume, blockbuffer, BLK_CHECKSUM);
                blockbuffer = getBlock
                        (afsbase, volume, OS_BE2LONG(blockbuffer->buffer[BLK_PARENT(volume)]));
                if (blockbuffer == NULL)
                        return ERROR_UNKNOWN;
        }
        /* last block is not written yet - it's the rootblock */
        /* we have to change BLK_VOLUME_xxx */
        blockbuffer->buffer[BLK_VOLUME_DAYS(volume)] = OS_LONG2BE(ds.ds_Days);
        blockbuffer->buffer[BLK_VOLUME_MINS(volume)] = OS_LONG2BE(ds.ds_Minute);
        blockbuffer->buffer[BLK_VOLUME_TICKS(volume)] = OS_LONG2BE(ds.ds_Tick);
        writeBlockDeferred(afsbase, volume, blockbuffer, BLK_CHECKSUM);
        return 0;
}

/*******************************************
 Name  : getDiskInfo
 Descr.: fills a InfoData structure with some
         Disk info;
         answer on ACTION_DISK_INFO
 Input : id - InfoData structure to fill
 Output: 0 = no error
********************************************/
LONG getDiskInfo(struct Volume *volume, struct InfoData *id) {

        id->id_NumSoftErrors = 0;
        id->id_UnitNumber = volume->unit;
        id->id_DiskState = volume->state;
        id->id_NumBlocks = volume->countblocks-volume->bootblocks;
        id->id_NumBlocksUsed = volume->usedblockscount;
        id->id_BytesPerBlock = volume->dosflags==0 ? BLOCK_SIZE(volume)-24 : BLOCK_SIZE(volume);
        id->id_DiskType = mediumPresent(&volume->ioh) ? (volume->dostype | volume->dosflags) : ID_NO_DISK_PRESENT;
        id->id_VolumeNode = MKBADDR(volume->volumenode);
        id->id_InUse = (LONG)TRUE; /* if we are here the device should be in use! */
        return 0;
}

/*******************************************
 Name  : inhibit
 Descr.: forbid/permit access for this volume
 Input : volume  - the volume
         forbid  - DOSTRUE to forbid
                   DOSFALSE to permit access
 Output: 0 = no error
********************************************/
LONG inhibit(struct AFSBase *afsbase, struct Volume *volume, ULONG forbid) {
        D(bug("[afs 0x%p] inhibit(%d)\n", volume, forbid));
        if (forbid)
        {
                if (volume->inhibitcounter++ == 0)
                {
                        D(bug("[afs 0x%p] inhibiting\n", volume));
/*              if (exclusiveLocks(&volume->locklist)) return DOSFALSE; */
                        if (mediumPresent(&volume->ioh))
                        {
                                flush(afsbase, volume);
                                osMediumFree(afsbase, volume, FALSE);
                        }
                }
        }
        else if (volume->inhibitcounter)
        {
                if (--volume->inhibitcounter == 0)
                {
                        D(bug("[afs 0x%p] uninhibiting\n", volume));
                        if (diskPresent(afsbase, &volume->ioh))
                        {
                                D(bug("[afs 0x%p] media inserted\n", volume));
                                newMedium(afsbase, volume);
                                volume->ioh.ioflags |= IOHF_DISK_IN;
                        }
                        else
                                volume->ioh.ioflags &= ~IOHF_DISK_IN;
                }
        }
        return 0;
}

/*******************************************
 Name  : markBitmaps
 Descr.: mark newly allocated bitmapblocks
         (for format)
 Input : volume  - the volume
 Output: -
********************************************/
void markBitmaps(struct AFSBase *afsbase, struct Volume *volume) {
struct BlockCache *blockbuffer;
ULONG i,curblock;

        for (i=0; (i<=24) && (volume->bitmapblockpointers[i] != 0); i++)
                markBlock(afsbase, volume, volume->bitmapblockpointers[i], 0);
        curblock = volume->bitmapextensionblock;
        while (curblock != 0)
        {
                blockbuffer = getBlock(afsbase, volume, curblock);
                if (blockbuffer == NULL)
                        return;
                blockbuffer->flags |= BCF_USED;
                markBlock(afsbase, volume, curblock, 0);
                for (i=0; i<volume->SizeBlock-1; i++)
                {
                        if (blockbuffer->buffer[i] == 0)
                                break;
                        markBlock(afsbase, volume, OS_BE2LONG(blockbuffer->buffer[i]), 0);
                }
                curblock = OS_BE2LONG(blockbuffer->buffer[volume->SizeBlock-1]);
                blockbuffer->flags &= ~BCF_USED;
        }
}

/*******************************************
 Name  : format
 Descr.: initialize a volume
 Input : volume  - volume to initialize
         name    - name of volume
         dostype - DOS\0/...
 Output: 0 for success; error code otherwise
********************************************/
LONG format
        (struct AFSBase *afsbase, struct Volume *volume, CONST_STRPTR name,
        ULONG dostype)
{
struct BlockCache *blockbuffer;
struct DateStamp ds;
UWORD i;

        blockbuffer = getFreeCacheBlock(afsbase, volume, 0);
        if (blockbuffer != NULL)
        {
                blockbuffer->buffer[0] = OS_LONG2BE(dostype);
                blockbuffer->buffer[2] = OS_LONG2BE(volume->rootblock);
                writeBlock(afsbase, volume, blockbuffer, -1);
                blockbuffer = getFreeCacheBlock(afsbase, volume, volume->rootblock);
                if (blockbuffer != NULL)
                {
                        blockbuffer->flags |= BCF_USED;
                        DateStamp(&ds);
                        blockbuffer->buffer[BLK_PRIMARY_TYPE] = OS_LONG2BE(T_SHORT);
                        blockbuffer->buffer[1] = 0;
                        blockbuffer->buffer[2] = 0;
                        blockbuffer->buffer[BLK_TABLE_SIZE] = OS_LONG2BE(volume->SizeBlock-56);
                        blockbuffer->buffer[4] = 0;
                        for (i=BLK_TABLE_START; i<=BLK_TABLE_END(volume); i++)
                                blockbuffer->buffer[i] = 0;
                        blockbuffer->buffer[BLK_BITMAP_VALID_FLAG(volume)] = -1;
                        createNewBitmapBlocks(afsbase, volume);
                        for (
                                        i=BLK_BITMAP_POINTERS_START(volume);
                                        i<=BLK_BITMAP_POINTERS_END(volume);
                                        i++
                                )
                        {
                                blockbuffer->buffer[i] = OS_LONG2BE
                                        (
                                                volume->bitmapblockpointers[i-BLK_BITMAP_POINTERS_START(volume)]
                                        );
                        }
                        blockbuffer->buffer[BLK_BITMAP_EXTENSION(volume)] =
                                OS_LONG2BE(volume->bitmapextensionblock);
                        blockbuffer->buffer[BLK_ROOT_DAYS(volume)] = OS_LONG2BE(ds.ds_Days);
                        blockbuffer->buffer[BLK_ROOT_MINS(volume)] = OS_LONG2BE(ds.ds_Minute);
                        blockbuffer->buffer[BLK_ROOT_TICKS(volume)] = OS_LONG2BE(ds.ds_Tick);
                        StrCpyToBstr
                                (
                                        name,
                                        (APTR)((char *)blockbuffer->buffer+(BLK_DISKNAME_START(volume)*4)),
                                        MAX_NAME_LENGTH
                                );
                        blockbuffer->buffer[volume->SizeBlock-12] = 0;
                        blockbuffer->buffer[volume->SizeBlock-11] = 0;
                        blockbuffer->buffer[BLK_VOLUME_DAYS(volume)] = OS_LONG2BE(ds.ds_Days);
                        blockbuffer->buffer[BLK_VOLUME_MINS(volume)] = OS_LONG2BE(ds.ds_Minute);
                        blockbuffer->buffer[BLK_VOLUME_TICKS(volume)] = OS_LONG2BE(ds.ds_Tick);
                        blockbuffer->buffer[BLK_CREATION_DAYS(volume)] = OS_LONG2BE(ds.ds_Days);
                        blockbuffer->buffer[BLK_CREATION_MINS(volume)] = OS_LONG2BE(ds.ds_Minute);
                        blockbuffer->buffer[BLK_CREATION_TICKS(volume)] = OS_LONG2BE(ds.ds_Tick);
                        blockbuffer->buffer[volume->SizeBlock-4] = 0;
                        blockbuffer->buffer[volume->SizeBlock-3] = 0;
                        blockbuffer->buffer[volume->SizeBlock-2] = 0;
                        blockbuffer->buffer[BLK_SECONDARY_TYPE(volume)] = OS_LONG2BE(ST_ROOT);
                        writeBlock(afsbase, volume, blockbuffer, BLK_CHECKSUM);
                        blockbuffer->flags &= ~BCF_USED;
                        invalidBitmap(afsbase, volume);
                        markBlock(afsbase, volume, volume->rootblock, 0);
                        markBitmaps(afsbase, volume);
                        validBitmap(afsbase, volume);
                        return 0;
                }
        }
        return ERROR_UNKNOWN;
}

/*******************************************
 Name  : relabel
 Descr.: rename a volume
 Input : volume  - volume to rename
         name    - new name for volume
 Output: DOSTRUE for success; DOSFALSE otherwise
********************************************/
LONG relabel(struct AFSBase *afsbase, struct Volume *volume,
        CONST_STRPTR name, SIPTR *error) {
struct BlockCache *blockbuffer;
struct DateStamp ds;

        if (0 == checkValid(afsbase, volume))
        {
                *error = ERROR_DISK_WRITE_PROTECTED;
                return DOSFALSE;
        }
        osMediumFree(afsbase, volume, FALSE);
        blockbuffer=getBlock(afsbase, volume,volume->rootblock);
        if (blockbuffer == NULL)
                return DOSFALSE;
    if (strlen(name) > MAX_NAME_LENGTH)
    {
        *error = ERROR_LINE_TOO_LONG;
        return DOSFALSE;
    }
        StrCpyToBstr
                (
                        name,
                        (APTR)((char *)blockbuffer->buffer+(BLK_DISKNAME_START(volume)*4)),
                        MAX_NAME_LENGTH
                );
        DateStamp(&ds);
        blockbuffer->buffer[BLK_ROOT_DAYS(volume)] = OS_LONG2BE(ds.ds_Days);
        blockbuffer->buffer[BLK_ROOT_MINS(volume)] = OS_LONG2BE(ds.ds_Minute);
        blockbuffer->buffer[BLK_ROOT_TICKS(volume)] = OS_LONG2BE(ds.ds_Tick);
        blockbuffer->buffer[BLK_VOLUME_DAYS(volume)] = OS_LONG2BE(ds.ds_Days);
        blockbuffer->buffer[BLK_VOLUME_MINS(volume)] = OS_LONG2BE(ds.ds_Minute);
        blockbuffer->buffer[BLK_VOLUME_TICKS(volume)] = OS_LONG2BE(ds.ds_Tick);
        writeBlock(afsbase, volume, blockbuffer, BLK_CHECKSUM);
        /* update os specific information of the medium */
        osMediumInit(afsbase, volume, blockbuffer);
        return DOSTRUE;
}

