Example #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;
}
Example #2
0
whefs_string * whefs_ls( whefs_fs * fs, char const * pattern, whefs_id_type * count  )
{
    /* FIXME: reimplement in terms of whefs_fs_entry_foreach(). */
    const whefs_id_type nc = whefs_fs_options_get(fs)->inode_count;
    whefs_id_type id = 2; /* ID 1 is reserved for root node entry. */
    int rc = whefs_rc.OK;
    whefs_string * head = 0;
    whefs_string * str = 0;
    whefs_string * prev = 0;
    whefs_string theString = whefs_string_empty;
    whefs_inode tmpn = whefs_inode_empty;
    if( ! fs ) return 0;
    if( count ) *count = 0;
    for( ; id <= nc; ++id )
    {
#if WHEFS_CONFIG_ENABLE_BITSET_CACHE
	if( fs->bits.i_loaded && !WHEFS_ICACHE_IS_USED(fs,id) )
	{
	    continue;
	}
	/*WHEFS_DBG("Cache says inode #%i is used.", i ); */
#endif
	rc = whefs_inode_name_get( fs, id, &theString );
	if( whefs_rc.OK != rc )
	{
	    WHEFS_DBG_ERR("whefs_inode_name_get() failed! rc=%d",rc);
	    whefs_string_clear( &theString, false );
	    return head;
	}
	if(0) WHEFS_DBG("Here. id=%"WHEFS_ID_TYPE_PFMT" str.len=%u str=[%s]",
			id, theString.length, theString.string);
	if( pattern && *pattern && !whglob_matches( pattern, theString.string ) )
	{
	    continue;
	}
        if(1)
        {/* make sure it's marked as used, or skip it */
#if 0
            uint32_t flagcheck = 0;
            whefs_inode_read_flags( fs, id, &flagcheck );
            if( ! (flagcheck & WHEFS_FLAG_Used) ) continue;
#else
            rc = whefs_inode_id_read( fs, id, &tmpn );
            if( whefs_rc.OK != rc ) break;
            if( ! (tmpn.flags & WHEFS_FLAG_Used) ) continue;
#endif
        }
	str = whefs_string_alloc();
	if( ! str ) return head;
	if( ! head ) head = str;
	*str = theString;
        theString = whefs_string_empty; /* take over ownership of theString.string */
	if( prev ) prev->next = str;
	prev = str;
	if( count ) ++(*count);
    }
    whefs_string_clear( &theString, false );
    return head;
}
Example #3
0
int whefs_inode_hash_cache( whefs_fs * fs, whefs_id_type id, char const * name )
{
    int rc = whefs_rc.OK;
    whefs_hashval_type h;
    whefs_hashid H;
    whefs_id_type ndx;
    if( ! WHEFS_FS_HASH_CACHE_IS_ENABLED(fs) )
    {
        return whefs_rc.OK;
    }
    if( ! fs || !name || !*name ) return whefs_rc.ArgError;
    if( ! fs->cache.hashes )
    {
        const whefs_id_type max = fs->options.inode_count;
        whefs_id_type dflt = 100/sizeof(whefs_hashid) /*for lack of a better default value.*/;
        if( dflt > max ) dflt = max;
        rc = whefs_hashid_list_alloc( &fs->cache.hashes, dflt );
        if( fs->cache.hashes )
        {
            fs->cache.hashes->maxAlloc = max;
        }
    }
    if( whefs_rc.OK != rc ) return rc;
    h = fs->cache.hashfunc( name );
#if 1
    ndx = whefs_hashid_list_index_of( fs->cache.hashes, h );
    if( whefs_rc.IDTypeEnd != ndx )
    {
        if(0) WHEFS_DBG("CHECKING: name cache count[%"WHEFS_ID_TYPE_PFMT"], alloced=[%"WHEFS_ID_TYPE_PFMT"], hash [%"WHEFS_HASHVAL_TYPE_PFMT"] for name [%s], ndx=[%"WHEFS_ID_TYPE_PFMT"]",
                        fs->cache.hashes->count, fs->cache.hashes->alloced, h, name, ndx );
        if( fs->cache.hashes->list[ndx].id == id ) return whefs_rc.OK;
        WHEFS_DBG_ERR("ERROR: name cache hash collision on hash code "
                      "%"WHEFS_HASHVAL_TYPE_PFMT" "
                      "between inodes #"
                      "%"WHEFS_ID_TYPE_PFMT
                      " and #%"WHEFS_ID_TYPE_PFMT"!",
                      h, id, ndx );
        return whefs_rc.InternalError;
    }
    WHEFS_DBG_CACHE("ADDING: name cache count[%"WHEFS_ID_TYPE_PFMT"], alloced=[%"WHEFS_ID_TYPE_PFMT"], hash [%"WHEFS_HASHVAL_TYPE_PFMT"] for name [%s]",
                          fs->cache.hashes->count, fs->cache.hashes->alloced, h, name );
#endif
    H = whefs_hashid_empty;
    H.hash = h;
    H.id = id;
    rc = whefs_hashid_list_add( fs->cache.hashes, &H );
    WHEFS_DBG_CACHE("Added to name cache: hash[%"WHEFS_HASHVAL_TYPE_PFMT"]=id[%"WHEFS_ID_TYPE_PFMT"], name=[%s], rc=%d", H.hash, H.id, name, rc );
    return whefs_rc.OK;
}
Example #4
0
int whefs_fs_stats_get( whefs_fs * fs, whefs_fs_stats * st )
{
    if( ! fs || ! st ) return whefs_rc.ArgError;
    WHEFS_DBG_ERR("NYI!");

    st->size = fs->filesize;
    /* FIXME: calculate used nodes. */
    st->used_inodes = 1; /* root node is always considered used. */
    /* FIXME: calculate used blocks */
    st->used_blocks = 0;
    /* FIXME: calculate used bytes */
    st->used_bytes = 0;

    return whefs_rc.OK;
}
Example #5
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;
}
Example #6
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;
    }
}
Example #7
0
/**
   Internal implementation of whio_dev_inode_read(). All arguments
   are as for whio_dev::read() except keepGoing:

   If this routine must "wrap" over multiple blocks, it will read what it
   can from one block and then set keepGoing to true and return the read
   size. The caller should, if keepGoing is true, call this function
   again, adding the returned size to dest and subtracting it from n.
*/
static whio_size_t whio_dev_inode_read_impl( whio_dev * dev,
					whio_dev_inode_meta * meta,
					void * dest,
					whio_size_t n,
					bool * keepGoing )
{
    int rc = 0;
    whefs_block block = whefs_block_empty;
#if 0
    if( ! dev || !meta || !dest || !n || ! keepGoing )
    {
	if( keepGoing ) *keepGoing = false;
	return 0;
    }
#endif
    *keepGoing = false;
    if( ! n ) return 0U;
    else if( meta->posabs >= meta->inode->data_size ) return 0;
    /*whio_size_t eofpos = meta->inode->data_size; */
    rc = whefs_block_for_pos( meta->fs, meta->inode, meta->posabs, &block, false );
    if( whefs_rc.OK != rc )
    {
#if 0
        if( !(meta->posabs % meta->fs->options.block_size) )
        {
            /* FIXME: ensure that meta->inode->blocks[end] is really the end block that should line up here. */
            /**
               This is an unusual special case. Directly at the EOF boundary we want to return
               a non-error code. We're at EOF. whefs_block_for_pos() isn't quite smart enough
               to know that, though.

               This fix should go in whefs_block_for_pos()
            */
            WHEFS_FIXME("Special-case block boundary story: inode #%"WHEFS_ID_TYPE_PFMT": error #%d getting block for meta->posabs=%u. n=%"WHIO_SIZE_T_PFMT", bs=%"WHIO_SIZE_T_PFMT", at end of the block chain.",
                        meta->inode->id, rc, meta->posabs, n, meta->fs->options.block_size );
            return 0;
        }
        else
        {
            WHEFS_DBG("Error #%d getting block for meta->posabs=%u. n=%"WHIO_SIZE_T_PFMT", bs=%"WHIO_SIZE_T_PFMT,
                      rc, meta->posabs, n, meta->fs->options.block_size );
            return 0;
        }
#else
        WHEFS_DBG("Error #%d getting block for meta->posabs=%u. n=%"WHIO_SIZE_T_PFMT", bs=%"WHIO_SIZE_T_PFMT,
                  rc, meta->posabs, n, meta->fs->options.block_size );
        return 0;
#endif
    }
    if(0) WHEFS_DBG("inode #%"WHEFS_ID_TYPE_PFMT" will be using block #%"WHEFS_ID_TYPE_PFMT" for a read at pos %"WHIO_SIZE_T_PFMT, meta->inode->id, block.id, meta->posabs );

    if( meta->posabs >= meta->inode->data_size ) return 0;
    else {
        const whio_size_t rdpos = (meta->posabs % meta->bs);
        const whio_size_t left = meta->bs - rdpos;
        const whio_size_t bdpos = whefs_block_data_pos( meta->fs, &block );
        whio_size_t rdlen = ( n > left ) ? left : n;
        whio_dev * fd;
        whio_size_t sz, szCheck;
        if( (rdlen + meta->posabs) >= meta->inode->data_size )
        {
            rdlen = meta->inode->data_size - meta->posabs;
        }
        /*WHEFS_DBG("rdpos=%u left=%u bdpos=%u rdlen=%u", rdpos, left, bdpos, rdlen ); */
        fd = meta->fs->dev;
        fd->api->seek( fd, bdpos + rdpos, SEEK_SET );
        sz = fd->api->read( fd, dest, rdlen );
        if( ! sz ) return 0;
        szCheck = meta->posabs + sz;
        if( szCheck > meta->posabs )
        {
            meta->posabs = szCheck;
        }
        else
        {
            WHEFS_DBG_ERR("Numeric overflow in read! (pos=%"WHIO_SIZE_T_PFMT" + readLength=%"WHIO_SIZE_T_PFMT") = overflow", meta->posabs, sz );
            return 0;
        }
        /*whefs_block_flush( meta->fs, &block ); */
        if(0) WHEFS_DBG("Read %"WHIO_SIZE_T_PFMT" of %"WHEFS_ID_TYPE_PFMT" (n=%"WHIO_SIZE_T_PFMT") bytes "
                        "from inode #%"WHEFS_ID_TYPE_PFMT"'s block #%"WHEFS_ID_TYPE_PFMT". "
                        "fs pos=%"WHIO_SIZE_T_PFMT", block offset=%"WHIO_SIZE_T_PFMT" file pos=%"WHIO_SIZE_T_PFMT", file eof=%"WHIO_SIZE_T_PFMT,
                        sz, rdlen, n,
                        meta->inode->id, block.id,
                        bdpos, rdpos, meta->posabs, meta->inode->data_size );
        if( sz < rdlen )
        { /* short write! */
            return sz;
        }
        else if( rdlen < n )
        { /* Wrap to next block and continue... */
            *keepGoing = true;
            return sz;
        }
        else
        { /* got the exact right amount */
            return sz;
        }
    }
}
Example #8
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;
    }
}