689 let nodes_len = nodes.len(); |
689 let nodes_len = nodes.len(); |
690 |
690 |
691 // First accumulate serialized nodes in a `Vec` |
691 // First accumulate serialized nodes in a `Vec` |
692 let mut on_disk_nodes = Vec::with_capacity(nodes_len); |
692 let mut on_disk_nodes = Vec::with_capacity(nodes_len); |
693 for node in nodes { |
693 for node in nodes { |
694 let children = |
694 let children = node.children(self.dirstate_map.on_disk)?; |
695 self.write_nodes(node.children(self.dirstate_map.on_disk)?)?; |
|
696 let full_path = node.full_path(self.dirstate_map.on_disk)?; |
695 let full_path = node.full_path(self.dirstate_map.on_disk)?; |
|
696 self.check_children(&children, full_path)?; |
|
697 |
|
698 let children = self.write_nodes(children)?; |
697 let full_path = self.write_path(full_path.as_bytes()); |
699 let full_path = self.write_path(full_path.as_bytes()); |
698 let copy_source = if let Some(source) = |
700 let copy_source = if let Some(source) = |
699 node.copy_source(self.dirstate_map.on_disk)? |
701 node.copy_source(self.dirstate_map.on_disk)? |
700 { |
702 { |
701 self.write_path(source.as_bytes()) |
703 self.write_path(source.as_bytes()) |
769 let len = child_nodes_len_from_usize(nodes_len); |
771 let len = child_nodes_len_from_usize(nodes_len); |
770 self.out.extend(on_disk_nodes.as_bytes()); |
772 self.out.extend(on_disk_nodes.as_bytes()); |
771 Ok(ChildNodes { start, len }) |
773 Ok(ChildNodes { start, len }) |
772 } |
774 } |
773 |
775 |
|
776 /// Catch some dirstate corruptions before writing them to disk |
|
777 fn check_children( |
|
778 &mut self, |
|
779 children: &dirstate_map::ChildNodesRef, |
|
780 full_path: &HgPath, |
|
781 ) -> Result<(), DirstateError> { |
|
782 for child in children.iter() { |
|
783 let child_full_path = |
|
784 child.full_path(self.dirstate_map.on_disk)?; |
|
785 |
|
786 let prefix_length = child_full_path.len() |
|
787 // remove the filename |
|
788 - child.base_name(self.dirstate_map.on_disk)?.len() |
|
789 // remove the slash |
|
790 - 1; |
|
791 |
|
792 let child_prefix = &child_full_path.as_bytes()[..prefix_length]; |
|
793 |
|
794 if child_prefix != full_path.as_bytes() { |
|
795 let explanation = format!( |
|
796 "dirstate child node's path '{}' \ |
|
797 does not start with its parent's path '{}'", |
|
798 child_full_path, full_path, |
|
799 ); |
|
800 |
|
801 return Err(HgError::corrupted(explanation).into()); |
|
802 } |
|
803 } |
|
804 Ok(()) |
|
805 } |
|
806 |
774 /// If the given slice of items is within `on_disk`, returns its offset |
807 /// If the given slice of items is within `on_disk`, returns its offset |
775 /// from the start of `on_disk`. |
808 /// from the start of `on_disk`. |
776 fn on_disk_offset_of<T>(&self, slice: &[T]) -> Option<Offset> |
809 fn on_disk_offset_of<T>(&self, slice: &[T]) -> Option<Offset> |
777 where |
810 where |
778 T: BytesCast, |
811 T: BytesCast, |