ssdb leveldb ldb文件恢复 ext4magic extundelete

数据库 专栏收录该内容
17 篇文章 0 订阅

因为误操作,rm -rf 删掉了盘里的全部文件, 使用 ext4magic /dev/sdb1 -M -d /backup 恢复文件。

wget ftp://ftp.pbone.net/mirror/ftp5.gwdg.de/pub/opensuse/repositories/home:/robi-1/CentOS_CentOS-6/x86_64/ext4magic-0.3.1-1.2.x86_64.rpm
rpm -ivh ext4magic-0.3.1-1.2.x86_64.rpm

wget https://downloads.sourceforge.net/project/extundelete/extundelete/0.2.4/extundelete-0.2.4.tar.bz2
tar -xjf extundelete-0.2.4.tar.bz2 && cd extundelete*
./configure
make && make install 

有个ssdb 数据库,恢复后启动提示 259 file missed. 同时提示了文件名, touch 建立这样一个空文件,按照提示,建立了200多个空文件,结果ssdb能启动了,可以get hget hscan,但是数据会不完全,赶紧把数据到走。

ext4magic 的恢复效果比 extundelete 能恢复出更多文件。ext4magic 除了按照原目录结构恢复出来了,还恢复出来了100多个 32M 的未知文件名的文件,从大小看,应该是 leveldb的一个 sst 文件。

花了大量时间研究leveldb的文件数据结构,试图自己写程序能够导出单个sst里面的数据。后来找到 https://antimatter15.com/2015/12/recovering-deleted-data-from-leveldb/

按照 http://blog.csdn.net/gold2008/article/details/69948892 安装 go 语言环境

go get github.com/golang/leveldb
cd /root/go/src/github.com/golang/leveldb/cmd/ldbdump
go build -o ldbdump main.go
cp ldbdump /usr/bin/

然后 ldbdump xxxxxx.ldb > raw.file 可以发现 raw.file 里面是明文字符了,但是如果原来的数据含有中文或者二进制内容,那么导出文件不好用php处理,于是对 main.go 进行了一点修改:

package main

import (
        "bytes"
        "flag"
        "fmt"
        "os"
"encoding/base64"

        "github.com/golang/leveldb/db"
        "github.com/golang/leveldb/table"
)

var (
        verifyChecksums = flag.Bool("c", false, "Verify checksums.")
        truncate        = flag.Bool("t", false, "Truncate long keys and values.")

        kBuf, vBuf bytes.Buffer
)

func main() {
        flag.Parse()
        bad := false
        for i, arg := range flag.Args() {
                if i != 0 {
                        fmt.Println()
                }
                //fmt.Printf("filename: %q\n", arg)
                if err := dump(arg); err != nil {
                        fmt.Printf("error: %q\n", err)
                        bad = true
                }
        }
        if bad {
                os.Exit(1)
        }
}
func byteString(p []byte) string {
        for i := 0; i < len(p); i++ {
                if p[i] == 0 {
                        return string(p[0:i])
                }
        }
        return string(p)
}

func dump(filename string) error {
        f, err := os.Open(filename)
        if err != nil {
                return err
        }
        // No need to "defer f.Close()", as closing r will close f.
        r := table.NewReader(f, &db.Options{
                VerifyChecksums: *verifyChecksums,
        })
        defer r.Close()

        t := r.Find(nil, nil)
        for t.Next() {
                k, v := t.Key(), t.Value()
                if *truncate {
                        k = trunc(&kBuf, k)
                        v = trunc(&vBuf, v)
                }
enc := base64.StdEncoding.EncodeToString([]byte(v))
                fmt.Printf("%q\t%v\n", k, enc)
        }
        return t.Close()
}

func trunc(dst *bytes.Buffer, b []byte) []byte {
        if len(b) < 64 {
                return b
        }
        dst.Reset()
        fmt.Fprintf(dst, "%s...(%d bytes)...%s", b[:20], len(b)-40, b[len(b)-20:])
        return dst.Bytes()
}

这样导出文件里面就是一行行的了,value 是 base64 编码的,用php可以直接处理。 ssdb 把hash 存入leveldb的时候,key是按照 h\thash=key\x 这样的格式存的,可以很容易提取出 hash 名和 key。这样又恢复 了一部分数据。整个过程花费了大量时间,以后都要在另一台电脑搞备份了,免得再有这样的灾难。

  • 1
    点赞
  • 3
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

评论 3 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

gold2008

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值