예제 #1
0
static int whio_dev_inode_flush( whio_dev * dev )
{
    int rc;
    WHIO_DEV_DECL(whio_rc.ArgError);
    if(0) WHEFS_DBG_FYI("Flushing i/o %s device for inode #%"WHIO_SIZE_T_PFMT". "
			"inode->data_size=%"WHIO_SIZE_T_PFMT" posabs=%"WHIO_SIZE_T_PFMT,
			meta->rw ? "read/write" : "read-only", meta->inode->id,
			meta->inode->data_size, meta->posabs
			);
    rc = meta->rw
	? whefs_inode_flush( meta->fs, meta->inode )
	: whefs_rc.OK;
#if 0 /* having this decreases performance by 50% or so in my simple tests. */
    if( meta->rw )
    {
        whefs_fs_flush( meta->fs );
    }
#endif
    if(0) WHEFS_DBG_FYI("Flushed (rc=%d) i/o %s device for inode #%"WHEFS_ID_TYPE_PFMT". "
			"inode->data_size=%"WHIO_SIZE_T_PFMT" posabs=%"WHIO_SIZE_T_PFMT,
			rc, meta->rw ? "read/write" : "read-only", meta->inode->id,
			meta->inode->data_size, meta->posabs
			);
    return rc;
}
예제 #2
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;
}
예제 #3
0
whio_dev * whefs_dev_for_inode( whefs_fs * fs, whefs_id_type nid, bool writeMode )
{
    /*WHEFS_DBG("trying to open dev for inode #%u", nid ); */
    whio_dev * dev;
    whefs_inode * ino;
    void const * writeKey;
    int rc;
    whio_dev_inode_meta * meta;
    if( ! whefs_inode_id_is_valid( fs, nid ) ) return 0;
    dev = whio_dev_alloc();
    if( ! dev ) return 0;
    ino = NULL;
    writeKey = (writeMode ? dev : 0);
    rc = whefs_inode_open( fs, nid, &ino, writeKey );
    if( rc != whefs_rc.OK )
    {
	WHEFS_DBG_ERR("whefs_inode_open(fs,[inode #%"WHEFS_ID_TYPE_PFMT"],inode,%d) failed with rc %d!", nid, writeMode, rc );
	whio_dev_free( dev );
	return 0;
    }
    /*WHEFS_DBG("Opened inode #%u[%s]", ino->id, ino->name ); */
    meta = whio_dev_inode_meta_alloc();
    if( ! meta )
    {
	whefs_inode_close( fs, ino, writeKey );
	whio_dev_free(dev);
	return 0;
    }
    *dev = whio_dev_inode_empty;
    *meta = whio_dev_inode_meta_empty;
    dev->impl.data = meta;
    meta->fs = fs;
    meta->rw = writeMode;
    meta->bs = whefs_fs_options_get(fs)->block_size;
    meta->inode = ino;
#if 0
    if( writeMode )
    {
	whefs_inode_flush( fs, meta->inode ); /* make sure on-disk matches */
    }
#endif
    whefs_fs_closer_dev_add( fs, dev );
    return dev;
}
예제 #4
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;
    }
}
예제 #5
0
int whefs_import_dev( whefs_fs * fs, whio_dev * src, char const * fname, bool overwrite )
{
    int rc = whefs_rc.OK;
    whefs_inode ino = whefs_inode_empty;
    bool existed = false;
    whio_dev * imp;
    whio_size_t oldPos, szrc;
    size_t oldFSize, newFSize;
    if( ! fs || !src || !fname || !*fname ) return whefs_rc.ArgError;
    rc = whefs_inode_by_name( fs, fname, &ino );
    if( rc == whefs_rc.OK )
    {
	if( ! overwrite ) return whefs_rc.AccessError;
	existed = true;
    }
    else
    {
	rc = whefs_inode_next_free( fs, &ino, true );
	if( whefs_rc.OK != rc ) return rc;
	rc = whefs_inode_name_set( fs, ino.id, fname );
	if( whefs_rc.OK != rc ) return rc;
	whefs_inode_flush( fs, &ino );
    }
    imp = whefs_dev_for_inode( fs, ino.id, true );
    if( ! imp ) return whefs_rc.InternalError;
    oldPos = src->api->tell( src );
    szrc = src->api->seek( src, 0, SEEK_SET );
    if( whio_rc.SizeTError == szrc )
    {
	imp->api->finalize( imp );
	if( ! existed )
	{
	    whefs_inode_unlink( fs, &ino );
	}
	return whefs_rc.RangeError;
    }

    oldFSize = ino.data_size;
    newFSize = whio_dev_size( src );
    rc = imp->api->truncate( imp, newFSize );
    if( rc != whefs_rc.OK )
    {
	WHEFS_DBG_ERR("Could not truncate '%s' to %u bytes!", fname, newFSize );
	imp->api->truncate( imp, oldFSize );
	src->api->seek( src, oldPos, SEEK_SET );
	imp->api->finalize( imp );
	if( ! existed )
	{
	    whefs_inode_unlink( fs, &ino );
	}
	return rc;
    }
    imp->api->flush( imp );
    if( 0 == newFSize )
    {
	/*WHEFS_DBG("Importing 0-byte file."); */
	src->api->seek( src, oldPos, SEEK_SET );
	imp->api->finalize(imp);
	return whefs_rc.OK;
    }
    else {
        enum { bufSize = 1024 * 8 };
        unsigned char buf[bufSize];
        size_t impSize;
        size_t wlen = newFSize;
        size_t totalR = 0;
        size_t totalW = 0;
        size_t rrc = 0;
        size_t wrc = 0;
        memset( buf, 0, bufSize );
        imp->api->seek( imp, 0, SEEK_SET );
        do
        {
            rrc = src->api->read( src, buf, bufSize );
            totalR += rrc;
            if( ! rrc ) break;
            if( (wlen - rrc) > wlen )
            {
                WHEFS_DBG_ERR("Read an unexpected length (%u)! Continuing would cause an underflow!", rrc);
                break;
            }
            wlen -= rrc;
            wrc = imp->api->write( imp, buf, rrc );
            /*WHEFS_DBG("wrc=%u, rrc=%u, xoimp->tell=%u",wrc, rrc, imp->api->tell(imp)); */
            totalW += wrc;
            if( wrc != rrc ) break;
        }
        while( rrc && wrc );
        src->api->seek( src, oldPos, SEEK_SET );
        impSize = whio_dev_size( imp );
        imp->api->finalize(imp);
        imp = 0;
        
        rc = whefs_rc.OK;
        if( totalR != totalW )
        {
            WHEFS_DBG_ERR("Pseudofile [%s]: Total read bytes (%u) != total written bytes (%u)", fname, totalR, totalW );
            rc = whefs_rc.IOError;
        }
        else if( impSize != newFSize )
        {
            WHEFS_DBG_ERR("Pseudofile [%s]: Imported file size (%u) does not match the source's size (%u)", fname, totalR, totalW );
            rc = whefs_rc.IOError;
        }
        if( whefs_rc.OK != rc )
        {
            if( ! existed )
            {
                whefs_inode_unlink( fs, &ino );
            }
        }
        return rc;
    }
}