static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)

{

    BDRVSheepdogState *s = bs->opaque;

    BDRVSheepdogState *old_s;

    char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];

    char *buf = NULL;

    uint32_t vid;

    uint32_t snapid = 0;

    int ret = 0, fd;



    old_s = g_malloc(sizeof(BDRVSheepdogState));



    memcpy(old_s, s, sizeof(BDRVSheepdogState));



    pstrcpy(vdi, sizeof(vdi), s->name);



    snapid = strtoul(snapshot_id, NULL, 10);

    if (snapid) {

        tag[0] = 0;

    } else {

        pstrcpy(tag, sizeof(tag), s->name);

    }



    ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1);

    if (ret) {

        error_report("Failed to find_vdi_name");

        goto out;

    }



    fd = connect_to_sdog(s->addr, s->port);

    if (fd < 0) {

        error_report("failed to connect");

        ret = fd;

        goto out;

    }



    buf = g_malloc(SD_INODE_SIZE);

    ret = read_object(fd, buf, vid_to_vdi_oid(vid), s->inode.nr_copies,

                      SD_INODE_SIZE, 0, s->cache_enabled);



    closesocket(fd);



    if (ret) {

        goto out;

    }



    memcpy(&s->inode, buf, sizeof(s->inode));



    if (!s->inode.vm_state_size) {

        error_report("Invalid snapshot");

        ret = -ENOENT;

        goto out;

    }



    s->is_snapshot = true;



    g_free(buf);

    g_free(old_s);



    return 0;

out:

    /* recover bdrv_sd_state */

    memcpy(s, old_s, sizeof(BDRVSheepdogState));

    g_free(buf);

    g_free(old_s);



    error_report("failed to open. recover old bdrv_sd_state.");



    return ret;

}
