fsrepair.c 1.91 KB
#include <PR/bcp.h>
#include "os.h"
#include "os_bbcard.h"
#include "os_bbfs.h"
#include "bbint.h"

s32
osBbFRepairBlock(s32 fd, u32 off, void* buf, u32 len) {
    s32 rv, rv2 = 0;
    BbInode* in;
    u32 b, i, old = 0;
    BbFat16* fat;
#ifdef _DEBUG
    if ((u32)buf&15) return BBFS_ERR_INVALID;
#endif
    if (fd < 0 || fd >= BB_INODE16_ENTRIES) return BBFS_ERR_INVALID;
    if ((rv = __osBbFsGetAccess()) < 0) return rv;
    fat = __osBbFat;
    in = fat->inode+fd;
    /* check size, etc */
    rv = BBFS_ERR_INVALID;
    if (!in->type) goto out;
    if ((off & (BB_FL_BLOCK_SIZE-1)) || off >= in->size) goto out;
    if (len != BB_FL_BLOCK_SIZE) goto out;
    if (off+len < off) goto out; /* overflow */
    if (off+len > in->size) goto out;

    /* find starting block */
    b = in->block;
    for(i = 0; i < BB_FL_BYTE_TO_BLOCK(off); i++)
	b = BB_FAT16_NEXT(fat,b);
    /* paranoia */
    if (b == 0 || b >= __osBbFsBlocks-BB_FAT16_BLOCKS) goto out;

    if ((rv = osBbCardReadBlock(0, b, buf, 0)) < 0) goto out;
    old = b;
retry:
    if ((i = __osBbFReallocBlock(in, b, BB_FAT_AVAIL)) == BB_FAT_BAD){
        goto error;
    }
    b = i;
    if ((rv = osBbCardEraseBlock(0, b)) < 0 ||
	(rv = osBbCardWriteBlock(0, b, buf, 0)) < 0) {
	if (rv != BBFS_ERR_FAIL) goto error;
        BB_FAT16_NEXT(fat, b) = BB_FAT_BAD;
	goto retry;
    }
    rv = BB_FL_BLOCK_SIZE;
    /* change it to be free rather than bad */
    old = BB_FAT_BAD; /* magic value for below */
error:
    if (old != BB_FAT_BAD && b != old) {
	/* failed after reallocating block, put back original block pointer */
	BB_FAT16_NEXT(fat,old) = BB_FAT16_NEXT(fat, b);
	BB_FAT16_NEXT(fat,b) = BB_FAT_AVAIL;
	if (off == 0)
	    in->block = old;
	else {
	    b = in->block;
	    for(i = 0; i < BB_FL_BYTE_TO_BLOCK(off)-1; i++)
		b = BB_FAT16_NEXT(fat,b);
	    BB_FAT16_NEXT(fat, b) = old;
	}
    }
    rv2 = __osBbFsSync(0);
out:
    __osBbFsRelAccess();
    return rv ? rv : rv2;
}