rust/hg-core/src/dirstate_tree/on_disk.rs
branchstable
changeset 49366 288de6f5d724
parent 49164 a932cad26d37
parent 49337 6cd249556e20
child 49373 f8ec7b16c98f
equal deleted inserted replaced
49364:e8ea403b1c46 49366:288de6f5d724
     1 //! The "version 2" disk representation of the dirstate
     1 //! The "version 2" disk representation of the dirstate
     2 //!
     2 //!
     3 //! See `mercurial/helptext/internals/dirstate-v2.txt`
     3 //! See `mercurial/helptext/internals/dirstate-v2.txt`
     4 
     4 
     5 use crate::dirstate::TruncatedTimestamp;
     5 use crate::dirstate::{DirstateV2Data, TruncatedTimestamp};
     6 use crate::dirstate_tree::dirstate_map::DirstateVersion;
     6 use crate::dirstate_tree::dirstate_map::DirstateVersion;
     7 use crate::dirstate_tree::dirstate_map::{self, DirstateMap, NodeRef};
     7 use crate::dirstate_tree::dirstate_map::{self, DirstateMap, NodeRef};
     8 use crate::dirstate_tree::path_with_basename::WithBasename;
     8 use crate::dirstate_tree::path_with_basename::WithBasename;
     9 use crate::errors::HgError;
     9 use crate::errors::HgError;
    10 use crate::utils::hg_path::HgPath;
    10 use crate::utils::hg_path::HgPath;
    83     ignore_patterns_hash: IgnorePatternsHash,
    83     ignore_patterns_hash: IgnorePatternsHash,
    84 }
    84 }
    85 
    85 
    86 /// Fields are documented in the *The data file format*
    86 /// Fields are documented in the *The data file format*
    87 /// section of `mercurial/helptext/internals/dirstate-v2.txt`
    87 /// section of `mercurial/helptext/internals/dirstate-v2.txt`
    88 #[derive(BytesCast)]
    88 #[derive(BytesCast, Debug)]
    89 #[repr(C)]
    89 #[repr(C)]
    90 pub(super) struct Node {
    90 pub(super) struct Node {
    91     full_path: PathSlice,
    91     full_path: PathSlice,
    92 
    92 
    93     /// In bytes from `self.full_path.start`
    93     /// In bytes from `self.full_path.start`
   123         const ALL_IGNORED_RECORDED = 1 <<15;
   123         const ALL_IGNORED_RECORDED = 1 <<15;
   124     }
   124     }
   125 }
   125 }
   126 
   126 
   127 /// Duration since the Unix epoch
   127 /// Duration since the Unix epoch
   128 #[derive(BytesCast, Copy, Clone)]
   128 #[derive(BytesCast, Copy, Clone, Debug)]
   129 #[repr(C)]
   129 #[repr(C)]
   130 struct PackedTruncatedTimestamp {
   130 struct PackedTruncatedTimestamp {
   131     truncated_seconds: U32Be,
   131     truncated_seconds: U32Be,
   132     nanoseconds: U32Be,
   132     nanoseconds: U32Be,
   133 }
   133 }
   151 /// of either some other node or of the repository root.
   151 /// of either some other node or of the repository root.
   152 ///
   152 ///
   153 /// Always sorted by ascending `full_path`, to allow binary search.
   153 /// Always sorted by ascending `full_path`, to allow binary search.
   154 /// Since nodes with the same parent nodes also have the same parent path,
   154 /// Since nodes with the same parent nodes also have the same parent path,
   155 /// only the `base_name`s need to be compared during binary search.
   155 /// only the `base_name`s need to be compared during binary search.
   156 #[derive(BytesCast, Copy, Clone)]
   156 #[derive(BytesCast, Copy, Clone, Debug)]
   157 #[repr(C)]
   157 #[repr(C)]
   158 struct ChildNodes {
   158 struct ChildNodes {
   159     start: Offset,
   159     start: Offset,
   160     len: Size,
   160     len: Size,
   161 }
   161 }
   162 
   162 
   163 /// A `HgPath` of `len` bytes
   163 /// A `HgPath` of `len` bytes
   164 #[derive(BytesCast, Copy, Clone)]
   164 #[derive(BytesCast, Copy, Clone, Debug)]
   165 #[repr(C)]
   165 #[repr(C)]
   166 struct PathSlice {
   166 struct PathSlice {
   167     start: Offset,
   167     start: Offset,
   168     len: PathSize,
   168     len: PathSize,
   169 }
   169 }
   415         Ok(m)
   415         Ok(m)
   416     }
   416     }
   417 
   417 
   418     fn assume_entry(&self) -> Result<DirstateEntry, DirstateV2ParseError> {
   418     fn assume_entry(&self) -> Result<DirstateEntry, DirstateV2ParseError> {
   419         // TODO: convert through raw bits instead?
   419         // TODO: convert through raw bits instead?
   420         let wdir_tracked = self.flags().contains(Flags::WDIR_TRACKED);
   420         let wc_tracked = self.flags().contains(Flags::WDIR_TRACKED);
   421         let p1_tracked = self.flags().contains(Flags::P1_TRACKED);
   421         let p1_tracked = self.flags().contains(Flags::P1_TRACKED);
   422         let p2_info = self.flags().contains(Flags::P2_INFO);
   422         let p2_info = self.flags().contains(Flags::P2_INFO);
   423         let mode_size = if self.flags().contains(Flags::HAS_MODE_AND_SIZE)
   423         let mode_size = if self.flags().contains(Flags::HAS_MODE_AND_SIZE)
   424             && !self.flags().contains(Flags::EXPECTED_STATE_IS_MODIFIED)
   424             && !self.flags().contains(Flags::EXPECTED_STATE_IS_MODIFIED)
   425         {
   425         {
   445             if self.flags().contains(Flags::HAS_FALLBACK_SYMLINK) {
   445             if self.flags().contains(Flags::HAS_FALLBACK_SYMLINK) {
   446                 Some(self.flags().contains(Flags::FALLBACK_SYMLINK))
   446                 Some(self.flags().contains(Flags::FALLBACK_SYMLINK))
   447             } else {
   447             } else {
   448                 None
   448                 None
   449             };
   449             };
   450         Ok(DirstateEntry::from_v2_data(
   450         Ok(DirstateEntry::from_v2_data(DirstateV2Data {
   451             wdir_tracked,
   451             wc_tracked,
   452             p1_tracked,
   452             p1_tracked,
   453             p2_info,
   453             p2_info,
   454             mode_size,
   454             mode_size,
   455             mtime,
   455             mtime,
   456             fallback_exec,
   456             fallback_exec,
   457             fallback_symlink,
   457             fallback_symlink,
   458         ))
   458         }))
   459     }
   459     }
   460 
   460 
   461     pub(super) fn entry(
   461     pub(super) fn entry(
   462         &self,
   462         &self,
   463     ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> {
   463     ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> {
   493     }
   493     }
   494 
   494 
   495     fn from_dirstate_entry(
   495     fn from_dirstate_entry(
   496         entry: &DirstateEntry,
   496         entry: &DirstateEntry,
   497     ) -> (Flags, U32Be, PackedTruncatedTimestamp) {
   497     ) -> (Flags, U32Be, PackedTruncatedTimestamp) {
   498         let (
   498         let DirstateV2Data {
   499             wdir_tracked,
   499             wc_tracked,
   500             p1_tracked,
   500             p1_tracked,
   501             p2_info,
   501             p2_info,
   502             mode_size_opt,
   502             mode_size: mode_size_opt,
   503             mtime_opt,
   503             mtime: mtime_opt,
   504             fallback_exec,
   504             fallback_exec,
   505             fallback_symlink,
   505             fallback_symlink,
   506         ) = entry.v2_data();
   506         } = entry.v2_data();
   507         // TODO: convert throug raw flag bits instead?
   507         // TODO: convert through raw flag bits instead?
   508         let mut flags = Flags::empty();
   508         let mut flags = Flags::empty();
   509         flags.set(Flags::WDIR_TRACKED, wdir_tracked);
   509         flags.set(Flags::WDIR_TRACKED, wc_tracked);
   510         flags.set(Flags::P1_TRACKED, p1_tracked);
   510         flags.set(Flags::P1_TRACKED, p1_tracked);
   511         flags.set(Flags::P2_INFO, p2_info);
   511         flags.set(Flags::P2_INFO, p2_info);
   512         let size = if let Some((m, s)) = mode_size_opt {
   512         let size = if let Some((m, s)) = mode_size_opt {
   513             let exec_perm = m & (libc::S_IXUSR as u32) != 0;
   513             let exec_perm = m & (libc::S_IXUSR as u32) != 0;
   514             let is_symlink = m & (libc::S_IFMT as u32) == libc::S_IFLNK as u32;
   514             let is_symlink = m & (libc::S_IFMT as u32) == libc::S_IFLNK as u32;
   590         nodes: ChildNodes,
   590         nodes: ChildNodes,
   591         f: &mut impl FnMut(&'on_disk HgPath),
   591         f: &mut impl FnMut(&'on_disk HgPath),
   592     ) -> Result<(), DirstateV2ParseError> {
   592     ) -> Result<(), DirstateV2ParseError> {
   593         for node in read_nodes(on_disk, nodes)? {
   593         for node in read_nodes(on_disk, nodes)? {
   594             if let Some(entry) = node.entry()? {
   594             if let Some(entry) = node.entry()? {
   595                 if entry.state().is_tracked() {
   595                 if entry.tracked() {
   596                     f(node.full_path(on_disk)?)
   596                     f(node.full_path(on_disk)?)
   597                 }
   597                 }
   598             }
   598             }
   599             recur(on_disk, node.children, f)?
   599             recur(on_disk, node.children, f)?
   600         }
   600         }