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

u16
__osBbFReallocBlock(BbInode* in, u16 block, BbFatEntry newVal) {
    u16 b, ob, prev = 0;
    s32 incr, rv;
    BbFat16* fat = __osBbFat;

    /* find new block */
    if (in->size > BB_BIG_FILE_THRESHOLD) {
	/* big files go low in the fat */
	b = BB_FL_BYTE_TO_BLOCK(BB_SYSTEM_AREA_SIZE); incr = 1;
    } else {
	/* small files at the other end */
	b = __osBbFsBlocks-1; incr = -1;
    }
    while(b < __osBbFsBlocks && BB_FAT16_NEXT(fat,b) != BB_FAT_AVAIL)
	b += incr;
    if (b >= __osBbFsBlocks) goto error;

    /* find old block */
    ob = in->block;
    while(ob != block) {
	prev = ob;
	ob = BB_FAT16_NEXT(fat,ob);
    }
    if (prev)
	BB_FAT16_NEXT(fat,prev) = b;
    else
	in->block = b;
    BB_FAT16_NEXT(fat,b) = BB_FAT16_NEXT(fat,ob);
    BB_FAT16_NEXT(fat,ob) = newVal;
    /* sync the metadata */
    if ((rv = __osBbFsSync(0)) == 0)
	return b;
    /*XXXblythe now what to do?*/
error:
    return BB_FAT_BAD;
}

s32
osBbFWrite(s32 fd, u32 off, const void* buf, u32 len) {
    s32 rv;
    BbInode* in;
    u32 count, b, i;
    BbFat16* fat;
#define MULTIPLANE
#ifdef MULTIPLANE
    u16 blocks[4], n;
#endif
#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 error;
    if ((off & (BB_FL_BLOCK_SIZE-1)) || off >= in->size) goto error;
    if (len & (BB_FL_BLOCK_SIZE-1)) goto error;
    if (off+len < off) goto error; /* overflow */
    if (off+len > in->size) goto error;
    if (!len) {
	rv = 0;
	goto error;
    }

    /* find starting block */
    b = in->block;
    for(i = 0; i < BB_FL_BYTE_TO_BLOCK(off); i++)
	b = BB_FAT16_NEXT(fat,b);
    count = 0;
#ifdef MULTIPLANE
    /* do 4 blocks at a time */
    while(len > 0) {
	for(n = 0; len > 0 && n < 4; n++) {
	    if (b == 0 || b >= __osBbFsBlocks-BB_FAT16_BLOCKS) goto error;
	    blocks[n] = b;
	    b = BB_FAT16_NEXT(fat,b);
	    len = len > BB_FL_BLOCK_SIZE ? len - BB_FL_BLOCK_SIZE : 0;
	    count += BB_FL_BLOCK_SIZE;
	}
	if ((rv = osBbCardEraseBlocks(0, blocks, n)) < 0 ||
	    (rv = osBbCardWriteBlocks(0, blocks, n, buf, 0)) < 0) {
	    int i;
	    if (rv != BBFS_ERR_FAIL) goto error;
	    /* determine which blocks are bad, by repeating one at a time  */
	    for(i = 0; i < n; i++) {
		u16 b = blocks[i];
retry:
		if ((rv = osBbCardEraseBlock(0, b)) < 0 ||
		    (rv = osBbCardWriteBlock(0, b, buf+i*BB_FL_BLOCK_SIZE, 0)) < 0) {
		    if (rv != BBFS_ERR_FAIL ||
			(b = __osBbFReallocBlock(in, b, BB_FAT_BAD)) == BB_FAT_BAD) goto error;
		    goto retry;
		}
	    }
	}
	buf += BB_FL_BLOCK_SIZE*n;
    }
#else
    while(len > 0) {
	if (b == 0 || b >= __osBbFsBlocks-BB_FAT16_BLOCKS) goto error;
retry:
	if ((rv = osBbCardEraseBlock(0, b)) < 0 ||
	    (rv = osBbCardWriteBlock(0, b, buf, 0)) < 0) {
	    if (rv != BBFS_ERR_FAIL ||
		(b = __osBbFReallocBlock(in, b, BB_FAT_BAD)) == BB_FAT_BAD) goto error;
	    goto retry;
	}
	b = BB_FAT16_NEXT(fat,b);
	buf += BB_FL_BLOCK_SIZE;
	len = len > BB_FL_BLOCK_SIZE ? len - BB_FL_BLOCK_SIZE : 0;
	count += BB_FL_BLOCK_SIZE;
    }
#endif
    rv = count;
error:
    __osBbFsRelAccess();
    return rv;
}