bool env_universal_t::move_new_vars_file_into_place(const wcstring &src, const wcstring &dst)
{
    int ret = wrename(src, dst);
    if (ret != 0)
    {
        int err = errno;
        report_error(err, L"Unable to rename file from '%ls' to '%ls'", src.c_str(), dst.c_str());
    }
    return ret == 0;
}
bool env_universal_t::load()
{
    scoped_lock locker(lock);
    callback_data_list_t callbacks;
    const wcstring vars_path = explicit_vars_path.empty() ? default_vars_path() : explicit_vars_path;
    bool success = load_from_path(vars_path, &callbacks);
    if (! success && ! tried_renaming && errno == ENOENT)
    {
        /* We failed to load, because the file was not found. Older fish used the hostname only. Try *moving* the filename based on the hostname into place; if that succeeds try again. Silently "upgraded." */
        tried_renaming = true;
        std::string hostname_id;
        if (get_hostname_identifier(&hostname_id))
        {
            const wcstring hostname_path = wdirname(vars_path) + L'/' + str2wcstring(hostname_id);
            if (0 == wrename(hostname_path, vars_path))
            {
                /* We renamed - try again */
                success = this->load();
            }
        }
    }
    return success;
}
Beispiel #3
0
/** Save the specified mode to file */
void history_t::save_internal()
{
    /* This must be called while locked */
    ASSERT_IS_LOCKED(lock);
    
    /* Nothing to do if there's no new items */
    if (new_items.empty() && deleted_items.empty())
        return;
        
    /* Compact our new items so we don't have duplicates */
    this->compact_new_items();
    
	bool ok = true;
    
    wcstring tmp_name = history_filename(name, L".tmp");    
	if( ! tmp_name.empty() )
	{        
        /* Make an LRU cache to save only the last N elements */
        history_lru_cache_t lru(HISTORY_SAVE_MAX);
        
        /* Insert old items in, from old to new. Merge them with our new items, inserting items with earlier timestamps first. */
        std::vector<history_item_t>::const_iterator new_item_iter = new_items.begin();
        
        /* Map in existing items (which may have changed out from underneath us, so don't trust our old mmap'd data) */
        const char *local_mmap_start = NULL;
        size_t local_mmap_size = 0;
        if (map_file(name, &local_mmap_start, &local_mmap_size)) {
            size_t cursor = 0;
            for (;;) {
                size_t offset = offset_of_next_item(local_mmap_start, local_mmap_size, &cursor, 0);
                /* If we get back -1, we're done */
                if (offset == (size_t)(-1))
                    break;

                /* Try decoding an old item */
                const history_item_t old_item = history_t::decode_item(local_mmap_start + offset, local_mmap_size - offset);
                if (old_item.empty() || is_deleted(old_item))
                {
//                    debug(0, L"Item is deleted : %s\n", old_item.str().c_str());
                    continue;
                }
                /* The old item may actually be more recent than our new item, if it came from another session. Insert all new items at the given index with an earlier timestamp. */
                for (; new_item_iter != new_items.end(); ++new_item_iter) {
                    if (new_item_iter->timestamp() < old_item.timestamp()) {
                        /* This "new item" is in fact older. */
                        lru.add_item(*new_item_iter);
                    } else {
                        /* The new item is not older. */
                        break;
                    }
                }
                
                /* Now add this old item */
                lru.add_item(old_item);
            }
            munmap((void *)local_mmap_start, local_mmap_size);
        }
        
        /* Insert any remaining new items */
        for (; new_item_iter != new_items.end(); ++new_item_iter)
        {
            lru.add_item(*new_item_iter);
        }
                
        signal_block();
    
        FILE *out;
		if( (out=wfopen( tmp_name, "w" ) ) )
		{
            /* Write them out */
            for (history_lru_cache_t::iterator iter = lru.begin(); iter != lru.end(); ++iter) {
                const history_lru_node_t *node = *iter;
                if (! node->write_yaml_to_file(out)) {
                    ok = false;
                    break;
                }
            }
            
			if( fclose( out ) || !ok )
			{
				/*
				  This message does not have high enough priority to
				  be shown by default.
				*/
				debug( 2, L"Error when writing history file" );
			}
			else
			{
                wcstring new_name = history_filename(name, wcstring());
				wrename(tmp_name, new_name);
			}
		}
        
        signal_unblock();
        
        /* Make sure we clear all nodes, since this doesn't happen automatically */
        lru.evict_all_nodes();
        
        /* We've saved everything, so we have no more unsaved items */
        unsaved_item_count = 0;
	}	

	if( ok )
	{
		/* Our history has been written to the file, so clear our state so we can re-reference the file. */
		this->clear_file_state();
	}
}
Beispiel #4
0
/**
   Save the specified mode to file
*/
static void history_save_mode( void *n, history_mode_t *m )
{
    FILE *out;
    history_mode_t *on_disk;
    int i;
    int has_new=0;
    wchar_t *tmp_name;

    int ok = 1;

    /*
      First check if there are any new entries to save. If not, then
      we can just return
    */
    for( i=0; i<al_get_count(&m->item); i++ )
    {
        void *ptr = al_get( &m->item, i );
        has_new = item_is_new( m, ptr );
        if( has_new )
        {
            break;
        }
    }

    if( !has_new )
    {
        return;
    }

    signal_block();

    /*
      Set up on_disk variable to describe the current contents of the
      history file
    */
    on_disk = history_create_mode( m->name );
    history_load( on_disk );

    tmp_name = history_filename( on_disk, m->name, L".tmp" );

    if( tmp_name )
    {
        tmp_name = wcsdup(tmp_name );

        if( (out=wfopen( tmp_name, "w" ) ) )
        {
            hash_table_t mine;

            hash_init( &mine, &hash_item_func, &hash_item_cmp );

            for( i=0; i<al_get_count(&m->item); i++ )
            {
                void *ptr = al_get( &m->item, i );
                int is_new = item_is_new( m, ptr );
                if( is_new )
                {
                    hash_put( &mine, item_get( m, ptr ), L"" );
                }
            }

            /*
              Re-save the old history
            */
            for( i=0; ok && (i<al_get_count(&on_disk->item)); i++ )
            {
                void *ptr = al_get( &on_disk->item, i );
                item_t *i = item_get( on_disk, ptr );
                if( !hash_get( &mine, i ) )
                {
                    if( item_write( out, on_disk, ptr ) == -1 )
                    {
                        ok = 0;
                        break;
                    }
                }

            }

            hash_destroy( &mine );

            /*
              Add our own items last
            */
            for( i=0; ok && (i<al_get_count(&m->item)); i++ )
            {
                void *ptr = al_get( &m->item, i );
                int is_new = item_is_new( m, ptr );
                if( is_new )
                {
                    if( item_write( out, m, ptr ) == -1 )
                    {
                        ok = 0;
                    }
                }
            }

            if( fclose( out ) || !ok )
            {
                /*
                  This message does not have high enough priority to
                  be shown by default.
                */
                debug( 2, L"Error when writing history file" );
            }
            else
            {
                wrename( tmp_name, history_filename( on_disk, m->name, 0 ) );
            }
        }
        free( tmp_name );
    }

    halloc_free( on_disk);

    if( ok )
    {

        /*
          Reset the history. The item_t entries created in this session
          are not lost or dropped, they are stored in the session_item
          hash table. On reload, they will be automatically inserted at
          the end of the history list.
        */

        if( m->mmap_start && (m->mmap_start != MAP_FAILED ) )
        {
            munmap( m->mmap_start, m->mmap_length );
        }

        al_truncate( &m->item, 0 );
        al_truncate( &m->used, 0 );
        m->pos = 0;
        m->has_loaded = 0;
        m->mmap_start=0;
        m->mmap_length=0;

        m->save_timestamp=time(0);
        m->new_count = 0;
    }

    signal_unblock();
}