btrfs_send_parse/
lib.rs

1extern crate byteorder;
2pub mod definitions;
3pub mod commands;
4use definitions::*;
5
6use std::io;
7use std::io::{Read, Cursor};
8use byteorder::{LittleEndian, ReadBytesExt};
9
10pub type Error = io::Error;
11pub type Result<T> = io::Result<T>;
12
13pub struct BtrfsReader<'a> {
14    r: &'a mut Read,
15    version: u32,
16}
17
18#[derive(Clone, Debug)]
19pub enum Command {
20    Unknown(commands::Unknown),
21    Subvol(commands::Subvol),
22    Snapshot(commands::Snapshot),
23    MkFile(commands::MkFile),
24    MkDir(commands::MkDir),
25    MkNod(commands::MkNod),
26    MkFifo(commands::MkFifo),
27    MkSock(commands::MkSock),
28    SymLink(commands::SymLink),
29    Rename(commands::Rename),
30    Link(commands::Link),
31    UnLink(commands::UnLink),
32    RmDir(commands::RmDir),
33    Write(commands::Write),
34    Clone(commands::Clone),
35    SetXattr(commands::SetXattr),
36    RemoveXattr(commands::RemoveXattr),
37    Truncate(commands::Truncate),
38    Chmod(commands::Chmod),
39    Chown(commands::Chown),
40    Utimes(commands::Utimes),
41    UpdateExtent(commands::UpdateExtent),
42    End(commands::End),
43}
44
45#[derive(Clone, Debug)]
46pub struct CommandHeader {
47    pub len: u32,
48    pub cmd: u16,
49    pub crc32: u32,
50}
51
52#[derive(Clone, Debug)]
53pub struct TLVData {
54    pub entries: Vec<TLVEntry>,
55}
56
57#[derive(Clone, Debug)]
58pub struct TLVEntry {
59    pub key: u16,
60    pub value: Vec<u8>,
61}
62
63pub const UUID_SIZE:usize = 16;
64#[derive(Clone, Debug, Copy, Default)]
65pub struct Uuid {
66    pub data: [u8; UUID_SIZE],
67}
68#[derive(Clone, Debug, Copy, Default)]
69pub struct Timespec {
70    pub sec: u64,
71    pub nsec: u32,
72}
73
74pub type BtrfsString = String;
75
76fn invalid_data<T>(err: &str) -> Result<T> {
77    return Err(io::Error::new(io::ErrorKind::InvalidData, err));
78}
79
80impl From<u16> for Cmd {
81	fn from(c: u16) -> Cmd{
82		unsafe {
83			std::mem::transmute_copy::<u16, Cmd>(&c)
84		}
85	}
86}
87
88impl From<u16> for Attr {
89	fn from(c: u16) -> Attr{
90		unsafe {
91			std::mem::transmute_copy::<u16, Attr>(&c)
92		}
93	}
94}
95
96impl TLVData {
97    pub fn get(&self, key: u16) -> Result<&Vec<u8>> {
98        for e in self.entries.iter() {
99            if e.key == key {
100                return Ok(&e.value)
101            }
102        }
103        invalid_data(&format!("item {} does not exist", key))
104    }
105    pub fn get_u8(&self, key: u16) -> Result<u8> {
106        match Cursor::new(try!(self.get(key)).clone()).bytes().next() {
107            None => Err(io::Error::from(io::ErrorKind::UnexpectedEof)),
108            Some(x) => x,
109        }
110    }
111    pub fn get_u16(&self, key: u16) -> Result<u16> {
112        Cursor::new(try!(self.get(key))).read_u16::<LittleEndian>()
113    }
114    pub fn get_u32(&self, key: u16) -> Result<u32> {
115        Cursor::new(try!(self.get(key))).read_u32::<LittleEndian>()
116    }
117    pub fn get_u64(&self, key: u16) -> Result<u64> {
118        Cursor::new(try!(self.get(key))).read_u64::<LittleEndian>()
119    }
120    pub fn get_string(&self, key: u16) -> Result<BtrfsString> {
121        // TODO: make the conversion function configurable
122        match String::from_utf8(try!(self.get(key)).clone()) {
123            Ok(x) => Ok(x),
124            Err(_   ) => invalid_data("utf-8 decoding problem"),
125        }
126    }
127    pub fn get_timespec(&self, key: u16) -> Result<Timespec> {
128        let mut r = Cursor::new(try!(self.get(key)));
129        Ok(Timespec {
130            sec: try!(r.read_u64::<LittleEndian>()),
131            nsec: try!(r.read_u32::<LittleEndian>()),
132        })
133    }
134    pub fn get_uuid(&self, key: u16) -> Result<Uuid> {
135        let data = try!(self.get(key));
136        let mut uuid = Uuid{data: [0u8; UUID_SIZE]};
137        try!(Cursor::new(data).read_exact(&mut uuid.data));
138        Ok(uuid)
139    }
140    pub fn uuid(&self) -> Result<Uuid> {
141        self.get_uuid(Attr::UUID as u16)
142    }
143    pub fn clone_uuid(&self) -> Result<Uuid> {
144        self.get_uuid(Attr::CLONE_UUID as u16)
145    }
146    pub fn path(&self) -> Result<BtrfsString> {
147        self.get_string(Attr::PATH as u16)
148    }
149    pub fn clone_path(&self) -> Result<BtrfsString> {
150        self.get_string(Attr::CLONE_PATH as u16)
151    }
152    pub fn path_link(&self) -> Result<BtrfsString> {
153        self.get_string(Attr::PATH_LINK as u16)
154    }
155    pub fn path_to(&self) -> Result<BtrfsString> {
156        self.get_string(Attr::PATH_TO as u16)
157    }
158    pub fn ctransid(&self) -> Result<u64> {
159        self.get_u64(Attr::CTRANSID as u16)
160    }
161    pub fn clone_ctransid(&self) -> Result<u64> {
162        self.get_u64(Attr::CLONE_CTRANSID as u16)
163    }
164    pub fn file_offset(&self) -> Result<u64> {
165        self.get_u64(Attr::FILE_OFFSET as u16)
166    }
167    pub fn clone_offset(&self) -> Result<u64> {
168        self.get_u64(Attr::CLONE_OFFSET as u16)
169    }
170    pub fn clone_len(&self) -> Result<u64> {
171        self.get_u64(Attr::CLONE_LEN as u16)
172    }
173    pub fn mode(&self) -> Result<u64> {
174        self.get_u64(Attr::MODE as u16)
175    }
176    pub fn uid(&self) -> Result<u64> {
177        self.get_u64(Attr::UID as u16)
178    }
179    pub fn gid(&self) -> Result<u64> {
180        self.get_u64(Attr::GID as u16)
181    }
182    pub fn rdev(&self) -> Result<u64> {
183        self.get_u64(Attr::RDEV as u16)
184    }
185    pub fn size(&self) -> Result<u64> {
186        self.get_u64(Attr::SIZE as u16)
187    }
188    pub fn data(&self) -> Result<&Vec<u8>> {
189        self.get(Attr::DATA as u16)
190    }
191    pub fn xattr_data(&self) -> Result<&Vec<u8>> {
192        self.get(Attr::XATTR_DATA as u16)
193    }
194    pub fn xattr_name(&self) -> Result<BtrfsString> {
195        self.get_string(Attr::XATTR_NAME as u16)
196    }
197    pub fn atime(&self) -> Result<Timespec> {
198        self.get_timespec(Attr::ATIME as u16)
199    }
200    pub fn mtime(&self) -> Result<Timespec> {
201        self.get_timespec(Attr::MTIME as u16)
202    }
203    pub fn ctime(&self) -> Result<Timespec> {
204        self.get_timespec(Attr::CTIME as u16)
205    }
206}
207
208/* Returns if eof was encountered on first read (true = eof) */
209fn read_exact_with_eof(r: &mut io::Read, buf: &mut [u8]) -> Result<bool>{
210    if buf.len() == 0 {
211        return Ok(false)
212    }
213    let size = try!(r.read(buf));
214    if size == 0 {
215        return Ok(true)
216    }
217    try!(r.read_exact(&mut buf[size..]));
218    Ok(false)
219}
220
221impl<'a> BtrfsReader<'a> {
222    pub fn new(r: &mut Read) -> Result<BtrfsReader> {
223        let mut magic_buf = [0u8; MAGIC_LEN];
224        try!(r.read_exact(&mut magic_buf));
225        if magic_buf != MAGIC.as_bytes() {
226            return invalid_data("btrfs stream header does not match");
227        }
228        let version = try!(r.read_u32::<LittleEndian>());
229        if version != 1 {
230            return invalid_data("unsupported btrfs stream version");
231        }
232        Ok(BtrfsReader{r: r, version: version})
233    }
234    pub fn version(&self) -> u32 {
235        self.version
236    }
237    pub fn read_command(&mut self) -> Result<Option<Command>> {
238        let cmd = try!(self.read_generic_command());
239        match cmd {
240            Some(cmd) => self.parse_command(cmd).map(|x| Some(x)),
241            None => Ok(None)
242        }
243    }
244    pub fn parse_command(&self, cmd: commands::Unknown) -> Result<Command> {
245        {
246            // println!("Parsing {}", cmd.header.cmd);
247            let t = &cmd.data;
248            match Cmd::from(cmd.header.cmd) {
249                Cmd::SUBVOL => return Ok(Command::Subvol(commands::Subvol {
250                    path: try!(t.path()),
251                    uuid: try!(t.uuid()),
252                    ctransid: try!(t.ctransid()),
253                })),
254                Cmd::SNAPSHOT => return Ok(Command::Snapshot(commands::Snapshot {
255                    path: try!(t.path()),
256                    uuid: try!(t.uuid()),
257                    ctransid: try!(t.ctransid()),
258                    clone_ctransid: try!(t.clone_ctransid()),
259                    clone_uuid: try!(t.clone_uuid()),
260                })),
261                Cmd::MKFILE => return Ok(Command::MkFile(commands::MkFile {
262                    path: try!(t.path()),
263                })),
264                Cmd::MKNOD => return Ok(Command::MkNod(commands::MkNod {
265                    path: try!(t.path()),
266                    mode: try!(t.mode()),
267                    rdev: try!(t.rdev()),
268                })),
269                Cmd::MKFIFO => return Ok(Command::MkFifo(commands::MkFifo {
270                    path: try!(t.path())
271                })),
272                Cmd::MKSOCK => return Ok(Command::MkSock(commands::MkSock {
273                    path: try!(t.path())
274                })),
275                Cmd::SYMLINK => return Ok(Command::SymLink(commands::SymLink {
276                    path: try!(t.path()),
277                    path_link: try!(t.path_link()),
278                })),
279                Cmd::RENAME => return Ok(Command::Rename(commands::Rename {
280                    path: try!(t.path()),
281                    path_to: try!(t.path_to()),
282                })),
283                Cmd::LINK => return Ok(Command::Link(commands::Link {
284                    path: try!(t.path()),
285                    path_link: try!(t.path_link()),
286                })),
287                Cmd::UNLINK => return Ok(Command::UnLink(commands::UnLink {
288                    path: try!(t.path()),
289                })),
290                Cmd::RMDIR => return Ok(Command::RmDir(commands::RmDir {
291                    path: try!(t.path()),
292                })),
293                Cmd::WRITE => return Ok(Command::Write(commands::Write {
294                    path: try!(t.path()),
295                    file_offset: try!(t.file_offset()),
296                    data: try!(t.data()).clone(),
297                })),
298                Cmd::CLONE => return Ok(Command::Clone(commands::Clone {
299                    path: try!(t.path()),
300                    file_offset: try!(t.file_offset()),
301                    clone_len: try!(t.clone_len()),
302                    clone_uuid: try!(t.uuid()),
303                    clone_ctransid: try!(t.clone_ctransid()),
304                    clone_path: try!(t.clone_path()),
305                    clone_offset: try!(t.clone_offset()),
306                })),
307                Cmd::SET_XATTR => return Ok(Command::SetXattr(commands::SetXattr {
308                    path: try!(t.path()),
309                    xattr_name: try!(t.xattr_name()),
310                    xattr_data: try!(t.xattr_data()).clone(),
311                })),
312                Cmd::REMOVE_XATTR => return Ok(Command::RemoveXattr(commands::RemoveXattr {
313                    path: try!(t.path()),
314                    xattr_name: try!(t.xattr_name()),
315                })),
316                Cmd::TRUNCATE => return Ok(Command::Truncate(commands::Truncate {
317                    path: try!(t.path()),
318                    size: try!(t.size()),
319                })),
320                Cmd::CHMOD => return Ok(Command::Chmod(commands::Chmod {
321                    path: try!(t.path()),
322                    mode: try!(t.mode()),
323                    
324                })),
325                Cmd::CHOWN => return Ok(Command::Chown(commands::Chown {
326                    path: try!(t.path()),
327                    uid: try!(t.uid()),
328                    gid: try!(t.gid()),
329                    
330                })),
331                Cmd::UTIMES => return Ok(Command::Utimes(commands::Utimes {
332                    path: try!(t.path()),
333                    atime: try!(t.atime()),
334                    mtime: try!(t.mtime()),
335                    ctime: try!(t.ctime()),
336                })),
337                Cmd::UPDATE_EXTENT => return Ok(Command::UpdateExtent(commands::UpdateExtent {
338                    path: try!(t.path()),
339                    file_offset: try!(t.file_offset()),
340                    size: try!(t.size()),
341                })),
342                Cmd::END => return Ok(Command::End(commands::End{})),
343                _ => {}
344            }
345        }
346        Ok(Command::Unknown(cmd))
347    }
348    pub fn read_generic_command(&mut self) -> Result<Option<commands::Unknown>> {
349        Ok(match try!(self.read_command_header()) {
350            Some(header) => Some(commands::Unknown {
351                header: header.clone(),
352                data: try!(self.read_tlvs(header.len)),
353            }),
354            None => None,
355        })  
356    }
357    pub fn read_command_header(&mut self) -> Result<Option<CommandHeader>> {
358        let mut len_buf = [0u8; 4];
359        let eof = try!(read_exact_with_eof(self.r, &mut len_buf))   ;
360        if eof {
361            return Ok(None)
362        }
363        Ok(Some(CommandHeader {
364            len: try!(Cursor::new(len_buf).read_u32::<LittleEndian>()),
365            cmd: try!(self.r.read_u16::<LittleEndian>()),
366            crc32: try!(self.r.read_u32::<LittleEndian>()),
367        }))
368    }
369    pub fn read_tlvs(&mut self, len_to_read: u32) -> Result<TLVData> {
370        let mut tlv_data = TLVData {entries:Vec::new()};
371        let mut remaining = len_to_read;
372        while remaining > 0 {
373            let key = try!(self.r.read_u16::<LittleEndian>());
374            let len = try!(self.r.read_u16::<LittleEndian>());
375            let mut data = vec![0; len as usize];
376            try!(self.r.read_exact(data.as_mut_slice()));
377            tlv_data.entries.push(TLVEntry{key: key, value: data});
378            remaining -= 2*2 + len as u32;
379        }
380        Ok(tlv_data)
381    }
382}
383
384pub struct CommandPrintOptions {
385}
386
387impl Default for CommandPrintOptions {
388    fn default() -> Self {
389        CommandPrintOptions {}
390    }
391}
392
393impl Command {
394    pub fn print(&self, f: &mut std::io::Write, _opts: &CommandPrintOptions) -> std::io::Result<()> {
395        match self {
396            Command::Write(w) => 
397                write!(f, "Write {{ path = {:?}, file_offset = {}, data_len = {} }}\n", w.path, w.file_offset, w.data.len()),   
398            _ => write!(f, "{:?}\n", self)
399        }
400    }
401}