libpijul_compat/backend/
file_header.rs

1/// File metadata, essentially flags to indicate permissions and
2/// nature of a file tracked by Pijul.
3#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
4pub struct FileMetadata(u16);
5const DIR_BIT: u16 = 0x200;
6use byteorder::ByteOrder;
7impl FileMetadata {
8    /// Read the file metadata from the file name encoded in the
9    /// repository.
10    pub fn from_contents(p: &[u8]) -> Self {
11        debug_assert!(p.len() == 2);
12        FileMetadata(BigEndian::read_u16(p))
13    }
14
15    /// Create a new file metadata with the given Unix permissions,
16    /// and "is directory" bit.
17    pub fn new(perm: usize, is_dir: bool) -> Self {
18        let mut m = FileMetadata(0);
19        m.set_permissions(perm as u16);
20        if is_dir {
21            m.set_dir()
22        } else {
23            m.unset_dir()
24        }
25        m
26    }
27
28    /// Permissions of this file (as in Unix).
29    pub fn permissions(&self) -> u16 {
30        u16::from_le(self.0) & 0x1ff
31    }
32
33    /// Set permissions of this file to the supplied parameters.
34    pub fn set_permissions(&mut self, perm: u16) {
35        let bits = u16::from_le(self.0);
36        let perm = (bits & !0x1ff) | perm;
37        self.0 = perm.to_le()
38    }
39
40    /// Tell whether this `FileMetadata` is a directory.
41    pub fn is_dir(&self) -> bool {
42        u16::from_le(self.0) & DIR_BIT != 0
43    }
44
45    /// Set this file metadata to be a directory.
46    pub fn set_dir(&mut self) {
47        let bits = u16::from_le(self.0);
48        self.0 = (bits | DIR_BIT).to_le()
49    }
50
51    /// Set this file metadata to be a file.
52    pub fn unset_dir(&mut self) {
53        let bits = u16::from_le(self.0);
54        self.0 = (bits & !DIR_BIT).to_le()
55    }
56}
57
58use byteorder::{BigEndian, WriteBytesExt};
59
60pub trait WriteMetadata: std::io::Write {
61    fn write_metadata(&mut self, m: FileMetadata) -> std::io::Result<()> {
62        self.write_u16::<BigEndian>(m.0)
63    }
64}
65impl<W: std::io::Write> WriteMetadata for W {}
66
67use super::key::*;
68use super::patch_id::*;
69use sanakirja::{Alignment, Representable};
70use std;
71#[repr(u8)]
72#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
73pub enum FileStatus {
74    Ok = 0,
75    Moved = 1,
76    Deleted = 2,
77    Zombie = 3,
78}
79
80// Warning: FileMetadata is 16 bit-aligned, don't change the order.
81#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
82pub struct FileHeader {
83    pub metadata: FileMetadata,
84    pub status: FileStatus,
85    pub key: Key<PatchId>,
86}
87
88#[test]
89fn test_fileheader_alignment() {
90    assert_eq!(std::mem::size_of::<FileHeader>(), 2 + 1 + 16)
91}
92
93impl Representable for FileHeader {
94    fn alignment() -> Alignment {
95        Alignment::B1
96    }
97    fn onpage_size(&self) -> u16 {
98        std::mem::size_of::<FileHeader>() as u16
99    }
100    unsafe fn write_value(&self, p: *mut u8) {
101        let meta = self.metadata.0;
102        *p = (meta & 255) as u8;
103        *(p.offset(1)) = (meta >> 8) as u8;
104        *(p.offset(2)) = self.status as u8;
105        self.key.write_value(p.offset(3))
106    }
107    unsafe fn read_value(p: *const u8) -> Self {
108        let metadata = {
109            let x0 = (*p) as u16;
110            let x1 = (*(p.offset(1))) as u16;
111            std::mem::transmute((x1 << 8) | x0)
112        };
113        let status = std::mem::transmute(*(p.offset(2)));
114        let key: Key<PatchId> = Representable::read_value(p.offset(3));
115        FileHeader {
116            metadata,
117            status,
118            key,
119        }
120    }
121    unsafe fn cmp_value<T>(&self, _: &T, x: Self) -> std::cmp::Ordering {
122        self.cmp(&x)
123    }
124    type PageOffsets = std::iter::Empty<u64>;
125    fn page_offsets(&self) -> Self::PageOffsets {
126        std::iter::empty()
127    }
128}