1#[cfg(any(unix, target_os = "redox"))]
2use std::os::unix::prelude::*;
3#[cfg(windows)]
4use std::os::windows::prelude::*;
5
6use std::{borrow::Cow, fmt, iter, iter::repeat, mem, str};
7
8use async_std::{
9 fs, io,
10 path::{Component, Path, PathBuf},
11};
12
13use crate::{other, EntryType};
14
15#[repr(C)]
17#[allow(missing_docs)]
18pub struct Header {
19 bytes: [u8; 512],
20}
21
22#[derive(Clone, Copy, PartialEq, Eq, Debug)]
25#[non_exhaustive]
26pub enum HeaderMode {
27 Complete,
30
31 Deterministic,
34}
35
36#[repr(C)]
38#[allow(missing_docs)]
39pub struct OldHeader {
40 pub name: [u8; 100],
41 pub mode: [u8; 8],
42 pub uid: [u8; 8],
43 pub gid: [u8; 8],
44 pub size: [u8; 12],
45 pub mtime: [u8; 12],
46 pub cksum: [u8; 8],
47 pub linkflag: [u8; 1],
48 pub linkname: [u8; 100],
49 pub pad: [u8; 255],
50}
51
52#[repr(C)]
54#[allow(missing_docs)]
55pub struct UstarHeader {
56 pub name: [u8; 100],
57 pub mode: [u8; 8],
58 pub uid: [u8; 8],
59 pub gid: [u8; 8],
60 pub size: [u8; 12],
61 pub mtime: [u8; 12],
62 pub cksum: [u8; 8],
63 pub typeflag: [u8; 1],
64 pub linkname: [u8; 100],
65
66 pub magic: [u8; 6],
68 pub version: [u8; 2],
69 pub uname: [u8; 32],
70 pub gname: [u8; 32],
71 pub dev_major: [u8; 8],
72 pub dev_minor: [u8; 8],
73 pub prefix: [u8; 155],
74 pub pad: [u8; 12],
75}
76
77#[repr(C)]
79#[allow(missing_docs)]
80pub struct GnuHeader {
81 pub name: [u8; 100],
82 pub mode: [u8; 8],
83 pub uid: [u8; 8],
84 pub gid: [u8; 8],
85 pub size: [u8; 12],
86 pub mtime: [u8; 12],
87 pub cksum: [u8; 8],
88 pub typeflag: [u8; 1],
89 pub linkname: [u8; 100],
90
91 pub magic: [u8; 6],
93 pub version: [u8; 2],
94 pub uname: [u8; 32],
95 pub gname: [u8; 32],
96 pub dev_major: [u8; 8],
97 pub dev_minor: [u8; 8],
98 pub atime: [u8; 12],
99 pub ctime: [u8; 12],
100 pub offset: [u8; 12],
101 pub longnames: [u8; 4],
102 pub unused: [u8; 1],
103 pub sparse: [GnuSparseHeader; 4],
104 pub isextended: [u8; 1],
105 pub realsize: [u8; 12],
106 pub pad: [u8; 17],
107}
108
109#[repr(C)]
113#[allow(missing_docs)]
114pub struct GnuSparseHeader {
115 pub offset: [u8; 12],
116 pub numbytes: [u8; 12],
117}
118
119#[repr(C)]
124#[allow(missing_docs)]
125#[derive(Debug)]
126pub struct GnuExtSparseHeader {
127 pub sparse: [GnuSparseHeader; 21],
128 pub isextended: [u8; 1],
129 pub padding: [u8; 7],
130}
131
132impl Header {
133 pub fn new_gnu() -> Header {
139 let mut header = Header { bytes: [0; 512] };
140 unsafe {
141 let gnu = cast_mut::<_, GnuHeader>(&mut header);
142 gnu.magic = *b"ustar ";
143 gnu.version = *b" \0";
144 }
145 header.set_mtime(0);
146 header
147 }
148
149 pub fn new_ustar() -> Header {
157 let mut header = Header { bytes: [0; 512] };
158 unsafe {
159 let gnu = cast_mut::<_, UstarHeader>(&mut header);
160 gnu.magic = *b"ustar\0";
161 gnu.version = *b"00";
162 }
163 header.set_mtime(0);
164 header
165 }
166
167 pub fn new_old() -> Header {
174 let mut header = Header { bytes: [0; 512] };
175 header.set_mtime(0);
176 header
177 }
178
179 fn is_ustar(&self) -> bool {
180 let ustar = unsafe { cast::<_, UstarHeader>(self) };
181 ustar.magic[..] == b"ustar\0"[..] && ustar.version[..] == b"00"[..]
182 }
183
184 fn is_gnu(&self) -> bool {
185 let ustar = unsafe { cast::<_, UstarHeader>(self) };
186 ustar.magic[..] == b"ustar "[..] && ustar.version[..] == b" \0"[..]
187 }
188
189 pub fn as_old(&self) -> &OldHeader {
194 unsafe { cast(self) }
195 }
196
197 pub fn as_old_mut(&mut self) -> &mut OldHeader {
199 unsafe { cast_mut(self) }
200 }
201
202 pub fn as_ustar(&self) -> Option<&UstarHeader> {
212 if self.is_ustar() {
213 Some(unsafe { cast(self) })
214 } else {
215 None
216 }
217 }
218
219 pub fn as_ustar_mut(&mut self) -> Option<&mut UstarHeader> {
221 if self.is_ustar() {
222 Some(unsafe { cast_mut(self) })
223 } else {
224 None
225 }
226 }
227
228 pub fn as_gnu(&self) -> Option<&GnuHeader> {
238 if self.is_gnu() {
239 Some(unsafe { cast(self) })
240 } else {
241 None
242 }
243 }
244
245 pub fn as_gnu_mut(&mut self) -> Option<&mut GnuHeader> {
247 if self.is_gnu() {
248 Some(unsafe { cast_mut(self) })
249 } else {
250 None
251 }
252 }
253
254 pub fn from_byte_slice(bytes: &[u8]) -> &Header {
258 assert_eq!(bytes.len(), mem::size_of::<Header>());
259 assert_eq!(mem::align_of_val(bytes), mem::align_of::<Header>());
260 unsafe { &*(bytes.as_ptr() as *const Header) }
261 }
262
263 pub fn as_bytes(&self) -> &[u8; 512] {
265 &self.bytes
266 }
267
268 pub fn as_mut_bytes(&mut self) -> &mut [u8; 512] {
270 &mut self.bytes
271 }
272
273 pub fn set_metadata(&mut self, meta: &fs::Metadata) {
280 self.fill_from(meta, HeaderMode::Complete);
281 }
282
283 pub fn set_metadata_in_mode(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
286 self.fill_from(meta, mode);
287 }
288
289 pub fn entry_size(&self) -> io::Result<u64> {
298 num_field_wrapper_from(&self.as_old().size).map_err(|err| {
299 io::Error::new(
300 err.kind(),
301 format!("{} when getting size for {}", err, self.path_lossy()),
302 )
303 })
304 }
305
306 pub fn size(&self) -> io::Result<u64> {
310 if self.entry_type().is_gnu_sparse() {
311 self.as_gnu()
312 .ok_or_else(|| other("sparse header was not a gnu header"))
313 .and_then(GnuHeader::real_size)
314 } else {
315 self.entry_size()
316 }
317 }
318
319 pub fn set_size(&mut self, size: u64) {
321 num_field_wrapper_into(&mut self.as_old_mut().size, size);
322 }
323
324 pub fn path(&self) -> io::Result<Cow<Path>> {
332 bytes2path(self.path_bytes())
333 }
334
335 pub fn path_bytes(&self) -> Cow<[u8]> {
343 if let Some(ustar) = self.as_ustar() {
344 ustar.path_bytes()
345 } else {
346 let name = truncate(&self.as_old().name);
347 Cow::Borrowed(name)
348 }
349 }
350
351 fn path_lossy(&self) -> String {
353 String::from_utf8_lossy(&self.path_bytes()).to_string()
354 }
355
356 pub fn set_path<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> {
362 self.set_path_inner(p.as_ref(), false)
363 }
364
365 pub(crate) fn set_truncated_path_for_gnu_header<P: AsRef<Path>>(
369 &mut self,
370 p: P,
371 ) -> io::Result<()> {
372 self.set_path_inner(p.as_ref(), true)
373 }
374
375 fn set_path_inner(&mut self, path: &Path, is_truncated_gnu_long_path: bool) -> io::Result<()> {
376 if let Some(ustar) = self.as_ustar_mut() {
377 return ustar.set_path(path);
378 }
379 if is_truncated_gnu_long_path {
380 copy_path_into_gnu_long(&mut self.as_old_mut().name, path, false)
381 } else {
382 copy_path_into(&mut self.as_old_mut().name, path, false)
383 }
384 .map_err(|err| {
385 io::Error::new(
386 err.kind(),
387 format!("{} when setting path for {}", err, self.path_lossy()),
388 )
389 })
390 }
391
392 pub fn link_name(&self) -> io::Result<Option<Cow<Path>>> {
401 match self.link_name_bytes() {
402 Some(bytes) => bytes2path(bytes).map(Some),
403 None => Ok(None),
404 }
405 }
406
407 pub fn link_name_bytes(&self) -> Option<Cow<[u8]>> {
415 let old = self.as_old();
416 if old.linkname[0] == 0 {
417 None
418 } else {
419 Some(Cow::Borrowed(truncate(&old.linkname)))
420 }
421 }
422
423 pub fn set_link_name<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> {
429 self._set_link_name(p.as_ref())
430 }
431
432 fn _set_link_name(&mut self, path: &Path) -> io::Result<()> {
433 copy_path_into(&mut self.as_old_mut().linkname, path, true).map_err(|err| {
434 io::Error::new(
435 err.kind(),
436 format!("{} when setting link name for {}", err, self.path_lossy()),
437 )
438 })
439 }
440
441 pub fn mode(&self) -> io::Result<u32> {
445 octal_from(&self.as_old().mode)
446 .map(|u| u as u32)
447 .map_err(|err| {
448 io::Error::new(
449 err.kind(),
450 format!("{} when getting mode for {}", err, self.path_lossy()),
451 )
452 })
453 }
454
455 pub fn set_mode(&mut self, mode: u32) {
457 octal_into(&mut self.as_old_mut().mode, mode);
458 }
459
460 pub fn uid(&self) -> io::Result<u64> {
464 num_field_wrapper_from(&self.as_old().uid).map_err(|err| {
465 io::Error::new(
466 err.kind(),
467 format!("{} when getting uid for {}", err, self.path_lossy()),
468 )
469 })
470 }
471
472 pub fn set_uid(&mut self, uid: u64) {
474 num_field_wrapper_into(&mut self.as_old_mut().uid, uid);
475 }
476
477 pub fn gid(&self) -> io::Result<u64> {
479 num_field_wrapper_from(&self.as_old().gid).map_err(|err| {
480 io::Error::new(
481 err.kind(),
482 format!("{} when getting gid for {}", err, self.path_lossy()),
483 )
484 })
485 }
486
487 pub fn set_gid(&mut self, gid: u64) {
489 num_field_wrapper_into(&mut self.as_old_mut().gid, gid);
490 }
491
492 pub fn mtime(&self) -> io::Result<u64> {
494 num_field_wrapper_from(&self.as_old().mtime).map_err(|err| {
495 io::Error::new(
496 err.kind(),
497 format!("{} when getting mtime for {}", err, self.path_lossy()),
498 )
499 })
500 }
501
502 pub fn set_mtime(&mut self, mtime: u64) {
507 num_field_wrapper_into(&mut self.as_old_mut().mtime, mtime);
508 }
509
510 pub fn username(&self) -> Result<Option<&str>, str::Utf8Error> {
517 match self.username_bytes() {
518 Some(bytes) => str::from_utf8(bytes).map(Some),
519 None => Ok(None),
520 }
521 }
522
523 pub fn username_bytes(&self) -> Option<&[u8]> {
528 if let Some(ustar) = self.as_ustar() {
529 Some(ustar.username_bytes())
530 } else if let Some(gnu) = self.as_gnu() {
531 Some(gnu.username_bytes())
532 } else {
533 None
534 }
535 }
536
537 pub fn set_username(&mut self, name: &str) -> io::Result<()> {
542 if let Some(ustar) = self.as_ustar_mut() {
543 return ustar.set_username(name);
544 }
545 if let Some(gnu) = self.as_gnu_mut() {
546 gnu.set_username(name)
547 } else {
548 Err(other("not a ustar or gnu archive, cannot set username"))
549 }
550 }
551
552 pub fn groupname(&self) -> Result<Option<&str>, str::Utf8Error> {
559 match self.groupname_bytes() {
560 Some(bytes) => str::from_utf8(bytes).map(Some),
561 None => Ok(None),
562 }
563 }
564
565 pub fn groupname_bytes(&self) -> Option<&[u8]> {
570 if let Some(ustar) = self.as_ustar() {
571 Some(ustar.groupname_bytes())
572 } else if let Some(gnu) = self.as_gnu() {
573 Some(gnu.groupname_bytes())
574 } else {
575 None
576 }
577 }
578
579 pub fn set_groupname(&mut self, name: &str) -> io::Result<()> {
584 if let Some(ustar) = self.as_ustar_mut() {
585 return ustar.set_groupname(name);
586 }
587 if let Some(gnu) = self.as_gnu_mut() {
588 gnu.set_groupname(name)
589 } else {
590 Err(other("not a ustar or gnu archive, cannot set groupname"))
591 }
592 }
593
594 pub fn device_major(&self) -> io::Result<Option<u32>> {
602 if let Some(ustar) = self.as_ustar() {
603 ustar.device_major().map(Some)
604 } else if let Some(gnu) = self.as_gnu() {
605 gnu.device_major().map(Some)
606 } else {
607 Ok(None)
608 }
609 }
610
611 pub fn set_device_major(&mut self, major: u32) -> io::Result<()> {
616 if let Some(ustar) = self.as_ustar_mut() {
617 ustar.set_device_major(major);
618 Ok(())
619 } else if let Some(gnu) = self.as_gnu_mut() {
620 gnu.set_device_major(major);
621 Ok(())
622 } else {
623 Err(other("not a ustar or gnu archive, cannot set dev_major"))
624 }
625 }
626
627 pub fn device_minor(&self) -> io::Result<Option<u32>> {
635 if let Some(ustar) = self.as_ustar() {
636 ustar.device_minor().map(Some)
637 } else if let Some(gnu) = self.as_gnu() {
638 gnu.device_minor().map(Some)
639 } else {
640 Ok(None)
641 }
642 }
643
644 pub fn set_device_minor(&mut self, minor: u32) -> io::Result<()> {
649 if let Some(ustar) = self.as_ustar_mut() {
650 ustar.set_device_minor(minor);
651 Ok(())
652 } else if let Some(gnu) = self.as_gnu_mut() {
653 gnu.set_device_minor(minor);
654 Ok(())
655 } else {
656 Err(other("not a ustar or gnu archive, cannot set dev_minor"))
657 }
658 }
659
660 pub fn entry_type(&self) -> EntryType {
662 EntryType::new(self.as_old().linkflag[0])
663 }
664
665 pub fn set_entry_type(&mut self, ty: EntryType) {
667 self.as_old_mut().linkflag = [ty.as_byte()];
668 }
669
670 pub fn cksum(&self) -> io::Result<u32> {
674 octal_from(&self.as_old().cksum)
675 .map(|u| u as u32)
676 .map_err(|err| {
677 io::Error::new(
678 err.kind(),
679 format!("{} when getting cksum for {}", err, self.path_lossy()),
680 )
681 })
682 }
683
684 pub fn set_cksum(&mut self) {
687 let cksum = self.calculate_cksum();
688 octal_into(&mut self.as_old_mut().cksum, cksum);
689 }
690
691 fn calculate_cksum(&self) -> u32 {
692 let old = self.as_old();
693 let start = old as *const _ as usize;
694 let cksum_start = old.cksum.as_ptr() as *const _ as usize;
695 let offset = cksum_start - start;
696 let len = old.cksum.len();
697 self.bytes[0..offset]
698 .iter()
699 .chain(iter::repeat(&b' ').take(len))
700 .chain(&self.bytes[offset + len..])
701 .fold(0, |a, b| a + (*b as u32))
702 }
703
704 fn fill_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
705 self.fill_platform_from(meta, mode);
706 self.set_size(if meta.is_dir() || meta.file_type().is_symlink() {
708 0
709 } else {
710 meta.len()
711 });
712 if let Some(ustar) = self.as_ustar_mut() {
713 ustar.set_device_major(0);
714 ustar.set_device_minor(0);
715 }
716 if let Some(gnu) = self.as_gnu_mut() {
717 gnu.set_device_major(0);
718 gnu.set_device_minor(0);
719 }
720 }
721
722 #[cfg(target_arch = "wasm32")]
723 #[allow(unused_variables)]
724 fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
725 unimplemented!();
726 }
727
728 #[cfg(any(unix, target_os = "redox"))]
729 fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
730 match mode {
731 HeaderMode::Complete => {
732 self.set_mtime(meta.mtime() as u64);
733 self.set_uid(meta.uid() as u64);
734 self.set_gid(meta.gid() as u64);
735 self.set_mode(meta.mode());
736 }
737 HeaderMode::Deterministic => {
738 self.set_mtime(0);
739 self.set_uid(0);
740 self.set_gid(0);
741
742 let fs_mode = if meta.is_dir() || (0o100 & meta.mode() == 0o100) {
744 0o755
745 } else {
746 0o644
747 };
748 self.set_mode(fs_mode);
749 }
750 }
751
752 self.set_entry_type(entry_type(meta.mode()));
763
764 #[cfg(not(target_os = "redox"))]
765 fn entry_type(mode: u32) -> EntryType {
766 match mode as libc::mode_t & libc::S_IFMT {
767 libc::S_IFREG => EntryType::file(),
768 libc::S_IFLNK => EntryType::symlink(),
769 libc::S_IFCHR => EntryType::character_special(),
770 libc::S_IFBLK => EntryType::block_special(),
771 libc::S_IFDIR => EntryType::dir(),
772 libc::S_IFIFO => EntryType::fifo(),
773 _ => EntryType::new(b' '),
774 }
775 }
776
777 #[cfg(target_os = "redox")]
778 fn entry_type(mode: u32) -> EntryType {
779 use syscall;
780 match mode as u16 & syscall::MODE_TYPE {
781 syscall::MODE_FILE => EntryType::file(),
782 syscall::MODE_SYMLINK => EntryType::symlink(),
783 syscall::MODE_DIR => EntryType::dir(),
784 _ => EntryType::new(b' '),
785 }
786 }
787 }
788
789 #[cfg(windows)]
790 fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
791 match mode {
793 HeaderMode::Complete => {
794 self.set_uid(0);
795 self.set_gid(0);
796 let mtime = (meta.last_write_time() / (1_000_000_000 / 100)) - 11644473600;
801 self.set_mtime(mtime);
802 let fs_mode = {
803 const FILE_ATTRIBUTE_READONLY: u32 = 0x00000001;
804 let readonly = meta.file_attributes() & FILE_ATTRIBUTE_READONLY;
805 match (meta.is_dir(), readonly != 0) {
806 (true, false) => 0o755,
807 (true, true) => 0o555,
808 (false, false) => 0o644,
809 (false, true) => 0o444,
810 }
811 };
812 self.set_mode(fs_mode);
813 }
814 HeaderMode::Deterministic => {
815 self.set_uid(0);
816 self.set_gid(0);
817 self.set_mtime(0);
818 let fs_mode = if meta.is_dir() { 0o755 } else { 0o644 };
819 self.set_mode(fs_mode);
820 }
821 }
822
823 let ft = meta.file_type();
824 self.set_entry_type(if ft.is_dir() {
825 EntryType::dir()
826 } else if ft.is_file() {
827 EntryType::file()
828 } else if ft.is_symlink() {
829 EntryType::symlink()
830 } else {
831 EntryType::new(b' ')
832 });
833 }
834
835 fn debug_fields(&self, b: &mut fmt::DebugStruct) {
836 if let Ok(entry_size) = self.entry_size() {
837 b.field("entry_size", &entry_size);
838 }
839 if let Ok(size) = self.size() {
840 b.field("size", &size);
841 }
842 if let Ok(path) = self.path() {
843 b.field("path", &path);
844 }
845 if let Ok(link_name) = self.link_name() {
846 b.field("link_name", &link_name);
847 }
848 if let Ok(mode) = self.mode() {
849 b.field("mode", &DebugAsOctal(mode));
850 }
851 if let Ok(uid) = self.uid() {
852 b.field("uid", &uid);
853 }
854 if let Ok(gid) = self.gid() {
855 b.field("gid", &gid);
856 }
857 if let Ok(mtime) = self.mtime() {
858 b.field("mtime", &mtime);
859 }
860 if let Ok(username) = self.username() {
861 b.field("username", &username);
862 }
863 if let Ok(groupname) = self.groupname() {
864 b.field("groupname", &groupname);
865 }
866 if let Ok(device_major) = self.device_major() {
867 b.field("device_major", &device_major);
868 }
869 if let Ok(device_minor) = self.device_minor() {
870 b.field("device_minor", &device_minor);
871 }
872 if let Ok(cksum) = self.cksum() {
873 b.field("cksum", &cksum);
874 b.field("cksum_valid", &(cksum == self.calculate_cksum()));
875 }
876 }
877}
878
879struct DebugAsOctal<T>(T);
880
881impl<T: fmt::Octal> fmt::Debug for DebugAsOctal<T> {
882 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
883 fmt::Octal::fmt(&self.0, f)
884 }
885}
886
887unsafe fn cast<T, U>(a: &T) -> &U {
888 assert_eq!(mem::size_of_val(a), mem::size_of::<U>());
889 assert_eq!(mem::align_of_val(a), mem::align_of::<U>());
890 &*(a as *const T as *const U)
891}
892
893unsafe fn cast_mut<T, U>(a: &mut T) -> &mut U {
894 assert_eq!(mem::size_of_val(a), mem::size_of::<U>());
895 assert_eq!(mem::align_of_val(a), mem::align_of::<U>());
896 &mut *(a as *mut T as *mut U)
897}
898
899impl Clone for Header {
900 fn clone(&self) -> Header {
901 Header { bytes: self.bytes }
902 }
903}
904
905impl fmt::Debug for Header {
906 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
907 if let Some(me) = self.as_ustar() {
908 me.fmt(f)
909 } else if let Some(me) = self.as_gnu() {
910 me.fmt(f)
911 } else {
912 self.as_old().fmt(f)
913 }
914 }
915}
916
917impl OldHeader {
918 pub fn as_header(&self) -> &Header {
920 unsafe { cast(self) }
921 }
922
923 pub fn as_header_mut(&mut self) -> &mut Header {
925 unsafe { cast_mut(self) }
926 }
927}
928
929impl fmt::Debug for OldHeader {
930 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
931 let mut f = f.debug_struct("OldHeader");
932 self.as_header().debug_fields(&mut f);
933 f.finish()
934 }
935}
936
937impl UstarHeader {
938 pub fn path_bytes(&self) -> Cow<[u8]> {
940 if self.prefix[0] == 0 && !self.name.contains(&b'\\') {
941 Cow::Borrowed(truncate(&self.name))
942 } else {
943 let mut bytes = Vec::new();
944 let prefix = truncate(&self.prefix);
945 if !prefix.is_empty() {
946 bytes.extend_from_slice(prefix);
947 bytes.push(b'/');
948 }
949 bytes.extend_from_slice(truncate(&self.name));
950 Cow::Owned(bytes)
951 }
952 }
953
954 fn path_lossy(&self) -> String {
956 String::from_utf8_lossy(&self.path_bytes()).to_string()
957 }
958
959 pub fn set_path<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> {
961 self._set_path(p.as_ref())
962 }
963
964 fn _set_path(&mut self, path: &Path) -> io::Result<()> {
965 let bytes = path2bytes(path)?;
974 let (maxnamelen, maxprefixlen) = (self.name.len(), self.prefix.len());
975 if bytes.len() <= maxnamelen {
976 copy_path_into(&mut self.name, path, false).map_err(|err| {
977 io::Error::new(
978 err.kind(),
979 format!("{} when setting path for {}", err, self.path_lossy()),
980 )
981 })?;
982 } else {
983 let mut prefix = path;
984 let mut prefixlen;
985 loop {
986 match prefix.parent() {
987 Some(parent) => prefix = parent,
988 None => {
989 return Err(other(&format!(
990 "path cannot be split to be inserted into archive: {}",
991 path.display()
992 )));
993 }
994 }
995 prefixlen = path2bytes(prefix)?.len();
996 if prefixlen <= maxprefixlen {
997 break;
998 }
999 }
1000 copy_path_into(&mut self.prefix, prefix, false).map_err(|err| {
1001 io::Error::new(
1002 err.kind(),
1003 format!("{} when setting path for {}", err, self.path_lossy()),
1004 )
1005 })?;
1006 let path = bytes2path(Cow::Borrowed(&bytes[prefixlen + 1..]))?;
1007 copy_path_into(&mut self.name, &path, false).map_err(|err| {
1008 io::Error::new(
1009 err.kind(),
1010 format!("{} when setting path for {}", err, self.path_lossy()),
1011 )
1012 })?;
1013 }
1014 Ok(())
1015 }
1016
1017 pub fn username_bytes(&self) -> &[u8] {
1019 truncate(&self.uname)
1020 }
1021
1022 pub fn set_username(&mut self, name: &str) -> io::Result<()> {
1024 copy_into(&mut self.uname, name.as_bytes()).map_err(|err| {
1025 io::Error::new(
1026 err.kind(),
1027 format!("{} when setting username for {}", err, self.path_lossy()),
1028 )
1029 })
1030 }
1031
1032 pub fn groupname_bytes(&self) -> &[u8] {
1034 truncate(&self.gname)
1035 }
1036
1037 pub fn set_groupname(&mut self, name: &str) -> io::Result<()> {
1039 copy_into(&mut self.gname, name.as_bytes()).map_err(|err| {
1040 io::Error::new(
1041 err.kind(),
1042 format!("{} when setting groupname for {}", err, self.path_lossy()),
1043 )
1044 })
1045 }
1046
1047 pub fn device_major(&self) -> io::Result<u32> {
1049 octal_from(&self.dev_major)
1050 .map(|u| u as u32)
1051 .map_err(|err| {
1052 io::Error::new(
1053 err.kind(),
1054 format!(
1055 "{} when getting device_major for {}",
1056 err,
1057 self.path_lossy()
1058 ),
1059 )
1060 })
1061 }
1062
1063 pub fn set_device_major(&mut self, major: u32) {
1065 octal_into(&mut self.dev_major, major);
1066 }
1067
1068 pub fn device_minor(&self) -> io::Result<u32> {
1070 octal_from(&self.dev_minor)
1071 .map(|u| u as u32)
1072 .map_err(|err| {
1073 io::Error::new(
1074 err.kind(),
1075 format!(
1076 "{} when getting device_minor for {}",
1077 err,
1078 self.path_lossy()
1079 ),
1080 )
1081 })
1082 }
1083
1084 pub fn set_device_minor(&mut self, minor: u32) {
1086 octal_into(&mut self.dev_minor, minor);
1087 }
1088
1089 pub fn as_header(&self) -> &Header {
1091 unsafe { cast(self) }
1092 }
1093
1094 pub fn as_header_mut(&mut self) -> &mut Header {
1096 unsafe { cast_mut(self) }
1097 }
1098}
1099
1100impl fmt::Debug for UstarHeader {
1101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1102 let mut f = f.debug_struct("UstarHeader");
1103 self.as_header().debug_fields(&mut f);
1104 f.finish()
1105 }
1106}
1107
1108impl GnuHeader {
1109 pub fn username_bytes(&self) -> &[u8] {
1111 truncate(&self.uname)
1112 }
1113
1114 fn fullname_lossy(&self) -> String {
1116 format!(
1117 "{}:{}",
1118 String::from_utf8_lossy(self.groupname_bytes()),
1119 String::from_utf8_lossy(self.username_bytes()),
1120 )
1121 }
1122
1123 pub fn set_username(&mut self, name: &str) -> io::Result<()> {
1125 copy_into(&mut self.uname, name.as_bytes()).map_err(|err| {
1126 io::Error::new(
1127 err.kind(),
1128 format!(
1129 "{} when setting username for {}",
1130 err,
1131 self.fullname_lossy()
1132 ),
1133 )
1134 })
1135 }
1136
1137 pub fn groupname_bytes(&self) -> &[u8] {
1139 truncate(&self.gname)
1140 }
1141
1142 pub fn set_groupname(&mut self, name: &str) -> io::Result<()> {
1144 copy_into(&mut self.gname, name.as_bytes()).map_err(|err| {
1145 io::Error::new(
1146 err.kind(),
1147 format!(
1148 "{} when setting groupname for {}",
1149 err,
1150 self.fullname_lossy()
1151 ),
1152 )
1153 })
1154 }
1155
1156 pub fn device_major(&self) -> io::Result<u32> {
1158 octal_from(&self.dev_major)
1159 .map(|u| u as u32)
1160 .map_err(|err| {
1161 io::Error::new(
1162 err.kind(),
1163 format!(
1164 "{} when getting device_major for {}",
1165 err,
1166 self.fullname_lossy()
1167 ),
1168 )
1169 })
1170 }
1171
1172 pub fn set_device_major(&mut self, major: u32) {
1174 octal_into(&mut self.dev_major, major);
1175 }
1176
1177 pub fn device_minor(&self) -> io::Result<u32> {
1179 octal_from(&self.dev_minor)
1180 .map(|u| u as u32)
1181 .map_err(|err| {
1182 io::Error::new(
1183 err.kind(),
1184 format!(
1185 "{} when getting device_minor for {}",
1186 err,
1187 self.fullname_lossy()
1188 ),
1189 )
1190 })
1191 }
1192
1193 pub fn set_device_minor(&mut self, minor: u32) {
1195 octal_into(&mut self.dev_minor, minor);
1196 }
1197
1198 pub fn atime(&self) -> io::Result<u64> {
1200 num_field_wrapper_from(&self.atime).map_err(|err| {
1201 io::Error::new(
1202 err.kind(),
1203 format!("{} when getting atime for {}", err, self.fullname_lossy()),
1204 )
1205 })
1206 }
1207
1208 pub fn set_atime(&mut self, atime: u64) {
1213 num_field_wrapper_into(&mut self.atime, atime);
1214 }
1215
1216 pub fn ctime(&self) -> io::Result<u64> {
1218 num_field_wrapper_from(&self.ctime).map_err(|err| {
1219 io::Error::new(
1220 err.kind(),
1221 format!("{} when getting ctime for {}", err, self.fullname_lossy()),
1222 )
1223 })
1224 }
1225
1226 pub fn set_ctime(&mut self, ctime: u64) {
1231 num_field_wrapper_into(&mut self.ctime, ctime);
1232 }
1233
1234 pub fn real_size(&self) -> io::Result<u64> {
1239 octal_from(&self.realsize).map_err(|err| {
1240 io::Error::new(
1241 err.kind(),
1242 format!(
1243 "{} when getting real_size for {}",
1244 err,
1245 self.fullname_lossy()
1246 ),
1247 )
1248 })
1249 }
1250
1251 pub fn is_extended(&self) -> bool {
1257 self.isextended[0] == 1
1258 }
1259
1260 pub fn as_header(&self) -> &Header {
1262 unsafe { cast(self) }
1263 }
1264
1265 pub fn as_header_mut(&mut self) -> &mut Header {
1267 unsafe { cast_mut(self) }
1268 }
1269}
1270
1271impl fmt::Debug for GnuHeader {
1272 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1273 let mut f = f.debug_struct("GnuHeader");
1274 self.as_header().debug_fields(&mut f);
1275 if let Ok(atime) = self.atime() {
1276 f.field("atime", &atime);
1277 }
1278 if let Ok(ctime) = self.ctime() {
1279 f.field("ctime", &ctime);
1280 }
1281 f.field("is_extended", &self.is_extended())
1282 .field("sparse", &DebugSparseHeaders(&self.sparse))
1283 .finish()
1284 }
1285}
1286
1287struct DebugSparseHeaders<'a>(&'a [GnuSparseHeader]);
1288
1289impl<'a> fmt::Debug for DebugSparseHeaders<'a> {
1290 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1291 let mut f = f.debug_list();
1292 for header in self.0 {
1293 if !header.is_empty() {
1294 f.entry(header);
1295 }
1296 }
1297 f.finish()
1298 }
1299}
1300
1301impl GnuSparseHeader {
1302 pub fn is_empty(&self) -> bool {
1304 self.offset[0] == 0 || self.numbytes[0] == 0
1305 }
1306
1307 pub fn offset(&self) -> io::Result<u64> {
1311 octal_from(&self.offset).map_err(|err| {
1312 io::Error::new(
1313 err.kind(),
1314 format!("{} when getting offset from sparse header", err),
1315 )
1316 })
1317 }
1318
1319 pub fn length(&self) -> io::Result<u64> {
1323 octal_from(&self.numbytes).map_err(|err| {
1324 io::Error::new(
1325 err.kind(),
1326 format!("{} when getting length from sparse header", err),
1327 )
1328 })
1329 }
1330}
1331
1332impl fmt::Debug for GnuSparseHeader {
1333 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1334 let mut f = f.debug_struct("GnuSparseHeader");
1335 if let Ok(offset) = self.offset() {
1336 f.field("offset", &offset);
1337 }
1338 if let Ok(length) = self.length() {
1339 f.field("length", &length);
1340 }
1341 f.finish()
1342 }
1343}
1344
1345impl GnuExtSparseHeader {
1346 pub fn new() -> GnuExtSparseHeader {
1348 unsafe { mem::zeroed() }
1349 }
1350
1351 pub fn as_bytes(&self) -> &[u8; 512] {
1353 debug_assert_eq!(mem::size_of_val(self), 512);
1354 unsafe { &*(self as *const GnuExtSparseHeader as *const [u8; 512]) }
1355 }
1356
1357 pub fn as_mut_bytes(&mut self) -> &mut [u8; 512] {
1359 debug_assert_eq!(mem::size_of_val(self), 512);
1360 unsafe { &mut *(self as *mut GnuExtSparseHeader as *mut [u8; 512]) }
1361 }
1362
1363 pub fn sparse(&self) -> &[GnuSparseHeader; 21] {
1368 &self.sparse
1369 }
1370
1371 pub fn is_extended(&self) -> bool {
1373 self.isextended[0] == 1
1374 }
1375}
1376
1377impl Default for GnuExtSparseHeader {
1378 fn default() -> Self {
1379 Self::new()
1380 }
1381}
1382
1383fn octal_from(slice: &[u8]) -> io::Result<u64> {
1384 let trun = truncate(slice);
1385 let num = match str::from_utf8(trun) {
1386 Ok(n) => n,
1387 Err(_) => {
1388 return Err(other(&format!(
1389 "numeric field did not have utf-8 text: {}",
1390 String::from_utf8_lossy(trun)
1391 )));
1392 }
1393 };
1394 match u64::from_str_radix(num.trim(), 8) {
1395 Ok(n) => Ok(n),
1396 Err(_) => Err(other(&format!("numeric field was not a number: {}", num))),
1397 }
1398}
1399
1400fn octal_into<T: fmt::Octal>(dst: &mut [u8], val: T) {
1401 let o = format!("{:o}", val);
1402 let value = o.bytes().rev().chain(repeat(b'0'));
1403 for (slot, value) in dst.iter_mut().rev().skip(1).zip(value) {
1404 *slot = value;
1405 }
1406}
1407
1408fn num_field_wrapper_into(dst: &mut [u8], src: u64) {
1411 if src >= 8_589_934_592 || (src >= 2_097_152 && dst.len() == 8) {
1412 numeric_extended_into(dst, src);
1413 } else {
1414 octal_into(dst, src);
1415 }
1416}
1417
1418fn num_field_wrapper_from(src: &[u8]) -> io::Result<u64> {
1421 if src[0] & 0x80 == 0 {
1422 octal_from(src)
1423 } else {
1424 Ok(numeric_extended_from(src))
1425 }
1426}
1427
1428fn numeric_extended_into(dst: &mut [u8], src: u64) {
1433 let len: usize = dst.len();
1434 for (slot, val) in dst.iter_mut().zip(
1435 repeat(0)
1436 .take(len - 8) .chain((0..8).rev().map(|x| ((src >> (8 * x)) & 0xff) as u8)),
1438 ) {
1439 *slot = val;
1440 }
1441 dst[0] |= 0x80;
1442}
1443
1444fn numeric_extended_from(src: &[u8]) -> u64 {
1445 let mut dst: u64 = 0;
1446 let mut b_to_skip = 1;
1447 if src.len() == 8 {
1448 dst = (src[0] ^ 0x80) as u64;
1450 } else {
1451 b_to_skip = src.len() - 8;
1453 }
1454 for byte in src.iter().skip(b_to_skip) {
1455 dst <<= 8;
1456 dst |= *byte as u64;
1457 }
1458 dst
1459}
1460
1461fn truncate(slice: &[u8]) -> &[u8] {
1462 match slice.iter().position(|i| *i == 0) {
1463 Some(i) => &slice[..i],
1464 None => slice,
1465 }
1466}
1467
1468fn copy_into(slot: &mut [u8], bytes: &[u8]) -> io::Result<()> {
1471 if bytes.len() > slot.len() {
1472 Err(other("provided value is too long"))
1473 } else if bytes.iter().any(|b| *b == 0) {
1474 Err(other("provided value contains a nul byte"))
1475 } else {
1476 for (slot, val) in slot.iter_mut().zip(bytes.iter().chain(Some(&0))) {
1477 *slot = *val;
1478 }
1479 Ok(())
1480 }
1481}
1482
1483fn copy_path_into_inner(
1484 mut slot: &mut [u8],
1485 path: &Path,
1486 is_link_name: bool,
1487 is_truncated_gnu_long_path: bool,
1488) -> io::Result<()> {
1489 let mut emitted = false;
1490 let mut needs_slash = false;
1491 let mut iter = path.components().peekable();
1492 while let Some(component) = iter.next() {
1493 let bytes = path2bytes(Path::new(component.as_os_str()))?;
1494 match (component, is_link_name) {
1495 (Component::Prefix(..), false) | (Component::RootDir, false) => {
1496 return Err(other("paths in archives must be relative"));
1497 }
1498 (Component::ParentDir, false) => {
1499 if is_truncated_gnu_long_path && iter.peek().is_none() {
1500 {}
1503 } else {
1504 return Err(other("paths in archives must not have `..`"));
1505 }
1506 }
1507 (Component::CurDir, false) if path.components().count() == 1 => {}
1509 (Component::CurDir, false) => continue,
1510 (Component::Normal(_), _) | (_, true) => {}
1511 };
1512 if needs_slash {
1513 copy(&mut slot, b"/")?;
1514 }
1515 if bytes.contains(&b'/') {
1516 if let Component::Normal(..) = component {
1517 return Err(other("path component in archive cannot contain `/`"));
1518 }
1519 }
1520 copy(&mut slot, &bytes)?;
1521 if &*bytes != b"/" {
1522 needs_slash = true;
1523 }
1524 emitted = true;
1525 }
1526 if !emitted {
1527 return Err(other("paths in archives must have at least one component"));
1528 }
1529 if ends_with_slash(path) {
1530 copy(&mut slot, &[b'/'])?;
1531 }
1532 return Ok(());
1533
1534 fn copy(slot: &mut &mut [u8], bytes: &[u8]) -> io::Result<()> {
1535 copy_into(slot, bytes)?;
1536 let tmp = std::mem::take(slot);
1537 *slot = &mut tmp[bytes.len()..];
1538 Ok(())
1539 }
1540}
1541
1542fn copy_path_into(slot: &mut [u8], path: &Path, is_link_name: bool) -> io::Result<()> {
1551 copy_path_into_inner(slot, path, is_link_name, false)
1552}
1553
1554fn copy_path_into_gnu_long(slot: &mut [u8], path: &Path, is_link_name: bool) -> io::Result<()> {
1565 copy_path_into_inner(slot, path, is_link_name, true)
1566}
1567
1568#[cfg(target_arch = "wasm32")]
1569fn ends_with_slash(p: &Path) -> bool {
1570 p.to_string_lossy().ends_with('/')
1571}
1572
1573#[cfg(windows)]
1574fn ends_with_slash(p: &Path) -> bool {
1575 let last = p.as_os_str().encode_wide().last();
1576 last == Some(b'/' as u16) || last == Some(b'\\' as u16)
1577}
1578
1579#[cfg(any(unix, target_os = "redox"))]
1580fn ends_with_slash(p: &Path) -> bool {
1581 p.as_os_str().as_bytes().ends_with(&[b'/'])
1582}
1583
1584#[cfg(any(windows, target_arch = "wasm32"))]
1585pub fn path2bytes(p: &Path) -> io::Result<Cow<[u8]>> {
1586 p.as_os_str()
1587 .to_str()
1588 .map(|s| s.as_bytes())
1589 .ok_or_else(|| other(&format!("path {} was not valid Unicode", p.display())))
1590 .map(|bytes| {
1591 if bytes.contains(&b'\\') {
1592 let mut bytes = bytes.to_owned();
1594 for b in &mut bytes {
1595 if *b == b'\\' {
1596 *b = b'/';
1597 }
1598 }
1599 Cow::Owned(bytes)
1600 } else {
1601 Cow::Borrowed(bytes)
1602 }
1603 })
1604}
1605
1606#[cfg(any(unix, target_os = "redox"))]
1607pub fn path2bytes(p: &Path) -> io::Result<Cow<[u8]>> {
1609 Ok(Cow::Borrowed(p.as_os_str().as_bytes()))
1610}
1611
1612#[cfg(windows)]
1613pub fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
1616 return match bytes {
1617 Cow::Borrowed(bytes) => {
1618 let s = str::from_utf8(bytes).map_err(|_| not_unicode(bytes))?;
1619 Ok(Cow::Borrowed(Path::new(s)))
1620 }
1621 Cow::Owned(bytes) => {
1622 let s = String::from_utf8(bytes).map_err(|uerr| not_unicode(&uerr.into_bytes()))?;
1623 Ok(Cow::Owned(PathBuf::from(s)))
1624 }
1625 };
1626
1627 fn not_unicode(v: &[u8]) -> io::Error {
1628 other(&format!(
1629 "only Unicode paths are supported on Windows: {}",
1630 String::from_utf8_lossy(v)
1631 ))
1632 }
1633}
1634
1635#[cfg(any(unix, target_os = "redox"))]
1636pub fn bytes2path(bytes: Cow<'_, [u8]>) -> io::Result<Cow<'_, Path>> {
1638 use std::ffi::{OsStr, OsString};
1639
1640 Ok(match bytes {
1641 Cow::Borrowed(bytes) => Cow::Borrowed(Path::new(OsStr::from_bytes(bytes))),
1642 Cow::Owned(bytes) => Cow::Owned(PathBuf::from(OsString::from_vec(bytes))),
1643 })
1644}
1645
1646#[cfg(target_arch = "wasm32")]
1647pub fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
1648 Ok(match bytes {
1649 Cow::Borrowed(bytes) => {
1650 Cow::Borrowed({ Path::new(str::from_utf8(bytes).map_err(invalid_utf8)?) })
1651 }
1652 Cow::Owned(bytes) => {
1653 Cow::Owned({ PathBuf::from(String::from_utf8(bytes).map_err(invalid_utf8)?) })
1654 }
1655 })
1656}
1657
1658#[cfg(target_arch = "wasm32")]
1659fn invalid_utf8<T>(_: T) -> io::Error {
1660 io::Error::new(io::ErrorKind::InvalidData, "Invalid utf-8")
1661}