1#![allow(dead_code)]
2mod crc;
3mod header;
4mod header_tests;
5mod metadata;
6mod metadata_tests;
7mod tests;
8
9pub use self::header::Header;
10pub use self::metadata::make_distribution_string;
11pub use self::metadata::make_too_much_meta_err_string;
12pub use self::metadata::Metadata;
13pub use self::metadata::MetadataID;
14
15use smallvec::SmallVec;
16
17pub fn meta_to_meta_id(meta: &Metadata) -> MetadataID {
18 self::metadata::meta_to_id(meta)
19}
20
21pub fn meta_id_to_str(id: MetadataID) -> &'static str {
22 self::metadata::id_to_str(id)
23}
24
25pub fn get_meta_ref_by_meta_id(metas: &[Metadata], id: MetadataID) -> Option<&Metadata> {
26 self::metadata::get_meta_ref_by_id(metas, id)
27}
28
29pub fn get_meta_ref_mut_by_meta_id(
30 metas: &mut [Metadata],
31 id: MetadataID,
32) -> Option<&mut Metadata> {
33 self::metadata::get_meta_ref_mut_by_id(metas, id)
34}
35
36use self::crc::*;
37use crate::sbx_specs::{
38 ver_to_block_size, ver_to_data_size, ver_uses_rs, Version, SBX_FILE_UID_LEN,
39 SBX_FIRST_DATA_SEQ_NUM, SBX_HEADER_SIZE,
40};
41
42use crate::multihash;
43
44macro_rules! make_meta_getter {
45 (
46 $func_name:ident => $meta_id:ident => ret_ref $ret_type:ty
47 ) => {
48 #[allow(non_snake_case)]
49 pub fn $func_name (&self) -> Result<Option<&$ret_type>, Error> {
50 match self.get_meta_ref_by_id(MetadataID::$meta_id)? {
51 None => Ok(None),
52 Some(Metadata::$meta_id(x)) => Ok(Some(x)),
53 _ => unreachable!(),
54 }
55 }
56 };
57 (
58 $func_name:ident => $meta_id:ident => ret_val $ret_type:ty
59 ) => {
60 #[allow(non_snake_case)]
61 pub fn $func_name (&self) -> Result<Option<$ret_type>, Error> {
62 match self.get_meta_ref_by_id(MetadataID::$meta_id)? {
63 None => Ok(None),
64 Some(&Metadata::$meta_id(x)) => Ok(Some(x)),
65 _ => panic!(),
66 }
67 }
68 };
69}
70
71macro_rules! check_ver_consistent_with_opt {
72 (
73 $version:expr, $val:expr
74 ) => {{
75 match $val {
76 None => assert!(!ver_uses_rs($version)),
77 Some(_) => assert!(ver_uses_rs($version)),
78 }
79 }};
80}
81
82#[derive(Clone, Copy, Debug, PartialEq)]
83pub enum BlockType {
84 Data,
85 Meta,
86}
87
88#[derive(Clone, Debug, PartialEq)]
89pub enum Error {
90 IncorrectBlockType,
91 IncorrectBufferSize,
92 TooMuchMetadata(Vec<Metadata>),
93 InvalidCRC,
94 SeqNumOverflow,
95 ParseError,
96 FailedPred,
97}
98
99#[derive(Clone, Debug, PartialEq)]
100pub enum Data {
101 Data,
102 Meta(Vec<Metadata>),
103}
104
105#[derive(Clone, Debug, PartialEq)]
106pub struct Block {
107 header: Header,
108 data: Data,
109}
110
111macro_rules! slice_buf {
112 (
113 whole => $self:ident, $buf:ident
114 ) => {
115 &$buf[..block_size!($self)]
116 };
117 (
118 whole_mut => $self:ident, $buf:ident
119 ) => {
120 &mut $buf[..block_size!($self)]
121 };
122 (
123 header => $self:ident, $buf:ident
124 ) => {
125 &$buf[..SBX_HEADER_SIZE]
126 };
127 (
128 header_mut => $self:ident, $buf:ident
129 ) => {
130 &mut $buf[..SBX_HEADER_SIZE]
131 };
132 (
133 data => $self:ident, $buf:ident
134 ) => {
135 &$buf[SBX_HEADER_SIZE..block_size!($self)]
136 };
137 (
138 data_mut => $self:ident, $buf:ident
139 ) => {
140 &mut $buf[SBX_HEADER_SIZE..block_size!($self)]
141 };
142}
143
144macro_rules! check_buffer {
145 (
146 $self:ident, $buf:ident
147 ) => {
148 if $buf.len() < block_size!($self) {
149 panic!("Insufficient buffer size");
150 }
151 };
152}
153
154macro_rules! block_size {
155 (
156 $self:ident
157 ) => {
158 ver_to_block_size($self.header.version)
159 };
160}
161
162pub fn write_padding(version: Version, skip: usize, buffer: &mut [u8]) -> usize {
171 let block_size = ver_to_block_size(version);
172 let start = SBX_HEADER_SIZE + skip;
173
174 for i in start..block_size {
175 buffer[i] = 0x1A;
176 }
177
178 block_size - start
179}
180
181pub fn slice_buf(version: Version, buffer: &[u8]) -> &[u8] {
182 &buffer[..ver_to_block_size(version)]
183}
184
185pub fn slice_buf_mut(version: Version, buffer: &mut [u8]) -> &mut [u8] {
186 &mut buffer[..ver_to_block_size(version)]
187}
188
189pub fn slice_header_buf(buffer: &[u8]) -> &[u8] {
190 &buffer[..SBX_HEADER_SIZE]
191}
192
193pub fn slice_header_buf_mut(buffer: &mut [u8]) -> &mut [u8] {
194 &mut buffer[..SBX_HEADER_SIZE]
195}
196
197pub fn slice_data_buf(version: Version, buffer: &[u8]) -> &[u8] {
198 &buffer[SBX_HEADER_SIZE..ver_to_block_size(version)]
199}
200
201pub fn slice_data_buf_mut(version: Version, buffer: &mut [u8]) -> &mut [u8] {
202 &mut buffer[SBX_HEADER_SIZE..ver_to_block_size(version)]
203}
204
205pub fn check_if_buffer_valid(buffer: &[u8]) -> bool {
206 let mut block = Block::new(Version::V1, b"\x00\x00\x00\x00\x00\x00", BlockType::Data);
207
208 match block.sync_from_buffer(buffer, None, None) {
209 Ok(()) => {}
210 Err(_) => {
211 return false;
212 }
213 }
214
215 block.verify_crc(buffer).unwrap()
216}
217
218pub fn seq_num_is_meta(seq_num: u32) -> bool {
219 seq_num == 0
220}
221
222pub fn seq_num_is_parity(seq_num: u32, data_shards: usize, parity_shards: usize) -> bool {
223 if seq_num == 0 {
224 false } else {
226 let index = seq_num - SBX_FIRST_DATA_SEQ_NUM as u32;
228 let index_in_set = index % (data_shards + parity_shards) as u32;
229
230 (data_shards as u32 <= index_in_set)
231 }
232}
233
234pub fn seq_num_is_parity_w_data_par_burst(
235 seq_num: u32,
236 data_par_burst: Option<(usize, usize, usize)>,
237) -> bool {
238 match data_par_burst {
239 Some((data, parity, _)) => seq_num_is_parity(seq_num, data, parity),
240 None => false,
241 }
242}
243
244pub fn calc_meta_block_dup_write_pos_s(
245 version: Version,
246 data_par_burst: Option<(usize, usize, usize)>,
247) -> SmallVec<[u64; 32]> {
248 check_ver_consistent_with_opt!(version, data_par_burst);
249
250 let block_size = ver_to_block_size(version) as u64;
251
252 let mut res = calc_meta_block_dup_write_indices(data_par_burst);
253
254 for i in res.iter_mut() {
255 *i = *i * block_size;
256 }
257
258 res
259}
260
261pub fn calc_meta_block_dup_write_indices(
262 data_par_burst: Option<(usize, usize, usize)>,
263) -> SmallVec<[u64; 32]> {
264 match data_par_burst {
265 Some((_, parity, burst)) => {
266 let mut res: SmallVec<[u64; 32]> = SmallVec::with_capacity(1 + parity);
267
268 for i in 1..1 + parity as u64 {
269 res.push(i * (1 + burst) as u64);
270 }
271
272 res
273 }
274 None => SmallVec::new(),
275 }
276}
277
278pub fn calc_meta_block_all_write_pos_s(
279 version: Version,
280 data_par_burst: Option<(usize, usize, usize)>,
281) -> SmallVec<[u64; 32]> {
282 let mut res = calc_meta_block_dup_write_pos_s(version, data_par_burst);
283
284 res.push(0);
285
286 res.sort();
287
288 res
289}
290
291pub fn calc_meta_block_all_write_indices(
292 data_par_burst: Option<(usize, usize, usize)>,
293) -> SmallVec<[u64; 32]> {
294 let mut res = calc_meta_block_dup_write_indices(data_par_burst);
295
296 res.push(0);
297
298 res.sort();
299
300 res
301}
302
303pub fn calc_data_block_write_pos(
304 version: Version,
305 seq_num: u32,
306 meta_enabled: Option<bool>,
307 data_par_burst: Option<(usize, usize, usize)>,
308) -> u64 {
309 check_ver_consistent_with_opt!(version, data_par_burst);
310
311 let block_size = ver_to_block_size(version) as u64;
312
313 calc_data_block_write_index(seq_num, meta_enabled, data_par_burst) * block_size
314}
315
316pub fn calc_data_block_write_index(
317 seq_num: u32,
318 meta_enabled: Option<bool>,
319 data_par_burst: Option<(usize, usize, usize)>,
320) -> u64 {
321 assert!(seq_num >= SBX_FIRST_DATA_SEQ_NUM);
324
325 let index = (seq_num - SBX_FIRST_DATA_SEQ_NUM) as u64;
327
328 match data_par_burst {
329 None => {
330 let meta_enabled = meta_enabled.unwrap_or(true);
331
332 if meta_enabled {
333 SBX_FIRST_DATA_SEQ_NUM as u64 + index
334 } else {
335 index
336 }
337 }
338 Some((data, parity, burst)) => {
339 shadow_to_avoid_use!(meta_enabled);
340
341 if burst == 0 {
342 let meta_block_count = 1 + parity as u64;
343
344 return meta_block_count + index;
345 }
346
347 let data_shards = data as u64;
348 let parity_shards = parity as u64;
349 let burst_err_resistance = burst as u64;
350
351 let super_block_set_size = (data_shards + parity_shards) * burst_err_resistance;
352
353 let sub_a_block_set_size = data_shards + parity_shards;
364 let sub_b_block_set_size = burst_err_resistance;
365
366 let super_block_set_index = index / super_block_set_size;
369 let index_in_super_block_set = index % super_block_set_size;
371
372 let sub_a_block_set_index = index_in_super_block_set / sub_a_block_set_size;
375 let index_in_sub_a_block_set = index_in_super_block_set % sub_a_block_set_size;
377
378 let sub_b_block_set_index = index_in_sub_a_block_set;
379 let index_in_sub_b_block_set = sub_a_block_set_index;
380
381 let new_index_in_super_block_set =
382 sub_b_block_set_index * sub_b_block_set_size + index_in_sub_b_block_set;
383
384 let meta_block_count = if super_block_set_index == 0 {
390 if sub_b_block_set_index < 1 + parity_shards {
393 1 + sub_b_block_set_index
394 } else {
395 1 + parity_shards
396 }
397 } else {
398 1 + parity_shards
399 };
400
401 let new_index =
403 meta_block_count
405
406 + (super_block_set_size * super_block_set_index)
408
409 + new_index_in_super_block_set;
411
412 new_index
413 }
414 }
415}
416
417pub fn calc_data_chunk_write_index(seq_num: u32, data_par: Option<(usize, usize)>) -> Option<u64> {
418 if seq_num < SBX_FIRST_DATA_SEQ_NUM {
419 None
420 } else {
421 let index = (seq_num - SBX_FIRST_DATA_SEQ_NUM) as u64;
422
423 match data_par {
424 None => Some(index),
425 Some((data, parity)) => {
426 if seq_num_is_parity(seq_num, data, parity) {
427 None
428 } else {
429 let block_set_index = index / (data + parity) as u64;
430 let index_in_block_set = index % (data + parity) as u64;
431
432 Some(block_set_index * data as u64 + index_in_block_set)
433 }
434 }
435 }
436 }
437}
438
439pub fn calc_data_chunk_write_pos(
440 version: Version,
441 seq_num: u32,
442 data_par: Option<(usize, usize)>,
443) -> Option<u64> {
444 check_ver_consistent_with_opt!(version, data_par);
445
446 let data_size = ver_to_data_size(version);
447
448 match calc_data_chunk_write_index(seq_num, data_par) {
449 None => None,
450 Some(x) => Some(x as u64 * data_size as u64),
451 }
452}
453
454pub fn calc_seq_num_at_index(
455 index: u64,
456 meta_enabled: Option<bool>,
457 data_par_burst: Option<(usize, usize, usize)>,
458) -> u32 {
459 match data_par_burst {
460 None => {
461 let meta_enabled = meta_enabled.unwrap_or(true);
462
463 if meta_enabled {
464 index as u32
465 } else {
466 SBX_FIRST_DATA_SEQ_NUM + index as u32
467 }
468 }
469 Some((data, parity, burst)) => {
470 shadow_to_avoid_use!(meta_enabled);
471
472 if burst == 0 {
475 if index < 1 + parity as u64 {
476 return 0;
477 } else {
478 let data_index = index - (1 + parity) as u64;
479
480 return (data_index + 1) as u32;
481 }
482 }
483
484 let data_shards = data as u64;
485 let parity_shards = parity as u64;
486 let burst_err_resistance = burst as u64;
487
488 if index < (1 + parity_shards) * (1 + burst_err_resistance)
495 && index % (1 + burst_err_resistance) == 0
497 {
498 return 0;
499 }
500
501 let meta_block_count =
502 if index < (1 + parity_shards) * (1 + burst_err_resistance) {
504 1 + index / (1 + burst_err_resistance)
505 } else {
506 1 + parity_shards
507 };
508
509 let super_block_set_size = (data_shards + parity_shards) * burst_err_resistance;
511
512 let sub_a_block_set_size = data_shards + parity_shards;
513 let sub_b_block_set_size = burst_err_resistance;
514
515 let index_without_meta = index - meta_block_count;
518
519 let super_block_set_index = index_without_meta / super_block_set_size;
521 let index_in_super_block_set = index_without_meta % super_block_set_size;
522
523 let sub_b_block_set_index = index_in_super_block_set / sub_b_block_set_size;
524 let index_in_sub_b_block_set = index_in_super_block_set % sub_b_block_set_size;
525
526 let sub_a_block_set_index = index_in_sub_b_block_set;
527 let index_in_sub_a_block_set = sub_b_block_set_index;
528
529 let old_index_in_super_block_set =
530 sub_a_block_set_index * sub_a_block_set_size + index_in_sub_a_block_set;
531
532 let old_index =
534 (super_block_set_size * super_block_set_index)
536
537 + old_index_in_super_block_set;
539
540 (old_index as u32) + SBX_FIRST_DATA_SEQ_NUM as u32
541 }
542 }
543}
544
545impl Block {
546 pub fn new(version: Version, uid: &[u8; SBX_FILE_UID_LEN], block_type: BlockType) -> Block {
547 match block_type {
548 BlockType::Data => {
549 let seq_num = SBX_FIRST_DATA_SEQ_NUM as u32;
550 Block {
551 header: Header::new(version, uid.clone(), seq_num),
552 data: Data::Data,
553 }
554 }
555 BlockType::Meta => {
556 let seq_num = 0 as u32;
557 Block {
558 header: Header::new(version, uid.clone(), seq_num),
559 data: Data::Meta(Vec::with_capacity(10)),
560 }
561 }
562 }
563 }
564
565 pub fn dummy() -> Block {
566 let version = Version::V1;
567 let seq_num = SBX_FIRST_DATA_SEQ_NUM as u32;
568 Block {
569 header: Header::new(version, [0; 6], seq_num),
570 data: Data::Data,
571 }
572 }
573
574 pub fn get_version(&self) -> Version {
575 self.header.version
576 }
577
578 pub fn set_version(&mut self, version: Version) {
579 self.header.version = version;
580 }
581
582 pub fn get_uid(&self) -> [u8; SBX_FILE_UID_LEN] {
583 self.header.uid
584 }
585
586 pub fn set_uid(&mut self, uid: [u8; SBX_FILE_UID_LEN]) {
587 self.header.uid = uid;
588 }
589
590 pub fn get_crc(&self) -> u16 {
591 self.header.crc
592 }
593
594 pub fn get_seq_num(&self) -> u32 {
595 self.header.seq_num
596 }
597
598 pub fn set_seq_num(&mut self, seq_num: u32) {
599 self.header.seq_num = seq_num;
600
601 self.switch_block_type_to_match_header();
602 }
603
604 pub fn add_seq_num(&mut self, val: u32) -> Result<(), Error> {
605 match self.header.seq_num.checked_add(val) {
606 None => {
607 return Err(Error::SeqNumOverflow);
608 }
609 Some(x) => {
610 self.header.seq_num = x;
611 }
612 }
613
614 self.switch_block_type_to_match_header();
615
616 Ok(())
617 }
618
619 pub fn add1_seq_num(&mut self) -> Result<(), Error> {
620 self.add_seq_num(1)
621 }
622
623 pub fn block_type(&self) -> BlockType {
624 match self.data {
625 Data::Data => BlockType::Data,
626 Data::Meta(_) => BlockType::Meta,
627 }
628 }
629
630 pub fn is_meta(&self) -> bool {
631 match self.block_type() {
632 BlockType::Data => false,
633 BlockType::Meta => true,
634 }
635 }
636
637 pub fn is_data(&self) -> bool {
638 match self.block_type() {
639 BlockType::Data => true,
640 BlockType::Meta => false,
641 }
642 }
643
644 pub fn is_parity(&self, data_shards: usize, parity_shards: usize) -> bool {
645 ver_uses_rs(self.header.version)
646 && seq_num_is_parity(self.get_seq_num(), data_shards, parity_shards)
647 }
648
649 pub fn is_parity_w_data_par_burst(
650 &self,
651 data_par_burst: Option<(usize, usize, usize)>,
652 ) -> bool {
653 ver_uses_rs(self.header.version)
654 && seq_num_is_parity_w_data_par_burst(self.get_seq_num(), data_par_burst)
655 }
656
657 pub fn get_meta_ref_by_id(&self, id: MetadataID) -> Result<Option<&Metadata>, Error> {
658 match self.data {
659 Data::Data => Err(Error::IncorrectBlockType),
660 Data::Meta(ref metas) => Ok(metadata::get_meta_ref_by_id(metas, id)),
661 }
662 }
663
664 pub fn get_meta_ref_mut_by_id(
665 &mut self,
666 id: MetadataID,
667 ) -> Result<Option<&mut Metadata>, Error> {
668 match self.data {
669 Data::Data => Err(Error::IncorrectBlockType),
670 Data::Meta(ref mut metas) => Ok(metadata::get_meta_ref_mut_by_id(metas, id)),
671 }
672 }
673
674 make_meta_getter!(get_FNM => FNM => ret_ref str);
675 make_meta_getter!(get_SNM => SNM => ret_ref str);
676 make_meta_getter!(get_FSZ => FSZ => ret_val u64);
677 make_meta_getter!(get_FDT => FDT => ret_val i64);
678 make_meta_getter!(get_SDT => SDT => ret_val i64);
679 make_meta_getter!(get_HSH => HSH => ret_ref multihash::HashBytes);
680 make_meta_getter!(get_RSD => RSD => ret_val u8);
681 make_meta_getter!(get_RSP => RSP => ret_val u8);
682
683 pub fn metas(&self) -> Result<&Vec<Metadata>, Error> {
684 match self.data {
685 Data::Data => Err(Error::IncorrectBlockType),
686 Data::Meta(ref meta) => Ok(meta),
687 }
688 }
689
690 pub fn metas_mut(&mut self) -> Result<&mut Vec<Metadata>, Error> {
691 match self.data {
692 Data::Data => Err(Error::IncorrectBlockType),
693 Data::Meta(ref mut meta) => Ok(meta),
694 }
695 }
696
697 pub fn update_meta(&mut self, m: &Metadata) -> Result<(), Error> {
698 match self.data {
699 Data::Data => Err(Error::IncorrectBlockType),
700 Data::Meta(ref mut metas) => {
701 let id = metadata::meta_to_id(m);
702 let m = m.clone();
703 match metadata::get_meta_ref_mut_by_id(metas, id) {
704 None => metas.push(m),
705 Some(x) => *x = m,
706 };
707 Ok(())
708 }
709 }
710 }
711
712 pub fn update_metas(&mut self, ms: &[Metadata]) -> Result<(), Error> {
713 for m in ms {
714 if let Err(e) = self.update_meta(m) {
715 return Err(e);
716 }
717 }
718 Ok(())
719 }
720
721 pub fn remove_metas(&mut self, ids: &[MetadataID]) -> Result<(), Error> {
722 match self.data {
723 Data::Data => Err(Error::IncorrectBlockType),
724 Data::Meta(ref mut metas) => {
725 metas.retain(|m| !ids.contains(&metadata::meta_to_id(m)));
726 Ok(())
727 }
728 }
729 }
730
731 pub fn calc_crc(&self, buffer: &[u8]) -> u16 {
732 check_buffer!(self, buffer);
733
734 let crc = self.header.calc_crc();
735
736 crc_ccitt_generic(crc, slice_buf!(data => self, buffer))
737 }
738
739 pub fn update_crc(&mut self, buffer: &[u8]) {
740 self.header.crc = self.calc_crc(buffer);
741 }
742
743 fn header_type_matches_block_type(&self) -> bool {
744 self.header.header_type() == self.block_type()
745 }
746
747 pub fn sync_to_buffer(
748 &mut self,
749 update_crc: Option<bool>,
750 buffer: &mut [u8],
751 ) -> Result<(), Error> {
752 check_buffer!(self, buffer);
753
754 let update_crc = update_crc.unwrap_or(true);
755
756 match self.data {
757 Data::Meta(ref meta) => {
758 if self.get_seq_num() == 0 {
759 metadata::to_bytes(meta, slice_buf!(data_mut => self, buffer))?;
762 }
763 }
764 Data::Data => {}
765 }
766
767 match self.block_type() {
768 BlockType::Data => {
769 if update_crc {
770 self.update_crc(buffer)
771 }
772 }
773 BlockType::Meta => self.update_crc(buffer),
774 }
775
776 self.header.to_bytes(slice_buf!(header_mut => self, buffer));
777
778 Ok(())
779 }
780
781 fn switch_block_type(&mut self) {
782 let block_type = self.block_type();
783
784 if block_type == BlockType::Meta {
785 self.data = Data::Data;
786 } else {
787 self.data = Data::Meta(Vec::with_capacity(10));
788 }
789 }
790
791 fn switch_block_type_to_match_header(&mut self) {
792 if !self.header_type_matches_block_type() {
793 self.switch_block_type();
794 }
795 }
796
797 pub fn sync_from_buffer_header_only(&mut self, buffer: &[u8]) -> Result<(), Error> {
798 self.header.from_bytes(slice_buf!(header => self, buffer))?;
799
800 self.switch_block_type_to_match_header();
801
802 Ok(())
803 }
804
805 pub fn sync_from_buffer(
806 &mut self,
807 buffer: &[u8],
808 header_pred: Option<&dyn Fn(&Header) -> bool>,
809 pred: Option<&dyn Fn(&Block) -> bool>,
810 ) -> Result<(), Error> {
811 self.sync_from_buffer_header_only(buffer)?;
812
813 if let Some(pred) = header_pred {
814 if !pred(&self.header) {
815 return Err(Error::FailedPred);
816 }
817 }
818
819 check_buffer!(self, buffer);
820
821 self.enforce_crc(buffer)?;
822
823 match self.data {
824 Data::Meta(ref mut meta) => {
825 if self.header.seq_num == 0 {
827 meta.clear();
828 let res = metadata::from_bytes(slice_buf!(data => self, buffer))?;
829 for r in res.into_iter() {
830 meta.push(r);
831 }
832 }
833 }
834 Data::Data => {}
835 }
836
837 match pred {
838 Some(pred) => {
839 if pred(&self) {
840 Ok(())
841 } else {
842 Err(Error::FailedPred)
843 }
844 }
845 None => Ok(()),
846 }
847 }
848
849 pub fn verify_crc(&self, buffer: &[u8]) -> Result<bool, Error> {
850 Ok(self.header.crc == self.calc_crc(buffer))
851 }
852
853 pub fn enforce_crc(&self, buffer: &[u8]) -> Result<(), Error> {
854 if self.verify_crc(buffer)? {
855 Ok(())
856 } else {
857 Err(Error::InvalidCRC)
858 }
859 }
860}