rev: 466e0f40365e rug/revlogs/src/main.rs -rw-r--r-- 3.7 KiB View raw Log this file
466e0f40365eNathan Goldbaum genericize to allow for more kinds of revlog content 4 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use byteorder::{BigEndian, ReadBytesExt};
use flate2::read::ZlibDecoder;
use std::fmt;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::io::Cursor;
use std::io::SeekFrom;

#[derive(Debug)]
struct RevlogHeader {
    offset: u64, // really 6 bytes but easier to represent as a u32
    bitflags: [u8; 2],
    compressedlength: u32,
    uncompressedlength: u32,
    baserev: i32,
    linkrev: i32,
    p1rev: i32,
    p2rev: i32,
    hash: [u8; 32],
}

impl RevlogHeader {
    fn new(buffer: &[u8; 64]) -> Result<RevlogHeader, io::Error> {
        let mut cursor = Cursor::new(buffer as &[u8]);
        Ok(RevlogHeader {
            offset: cursor.read_u48::<BigEndian>()? as u64,
            bitflags: cursor.read_u16::<BigEndian>()?.to_be_bytes(),
            compressedlength: cursor.read_u32::<BigEndian>()?,
            uncompressedlength: cursor.read_u32::<BigEndian>()?,
            baserev: cursor.read_i32::<BigEndian>()?,
            linkrev: cursor.read_i32::<BigEndian>()?,
            p1rev: cursor.read_i32::<BigEndian>()?,
            p2rev: cursor.read_i32::<BigEndian>()?,
            hash: {
                let mut res = [0u8; 32];
                cursor.read_exact(&mut res)?;
                res
            },
        })
    }
}

#[derive(Debug)]
struct RevlogEntry {
    header: RevlogHeader,
    content: RevlogContent,
}

#[derive(Debug)]
enum RevlogContent {
    Generic(String),
}

impl RevlogEntry {
    fn new(f: &mut File) -> Result<RevlogEntry, io::Error> {
        let mut header_buffer = [0u8; 64];
        let pos = (*f).seek(SeekFrom::Current(0))?;
        f.read_exact(&mut header_buffer)?;
        if pos == 0 {
            for i in 0..4 {
                header_buffer[i] = 0;
            }
        }
        let header = RevlogHeader::new(&header_buffer)?;
        let mut zlib_buffer = vec![0u8; header.compressedlength as usize];
        f.read_exact(&mut zlib_buffer)?;
        Ok(RevlogEntry {
            header: header,
            content: {
                let mut gz = ZlibDecoder::new(&zlib_buffer[..]);
                let mut decompressed_data = String::new();
                gz.read_to_string(&mut decompressed_data)?;
                RevlogContent::Generic(decompressed_data)
            },
        })
    }
}

impl fmt::Display for RevlogHeader {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let hash: Vec<String> = self.hash.iter().map(|b| format!("{:02x}", b)).collect();
        write!(
            f,
            "offset: {}\n\
             bitflags: {:?}\n\
             compressed length: {}\n\
             uncompressed length: {}\n\
             base revision: {}\n\
             linked revision: {}\n\
             p1: {}\n\
             p2: {}\n\
             hash: {}\n",
            self.offset,
            self.bitflags,
            self.compressedlength,
            self.uncompressedlength,
            self.baserev,
            self.linkrev,
            self.p1rev,
            self.p2rev,
            hash.join("")
        )
    }
}

impl fmt::Display for RevlogEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "header:\n{}\ncontent: {}\n", self.header, self.content)
    }
}

impl fmt::Display for RevlogContent {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let printable = match self {
            RevlogContent::Generic(s) => s,
        };
        write!(f, "{}", printable)
    }
}

fn main() -> std::io::Result<()> {
    let fname = "/home/goldbaum/Documents/test-repository/.hg/store/00changelog.i";

    // open file
    let mut f = File::open(fname)?;

    loop {
        let rev = match RevlogEntry::new(&mut f) {
            Ok(revlog) => revlog,
            Err(_) => break,
        };

        println!("{}", rev);
    }

    Ok(())
}