Example #1
0
static inline void undo_rm_helper( entry_id_t * id, const char *last_known_path,
#ifdef _HSM_LITE
                             const char *bkpath
#endif
                             )
{
    entry_id_t new_id;
    recov_status_t st;
    attr_set_t     attrs, new_attrs;
    int rc;

    /* XXX src path must be in the same filesystem as backend
     * because it we be renamed */

    if ( EMPTY_STRING( last_known_path ) )
    {
        fprintf(stderr, "Last filesystem path is not known for fid "DFID", backend_path=%s.\n",
                PFID(id), bkpath);
        fprintf(stderr, " ----> skipped\n");
        return;
    }

    printf("Restoring '%s'...\n", last_known_path );

    ATTR_MASK_INIT(&attrs);
    ATTR_MASK_SET(&attrs, fullpath);
    strcpy( ATTR(&attrs, fullpath), last_known_path );

    if ( !EMPTY_STRING( bkpath ) )
    {
        ATTR_MASK_SET(&attrs, backendpath);
        strcpy( ATTR(&attrs, backendpath), bkpath );
    }

    /* copy file to Lustre */
    ATTR_MASK_INIT(&new_attrs);
    st = rbhext_recover( id, &attrs, &new_id, &new_attrs, NULL );
    if ((st == RS_FILE_OK) || (st == RS_FILE_DELTA)|| (st == RS_FILE_EMPTY)
        ||  (st == RS_NON_FILE))
    {
        printf("Success\n");
        /* discard entry from remove list */
        if ( ListMgr_SoftRemove_Discard(&lmgr, id) != 0 )
            fprintf(stderr, "Error: could not remove previous id "DFID" from database\n", PFID(id) );
        /* clean read-only attrs */
        new_attrs.attr_mask &= ~readonly_attr_set;
        /* insert or update it in the db */
        rc = ListMgr_Insert( &lmgr, &new_id, &new_attrs, TRUE );
        if ( rc == 0 )
            printf("Entry successfully updated in the dabatase\n");
        else
            fprintf(stderr, "ERROR %d inserting entry in the database\n", rc );
    }
    else
    {
        printf("ERROR\n");
    }
}
Example #2
0
int update_stripe_info(lmgr_t *p_mgr, PK_ARG_T pk, int validator,
                       const stripe_info_t *p_stripe,
                       const stripe_items_t *p_items, bool insert_if_absent)
{
    attr_set_t fake_attr;
    attr_set_t *p_attr = &fake_attr;
    pktype list[1];

    rh_strncpy(list[0], pk, sizeof(*list));

    ATTR_MASK_INIT(&fake_attr);
    if (p_stripe) {
        ATTR_MASK_SET(&fake_attr, stripe_info);
        ATTR(&fake_attr, stripe_info) = *p_stripe;
    }
    if (p_items) {
        ATTR_MASK_SET(&fake_attr, stripe_items);
        ATTR(&fake_attr, stripe_items) = *p_items;
    }

    return batch_insert_stripe_info(p_mgr, list, &validator, &p_attr, 1, true);
}
int EntryProc_db_flag_op( struct entry_proc_op_t *p_op, lmgr_t * lmgr )
{
    int            rc;

    /* insert to DB */
    switch ( p_op->db_op_type )
    {
        attr_set_t     attr_chg;
        lmgr_filter_t  filter;
        filter_value_t val;

    case OP_TYPE_UPDATE:
        /* set previous_scan flag */
        ATTR_MASK_INIT( &attr_chg );
        ATTR_MASK_SET( &attr_chg, previous_scan );
        ATTR( &attr_chg, previous_scan ) = TRUE;

        rc = ListMgr_MassUpdate( lmgr, NULL, &attr_chg );
        break;
    case OP_TYPE_REMOVE:
        val.val_bool = TRUE;
        lmgr_simple_filter_init( &filter );
        lmgr_simple_filter_add( &filter, ATTR_INDEX_previous_scan, EQUAL, val );

        /* remove entries with previous_scan flag */
        rc = ListMgr_MassRemove( lmgr, &filter );

        lmgr_simple_filter_free( &filter );
        break;
    default:
        printf( "unhandled\n" );
        rc = -1;
    }
    if ( rc )
        printf( "ERROR: ListMgr mass operation returned %d\n", rc );

    if ( p_op->callback_func )
        p_op->callback_func( lmgr, p_op, p_op->callback_param );

    rc = EntryProcessor_Acknowledge( p_op, 0, TRUE );

    return rc;
}
Example #4
0
/** retrieve directory attributes (nbr of entries, avg size of entries)*/
int listmgr_get_dirattrs( lmgr_t * p_mgr, PK_ARG_T dir_pk, attr_set_t * p_attrs )
{
    GString         *req;
    result_handle_t  result;
    char            *str_info[1];
    int              rc = 0;
    int              tmp_val;
    long long        tmp_long;

    if (ATTR_MASK_TEST(p_attrs, type) &&
        (strcmp(ATTR(p_attrs, type), STR_TYPE_DIR) != 0))
    {
        DisplayLog(LVL_FULL, LISTMGR_TAG,
                   "Type='%s' != 'dir' => unsetting dirattrs in attr mask",
                   ATTR(p_attrs, type));
        p_attrs->attr_mask = attr_mask_and_not(&p_attrs->attr_mask, &dir_attr_set);
        return 0;
    }

    req = g_string_new(NULL);

    /* get child entry count from DNAMES_TABLE */
    if (ATTR_MASK_TEST(p_attrs, dircount))
    {
        g_string_printf(req, "SELECT %s FROM "DNAMES_TABLE" WHERE parent_id="DPK,
                        dirattr2str(ATTR_INDEX_dircount), dir_pk);

        rc = db_exec_sql(&p_mgr->conn, req->str, &result);
        if (rc)
            goto free_str;

        rc = db_next_record(&p_mgr->conn, &result, str_info, 1);
        if (rc == DB_END_OF_LIST)
        {
            ATTR_MASK_UNSET(p_attrs, dircount);
            rc = DB_SUCCESS;
        }
        else if (rc == DB_SUCCESS)
        {
            if (str_info[0] == NULL)
                /* count(*) should at least return 0 */
                rc = DB_REQUEST_FAILED;
            else
            {
                tmp_val = str2int(str_info[0]);
                if (tmp_val != -1)
                {
                    ATTR_MASK_SET(p_attrs, dircount);
                    ATTR(p_attrs, dircount) = tmp_val;
                    rc = DB_SUCCESS;
                }
                else
                    /* invalid output format */
                    rc = DB_REQUEST_FAILED;
            }
        }
        db_result_free(&p_mgr->conn, &result);
        if (rc)
            goto free_str;
    }

    /* get avgsize of child entries from MAIN_TABLE */
    if (ATTR_MASK_TEST(p_attrs, avgsize))
    {
        g_string_printf(req, "SELECT %s FROM "MAIN_TABLE" m, "DNAMES_TABLE" d"
                        " WHERE m.id = d.id and type='file' and d.parent_id="DPK,
                        dirattr2str(ATTR_INDEX_avgsize), dir_pk);

        rc = db_exec_sql(&p_mgr->conn, req->str, &result);
        if (rc)
            goto free_str;

        rc = db_next_record(&p_mgr->conn, &result, str_info, 1);
        if (rc == DB_END_OF_LIST)
            ATTR_MASK_UNSET(p_attrs, avgsize);
        else if (rc == DB_SUCCESS)
        {
            if (str_info[0] == NULL)
            {
                /* NULL if no entry matches the criteria */
                ATTR_MASK_UNSET(p_attrs, avgsize);
                rc = DB_SUCCESS;
            }
            else
            {
                tmp_long = str2bigint(str_info[0]);
                if (tmp_long != -1LL)
                {
                    ATTR_MASK_SET(p_attrs, avgsize);
                    ATTR(p_attrs, avgsize) = tmp_long;
                    rc = DB_SUCCESS;
                }
                else
                    /* invalid output format */
                    rc = DB_REQUEST_FAILED;
            }
        }
        db_result_free(&p_mgr->conn, &result);
    }

free_str:
    g_string_free(req, TRUE);
    return rc;
}
Example #5
0
/**
 * Bulk filtering in the DB.
 */
static int list_bulk(void)
{
    attr_set_t  root_attrs, attrs;
    entry_id_t  root_id, id;
    int rc;
    struct stat st;
    struct lmgr_iterator_t *it;

    /* no tranvsersal => no wagon
     * so we need the path from the DB.
     */
    query_mask |= ATTR_MASK_fullpath;

    ATTR_MASK_INIT(&root_attrs);

    rc = retrieve_root_id(&root_id);
    if (rc)
        return rc;

    /* root is not a part of the DB: print it now */
    ATTR_MASK_SET(&root_attrs, fullpath);
    strcpy(ATTR(&root_attrs, fullpath), config.global_config.fs_path);

    if (lstat(ATTR(&root_attrs, fullpath), &st) == 0)
    {
        PosixStat2EntryAttr(&st, &root_attrs, TRUE);
        ListMgr_GenerateFields(&root_attrs, disp_mask | query_mask);
    }
    /* root has no name... */
    ATTR_MASK_SET(&root_attrs, name);
    ATTR(&root_attrs, name)[0] = '\0';

    /* match condition on dirs parent */
    if (!is_expr || (EntryMatches(&root_id, &root_attrs,
                     &match_expr, NULL) == POLICY_MATCH))
    {
        /* don't display dirs if no_dir is specified */
        if (! (prog_options.no_dir && ATTR_MASK_TEST(&root_attrs, type)
               && !strcasecmp(ATTR(&root_attrs, type), STR_TYPE_DIR))) {
            wagon_t w;
            w.id = root_id;
            w.fullname = ATTR(&root_attrs, fullpath);
            print_entry(&w, &root_attrs);
        }
    }

    /* list all, including dirs */
    it = ListMgr_Iterator(&lmgr, &entry_filter, NULL, NULL);
    if (!it)
    {
        DisplayLog(LVL_MAJOR, FIND_TAG, "ERROR: cannot retrieve entry list from database");
        return -1;
    }

    attrs.attr_mask = disp_mask | query_mask;
    while ((rc = ListMgr_GetNext(it, &id, &attrs)) == DB_SUCCESS)
    {
        if (!is_expr || (EntryMatches(&id, &attrs, &match_expr, NULL)
                                      == POLICY_MATCH))
        {
            /* don't display dirs if no_dir is specified */
            if (! (prog_options.no_dir && ATTR_MASK_TEST(&attrs, type)
                   && !strcasecmp(ATTR(&attrs, type), STR_TYPE_DIR))) {
                wagon_t w;
                w.id = id;
                w.fullname = ATTR(&attrs, fullpath);
                print_entry(&w, &attrs);
            }
            /* don't display non dirs is dir_only is specified */
            else if (! (prog_options.dir_only && ATTR_MASK_TEST(&attrs, type)
                        && strcasecmp(ATTR(&attrs, type), STR_TYPE_DIR))) {
                wagon_t w;
                w.id = id;
                w.fullname = ATTR(&attrs, fullpath);
                print_entry(&w, &attrs);
            }
            else
                /* return entry don't match? */
                DisplayLog(LVL_DEBUG, FIND_TAG, "Warning: returned DB entry doesn't match filter: %s",
                           ATTR(&attrs, fullpath));
        }
        ListMgr_FreeAttrs(&attrs);

        /* prepare next call */
        attrs.attr_mask = disp_mask | query_mask;
    }
    ListMgr_CloseIterator(it);

    return 0;
}
Example #6
0
/**
 * List contents of the given id/path list
 */
static int list_contents(char ** id_list, int id_count)
{
    wagon_t *ids;
    int i, rc;
    attr_set_t root_attrs;
    entry_id_t root_id;
    int is_id;

    rc = retrieve_root_id(&root_id);
    if (rc)
        return rc;

    ids = MemCalloc(id_count, sizeof(wagon_t));
    if (!ids)
        return -ENOMEM;

    for (i = 0; i < id_count; i++)
    {
        is_id = TRUE;
        /* is it a path or fid? */
        if (sscanf(id_list[i], SFID, RFID(&ids[i].id)) != FID_SCAN_CNT)
        {
            is_id = FALSE;
            /* take it as a path */
            rc = Path2Id(id_list[i], &ids[i].id);
            if (!rc) {
                ids[i].fullname = id_list[i];
                if (FINAL_SLASH(ids[i].fullname))
                    REMOVE_FINAL_SLASH(ids[i].fullname);
            }
        } else {
#if _HAVE_FID
            /* Take it as an FID. */
            char path[RBH_PATH_MAX];
            rc = Lustre_GetFullPath( &ids[i].id, path, sizeof(path));
            if (!rc)
                ids[i].fullname = strdup(path);
#endif
        }

        if (rc) {
            DisplayLog(LVL_MAJOR, FIND_TAG, "Invalid parameter: %s: %s",
                       id_list[i], strerror(-rc));
            goto out;
        }

        if ((prog_options.bulk != force_nobulk) &&
            (id_count == 1) && entry_id_equal(&ids[i].id, &root_id))
        {
            /* the ID is FS root: use list_bulk instead */
            DisplayLog(LVL_DEBUG, FIND_TAG, "Optimization: switching to bulk DB request mode");
            mkfilters(FALSE); /* keep dirs */
            MemFree(ids);
            return list_bulk();
        }

        /* get root attrs to print it (if it matches program options) */
        root_attrs.attr_mask = disp_mask | query_mask;
        rc = ListMgr_Get(&lmgr, &ids[i].id, &root_attrs);
        if (rc == 0)
            dircb(&ids[i], &root_attrs, 1, NULL);
        else
        {
            DisplayLog(LVL_VERB, FIND_TAG, "Notice: no attrs in DB for %s", id_list[i]);

            if (!is_id)
            {
                struct stat st;
                ATTR_MASK_SET(&root_attrs, fullpath);
                strcpy(ATTR(&root_attrs, fullpath), id_list[i]);

                if (lstat(ATTR(&root_attrs, fullpath ), &st) == 0)
                {
                    PosixStat2EntryAttr(&st, &root_attrs, TRUE);
                    ListMgr_GenerateFields( &root_attrs, disp_mask | query_mask);
                }
            }
            else if (entry_id_equal(&ids[i].id, &root_id))
            {
                /* this is root id */
                struct stat st;
                ATTR_MASK_SET(&root_attrs, fullpath);
                strcpy(ATTR(&root_attrs, fullpath), config.global_config.fs_path);

                if (lstat(ATTR(&root_attrs, fullpath ), &st) == 0)
                {
                    PosixStat2EntryAttr(&st, &root_attrs, TRUE);
                    ListMgr_GenerateFields( &root_attrs, disp_mask | query_mask);
                }
            }

            dircb(&ids[i], &root_attrs, 1, NULL);
        }

        rc = rbh_scrub(&lmgr, &ids[i], 1, disp_mask | query_mask, dircb, NULL);
    }

out:
    /* ids have been processed, free them */
    MemFree(ids);
    return rc;
}
Example #7
0
void PosixStat2EntryAttr( struct stat *p_inode, attr_set_t * p_attr_set, int size_info )
{
    ATTR_MASK_SET( p_attr_set, owner );
    uid2str( p_inode->st_uid, ATTR( p_attr_set, owner ) );

    ATTR_MASK_SET( p_attr_set, gr_name );
    gid2str( p_inode->st_gid, ATTR( p_attr_set, gr_name ) );

    if ( size_info )
    {
        ATTR_MASK_SET( p_attr_set, size );
        ATTR( p_attr_set, size ) = p_inode->st_size;

        ATTR_MASK_SET( p_attr_set, blocks );
        ATTR( p_attr_set, blocks ) = p_inode->st_blocks;

#ifdef ATTR_INDEX_blksize
        ATTR_MASK_SET( p_attr_set, blksize );
        ATTR( p_attr_set, blksize ) = p_inode->st_blksize;
#endif
    }

    ATTR_MASK_SET( p_attr_set, last_access );
    ATTR( p_attr_set, last_access ) =
        MAX3( p_inode->st_atime, p_inode->st_mtime, p_inode->st_ctime );

    ATTR_MASK_SET( p_attr_set, last_mod );
    /* @TODO is this really what we want? */
#if defined(_SHERPA) || defined(_HSM_LITE)
    ATTR( p_attr_set, last_mod ) = p_inode->st_mtime;
#else
    ATTR( p_attr_set, last_mod ) = MAX2( p_inode->st_mtime, p_inode->st_ctime );
#endif

#ifdef ATTR_INDEX_type
    if ( S_ISREG( p_inode->st_mode ) )
    {
        ATTR_MASK_SET( p_attr_set, type );
        strcpy( ATTR( p_attr_set, type ), STR_TYPE_FILE );
    }
    else if ( S_ISDIR( p_inode->st_mode ) )
    {
        ATTR_MASK_SET( p_attr_set, type );
        strcpy( ATTR( p_attr_set, type ), STR_TYPE_DIR );
    }
    else if ( S_ISCHR( p_inode->st_mode ) )
    {
        ATTR_MASK_SET( p_attr_set, type );
        strcpy( ATTR( p_attr_set, type ), STR_TYPE_CHR );
    }
    else if ( S_ISBLK( p_inode->st_mode ) )
    {
        ATTR_MASK_SET( p_attr_set, type );
        strcpy( ATTR( p_attr_set, type ), STR_TYPE_BLK );
    }
    else if ( S_ISFIFO( p_inode->st_mode ) )
    {
        ATTR_MASK_SET( p_attr_set, type );
        strcpy( ATTR( p_attr_set, type ), STR_TYPE_FIFO );
    }
    else if ( S_ISLNK( p_inode->st_mode ) )
    {
        ATTR_MASK_SET( p_attr_set, type );
        strcpy( ATTR( p_attr_set, type ), STR_TYPE_LINK );
    }
    else if ( S_ISSOCK( p_inode->st_mode ) )
    {
        ATTR_MASK_SET( p_attr_set, type );
        strcpy( ATTR( p_attr_set, type ), STR_TYPE_SOCK );
    }
#endif

#ifdef ATTR_INDEX_nlink
    ATTR_MASK_SET( p_attr_set, nlink );
    ATTR( p_attr_set, nlink ) = p_inode->st_nlink;
#endif
}
Example #8
0
/**
 * check if the entry exists in the database and what info
 * must be retrieved.
 */
int EntryProc_get_info_db( struct entry_proc_op_t *p_op, lmgr_t * lmgr )
{
    int      rc = 0;
    int      next_stage = -1; /* -1 = skip */
    attr_mask_t attr_allow_cached = null_mask;
    attr_mask_t attr_need_fresh = null_mask;
    uint32_t status_scope = 0; /* status mask only */
    attr_mask_t tmp;

    const pipeline_stage_t *stage_info =
        &entry_proc_pipeline[p_op->pipeline_stage];

    /* check if entry is in policies scope */
    add_matching_scopes_mask(&p_op->entry_id, &p_op->fs_attrs, true,
                             &status_scope);

    /* XXX also retrieve needed attributes to check the scope? */

    /* get diff attributes from DB and FS (to allow comparison) */
    p_op->db_attr_need = attr_mask_or(&p_op->db_attr_need, &diff_mask);

    tmp = attr_mask_and_not(&diff_mask, &p_op->fs_attrs.attr_mask);
    p_op->fs_attr_need = attr_mask_or(&p_op->fs_attr_need, &tmp);

    if (entry_proc_conf.detect_fake_mtime)
        attr_mask_set_index(&p_op->db_attr_need, ATTR_INDEX_creation_time);

    attr_allow_cached = attrs_for_status_mask(status_scope, false);
    attr_need_fresh = attrs_for_status_mask(status_scope, true);
    /* XXX check if entry is in policy scope? */

    /* what must be retrieved from DB: */
    tmp = attr_mask_and_not(&attr_allow_cached, &p_op->fs_attrs.attr_mask);
    p_op->db_attr_need = attr_mask_or(&p_op->db_attr_need, &tmp);

    /* no dircount for non-dirs */
    if (ATTR_MASK_TEST(&p_op->fs_attrs, type) &&
        !strcmp(ATTR(&p_op->fs_attrs, type), STR_TYPE_DIR))
    {
        attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_dircount);
    }

    /* no readlink for non symlinks */
    if (ATTR_MASK_TEST(&p_op->fs_attrs, type)) /* likely */
    {
        if (!strcmp(ATTR(&p_op->fs_attrs, type), STR_TYPE_LINK))
        {
            attr_mask_set_index(&p_op->db_attr_need, ATTR_INDEX_link); /* check if it is known */
            /* no stripe for symlinks */
            attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_stripe_info);
            attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_stripe_items);
        }
        else
            attr_mask_unset_index(&p_op->db_attr_need, ATTR_INDEX_link);
    }

    if (!attr_mask_is_null(p_op->db_attr_need))
    {
        p_op->db_attrs.attr_mask = p_op->db_attr_need;
        rc = ListMgr_Get(lmgr, &p_op->entry_id, &p_op->db_attrs);

        if (rc == DB_SUCCESS)
        {
            p_op->db_exists = 1;
        }
        else if (rc == DB_NOT_EXISTS )
        {
            p_op->db_exists = 0;
            ATTR_MASK_INIT( &p_op->db_attrs );
        }
        else
        {
            /* ERROR */
            DisplayLog(LVL_CRIT, ENTRYPROC_TAG,
                       "Error %d retrieving entry "DFID" from DB: %s.", rc,
                       PFID(&p_op->entry_id), lmgr_err2str(rc));
            p_op->db_exists = 0;
            ATTR_MASK_INIT( &p_op->db_attrs );
        }
    }
    else
    {
        p_op->db_exists = ListMgr_Exists( lmgr, &p_op->entry_id );
    }

    /* get status for all policies with a matching scope */
    add_matching_scopes_mask(&p_op->entry_id, &p_op->fs_attrs, true,
                             &p_op->fs_attr_need.status);
    tmp = attr_mask_and_not(&attr_need_fresh, &p_op->fs_attrs.attr_mask);
    p_op->fs_attr_need = attr_mask_or(&p_op->fs_attr_need, &tmp);

    if ( !p_op->db_exists )
    {
        /* new entry */
        p_op->db_op_type = OP_TYPE_INSERT;

        /* set creation time if it was not set by scan module */
        if (!ATTR_MASK_TEST(&p_op->fs_attrs, creation_time))
        {
            ATTR_MASK_SET( &p_op->fs_attrs, creation_time );
            ATTR( &p_op->fs_attrs, creation_time ) = time(NULL); /* XXX min(atime,mtime,ctime)? */
        }

#ifdef _LUSTRE
        if (ATTR_MASK_TEST(&p_op->fs_attrs, type)
            && !strcmp(ATTR( &p_op->fs_attrs, type ), STR_TYPE_FILE )
                /* only if it was not retrieved during the scan */
                && !(ATTR_MASK_TEST(&p_op->fs_attrs, stripe_info)
                    && ATTR_MASK_TEST(&p_op->fs_attrs, stripe_items)))
        {
            attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_stripe_info);
            attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_stripe_items);
        }
#endif

        /* readlink for symlinks (if not already known) */
        if (ATTR_MASK_TEST(&p_op->fs_attrs, type)
            && !strcmp(ATTR( &p_op->fs_attrs, type ), STR_TYPE_LINK)
            && !ATTR_MASK_TEST(&p_op->fs_attrs, link))
        {
            attr_mask_set_index(&p_op->fs_attr_need, ATTR_INDEX_link);
        }
        else
        {
            attr_mask_unset_index(&p_op->fs_attr_need, ATTR_INDEX_link);
        }

#ifdef ATTR_INDEX_status /** @FIXME RBHv3 drop old-style status reference */
        if (ATTR_MASK_TEST(&p_op->fs_attrs, type)
#ifdef _LUSTRE_HSM
            && !strcmp( ATTR(&p_op->fs_attrs, type), STR_TYPE_FILE ))
#elif defined (_HSM_LITE)
            && (strcmp( ATTR(&p_op->fs_attrs, type), STR_TYPE_DIR ) != 0)
            && !p_op->extra_info.not_supp)
#endif
        {
            p_op->fs_attr_need |= ATTR_MASK_status;
#ifdef _HSM_LITE
            p_op->fs_attr_need |= (attr_need_fresh & ~p_op->fs_attrs.attr_mask);
#endif
        }
        else
        {
Example #9
0
static inline int rebind_helper(const char *old_bk_id,
                                const char *new_bk_id,
                                const char *new_path,
                                const char *new_fid_str)
{
    int rc;
    attr_set_t old_attrs = ATTR_SET_INIT;
    attr_set_t new_attrs = ATTR_SET_INIT;
    entry_id_t new_fid;
    entry_id_t old_fid;
    bool old_fid_set = false;
    char *tmp;

    /* full path required */
    tmp = realpath(new_path, NULL);
    if (tmp == NULL) {
        rc = -errno;
        DisplayLog(LVL_CRIT, LOGTAG, "Error in realpath(%s): %s",
                   new_path, strerror(-rc));
        return rc;
    }
    if (strlen(tmp) >= RBH_PATH_MAX) {
        DisplayLog(LVL_CRIT, LOGTAG, "Path length is too long!");
        return -ENAMETOOLONG;
    }
    /* safe because of previous check */
    strcpy(ATTR(&new_attrs, fullpath), tmp);
    ATTR_MASK_SET(&new_attrs, fullpath);
    strcpy(ATTR(&old_attrs, fullpath), tmp);
    ATTR_MASK_SET(&old_attrs, fullpath);
    /* now we can free tmp path */
    free(tmp);

    if ((new_fid_str != NULL) && !EMPTY_STRING(new_fid_str))
        rc = read_fid(new_fid_str, &new_fid);
    else
        /* get fid for the given file */
        rc = Path2Id(new_path, &new_fid);

    if (rc)
        return rc;

    printf("Rebinding '%s' (" DFID ") from '%s' to '%s'...\n", new_path,
           PFID(&new_fid), old_bk_id, new_bk_id);

    /* parse old/new bk ids and set attr accordingly */
    if (parse_bk_id(&old_attrs, old_bk_id, &old_fid, &old_fid_set))
        return -EINVAL;
    if (parse_bk_id(&new_attrs, new_bk_id, &new_fid, NULL))
        return -EINVAL;

    /* rebind is like undelete with 'already recovered = true' */
    rc = smi->sm->undelete_func(smi, old_fid_set ? &old_fid : NULL,
                                &old_attrs, &new_fid, &new_attrs,
                                true);
    fprintf(stderr, "Rebind status for '%s': %s\n", ATTR(&new_attrs, fullpath),
            recov_status2str(rc));
    if (rc == RS_NOBACKUP || rc == RS_ERROR)
        return -1;
    return 0;
}