Example #1
0
/**
   Assumes ino is an opened inode and loads a block list cache for it.
   If !ino->first_block then this function does nothing but returns
   whefs_rc.OK, otherwise...

   For each block in the chain starting at ino->first_block,
   the block is loaded and appended to ino->blocks.list.

   On success ino->blocks.list contains ino->blocks.count
   whefs_block items representing ino's block chain. To add
   items to the list use whefs_inode_block_list_append().
   To remove them, change ino->blocks.count, empty out
   the now-unused entries, and update the on-disk blocks.

   ino->blocks.count should be 0 when this function is called. If not,
   it may emit a warning debug message but will return a success
   value.
*/
static int whefs_inode_block_list_load( whefs_fs * fs,
					whefs_inode * ino )
{
    if( ! whefs_inode_is_valid(fs,ino) ) return whefs_rc.ArgError;
    if( ! ino->first_block ) return whefs_rc.OK;
    if( ino->blocks.count )
    {
	WHEFS_DBG_WARN("this function shouldn't be called when ino->blocks.count is !0. inode=#%u",
		       ino->id);
	return whefs_rc.OK;
    }
    whefs_block bl = whefs_block_empty;
    int rc = whefs_block_read( fs, ino->first_block, &bl );
    if( whefs_rc.OK != rc ) return rc;
#if 0
    if( ! ino->blocks.list )
    {
	rc = whefs_inode_block_list_reserve( fs, ino, 5 /* arbitrarily chosen */ );
	if( whefs_rc.OK != rc ) return rc;
    }
#endif
    rc = whefs_inode_block_list_append( fs, ino, &bl );
    if( whefs_rc.OK != rc ) return rc;
    while( bl.next_block )
    {
	rc = whefs_block_read_next( fs, &bl, &bl );
	if( whefs_rc.OK != rc ) return rc;
        rc = whefs_inode_block_list_append( fs, ino, &bl );
	if( whefs_rc.OK != rc ) return rc;
    }
    //WHEFS_DBG("Loaded block chain of %u block(s) for inode #%u[%s].", ino->blocks.count, ino->id, ino->name );
    return whefs_rc.OK;
}
Example #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;
    }
}