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 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
208fn 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 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}