1#[cfg(all(unix, not(target_arch = "wasm32")))]
2use std::os::unix::prelude::*;
3#[cfg(windows)]
4use std::os::windows::prelude::*;
5
6use std::borrow::Cow;
7use std::fmt;
8use std::fs;
9use std::io;
10use std::iter;
11use std::iter::{once, repeat};
12use std::mem;
13use std::path::{Component, Path, PathBuf};
14use std::str;
15
16use crate::other;
17use crate::EntryType;
18
19#[cfg(all(any(unix, windows), not(target_arch = "wasm32")))]
25const DETERMINISTIC_TIMESTAMP: u64 = 1153704088;
26
27pub(crate) const BLOCK_SIZE: u64 = 512;
28
29pub(crate) const GNU_SPARSE_HEADERS_COUNT: usize = 4;
30
31pub(crate) const GNU_EXT_SPARSE_HEADERS_COUNT: usize = 21;
32
33#[repr(C)]
35#[allow(missing_docs)]
36pub struct Header {
37 bytes: [u8; BLOCK_SIZE as usize],
38}
39
40#[derive(Clone, Copy, PartialEq, Eq, Debug)]
43#[non_exhaustive]
44pub enum HeaderMode {
45 Complete,
48
49 Deterministic,
52}
53
54#[repr(C)]
56#[allow(missing_docs)]
57pub struct OldHeader {
58 pub name: [u8; 100],
59 pub mode: [u8; 8],
60 pub uid: [u8; 8],
61 pub gid: [u8; 8],
62 pub size: [u8; 12],
63 pub mtime: [u8; 12],
64 pub cksum: [u8; 8],
65 pub linkflag: [u8; 1],
66 pub linkname: [u8; 100],
67 pub pad: [u8; 255],
68}
69
70#[repr(C)]
72#[allow(missing_docs)]
73pub struct UstarHeader {
74 pub name: [u8; 100],
75 pub mode: [u8; 8],
76 pub uid: [u8; 8],
77 pub gid: [u8; 8],
78 pub size: [u8; 12],
79 pub mtime: [u8; 12],
80 pub cksum: [u8; 8],
81 pub typeflag: [u8; 1],
82 pub linkname: [u8; 100],
83
84 pub magic: [u8; 6],
86 pub version: [u8; 2],
87 pub uname: [u8; 32],
88 pub gname: [u8; 32],
89 pub dev_major: [u8; 8],
90 pub dev_minor: [u8; 8],
91 pub prefix: [u8; 155],
92 pub pad: [u8; 12],
93}
94
95#[repr(C)]
97#[allow(missing_docs)]
98pub struct GnuHeader {
99 pub name: [u8; 100],
100 pub mode: [u8; 8],
101 pub uid: [u8; 8],
102 pub gid: [u8; 8],
103 pub size: [u8; 12],
104 pub mtime: [u8; 12],
105 pub cksum: [u8; 8],
106 pub typeflag: [u8; 1],
107 pub linkname: [u8; 100],
108
109 pub magic: [u8; 6],
111 pub version: [u8; 2],
112 pub uname: [u8; 32],
113 pub gname: [u8; 32],
114 pub dev_major: [u8; 8],
115 pub dev_minor: [u8; 8],
116 pub atime: [u8; 12],
117 pub ctime: [u8; 12],
118 pub offset: [u8; 12],
119 pub longnames: [u8; 4],
120 pub unused: [u8; 1],
121 pub sparse: [GnuSparseHeader; GNU_SPARSE_HEADERS_COUNT],
122 pub isextended: [u8; 1],
123 pub realsize: [u8; 12],
124 pub pad: [u8; 17],
125}
126
127#[repr(C)]
131#[allow(missing_docs)]
132pub struct GnuSparseHeader {
133 pub offset: [u8; 12],
134 pub numbytes: [u8; 12],
135}
136
137#[repr(C)]
142#[allow(missing_docs)]
143pub struct GnuExtSparseHeader {
144 pub sparse: [GnuSparseHeader; GNU_EXT_SPARSE_HEADERS_COUNT],
145 pub isextended: [u8; 1],
146 pub padding: [u8; 7],
147}
148
149impl Header {
150 pub fn new_gnu() -> Header {
156 let mut header = Header {
157 bytes: [0; BLOCK_SIZE as usize],
158 };
159 unsafe {
160 let gnu = cast_mut::<_, GnuHeader>(&mut header);
161 gnu.magic = *b"ustar ";
162 gnu.version = *b" \0";
163 }
164 header.set_mtime(0);
165 header
166 }
167
168 pub fn new_ustar() -> Header {
176 let mut header = Header {
177 bytes: [0; BLOCK_SIZE as usize],
178 };
179 unsafe {
180 let gnu = cast_mut::<_, UstarHeader>(&mut header);
181 gnu.magic = *b"ustar\0";
182 gnu.version = *b"00";
183 }
184 header.set_mtime(0);
185 header
186 }
187
188 pub fn new_old() -> Header {
195 let mut header = Header {
196 bytes: [0; BLOCK_SIZE as usize],
197 };
198 header.set_mtime(0);
199 header
200 }
201
202 fn is_ustar(&self) -> bool {
203 let ustar = unsafe { cast::<_, UstarHeader>(self) };
204 ustar.magic[..] == b"ustar\0"[..] && ustar.version[..] == b"00"[..]
205 }
206
207 fn is_gnu(&self) -> bool {
208 let ustar = unsafe { cast::<_, UstarHeader>(self) };
209 ustar.magic[..] == b"ustar "[..] && ustar.version[..] == b" \0"[..]
210 }
211
212 pub fn as_old(&self) -> &OldHeader {
217 unsafe { cast(self) }
218 }
219
220 pub fn as_old_mut(&mut self) -> &mut OldHeader {
222 unsafe { cast_mut(self) }
223 }
224
225 pub fn as_ustar(&self) -> Option<&UstarHeader> {
235 if self.is_ustar() {
236 Some(unsafe { cast(self) })
237 } else {
238 None
239 }
240 }
241
242 pub fn as_ustar_mut(&mut self) -> Option<&mut UstarHeader> {
244 if self.is_ustar() {
245 Some(unsafe { cast_mut(self) })
246 } else {
247 None
248 }
249 }
250
251 pub fn as_gnu(&self) -> Option<&GnuHeader> {
261 if self.is_gnu() {
262 Some(unsafe { cast(self) })
263 } else {
264 None
265 }
266 }
267
268 pub fn as_gnu_mut(&mut self) -> Option<&mut GnuHeader> {
270 if self.is_gnu() {
271 Some(unsafe { cast_mut(self) })
272 } else {
273 None
274 }
275 }
276
277 pub fn from_byte_slice(bytes: &[u8]) -> &Header {
281 assert_eq!(bytes.len(), mem::size_of::<Header>());
282 assert_eq!(mem::align_of_val(bytes), mem::align_of::<Header>());
283 unsafe { &*(bytes.as_ptr() as *const Header) }
284 }
285
286 pub fn as_bytes(&self) -> &[u8; BLOCK_SIZE as usize] {
288 &self.bytes
289 }
290
291 pub fn as_mut_bytes(&mut self) -> &mut [u8; BLOCK_SIZE as usize] {
293 &mut self.bytes
294 }
295
296 pub fn set_metadata(&mut self, meta: &fs::Metadata) {
303 self.fill_from(meta, HeaderMode::Complete);
304 }
305
306 pub fn set_metadata_in_mode(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
309 self.fill_from(meta, mode);
310 }
311
312 pub fn entry_size(&self) -> io::Result<u64> {
321 num_field_wrapper_from(&self.as_old().size).map_err(|err| {
322 io::Error::new(
323 err.kind(),
324 format!("{} when getting size for {}", err, self.path_lossy()),
325 )
326 })
327 }
328
329 pub fn size(&self) -> io::Result<u64> {
333 if self.entry_type().is_gnu_sparse() {
334 self.as_gnu()
335 .ok_or_else(|| other("sparse header was not a gnu header"))
336 .and_then(|h| h.real_size())
337 } else {
338 self.entry_size()
339 }
340 }
341
342 pub fn set_size(&mut self, size: u64) {
344 num_field_wrapper_into(&mut self.as_old_mut().size, size);
345 }
346
347 pub fn path(&self) -> io::Result<Cow<Path>> {
355 bytes2path(self.path_bytes())
356 }
357
358 pub fn path_bytes(&self) -> Cow<[u8]> {
366 if let Some(ustar) = self.as_ustar() {
367 ustar.path_bytes()
368 } else {
369 let name = truncate(&self.as_old().name);
370 Cow::Borrowed(name)
371 }
372 }
373
374 fn path_lossy(&self) -> String {
376 String::from_utf8_lossy(&self.path_bytes()).to_string()
377 }
378
379 pub fn set_path<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> {
391 self.set_path_inner(p.as_ref(), false)
392 }
393
394 pub(crate) fn set_truncated_path_for_gnu_header<P: AsRef<Path>>(
398 &mut self,
399 p: P,
400 ) -> io::Result<()> {
401 self.set_path_inner(p.as_ref(), true)
402 }
403
404 fn set_path_inner(&mut self, path: &Path, is_truncated_gnu_long_path: bool) -> io::Result<()> {
405 if let Some(ustar) = self.as_ustar_mut() {
406 return ustar.set_path(path);
407 }
408 if is_truncated_gnu_long_path {
409 copy_path_into_gnu_long(&mut self.as_old_mut().name, path, false)
410 } else {
411 copy_path_into(&mut self.as_old_mut().name, path, false)
412 }
413 .map_err(|err| {
414 io::Error::new(
415 err.kind(),
416 format!("{} when setting path for {}", err, self.path_lossy()),
417 )
418 })
419 }
420
421 pub fn link_name(&self) -> io::Result<Option<Cow<Path>>> {
430 match self.link_name_bytes() {
431 Some(bytes) => bytes2path(bytes).map(Some),
432 None => Ok(None),
433 }
434 }
435
436 pub fn link_name_bytes(&self) -> Option<Cow<[u8]>> {
444 let old = self.as_old();
445 if old.linkname[0] != 0 {
446 Some(Cow::Borrowed(truncate(&old.linkname)))
447 } else {
448 None
449 }
450 }
451
452 pub fn set_link_name<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> {
461 self._set_link_name(p.as_ref())
462 }
463
464 fn _set_link_name(&mut self, path: &Path) -> io::Result<()> {
465 copy_path_into(&mut self.as_old_mut().linkname, path, true).map_err(|err| {
466 io::Error::new(
467 err.kind(),
468 format!("{} when setting link name for {}", err, self.path_lossy()),
469 )
470 })
471 }
472
473 pub fn set_link_name_literal<P: AsRef<[u8]>>(&mut self, p: P) -> io::Result<()> {
478 self._set_link_name_literal(p.as_ref())
479 }
480
481 fn _set_link_name_literal(&mut self, bytes: &[u8]) -> io::Result<()> {
482 copy_into(&mut self.as_old_mut().linkname, bytes)
483 }
484
485 pub fn mode(&self) -> io::Result<u32> {
489 octal_from(&self.as_old().mode)
490 .map(|u| u as u32)
491 .map_err(|err| {
492 io::Error::new(
493 err.kind(),
494 format!("{} when getting mode for {}", err, self.path_lossy()),
495 )
496 })
497 }
498
499 pub fn set_mode(&mut self, mode: u32) {
501 octal_into(&mut self.as_old_mut().mode, mode);
502 }
503
504 pub fn uid(&self) -> io::Result<u64> {
508 num_field_wrapper_from(&self.as_old().uid)
509 .map(|u| u as u64)
510 .map_err(|err| {
511 io::Error::new(
512 err.kind(),
513 format!("{} when getting uid for {}", err, self.path_lossy()),
514 )
515 })
516 }
517
518 pub fn set_uid(&mut self, uid: u64) {
520 num_field_wrapper_into(&mut self.as_old_mut().uid, uid);
521 }
522
523 pub fn gid(&self) -> io::Result<u64> {
525 num_field_wrapper_from(&self.as_old().gid)
526 .map(|u| u as u64)
527 .map_err(|err| {
528 io::Error::new(
529 err.kind(),
530 format!("{} when getting gid for {}", err, self.path_lossy()),
531 )
532 })
533 }
534
535 pub fn set_gid(&mut self, gid: u64) {
537 num_field_wrapper_into(&mut self.as_old_mut().gid, gid);
538 }
539
540 pub fn mtime(&self) -> io::Result<u64> {
542 num_field_wrapper_from(&self.as_old().mtime).map_err(|err| {
543 io::Error::new(
544 err.kind(),
545 format!("{} when getting mtime for {}", err, self.path_lossy()),
546 )
547 })
548 }
549
550 pub fn set_mtime(&mut self, mtime: u64) {
555 num_field_wrapper_into(&mut self.as_old_mut().mtime, mtime);
556 }
557
558 pub fn username(&self) -> Result<Option<&str>, str::Utf8Error> {
565 match self.username_bytes() {
566 Some(bytes) => str::from_utf8(bytes).map(Some),
567 None => Ok(None),
568 }
569 }
570
571 pub fn username_bytes(&self) -> Option<&[u8]> {
576 if let Some(ustar) = self.as_ustar() {
577 Some(ustar.username_bytes())
578 } else if let Some(gnu) = self.as_gnu() {
579 Some(gnu.username_bytes())
580 } else {
581 None
582 }
583 }
584
585 pub fn set_username(&mut self, name: &str) -> io::Result<()> {
590 if let Some(ustar) = self.as_ustar_mut() {
591 return ustar.set_username(name);
592 }
593 if let Some(gnu) = self.as_gnu_mut() {
594 gnu.set_username(name)
595 } else {
596 Err(other("not a ustar or gnu archive, cannot set username"))
597 }
598 }
599
600 pub fn groupname(&self) -> Result<Option<&str>, str::Utf8Error> {
607 match self.groupname_bytes() {
608 Some(bytes) => str::from_utf8(bytes).map(Some),
609 None => Ok(None),
610 }
611 }
612
613 pub fn groupname_bytes(&self) -> Option<&[u8]> {
618 if let Some(ustar) = self.as_ustar() {
619 Some(ustar.groupname_bytes())
620 } else if let Some(gnu) = self.as_gnu() {
621 Some(gnu.groupname_bytes())
622 } else {
623 None
624 }
625 }
626
627 pub fn set_groupname(&mut self, name: &str) -> io::Result<()> {
632 if let Some(ustar) = self.as_ustar_mut() {
633 return ustar.set_groupname(name);
634 }
635 if let Some(gnu) = self.as_gnu_mut() {
636 gnu.set_groupname(name)
637 } else {
638 Err(other("not a ustar or gnu archive, cannot set groupname"))
639 }
640 }
641
642 pub fn device_major(&self) -> io::Result<Option<u32>> {
650 if let Some(ustar) = self.as_ustar() {
651 ustar.device_major().map(Some)
652 } else if let Some(gnu) = self.as_gnu() {
653 gnu.device_major().map(Some)
654 } else {
655 Ok(None)
656 }
657 }
658
659 pub fn set_device_major(&mut self, major: u32) -> io::Result<()> {
664 if let Some(ustar) = self.as_ustar_mut() {
665 ustar.set_device_major(major);
666 Ok(())
667 } else if let Some(gnu) = self.as_gnu_mut() {
668 gnu.set_device_major(major);
669 Ok(())
670 } else {
671 Err(other("not a ustar or gnu archive, cannot set dev_major"))
672 }
673 }
674
675 pub fn device_minor(&self) -> io::Result<Option<u32>> {
683 if let Some(ustar) = self.as_ustar() {
684 ustar.device_minor().map(Some)
685 } else if let Some(gnu) = self.as_gnu() {
686 gnu.device_minor().map(Some)
687 } else {
688 Ok(None)
689 }
690 }
691
692 pub fn set_device_minor(&mut self, minor: u32) -> io::Result<()> {
697 if let Some(ustar) = self.as_ustar_mut() {
698 ustar.set_device_minor(minor);
699 Ok(())
700 } else if let Some(gnu) = self.as_gnu_mut() {
701 gnu.set_device_minor(minor);
702 Ok(())
703 } else {
704 Err(other("not a ustar or gnu archive, cannot set dev_minor"))
705 }
706 }
707
708 pub fn entry_type(&self) -> EntryType {
710 EntryType::new(self.as_old().linkflag[0])
711 }
712
713 pub fn set_entry_type(&mut self, ty: EntryType) {
715 self.as_old_mut().linkflag = [ty.as_byte()];
716 }
717
718 pub fn cksum(&self) -> io::Result<u32> {
722 octal_from(&self.as_old().cksum)
723 .map(|u| u as u32)
724 .map_err(|err| {
725 io::Error::new(
726 err.kind(),
727 format!("{} when getting cksum for {}", err, self.path_lossy()),
728 )
729 })
730 }
731
732 pub fn set_cksum(&mut self) {
735 let cksum = self.calculate_cksum();
736 octal_into(&mut self.as_old_mut().cksum, cksum);
737 }
738
739 fn calculate_cksum(&self) -> u32 {
740 let old = self.as_old();
741 let start = old as *const _ as usize;
742 let cksum_start = old.cksum.as_ptr() as *const _ as usize;
743 let offset = cksum_start - start;
744 let len = old.cksum.len();
745 self.bytes[0..offset]
746 .iter()
747 .chain(iter::repeat(&b' ').take(len))
748 .chain(&self.bytes[offset + len..])
749 .fold(0, |a, b| a + (*b as u32))
750 }
751
752 fn fill_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
753 self.fill_platform_from(meta, mode);
754 self.set_size(if meta.is_dir() || meta.file_type().is_symlink() {
756 0
757 } else {
758 meta.len()
759 });
760 if let Some(ustar) = self.as_ustar_mut() {
761 ustar.set_device_major(0);
762 ustar.set_device_minor(0);
763 }
764 if let Some(gnu) = self.as_gnu_mut() {
765 gnu.set_device_major(0);
766 gnu.set_device_minor(0);
767 }
768 }
769
770 #[cfg(target_arch = "wasm32")]
771 #[allow(unused_variables)]
772 fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
773 unimplemented!();
774 }
775
776 #[cfg(all(unix, not(target_arch = "wasm32")))]
777 fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
778 match mode {
779 HeaderMode::Complete => {
780 self.set_mtime(meta.mtime() as u64);
781 self.set_uid(meta.uid() as u64);
782 self.set_gid(meta.gid() as u64);
783 self.set_mode(meta.mode() as u32);
784 }
785 HeaderMode::Deterministic => {
786 self.set_mtime(DETERMINISTIC_TIMESTAMP);
791
792 self.set_uid(0);
793 self.set_gid(0);
794
795 let fs_mode = if meta.is_dir() || (0o100 & meta.mode() == 0o100) {
797 0o755
798 } else {
799 0o644
800 };
801 self.set_mode(fs_mode);
802 }
803 }
804
805 self.set_entry_type(entry_type(meta.mode()));
816
817 fn entry_type(mode: u32) -> EntryType {
818 match mode as libc::mode_t & libc::S_IFMT {
819 libc::S_IFREG => EntryType::file(),
820 libc::S_IFLNK => EntryType::symlink(),
821 libc::S_IFCHR => EntryType::character_special(),
822 libc::S_IFBLK => EntryType::block_special(),
823 libc::S_IFDIR => EntryType::dir(),
824 libc::S_IFIFO => EntryType::fifo(),
825 _ => EntryType::new(b' '),
826 }
827 }
828 }
829
830 #[cfg(windows)]
831 fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
832 match mode {
834 HeaderMode::Complete => {
835 self.set_uid(0);
836 self.set_gid(0);
837 let mtime = (meta.last_write_time() / (1_000_000_000 / 100)) - 11644473600;
842 self.set_mtime(mtime);
843 let fs_mode = {
844 const FILE_ATTRIBUTE_READONLY: u32 = 0x00000001;
845 let readonly = meta.file_attributes() & FILE_ATTRIBUTE_READONLY;
846 match (meta.is_dir(), readonly != 0) {
847 (true, false) => 0o755,
848 (true, true) => 0o555,
849 (false, false) => 0o644,
850 (false, true) => 0o444,
851 }
852 };
853 self.set_mode(fs_mode);
854 }
855 HeaderMode::Deterministic => {
856 self.set_uid(0);
857 self.set_gid(0);
858 self.set_mtime(DETERMINISTIC_TIMESTAMP); let fs_mode = if meta.is_dir() { 0o755 } else { 0o644 };
860 self.set_mode(fs_mode);
861 }
862 }
863
864 let ft = meta.file_type();
865 self.set_entry_type(if ft.is_dir() {
866 EntryType::dir()
867 } else if ft.is_file() {
868 EntryType::file()
869 } else if ft.is_symlink() {
870 EntryType::symlink()
871 } else {
872 EntryType::new(b' ')
873 });
874 }
875
876 fn debug_fields(&self, b: &mut fmt::DebugStruct) {
877 if let Ok(entry_size) = self.entry_size() {
878 b.field("entry_size", &entry_size);
879 }
880 if let Ok(size) = self.size() {
881 b.field("size", &size);
882 }
883 if let Ok(path) = self.path() {
884 b.field("path", &path);
885 }
886 if let Ok(link_name) = self.link_name() {
887 b.field("link_name", &link_name);
888 }
889 if let Ok(mode) = self.mode() {
890 b.field("mode", &DebugAsOctal(mode));
891 }
892 if let Ok(uid) = self.uid() {
893 b.field("uid", &uid);
894 }
895 if let Ok(gid) = self.gid() {
896 b.field("gid", &gid);
897 }
898 if let Ok(mtime) = self.mtime() {
899 b.field("mtime", &mtime);
900 }
901 if let Ok(username) = self.username() {
902 b.field("username", &username);
903 }
904 if let Ok(groupname) = self.groupname() {
905 b.field("groupname", &groupname);
906 }
907 if let Ok(device_major) = self.device_major() {
908 b.field("device_major", &device_major);
909 }
910 if let Ok(device_minor) = self.device_minor() {
911 b.field("device_minor", &device_minor);
912 }
913 if let Ok(cksum) = self.cksum() {
914 b.field("cksum", &cksum);
915 b.field("cksum_valid", &(cksum == self.calculate_cksum()));
916 }
917 }
918}
919
920struct DebugAsOctal<T>(T);
921
922impl<T: fmt::Octal> fmt::Debug for DebugAsOctal<T> {
923 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
924 fmt::Octal::fmt(&self.0, f)
925 }
926}
927
928unsafe fn cast<T, U>(a: &T) -> &U {
929 assert_eq!(mem::size_of_val(a), mem::size_of::<U>());
930 assert_eq!(mem::align_of_val(a), mem::align_of::<U>());
931 &*(a as *const T as *const U)
932}
933
934unsafe fn cast_mut<T, U>(a: &mut T) -> &mut U {
935 assert_eq!(mem::size_of_val(a), mem::size_of::<U>());
936 assert_eq!(mem::align_of_val(a), mem::align_of::<U>());
937 &mut *(a as *mut T as *mut U)
938}
939
940impl Clone for Header {
941 fn clone(&self) -> Header {
942 Header { bytes: self.bytes }
943 }
944}
945
946impl fmt::Debug for Header {
947 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
948 if let Some(me) = self.as_ustar() {
949 me.fmt(f)
950 } else if let Some(me) = self.as_gnu() {
951 me.fmt(f)
952 } else {
953 self.as_old().fmt(f)
954 }
955 }
956}
957
958impl OldHeader {
959 pub fn as_header(&self) -> &Header {
961 unsafe { cast(self) }
962 }
963
964 pub fn as_header_mut(&mut self) -> &mut Header {
966 unsafe { cast_mut(self) }
967 }
968}
969
970impl fmt::Debug for OldHeader {
971 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
972 let mut f = f.debug_struct("OldHeader");
973 self.as_header().debug_fields(&mut f);
974 f.finish()
975 }
976}
977
978impl UstarHeader {
979 pub fn path_bytes(&self) -> Cow<[u8]> {
981 if self.prefix[0] == 0 && !self.name.contains(&b'\\') {
982 Cow::Borrowed(truncate(&self.name))
983 } else {
984 let mut bytes = Vec::new();
985 let prefix = truncate(&self.prefix);
986 if !prefix.is_empty() {
987 bytes.extend_from_slice(prefix);
988 bytes.push(b'/');
989 }
990 bytes.extend_from_slice(truncate(&self.name));
991 Cow::Owned(bytes)
992 }
993 }
994
995 fn path_lossy(&self) -> String {
997 String::from_utf8_lossy(&self.path_bytes()).to_string()
998 }
999
1000 pub fn set_path<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> {
1002 self._set_path(p.as_ref())
1003 }
1004
1005 fn _set_path(&mut self, path: &Path) -> io::Result<()> {
1006 let bytes = path2bytes(path)?;
1015 let (maxnamelen, maxprefixlen) = (self.name.len(), self.prefix.len());
1016 if bytes.len() <= maxnamelen {
1017 copy_path_into(&mut self.name, path, false).map_err(|err| {
1018 io::Error::new(
1019 err.kind(),
1020 format!("{} when setting path for {}", err, self.path_lossy()),
1021 )
1022 })?;
1023 } else {
1024 let mut prefix = path;
1025 let mut prefixlen;
1026 loop {
1027 match prefix.parent() {
1028 Some(parent) => prefix = parent,
1029 None => {
1030 return Err(other(&format!(
1031 "path cannot be split to be inserted into archive: {}",
1032 path.display()
1033 )));
1034 }
1035 }
1036 prefixlen = path2bytes(prefix)?.len();
1037 if prefixlen <= maxprefixlen {
1038 break;
1039 }
1040 }
1041 copy_path_into(&mut self.prefix, prefix, false).map_err(|err| {
1042 io::Error::new(
1043 err.kind(),
1044 format!("{} when setting path for {}", err, self.path_lossy()),
1045 )
1046 })?;
1047 let path = bytes2path(Cow::Borrowed(&bytes[prefixlen + 1..]))?;
1048 copy_path_into(&mut self.name, &path, false).map_err(|err| {
1049 io::Error::new(
1050 err.kind(),
1051 format!("{} when setting path for {}", err, self.path_lossy()),
1052 )
1053 })?;
1054 }
1055 Ok(())
1056 }
1057
1058 pub fn username_bytes(&self) -> &[u8] {
1060 truncate(&self.uname)
1061 }
1062
1063 pub fn set_username(&mut self, name: &str) -> io::Result<()> {
1065 copy_into(&mut self.uname, name.as_bytes()).map_err(|err| {
1066 io::Error::new(
1067 err.kind(),
1068 format!("{} when setting username for {}", err, self.path_lossy()),
1069 )
1070 })
1071 }
1072
1073 pub fn groupname_bytes(&self) -> &[u8] {
1075 truncate(&self.gname)
1076 }
1077
1078 pub fn set_groupname(&mut self, name: &str) -> io::Result<()> {
1080 copy_into(&mut self.gname, name.as_bytes()).map_err(|err| {
1081 io::Error::new(
1082 err.kind(),
1083 format!("{} when setting groupname for {}", err, self.path_lossy()),
1084 )
1085 })
1086 }
1087
1088 pub fn device_major(&self) -> io::Result<u32> {
1090 octal_from(&self.dev_major)
1091 .map(|u| u as u32)
1092 .map_err(|err| {
1093 io::Error::new(
1094 err.kind(),
1095 format!(
1096 "{} when getting device_major for {}",
1097 err,
1098 self.path_lossy()
1099 ),
1100 )
1101 })
1102 }
1103
1104 pub fn set_device_major(&mut self, major: u32) {
1106 octal_into(&mut self.dev_major, major);
1107 }
1108
1109 pub fn device_minor(&self) -> io::Result<u32> {
1111 octal_from(&self.dev_minor)
1112 .map(|u| u as u32)
1113 .map_err(|err| {
1114 io::Error::new(
1115 err.kind(),
1116 format!(
1117 "{} when getting device_minor for {}",
1118 err,
1119 self.path_lossy()
1120 ),
1121 )
1122 })
1123 }
1124
1125 pub fn set_device_minor(&mut self, minor: u32) {
1127 octal_into(&mut self.dev_minor, minor);
1128 }
1129
1130 pub fn as_header(&self) -> &Header {
1132 unsafe { cast(self) }
1133 }
1134
1135 pub fn as_header_mut(&mut self) -> &mut Header {
1137 unsafe { cast_mut(self) }
1138 }
1139}
1140
1141impl fmt::Debug for UstarHeader {
1142 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1143 let mut f = f.debug_struct("UstarHeader");
1144 self.as_header().debug_fields(&mut f);
1145 f.finish()
1146 }
1147}
1148
1149impl GnuHeader {
1150 pub fn username_bytes(&self) -> &[u8] {
1152 truncate(&self.uname)
1153 }
1154
1155 fn fullname_lossy(&self) -> String {
1157 format!(
1158 "{}:{}",
1159 String::from_utf8_lossy(self.groupname_bytes()),
1160 String::from_utf8_lossy(self.username_bytes()),
1161 )
1162 }
1163
1164 pub fn set_username(&mut self, name: &str) -> io::Result<()> {
1166 copy_into(&mut self.uname, name.as_bytes()).map_err(|err| {
1167 io::Error::new(
1168 err.kind(),
1169 format!(
1170 "{} when setting username for {}",
1171 err,
1172 self.fullname_lossy()
1173 ),
1174 )
1175 })
1176 }
1177
1178 pub fn groupname_bytes(&self) -> &[u8] {
1180 truncate(&self.gname)
1181 }
1182
1183 pub fn set_groupname(&mut self, name: &str) -> io::Result<()> {
1185 copy_into(&mut self.gname, name.as_bytes()).map_err(|err| {
1186 io::Error::new(
1187 err.kind(),
1188 format!(
1189 "{} when setting groupname for {}",
1190 err,
1191 self.fullname_lossy()
1192 ),
1193 )
1194 })
1195 }
1196
1197 pub fn device_major(&self) -> io::Result<u32> {
1199 octal_from(&self.dev_major)
1200 .map(|u| u as u32)
1201 .map_err(|err| {
1202 io::Error::new(
1203 err.kind(),
1204 format!(
1205 "{} when getting device_major for {}",
1206 err,
1207 self.fullname_lossy()
1208 ),
1209 )
1210 })
1211 }
1212
1213 pub fn set_device_major(&mut self, major: u32) {
1215 octal_into(&mut self.dev_major, major);
1216 }
1217
1218 pub fn device_minor(&self) -> io::Result<u32> {
1220 octal_from(&self.dev_minor)
1221 .map(|u| u as u32)
1222 .map_err(|err| {
1223 io::Error::new(
1224 err.kind(),
1225 format!(
1226 "{} when getting device_minor for {}",
1227 err,
1228 self.fullname_lossy()
1229 ),
1230 )
1231 })
1232 }
1233
1234 pub fn set_device_minor(&mut self, minor: u32) {
1236 octal_into(&mut self.dev_minor, minor);
1237 }
1238
1239 pub fn atime(&self) -> io::Result<u64> {
1241 num_field_wrapper_from(&self.atime).map_err(|err| {
1242 io::Error::new(
1243 err.kind(),
1244 format!("{} when getting atime for {}", err, self.fullname_lossy()),
1245 )
1246 })
1247 }
1248
1249 pub fn set_atime(&mut self, atime: u64) {
1254 num_field_wrapper_into(&mut self.atime, atime);
1255 }
1256
1257 pub fn ctime(&self) -> io::Result<u64> {
1259 num_field_wrapper_from(&self.ctime).map_err(|err| {
1260 io::Error::new(
1261 err.kind(),
1262 format!("{} when getting ctime for {}", err, self.fullname_lossy()),
1263 )
1264 })
1265 }
1266
1267 pub fn set_ctime(&mut self, ctime: u64) {
1272 num_field_wrapper_into(&mut self.ctime, ctime);
1273 }
1274
1275 pub fn real_size(&self) -> io::Result<u64> {
1280 num_field_wrapper_from(&self.realsize).map_err(|err| {
1281 io::Error::new(
1282 err.kind(),
1283 format!(
1284 "{} when getting real_size for {}",
1285 err,
1286 self.fullname_lossy()
1287 ),
1288 )
1289 })
1290 }
1291
1292 pub fn set_real_size(&mut self, real_size: u64) {
1294 num_field_wrapper_into(&mut self.realsize, real_size);
1295 }
1296
1297 pub fn is_extended(&self) -> bool {
1303 self.isextended[0] == 1
1304 }
1305
1306 pub fn set_is_extended(&mut self, is_extended: bool) {
1312 self.isextended[0] = if is_extended { 1 } else { 0 };
1313 }
1314
1315 pub fn as_header(&self) -> &Header {
1317 unsafe { cast(self) }
1318 }
1319
1320 pub fn as_header_mut(&mut self) -> &mut Header {
1322 unsafe { cast_mut(self) }
1323 }
1324}
1325
1326impl fmt::Debug for GnuHeader {
1327 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1328 let mut f = f.debug_struct("GnuHeader");
1329 self.as_header().debug_fields(&mut f);
1330 if let Ok(atime) = self.atime() {
1331 f.field("atime", &atime);
1332 }
1333 if let Ok(ctime) = self.ctime() {
1334 f.field("ctime", &ctime);
1335 }
1336 f.field("is_extended", &self.is_extended())
1337 .field("sparse", &DebugSparseHeaders(&self.sparse))
1338 .finish()
1339 }
1340}
1341
1342struct DebugSparseHeaders<'a>(&'a [GnuSparseHeader]);
1343
1344impl<'a> fmt::Debug for DebugSparseHeaders<'a> {
1345 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1346 let mut f = f.debug_list();
1347 for header in self.0 {
1348 if !header.is_empty() {
1349 f.entry(header);
1350 }
1351 }
1352 f.finish()
1353 }
1354}
1355
1356impl GnuSparseHeader {
1357 pub fn is_empty(&self) -> bool {
1359 self.offset[0] == 0 || self.numbytes[0] == 0
1360 }
1361
1362 pub fn offset(&self) -> io::Result<u64> {
1366 num_field_wrapper_from(&self.offset).map_err(|err| {
1367 io::Error::new(
1368 err.kind(),
1369 format!("{} when getting offset from sparse header", err),
1370 )
1371 })
1372 }
1373
1374 pub fn set_offset(&mut self, offset: u64) {
1376 num_field_wrapper_into(&mut self.offset, offset);
1377 }
1378
1379 pub fn length(&self) -> io::Result<u64> {
1383 num_field_wrapper_from(&self.numbytes).map_err(|err| {
1384 io::Error::new(
1385 err.kind(),
1386 format!("{} when getting length from sparse header", err),
1387 )
1388 })
1389 }
1390
1391 pub fn set_length(&mut self, length: u64) {
1393 num_field_wrapper_into(&mut self.numbytes, length);
1394 }
1395}
1396
1397impl fmt::Debug for GnuSparseHeader {
1398 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1399 let mut f = f.debug_struct("GnuSparseHeader");
1400 if let Ok(offset) = self.offset() {
1401 f.field("offset", &offset);
1402 }
1403 if let Ok(length) = self.length() {
1404 f.field("length", &length);
1405 }
1406 f.finish()
1407 }
1408}
1409
1410impl GnuExtSparseHeader {
1411 pub fn new() -> GnuExtSparseHeader {
1413 unsafe { mem::zeroed() }
1414 }
1415
1416 pub fn as_bytes(&self) -> &[u8; BLOCK_SIZE as usize] {
1418 debug_assert_eq!(mem::size_of_val(self), BLOCK_SIZE as usize);
1419 unsafe { mem::transmute(self) }
1420 }
1421
1422 pub fn as_mut_bytes(&mut self) -> &mut [u8; BLOCK_SIZE as usize] {
1424 debug_assert_eq!(mem::size_of_val(self), BLOCK_SIZE as usize);
1425 unsafe { mem::transmute(self) }
1426 }
1427
1428 pub fn sparse(&self) -> &[GnuSparseHeader; 21] {
1433 &self.sparse
1434 }
1435
1436 pub fn sparse_mut(&mut self) -> &mut [GnuSparseHeader; 21] {
1438 &mut self.sparse
1439 }
1440
1441 pub fn is_extended(&self) -> bool {
1443 self.isextended[0] == 1
1444 }
1445
1446 pub fn set_is_extended(&mut self, is_extended: bool) {
1448 self.isextended[0] = if is_extended { 1 } else { 0 };
1449 }
1450}
1451
1452impl Default for GnuExtSparseHeader {
1453 fn default() -> Self {
1454 Self::new()
1455 }
1456}
1457
1458fn octal_from(slice: &[u8]) -> io::Result<u64> {
1459 let trun = truncate(slice);
1460 let num = match str::from_utf8(trun) {
1461 Ok(n) => n,
1462 Err(_) => {
1463 return Err(other(&format!(
1464 "numeric field did not have utf-8 text: {}",
1465 String::from_utf8_lossy(trun)
1466 )));
1467 }
1468 };
1469 match u64::from_str_radix(num.trim(), 8) {
1470 Ok(n) => Ok(n),
1471 Err(_) => Err(other(&format!("numeric field was not a number: {}", num))),
1472 }
1473}
1474
1475fn octal_into<T: fmt::Octal>(dst: &mut [u8], val: T) {
1476 let o = format!("{:o}", val);
1477 let value = once(b'\0').chain(o.bytes().rev().chain(repeat(b'0')));
1478 for (slot, value) in dst.iter_mut().rev().zip(value) {
1479 *slot = value;
1480 }
1481}
1482
1483fn num_field_wrapper_into(dst: &mut [u8], src: u64) {
1486 if src >= 8589934592 || (src >= 2097152 && dst.len() == 8) {
1487 numeric_extended_into(dst, src);
1488 } else {
1489 octal_into(dst, src);
1490 }
1491}
1492
1493fn num_field_wrapper_from(src: &[u8]) -> io::Result<u64> {
1496 if src[0] & 0x80 != 0 {
1497 Ok(numeric_extended_from(src))
1498 } else {
1499 octal_from(src)
1500 }
1501}
1502
1503fn numeric_extended_into(dst: &mut [u8], src: u64) {
1508 let len: usize = dst.len();
1509 for (slot, val) in dst.iter_mut().zip(
1510 repeat(0)
1511 .take(len - 8) .chain((0..8).rev().map(|x| ((src >> (8 * x)) & 0xff) as u8)),
1513 ) {
1514 *slot = val;
1515 }
1516 dst[0] |= 0x80;
1517}
1518
1519fn numeric_extended_from(src: &[u8]) -> u64 {
1520 let mut dst: u64 = 0;
1521 let mut b_to_skip = 1;
1522 if src.len() == 8 {
1523 dst = (src[0] ^ 0x80) as u64;
1525 } else {
1526 b_to_skip = src.len() - 8;
1528 }
1529 for byte in src.iter().skip(b_to_skip) {
1530 dst <<= 8;
1531 dst |= *byte as u64;
1532 }
1533 dst
1534}
1535
1536fn truncate(slice: &[u8]) -> &[u8] {
1537 match slice.iter().position(|i| *i == 0) {
1538 Some(i) => &slice[..i],
1539 None => slice,
1540 }
1541}
1542
1543fn copy_into(slot: &mut [u8], bytes: &[u8]) -> io::Result<()> {
1546 if bytes.len() > slot.len() {
1547 Err(other("provided value is too long"))
1548 } else if bytes.iter().any(|b| *b == 0) {
1549 Err(other("provided value contains a nul byte"))
1550 } else {
1551 for (slot, val) in slot.iter_mut().zip(bytes.iter().chain(Some(&0))) {
1552 *slot = *val;
1553 }
1554 Ok(())
1555 }
1556}
1557
1558fn copy_path_into_inner(
1559 mut slot: &mut [u8],
1560 path: &Path,
1561 is_link_name: bool,
1562 is_truncated_gnu_long_path: bool,
1563) -> io::Result<()> {
1564 let mut emitted = false;
1565 let mut needs_slash = false;
1566 let mut iter = path.components().peekable();
1567 while let Some(component) = iter.next() {
1568 let bytes = path2bytes(Path::new(component.as_os_str()))?;
1569 match (component, is_link_name) {
1570 (Component::Prefix(..), false) | (Component::RootDir, false) => {
1571 return Err(other("paths in archives must be relative"));
1572 }
1573 (Component::ParentDir, false) => {
1574 if !is_truncated_gnu_long_path || iter.peek().is_some() {
1578 return Err(other("paths in archives must not have `..`"));
1579 }
1580 }
1581 (Component::CurDir, false) if path.components().count() == 1 => {}
1583 (Component::CurDir, false) => continue,
1584 (Component::Normal(_), _) | (_, true) => {}
1585 };
1586 if needs_slash {
1587 copy(&mut slot, b"/")?;
1588 }
1589 if bytes.contains(&b'/') {
1590 if let Component::Normal(..) = component {
1591 return Err(other("path component in archive cannot contain `/`"));
1592 }
1593 }
1594 copy(&mut slot, &*bytes)?;
1595 if &*bytes != b"/" {
1596 needs_slash = true;
1597 }
1598 emitted = true;
1599 }
1600 if !emitted {
1601 return Err(other("paths in archives must have at least one component"));
1602 }
1603 if ends_with_slash(path) {
1604 copy(&mut slot, &[b'/'])?;
1605 }
1606 return Ok(());
1607
1608 fn copy(slot: &mut &mut [u8], bytes: &[u8]) -> io::Result<()> {
1609 copy_into(*slot, bytes)?;
1610 let tmp = mem::replace(slot, &mut []);
1611 *slot = &mut tmp[bytes.len()..];
1612 Ok(())
1613 }
1614}
1615
1616fn copy_path_into(slot: &mut [u8], path: &Path, is_link_name: bool) -> io::Result<()> {
1625 copy_path_into_inner(slot, path, is_link_name, false)
1626}
1627
1628fn copy_path_into_gnu_long(slot: &mut [u8], path: &Path, is_link_name: bool) -> io::Result<()> {
1639 copy_path_into_inner(slot, path, is_link_name, true)
1640}
1641
1642#[cfg(target_arch = "wasm32")]
1643fn ends_with_slash(p: &Path) -> bool {
1644 p.to_string_lossy().ends_with('/')
1645}
1646
1647#[cfg(windows)]
1648fn ends_with_slash(p: &Path) -> bool {
1649 let last = p.as_os_str().encode_wide().last();
1650 last == Some(b'/' as u16) || last == Some(b'\\' as u16)
1651}
1652
1653#[cfg(all(unix, not(target_arch = "wasm32")))]
1654fn ends_with_slash(p: &Path) -> bool {
1655 p.as_os_str().as_bytes().ends_with(&[b'/'])
1656}
1657
1658#[cfg(any(windows, target_arch = "wasm32"))]
1659pub fn path2bytes(p: &Path) -> io::Result<Cow<[u8]>> {
1660 p.as_os_str()
1661 .to_str()
1662 .map(|s| s.as_bytes())
1663 .ok_or_else(|| other(&format!("path {} was not valid Unicode", p.display())))
1664 .map(|bytes| {
1665 if bytes.contains(&b'\\') {
1666 let mut bytes = bytes.to_owned();
1668 for b in &mut bytes {
1669 if *b == b'\\' {
1670 *b = b'/';
1671 }
1672 }
1673 Cow::Owned(bytes)
1674 } else {
1675 Cow::Borrowed(bytes)
1676 }
1677 })
1678}
1679
1680#[cfg(all(unix, not(target_arch = "wasm32")))]
1681pub fn path2bytes(p: &Path) -> io::Result<Cow<[u8]>> {
1683 Ok(p.as_os_str().as_bytes()).map(Cow::Borrowed)
1684}
1685
1686#[cfg(windows)]
1687pub fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
1690 return match bytes {
1691 Cow::Borrowed(bytes) => {
1692 let s = str::from_utf8(bytes).map_err(|_| not_unicode(bytes))?;
1693 Ok(Cow::Borrowed(Path::new(s)))
1694 }
1695 Cow::Owned(bytes) => {
1696 let s = String::from_utf8(bytes).map_err(|uerr| not_unicode(&uerr.into_bytes()))?;
1697 Ok(Cow::Owned(PathBuf::from(s)))
1698 }
1699 };
1700
1701 fn not_unicode(v: &[u8]) -> io::Error {
1702 other(&format!(
1703 "only Unicode paths are supported on Windows: {}",
1704 String::from_utf8_lossy(v)
1705 ))
1706 }
1707}
1708
1709#[cfg(all(unix, not(target_arch = "wasm32")))]
1710pub fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
1712 use std::ffi::{OsStr, OsString};
1713
1714 Ok(match bytes {
1715 Cow::Borrowed(bytes) => Cow::Borrowed(Path::new(OsStr::from_bytes(bytes))),
1716 Cow::Owned(bytes) => Cow::Owned(PathBuf::from(OsString::from_vec(bytes))),
1717 })
1718}
1719
1720#[cfg(target_arch = "wasm32")]
1721pub fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
1722 Ok(match bytes {
1723 Cow::Borrowed(bytes) => {
1724 Cow::Borrowed(Path::new(str::from_utf8(bytes).map_err(invalid_utf8)?))
1725 }
1726 Cow::Owned(bytes) => Cow::Owned(PathBuf::from(
1727 String::from_utf8(bytes).map_err(invalid_utf8)?,
1728 )),
1729 })
1730}
1731
1732#[cfg(target_arch = "wasm32")]
1733fn invalid_utf8<T>(_: T) -> io::Error {
1734 io::Error::new(io::ErrorKind::InvalidData, "Invalid utf-8")
1735}