Esempio n. 1
0
/**
   Appends a copy of bl to ino's block list, expanding the list as
   necessary. If ino has blocks already, the last block has bl added
   as its next block and that block is flushed to disk.

   ino is assumed to be an opened inode. If it is not, results
   are undefined.

   Returns whefs_rc.OK on success.
*/
static int whefs_inode_block_list_append( whefs_fs * fs,
					  whefs_inode * ino,
					  whefs_block const * bl )
{
    if( ! fs || !ino || !bl ) return whefs_rc.ArgError;
    if( ino->blocks.alloced <= ino->blocks.count )
    {
	int rc = whefs_inode_block_list_reserve( fs, ino, (ino->blocks.count ? ino->blocks.count : 4 /* arbitrarily chosen*/) * 2 );
	if( whefs_rc.OK != rc ) return rc;
    }
    ino->blocks.list[ino->blocks.count] = *bl;
    if( 0 < ino->blocks.count )
    { // append block to the list
	whefs_block * prev = &ino->blocks.list[ino->blocks.count-1];
	if( ! prev->next_block )
	{
	    prev->next_block = bl->id;
	    whefs_block_flush( fs, prev );
	}
	else if( prev->next_block != bl->id )
	{
	    WHEFS_DBG_ERR("Internal error: previous block (#%"WHEFS_ID_TYPE_PFMT") says its next block is #%"WHEFS_ID_TYPE_PFMT", but request was made to append #%"WHEFS_ID_TYPE_PFMT,
			  prev->id, prev->next_block, bl->id );
	    assert( 0 && "Internal consistency error." );
	    return whefs_rc.InternalError;
	}
    }
    else
    { // set bl as the first block...
	if( ino->first_block )
	{
	    if( ino->first_block != bl->id )
	    {
		WHEFS_DBG_ERR("Internal error: inode #%"WHEFS_ID_TYPE_PFMT" says its first block is #%"WHEFS_ID_TYPE_PFMT", but #%"WHEFS_ID_TYPE_PFMT" was added as the first item of its block list.",
			      ino->id, ino->first_block, bl->id );
		assert( 0 && "Internal consistency error." );
		return whefs_rc.InternalError;
	    }
	}
	else
	{
	    ino->first_block = bl->id;
	    whefs_inode_flush( fs, ino );
	}
    }
    ++ino->blocks.count;
    //WHEFS_DBG("Appended block #%"WHEFS_ID_TYPE_PFMT" to chain (of %"WHEFS_ID_TYPE_PFMT" item(s)) for inode #%"WHEFS_ID_TYPE_PFMT"[%s].", bl->id, ino->blocks.count, ino->id, ino->name );
    return whefs_rc.OK;
}
Esempio n. 2
0
static int whio_dev_inode_trunc( whio_dev * dev, whio_off_t len )
{
    /* Man, this was a bitch to do! */
    whio_size_t off;
    int rc = whio_rc.OK;
    WHIO_DEV_DECL(whio_rc.ArgError);
    if( len < 0 ) return whio_rc.ArgError;
    if( ! meta->rw ) return whio_rc.AccessError;
    off = (whio_size_t)len;
    if( off > len ) return whio_rc.RangeError; /* overflow */
    if( off == meta->inode->data_size ) return whefs_rc.OK;
    if( 0 == len )
    { /* special (simpler) case for 0 byte truncate */
	/* (WTF?) FIXME: update ino->blocks.list[0] */
        if( meta->inode->first_block ) 
        {
            whefs_block block = whefs_block_empty;
            rc = whefs_block_read( meta->fs, meta->inode->first_block, &block ); /* ensure we pick up whole block chain */
            if( whefs_rc.OK != rc )
            {
                rc = whefs_block_wipe( meta->fs, &block, true, true, true );
            }
            if( whefs_rc.OK != rc ) return rc;
        }
	meta->inode->blocks.count = 0;
	meta->inode->first_block = 0;
	meta->inode->data_size = 0;
	whefs_inode_flush(meta->fs, meta->inode );
	return whio_rc.OK;
    }
    else {
        /*const size_t oldSize = off>meta->inode->data_size; */
        whefs_block bl = whefs_block_empty;
        const short dir = (off < meta->inode->data_size)
            ? -1
            : ((off>meta->inode->data_size) ? 1 : 0);
        assert( (0 != off) && "This shouldn't be able to happen!" );

        /* Update inode metadata... */
        /*WHEFS_DBG("truncating from %u to %u bytes",meta->inode->data_size, off); */
        meta->inode->data_size = off;
        rc = whefs_inode_flush( meta->fs, meta->inode );
        if( whefs_rc.OK != rc )
        {
            WHEFS_DBG_ERR("Flush failed for inode #%u. Error code=%d.",
                          meta->inode->id, rc );
            return rc;
        }
        /* Update block info... */
        rc = whefs_block_for_pos( meta->fs, meta->inode, off-1, &bl, true );
        if( whefs_rc.OK != rc )
        {
            WHEFS_DBG_ERR("Could not get block for write position %u of inode #%u. Error code=%d.",
                          off, meta->inode->id, rc );
            return rc;
        }
        /*const size_t dest = meta->inode->data_size; */
        if( dir < 0 )
        { /* we shrunk */
#if 1
            /*
              We'll be nice and zero the remaining bytes... We do this
              partially for consistency with how blocks will get removed
              (they get wiped as well).  Theoretically we don't need this
              because they get wiped when created and when unlinked, but a
              failed unlink could leave data lying around, so we clean it
              here. Maybe we should consider a 'dirty' flag for blocks,
              wiping only dirty blocks, but that could get messy (no pun
              intended).
            */
            const uint32_t bs = whefs_fs_options_get( meta->fs )->block_size;
            whefs_block * blP;
            whefs_block * nblP;
            uint32_t x;
            rc = whefs_block_wipe_data( meta->fs, &bl, ( off % bs ) );
            if( whefs_rc.OK != rc ) return rc;
#endif
            if( ! bl.next_block )
            { /* Lucky for us! No more work to do! */
                meta->inode->blocks.count = 1;
                return whefs_rc.OK;
            }

            blP = &meta->inode->blocks.list[0];
            nblP = blP + 1;
            x = 1;
            for( ; (x < meta->inode->blocks.count)
                     && (nblP->id != bl.next_block)
                     ; ++nblP, ++x )
            {
                /* Skip to bl.next_block */
            }
            if( (x == meta->inode->blocks.count) || (nblP->id != bl.next_block) )
            {
                WHEFS_DBG_ERR("nblP->id=%u, bl.next_block=%u", nblP->id, bl.next_block );
                WHEFS_DBG_ERR("Internal block cache for inode #%u is not as "
                              "long as we expect it to be or is missing entries!",
                              meta->inode->id );
                return whefs_rc.InternalError;
            }
            blP = nblP - 1;
            meta->inode->blocks.count = x;
            whefs_block_wipe( meta->fs, nblP, true, true, true );
            blP->next_block = 0;
            return whefs_block_flush( meta->fs, blP );
        }
        else if( dir > 0 )
        { /* we grew - fill the new bytes with zeroes */
            /*
              Actually... since we zero these when shrinking and during mkfs(),
              we probably don't need to do this.
            */
            enum { bufSize = 1024 * 4 };
            unsigned char buf[bufSize];
            const whio_size_t PosAbs = meta->posabs;
            const whio_size_t orig = meta->inode->data_size;
            const whio_size_t dest = off;
            whio_size_t wlen, iorc, wsz;
            memset( buf, 0, bufSize );
            dev->api->seek( dev, orig, SEEK_SET );
            wlen = dest - orig;
            iorc = 0;
            wsz = 0;
            do
            {
                wsz = (wlen < bufSize) ? wlen : bufSize;
                iorc = dev->api->write( dev, buf, wsz );
                wlen -= iorc;
            }
            while( iorc && (iorc == wsz) );
            iorc = dev->api->seek( dev, PosAbs, SEEK_SET );
            return (iorc == PosAbs)
                ? whefs_rc.OK
                : whefs_rc.IOError;
        }
        else
        {
            /* cannot happen due to special-case handling of truncate(0), above. */
            assert( 0 && "This is impossible!" );
        }
        WHEFS_DBG("You should never have gotten to this line!");
        return whefs_rc.InternalError;
    }
}