1#[cfg(unix)]
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::repeat;
12use std::mem;
13use std::path::{Component, Path, PathBuf};
14use std::str;
15
16use crate::other;
17use crate::EntryType;
18
19pub const BLOCK_SIZE: usize = 512;
20
21#[cfg(any(unix, windows))]
27const DETERMINISTIC_TIMESTAMP: u64 = 1153704088;
28
29#[repr(C)]
31#[allow(missing_docs)]
32pub struct Header {
33 bytes: [u8; BLOCK_SIZE],
34}
35
36#[derive(Clone, Copy, PartialEq, Eq, Debug)]
39#[non_exhaustive]
40pub enum HeaderMode {
41 Complete,
44
45 Deterministic,
48}
49
50#[repr(C)]
52#[allow(missing_docs)]
53pub struct OldHeader {
54 pub name: [u8; 100],
55 pub mode: [u8; 8],
56 pub uid: [u8; 8],
57 pub gid: [u8; 8],
58 pub size: [u8; 12],
59 pub mtime: [u8; 12],
60 pub cksum: [u8; 8],
61 pub linkflag: [u8; 1],
62 pub linkname: [u8; 100],
63 pub pad: [u8; 255],
64}
65
66#[repr(C)]
68#[allow(missing_docs)]
69pub struct UstarHeader {
70 pub name: [u8; 100],
71 pub mode: [u8; 8],
72 pub uid: [u8; 8],
73 pub gid: [u8; 8],
74 pub size: [u8; 12],
75 pub mtime: [u8; 12],
76 pub cksum: [u8; 8],
77 pub typeflag: [u8; 1],
78 pub linkname: [u8; 100],
79
80 pub magic: [u8; 6],
82 pub version: [u8; 2],
83 pub uname: [u8; 32],
84 pub gname: [u8; 32],
85 pub dev_major: [u8; 8],
86 pub dev_minor: [u8; 8],
87 pub prefix: [u8; 155],
88 pub pad: [u8; 12],
89}
90
91#[repr(C)]
93#[allow(missing_docs)]
94pub struct GnuHeader {
95 pub name: [u8; 100],
96 pub mode: [u8; 8],
97 pub uid: [u8; 8],
98 pub gid: [u8; 8],
99 pub size: [u8; 12],
100 pub mtime: [u8; 12],
101 pub cksum: [u8; 8],
102 pub typeflag: [u8; 1],
103 pub linkname: [u8; 100],
104
105 pub magic: [u8; 6],
107 pub version: [u8; 2],
108 pub uname: [u8; 32],
109 pub gname: [u8; 32],
110 pub dev_major: [u8; 8],
111 pub dev_minor: [u8; 8],
112 pub atime: [u8; 12],
113 pub ctime: [u8; 12],
114 pub offset: [u8; 12],
115 pub longnames: [u8; 4],
116 pub unused: [u8; 1],
117 pub sparse: [GnuSparseHeader; 4],
118 pub isextended: [u8; 1],
119 pub realsize: [u8; 12],
120 pub pad: [u8; 17],
121}
122
123pub struct SparseEntry {
125 pub offset: u64,
126 pub size: u64,
127}
128
129#[repr(C)]
133#[allow(missing_docs)]
134pub struct GnuSparseHeader {
135 pub offset: [u8; 12],
136 pub numbytes: [u8; 12],
137}
138
139#[repr(C)]
144#[allow(missing_docs)]
145pub struct GnuExtSparseHeader {
146 pub sparse: [GnuSparseHeader; 21],
147 pub isextended: [u8; 1],
148 pub padding: [u8; 7],
149}
150
151impl Header {
152 pub fn new_gnu() -> Header {
158 let mut header = Header { bytes: [0; 512] };
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 { bytes: [0; 512] };
177 unsafe {
178 let gnu = cast_mut::<_, UstarHeader>(&mut header);
179 gnu.magic = *b"ustar\0";
180 gnu.version = *b"00";
181 }
182 header.set_mtime(0);
183 header
184 }
185
186 pub fn new_old() -> Header {
193 let mut header = Header { bytes: [0; 512] };
194 header.set_mtime(0);
195 header
196 }
197
198 fn is_ustar(&self) -> bool {
199 let ustar = unsafe { cast::<_, UstarHeader>(self) };
200 ustar.magic[..] == b"ustar\0"[..] && ustar.version[..] == b"00"[..]
201 }
202
203 fn is_gnu(&self) -> bool {
204 let ustar = unsafe { cast::<_, UstarHeader>(self) };
205 ustar.magic[..] == b"ustar "[..] && ustar.version[..] == b" \0"[..]
206 }
207
208 pub fn as_old(&self) -> &OldHeader {
213 unsafe { cast(self) }
214 }
215
216 pub fn as_old_mut(&mut self) -> &mut OldHeader {
218 unsafe { cast_mut(self) }
219 }
220
221 pub fn as_ustar(&self) -> Option<&UstarHeader> {
231 if self.is_ustar() {
232 Some(unsafe { cast(self) })
233 } else {
234 None
235 }
236 }
237
238 pub fn as_ustar_mut(&mut self) -> Option<&mut UstarHeader> {
240 if self.is_ustar() {
241 Some(unsafe { cast_mut(self) })
242 } else {
243 None
244 }
245 }
246
247 pub fn as_gnu(&self) -> Option<&GnuHeader> {
257 if self.is_gnu() {
258 Some(unsafe { cast(self) })
259 } else {
260 None
261 }
262 }
263
264 pub fn as_gnu_mut(&mut self) -> Option<&mut GnuHeader> {
266 if self.is_gnu() {
267 Some(unsafe { cast_mut(self) })
268 } else {
269 None
270 }
271 }
272
273 pub fn from_byte_slice(bytes: &[u8]) -> &Header {
277 assert_eq!(bytes.len(), mem::size_of::<Header>());
278 assert_eq!(mem::align_of_val(bytes), mem::align_of::<Header>());
279 unsafe { &*(bytes.as_ptr() as *const Header) }
280 }
281
282 pub fn as_bytes(&self) -> &[u8; 512] {
284 &self.bytes
285 }
286
287 pub fn as_mut_bytes(&mut self) -> &mut [u8; 512] {
289 &mut self.bytes
290 }
291
292 pub fn set_metadata(&mut self, meta: &fs::Metadata) {
299 self.fill_from(meta, HeaderMode::Complete);
300 }
301
302 pub fn set_metadata_in_mode(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
305 self.fill_from(meta, mode);
306 }
307
308 pub fn entry_size(&self) -> io::Result<u64> {
317 num_field_wrapper_from(&self.as_old().size).map_err(|err| {
318 io::Error::new(
319 err.kind(),
320 format!("{} when getting size for {}", err, self.path_lossy()),
321 )
322 })
323 }
324
325 pub fn size(&self) -> io::Result<u64> {
329 if self.entry_type().is_gnu_sparse() {
330 self.as_gnu()
331 .ok_or_else(|| other("sparse header was not a gnu header"))
332 .and_then(|h| h.real_size())
333 } else {
334 self.entry_size()
335 }
336 }
337
338 pub fn set_size(&mut self, size: u64) {
340 num_field_wrapper_into(&mut self.as_old_mut().size, size);
341 }
342
343 pub fn path(&self) -> io::Result<Cow<Path>> {
351 bytes2path(self.path_bytes())
352 }
353
354 pub fn path_bytes(&self) -> Cow<[u8]> {
362 if let Some(ustar) = self.as_ustar() {
363 ustar.path_bytes()
364 } else {
365 let name = truncate(&self.as_old().name);
366 Cow::Borrowed(name)
367 }
368 }
369
370 fn path_lossy(&self) -> String {
372 String::from_utf8_lossy(&self.path_bytes()).to_string()
373 }
374
375 pub fn set_path<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> {
387 self._set_path(p.as_ref())
388 }
389
390 fn _set_path(&mut self, path: &Path) -> io::Result<()> {
391 if let Some(ustar) = self.as_ustar_mut() {
392 return ustar.set_path(path);
393 }
394 copy_path_into(&mut self.as_old_mut().name, path, false).map_err(|err| {
395 io::Error::new(
396 err.kind(),
397 format!("{} when setting path for {}", err, self.path_lossy()),
398 )
399 })
400 }
401
402 pub fn link_name(&self) -> io::Result<Option<Cow<Path>>> {
411 match self.link_name_bytes() {
412 Some(bytes) => bytes2path(bytes).map(Some),
413 None => Ok(None),
414 }
415 }
416
417 pub fn link_name_bytes(&self) -> Option<Cow<[u8]>> {
425 let old = self.as_old();
426 if old.linkname[0] != 0 {
427 Some(Cow::Borrowed(truncate(&old.linkname)))
428 } else {
429 None
430 }
431 }
432
433 pub fn set_link_name<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> {
442 self._set_link_name(p.as_ref())
443 }
444
445 fn _set_link_name(&mut self, path: &Path) -> io::Result<()> {
446 copy_path_into(&mut self.as_old_mut().linkname, path, true).map_err(|err| {
447 io::Error::new(
448 err.kind(),
449 format!("{} when setting link name for {}", err, self.path_lossy()),
450 )
451 })
452 }
453
454 pub fn set_link_name_literal<P: AsRef<[u8]>>(&mut self, p: P) -> io::Result<()> {
459 self._set_link_name_literal(p.as_ref())
460 }
461
462 fn _set_link_name_literal(&mut self, bytes: &[u8]) -> io::Result<()> {
463 copy_into(&mut self.as_old_mut().linkname, bytes)
464 }
465
466 pub fn mode(&self) -> io::Result<u32> {
470 octal_from(&self.as_old().mode)
471 .map(|u| u as u32)
472 .map_err(|err| {
473 io::Error::new(
474 err.kind(),
475 format!("{} when getting mode for {}", err, self.path_lossy()),
476 )
477 })
478 }
479
480 pub fn set_mode(&mut self, mode: u32) {
482 octal_into(&mut self.as_old_mut().mode, mode);
483 }
484
485 pub fn uid(&self) -> io::Result<u64> {
489 num_field_wrapper_from(&self.as_old().uid)
490 .map(|u| u as u64)
491 .map_err(|err| {
492 io::Error::new(
493 err.kind(),
494 format!("{} when getting uid for {}", err, self.path_lossy()),
495 )
496 })
497 }
498
499 pub fn set_uid(&mut self, uid: u64) {
501 num_field_wrapper_into(&mut self.as_old_mut().uid, uid);
502 }
503
504 pub fn gid(&self) -> io::Result<u64> {
506 num_field_wrapper_from(&self.as_old().gid)
507 .map(|u| u as u64)
508 .map_err(|err| {
509 io::Error::new(
510 err.kind(),
511 format!("{} when getting gid for {}", err, self.path_lossy()),
512 )
513 })
514 }
515
516 pub fn set_gid(&mut self, gid: u64) {
518 num_field_wrapper_into(&mut self.as_old_mut().gid, gid);
519 }
520
521 pub fn mtime(&self) -> io::Result<u64> {
523 num_field_wrapper_from(&self.as_old().mtime).map_err(|err| {
524 io::Error::new(
525 err.kind(),
526 format!("{} when getting mtime for {}", err, self.path_lossy()),
527 )
528 })
529 }
530
531 pub fn set_mtime(&mut self, mtime: u64) {
536 num_field_wrapper_into(&mut self.as_old_mut().mtime, mtime);
537 }
538
539 pub fn username(&self) -> Result<Option<&str>, str::Utf8Error> {
546 match self.username_bytes() {
547 Some(bytes) => str::from_utf8(bytes).map(Some),
548 None => Ok(None),
549 }
550 }
551
552 pub fn username_bytes(&self) -> Option<&[u8]> {
557 if let Some(ustar) = self.as_ustar() {
558 Some(ustar.username_bytes())
559 } else if let Some(gnu) = self.as_gnu() {
560 Some(gnu.username_bytes())
561 } else {
562 None
563 }
564 }
565
566 pub fn set_username(&mut self, name: &str) -> io::Result<()> {
571 if let Some(ustar) = self.as_ustar_mut() {
572 return ustar.set_username(name);
573 }
574 if let Some(gnu) = self.as_gnu_mut() {
575 gnu.set_username(name)
576 } else {
577 Err(other("not a ustar or gnu archive, cannot set username"))
578 }
579 }
580
581 pub fn groupname(&self) -> Result<Option<&str>, str::Utf8Error> {
588 match self.groupname_bytes() {
589 Some(bytes) => str::from_utf8(bytes).map(Some),
590 None => Ok(None),
591 }
592 }
593
594 pub fn groupname_bytes(&self) -> Option<&[u8]> {
599 if let Some(ustar) = self.as_ustar() {
600 Some(ustar.groupname_bytes())
601 } else if let Some(gnu) = self.as_gnu() {
602 Some(gnu.groupname_bytes())
603 } else {
604 None
605 }
606 }
607
608 pub fn set_groupname(&mut self, name: &str) -> io::Result<()> {
613 if let Some(ustar) = self.as_ustar_mut() {
614 return ustar.set_groupname(name);
615 }
616 if let Some(gnu) = self.as_gnu_mut() {
617 gnu.set_groupname(name)
618 } else {
619 Err(other("not a ustar or gnu archive, cannot set groupname"))
620 }
621 }
622
623 pub fn device_major(&self) -> io::Result<Option<u32>> {
631 if let Some(ustar) = self.as_ustar() {
632 ustar.device_major().map(Some)
633 } else if let Some(gnu) = self.as_gnu() {
634 gnu.device_major().map(Some)
635 } else {
636 Ok(None)
637 }
638 }
639
640 pub fn set_device_major(&mut self, major: u32) -> io::Result<()> {
645 if let Some(ustar) = self.as_ustar_mut() {
646 ustar.set_device_major(major);
647 Ok(())
648 } else if let Some(gnu) = self.as_gnu_mut() {
649 gnu.set_device_major(major);
650 Ok(())
651 } else {
652 Err(other("not a ustar or gnu archive, cannot set dev_major"))
653 }
654 }
655
656 pub fn device_minor(&self) -> io::Result<Option<u32>> {
664 if let Some(ustar) = self.as_ustar() {
665 ustar.device_minor().map(Some)
666 } else if let Some(gnu) = self.as_gnu() {
667 gnu.device_minor().map(Some)
668 } else {
669 Ok(None)
670 }
671 }
672
673 pub fn set_device_minor(&mut self, minor: u32) -> io::Result<()> {
678 if let Some(ustar) = self.as_ustar_mut() {
679 ustar.set_device_minor(minor);
680 Ok(())
681 } else if let Some(gnu) = self.as_gnu_mut() {
682 gnu.set_device_minor(minor);
683 Ok(())
684 } else {
685 Err(other("not a ustar or gnu archive, cannot set dev_minor"))
686 }
687 }
688
689 pub fn entry_type(&self) -> EntryType {
691 EntryType::new(self.as_old().linkflag[0])
692 }
693
694 pub fn set_entry_type(&mut self, ty: EntryType) {
696 self.as_old_mut().linkflag = [ty.as_byte()];
697 }
698
699 pub fn cksum(&self) -> io::Result<u32> {
703 octal_from(&self.as_old().cksum)
704 .map(|u| u as u32)
705 .map_err(|err| {
706 io::Error::new(
707 err.kind(),
708 format!("{} when getting cksum for {}", err, self.path_lossy()),
709 )
710 })
711 }
712
713 pub fn set_cksum(&mut self) {
716 let cksum = self.calculate_cksum();
717 octal_into(&mut self.as_old_mut().cksum, cksum);
718 }
719
720 fn calculate_cksum(&self) -> u32 {
721 let old = self.as_old();
722 let start = old as *const _ as usize;
723 let cksum_start = old.cksum.as_ptr() as *const _ as usize;
724 let offset = cksum_start - start;
725 let len = old.cksum.len();
726 self.bytes[0..offset]
727 .iter()
728 .chain(iter::repeat(&b' ').take(len))
729 .chain(&self.bytes[offset + len..])
730 .fold(0, |a, b| a + (*b as u32))
731 }
732
733 fn fill_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
734 self.fill_platform_from(meta, mode);
735 self.set_size(if meta.is_dir() || meta.file_type().is_symlink() {
737 0
738 } else {
739 meta.len()
740 });
741 if let Some(ustar) = self.as_ustar_mut() {
742 ustar.set_device_major(0);
743 ustar.set_device_minor(0);
744 }
745 if let Some(gnu) = self.as_gnu_mut() {
746 gnu.set_device_major(0);
747 gnu.set_device_minor(0);
748 }
749 }
750
751 #[cfg(target_arch = "wasm32")]
752 #[allow(unused_variables)]
753 fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
754 unimplemented!();
755 }
756
757 #[cfg(unix)]
758 fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
759 match mode {
760 HeaderMode::Complete => {
761 self.set_mtime(meta.mtime() as u64);
762 self.set_uid(meta.uid() as u64);
763 self.set_gid(meta.gid() as u64);
764 self.set_mode(meta.mode() as u32);
765 }
766 HeaderMode::Deterministic => {
767 self.set_mtime(DETERMINISTIC_TIMESTAMP);
772
773 self.set_uid(0);
774 self.set_gid(0);
775
776 let fs_mode = if meta.is_dir() || (0o100 & meta.mode() == 0o100) {
778 0o755
779 } else {
780 0o644
781 };
782 self.set_mode(fs_mode);
783 }
784 }
785
786 self.set_entry_type(entry_type(meta.mode()));
797
798 fn entry_type(mode: u32) -> EntryType {
799 match mode as libc::mode_t & libc::S_IFMT {
800 libc::S_IFREG => EntryType::file(),
801 libc::S_IFLNK => EntryType::symlink(),
802 libc::S_IFCHR => EntryType::character_special(),
803 libc::S_IFBLK => EntryType::block_special(),
804 libc::S_IFDIR => EntryType::dir(),
805 libc::S_IFIFO => EntryType::fifo(),
806 _ => EntryType::new(b' '),
807 }
808 }
809 }
810
811 #[cfg(windows)]
812 fn fill_platform_from(&mut self, meta: &fs::Metadata, mode: HeaderMode) {
813 match mode {
815 HeaderMode::Complete => {
816 self.set_uid(0);
817 self.set_gid(0);
818 let mtime = (meta.last_write_time() / (1_000_000_000 / 100)) - 11644473600;
823 self.set_mtime(mtime);
824 let fs_mode = {
825 const FILE_ATTRIBUTE_READONLY: u32 = 0x00000001;
826 let readonly = meta.file_attributes() & FILE_ATTRIBUTE_READONLY;
827 match (meta.is_dir(), readonly != 0) {
828 (true, false) => 0o755,
829 (true, true) => 0o555,
830 (false, false) => 0o644,
831 (false, true) => 0o444,
832 }
833 };
834 self.set_mode(fs_mode);
835 }
836 HeaderMode::Deterministic => {
837 self.set_uid(0);
838 self.set_gid(0);
839 self.set_mtime(DETERMINISTIC_TIMESTAMP); let fs_mode = if meta.is_dir() { 0o755 } else { 0o644 };
841 self.set_mode(fs_mode);
842 }
843 }
844
845 let ft = meta.file_type();
846 self.set_entry_type(if ft.is_dir() {
847 EntryType::dir()
848 } else if ft.is_file() {
849 EntryType::file()
850 } else if ft.is_symlink() {
851 EntryType::symlink()
852 } else {
853 EntryType::new(b' ')
854 });
855 }
856
857 fn debug_fields(&self, b: &mut fmt::DebugStruct) {
858 if let Ok(entry_size) = self.entry_size() {
859 b.field("entry_size", &entry_size);
860 }
861 if let Ok(size) = self.size() {
862 b.field("size", &size);
863 }
864 if let Ok(path) = self.path() {
865 b.field("path", &path);
866 }
867 if let Ok(link_name) = self.link_name() {
868 b.field("link_name", &link_name);
869 }
870 if let Ok(mode) = self.mode() {
871 b.field("mode", &DebugAsOctal(mode));
872 }
873 if let Ok(uid) = self.uid() {
874 b.field("uid", &uid);
875 }
876 if let Ok(gid) = self.gid() {
877 b.field("gid", &gid);
878 }
879 if let Ok(mtime) = self.mtime() {
880 b.field("mtime", &mtime);
881 }
882 if let Ok(username) = self.username() {
883 b.field("username", &username);
884 }
885 if let Ok(groupname) = self.groupname() {
886 b.field("groupname", &groupname);
887 }
888 if let Ok(device_major) = self.device_major() {
889 b.field("device_major", &device_major);
890 }
891 if let Ok(device_minor) = self.device_minor() {
892 b.field("device_minor", &device_minor);
893 }
894 if let Ok(cksum) = self.cksum() {
895 b.field("cksum", &cksum);
896 b.field("cksum_valid", &(cksum == self.calculate_cksum()));
897 }
898 }
899}
900
901struct DebugAsOctal<T>(T);
902
903impl<T: fmt::Octal> fmt::Debug for DebugAsOctal<T> {
904 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
905 fmt::Octal::fmt(&self.0, f)
906 }
907}
908
909unsafe fn cast<T, U>(a: &T) -> &U {
910 assert_eq!(mem::size_of_val(a), mem::size_of::<U>());
911 assert_eq!(mem::align_of_val(a), mem::align_of::<U>());
912 &*(a as *const T as *const U)
913}
914
915unsafe fn cast_mut<T, U>(a: &mut T) -> &mut U {
916 assert_eq!(mem::size_of_val(a), mem::size_of::<U>());
917 assert_eq!(mem::align_of_val(a), mem::align_of::<U>());
918 &mut *(a as *mut T as *mut U)
919}
920
921impl Clone for Header {
922 fn clone(&self) -> Header {
923 Header { bytes: self.bytes }
924 }
925}
926
927impl fmt::Debug for Header {
928 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
929 if let Some(me) = self.as_ustar() {
930 me.fmt(f)
931 } else if let Some(me) = self.as_gnu() {
932 me.fmt(f)
933 } else {
934 self.as_old().fmt(f)
935 }
936 }
937}
938
939impl OldHeader {
940 pub fn as_header(&self) -> &Header {
942 unsafe { cast(self) }
943 }
944
945 pub fn as_header_mut(&mut self) -> &mut Header {
947 unsafe { cast_mut(self) }
948 }
949}
950
951impl fmt::Debug for OldHeader {
952 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
953 let mut f = f.debug_struct("OldHeader");
954 self.as_header().debug_fields(&mut f);
955 f.finish()
956 }
957}
958
959impl UstarHeader {
960 pub fn path_bytes(&self) -> Cow<[u8]> {
962 if self.prefix[0] == 0 && !self.name.contains(&b'\\') {
963 Cow::Borrowed(truncate(&self.name))
964 } else {
965 let mut bytes = Vec::new();
966 let prefix = truncate(&self.prefix);
967 if !prefix.is_empty() {
968 bytes.extend_from_slice(prefix);
969 bytes.push(b'/');
970 }
971 bytes.extend_from_slice(truncate(&self.name));
972 Cow::Owned(bytes)
973 }
974 }
975
976 fn path_lossy(&self) -> String {
978 String::from_utf8_lossy(&self.path_bytes()).to_string()
979 }
980
981 pub fn set_path<P: AsRef<Path>>(&mut self, p: P) -> io::Result<()> {
983 self._set_path(p.as_ref())
984 }
985
986 fn _set_path(&mut self, path: &Path) -> io::Result<()> {
987 let bytes = path2bytes(path)?;
996 let (maxnamelen, maxprefixlen) = (self.name.len(), self.prefix.len());
997 if bytes.len() <= maxnamelen {
998 copy_path_into(&mut self.name, path, false).map_err(|err| {
999 io::Error::new(
1000 err.kind(),
1001 format!("{} when setting path for {}", err, self.path_lossy()),
1002 )
1003 })?;
1004 } else {
1005 let mut prefix = path;
1006 let mut prefixlen;
1007 loop {
1008 match prefix.parent() {
1009 Some(parent) => prefix = parent,
1010 None => {
1011 return Err(other(&format!(
1012 "path cannot be split to be inserted into archive: {}",
1013 path.display()
1014 )));
1015 }
1016 }
1017 prefixlen = path2bytes(prefix)?.len();
1018 if prefixlen <= maxprefixlen {
1019 break;
1020 }
1021 }
1022 copy_path_into(&mut self.prefix, prefix, false).map_err(|err| {
1023 io::Error::new(
1024 err.kind(),
1025 format!("{} when setting path for {}", err, self.path_lossy()),
1026 )
1027 })?;
1028 let path = bytes2path(Cow::Borrowed(&bytes[prefixlen + 1..]))?;
1029 copy_path_into(&mut self.name, &path, false).map_err(|err| {
1030 io::Error::new(
1031 err.kind(),
1032 format!("{} when setting path for {}", err, self.path_lossy()),
1033 )
1034 })?;
1035 }
1036 Ok(())
1037 }
1038
1039 pub fn username_bytes(&self) -> &[u8] {
1041 truncate(&self.uname)
1042 }
1043
1044 pub fn set_username(&mut self, name: &str) -> io::Result<()> {
1046 copy_into(&mut self.uname, name.as_bytes()).map_err(|err| {
1047 io::Error::new(
1048 err.kind(),
1049 format!("{} when setting username for {}", err, self.path_lossy()),
1050 )
1051 })
1052 }
1053
1054 pub fn groupname_bytes(&self) -> &[u8] {
1056 truncate(&self.gname)
1057 }
1058
1059 pub fn set_groupname(&mut self, name: &str) -> io::Result<()> {
1061 copy_into(&mut self.gname, name.as_bytes()).map_err(|err| {
1062 io::Error::new(
1063 err.kind(),
1064 format!("{} when setting groupname for {}", err, self.path_lossy()),
1065 )
1066 })
1067 }
1068
1069 pub fn device_major(&self) -> io::Result<u32> {
1071 octal_from(&self.dev_major)
1072 .map(|u| u as u32)
1073 .map_err(|err| {
1074 io::Error::new(
1075 err.kind(),
1076 format!(
1077 "{} when getting device_major for {}",
1078 err,
1079 self.path_lossy()
1080 ),
1081 )
1082 })
1083 }
1084
1085 pub fn set_device_major(&mut self, major: u32) {
1087 octal_into(&mut self.dev_major, major);
1088 }
1089
1090 pub fn device_minor(&self) -> io::Result<u32> {
1092 octal_from(&self.dev_minor)
1093 .map(|u| u as u32)
1094 .map_err(|err| {
1095 io::Error::new(
1096 err.kind(),
1097 format!(
1098 "{} when getting device_minor for {}",
1099 err,
1100 self.path_lossy()
1101 ),
1102 )
1103 })
1104 }
1105
1106 pub fn set_device_minor(&mut self, minor: u32) {
1108 octal_into(&mut self.dev_minor, minor);
1109 }
1110
1111 pub fn as_header(&self) -> &Header {
1113 unsafe { cast(self) }
1114 }
1115
1116 pub fn as_header_mut(&mut self) -> &mut Header {
1118 unsafe { cast_mut(self) }
1119 }
1120}
1121
1122impl fmt::Debug for UstarHeader {
1123 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1124 let mut f = f.debug_struct("UstarHeader");
1125 self.as_header().debug_fields(&mut f);
1126 f.finish()
1127 }
1128}
1129
1130impl GnuHeader {
1131 pub fn username_bytes(&self) -> &[u8] {
1133 truncate(&self.uname)
1134 }
1135
1136 fn fullname_lossy(&self) -> String {
1138 format!(
1139 "{}:{}",
1140 String::from_utf8_lossy(self.groupname_bytes()),
1141 String::from_utf8_lossy(self.username_bytes()),
1142 )
1143 }
1144
1145 pub fn set_username(&mut self, name: &str) -> io::Result<()> {
1147 copy_into(&mut self.uname, name.as_bytes()).map_err(|err| {
1148 io::Error::new(
1149 err.kind(),
1150 format!(
1151 "{} when setting username for {}",
1152 err,
1153 self.fullname_lossy()
1154 ),
1155 )
1156 })
1157 }
1158
1159 pub fn groupname_bytes(&self) -> &[u8] {
1161 truncate(&self.gname)
1162 }
1163
1164 pub fn set_groupname(&mut self, name: &str) -> io::Result<()> {
1166 copy_into(&mut self.gname, name.as_bytes()).map_err(|err| {
1167 io::Error::new(
1168 err.kind(),
1169 format!(
1170 "{} when setting groupname for {}",
1171 err,
1172 self.fullname_lossy()
1173 ),
1174 )
1175 })
1176 }
1177
1178 pub fn device_major(&self) -> io::Result<u32> {
1180 octal_from(&self.dev_major)
1181 .map(|u| u as u32)
1182 .map_err(|err| {
1183 io::Error::new(
1184 err.kind(),
1185 format!(
1186 "{} when getting device_major for {}",
1187 err,
1188 self.fullname_lossy()
1189 ),
1190 )
1191 })
1192 }
1193
1194 pub fn set_device_major(&mut self, major: u32) {
1196 octal_into(&mut self.dev_major, major);
1197 }
1198
1199 pub fn device_minor(&self) -> io::Result<u32> {
1201 octal_from(&self.dev_minor)
1202 .map(|u| u as u32)
1203 .map_err(|err| {
1204 io::Error::new(
1205 err.kind(),
1206 format!(
1207 "{} when getting device_minor for {}",
1208 err,
1209 self.fullname_lossy()
1210 ),
1211 )
1212 })
1213 }
1214
1215 pub fn set_device_minor(&mut self, minor: u32) {
1217 octal_into(&mut self.dev_minor, minor);
1218 }
1219
1220 pub fn atime(&self) -> io::Result<u64> {
1222 num_field_wrapper_from(&self.atime).map_err(|err| {
1223 io::Error::new(
1224 err.kind(),
1225 format!("{} when getting atime for {}", err, self.fullname_lossy()),
1226 )
1227 })
1228 }
1229
1230 pub fn set_atime(&mut self, atime: u64) {
1235 num_field_wrapper_into(&mut self.atime, atime);
1236 }
1237
1238 pub fn ctime(&self) -> io::Result<u64> {
1240 num_field_wrapper_from(&self.ctime).map_err(|err| {
1241 io::Error::new(
1242 err.kind(),
1243 format!("{} when getting ctime for {}", err, self.fullname_lossy()),
1244 )
1245 })
1246 }
1247
1248 pub fn set_ctime(&mut self, ctime: u64) {
1253 num_field_wrapper_into(&mut self.ctime, ctime);
1254 }
1255
1256 pub fn real_size(&self) -> io::Result<u64> {
1261 octal_from(&self.realsize).map_err(|err| {
1262 io::Error::new(
1263 err.kind(),
1264 format!(
1265 "{} when getting real_size for {}",
1266 err,
1267 self.fullname_lossy()
1268 ),
1269 )
1270 })
1271 }
1272
1273 pub fn is_extended(&self) -> bool {
1279 self.isextended[0] == 1
1280 }
1281
1282 pub fn as_header(&self) -> &Header {
1284 unsafe { cast(self) }
1285 }
1286
1287 pub fn as_header_mut(&mut self) -> &mut Header {
1289 unsafe { cast_mut(self) }
1290 }
1291}
1292
1293impl fmt::Debug for GnuHeader {
1294 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1295 let mut f = f.debug_struct("GnuHeader");
1296 self.as_header().debug_fields(&mut f);
1297 if let Ok(atime) = self.atime() {
1298 f.field("atime", &atime);
1299 }
1300 if let Ok(ctime) = self.ctime() {
1301 f.field("ctime", &ctime);
1302 }
1303 f.field("is_extended", &self.is_extended())
1304 .field("sparse", &DebugSparseHeaders(&self.sparse))
1305 .finish()
1306 }
1307}
1308
1309struct DebugSparseHeaders<'a>(&'a [GnuSparseHeader]);
1310
1311impl<'a> fmt::Debug for DebugSparseHeaders<'a> {
1312 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1313 let mut f = f.debug_list();
1314 for header in self.0 {
1315 if !header.is_empty() {
1316 f.entry(header);
1317 }
1318 }
1319 f.finish()
1320 }
1321}
1322
1323impl GnuSparseHeader {
1324 pub fn is_empty(&self) -> bool {
1326 self.offset[0] == 0 || self.numbytes[0] == 0
1327 }
1328
1329 pub fn offset(&self) -> io::Result<u64> {
1333 octal_from(&self.offset).map_err(|err| {
1334 io::Error::new(
1335 err.kind(),
1336 format!("{} when getting offset from sparse header", err),
1337 )
1338 })
1339 }
1340
1341 pub fn length(&self) -> io::Result<u64> {
1345 octal_from(&self.numbytes).map_err(|err| {
1346 io::Error::new(
1347 err.kind(),
1348 format!("{} when getting length from sparse header", err),
1349 )
1350 })
1351 }
1352}
1353
1354impl fmt::Debug for GnuSparseHeader {
1355 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1356 let mut f = f.debug_struct("GnuSparseHeader");
1357 if let Ok(offset) = self.offset() {
1358 f.field("offset", &offset);
1359 }
1360 if let Ok(length) = self.length() {
1361 f.field("length", &length);
1362 }
1363 f.finish()
1364 }
1365}
1366
1367impl GnuExtSparseHeader {
1368 pub fn new() -> GnuExtSparseHeader {
1370 unsafe { mem::zeroed() }
1371 }
1372
1373 pub fn as_bytes(&self) -> &[u8; 512] {
1375 debug_assert_eq!(mem::size_of_val(self), 512);
1376 unsafe { mem::transmute(self) }
1377 }
1378
1379 pub fn as_mut_bytes(&mut self) -> &mut [u8; 512] {
1381 debug_assert_eq!(mem::size_of_val(self), 512);
1382 unsafe { mem::transmute(self) }
1383 }
1384
1385 pub fn sparse(&self) -> &[GnuSparseHeader; 21] {
1390 &self.sparse
1391 }
1392
1393 pub fn is_extended(&self) -> bool {
1395 self.isextended[0] == 1
1396 }
1397}
1398
1399impl Default for GnuExtSparseHeader {
1400 fn default() -> Self {
1401 Self::new()
1402 }
1403}
1404
1405fn octal_from(slice: &[u8]) -> io::Result<u64> {
1406 let trun = truncate(slice);
1407 let num = match str::from_utf8(trun) {
1408 Ok(n) => n,
1409 Err(_) => {
1410 return Err(other(&format!(
1411 "numeric field did not have utf-8 text: {}",
1412 String::from_utf8_lossy(trun)
1413 )));
1414 }
1415 };
1416 match u64::from_str_radix(num.trim(), 8) {
1417 Ok(n) => Ok(n),
1418 Err(_) => Err(other(&format!("numeric field was not a number: {}", num))),
1419 }
1420}
1421
1422fn octal_into<T: fmt::Octal>(dst: &mut [u8], val: T) {
1423 let o = format!("{:o}", val);
1424 let value = o.bytes().rev().chain(repeat(b'0'));
1425 for (slot, value) in dst.iter_mut().rev().skip(1).zip(value) {
1426 *slot = value;
1427 }
1428}
1429
1430fn num_field_wrapper_into(dst: &mut [u8], src: u64) {
1433 if src >= 8589934592 || (src >= 2097152 && dst.len() == 8) {
1434 numeric_extended_into(dst, src);
1435 } else {
1436 octal_into(dst, src);
1437 }
1438}
1439
1440fn num_field_wrapper_from(src: &[u8]) -> io::Result<u64> {
1443 if src[0] & 0x80 != 0 {
1444 Ok(numeric_extended_from(src))
1445 } else {
1446 octal_from(src)
1447 }
1448}
1449
1450fn numeric_extended_into(dst: &mut [u8], src: u64) {
1455 let len: usize = dst.len();
1456 for (slot, val) in dst.iter_mut().zip(
1457 repeat(0)
1458 .take(len - 8) .chain((0..8).rev().map(|x| ((src >> (8 * x)) & 0xff) as u8)),
1460 ) {
1461 *slot = val;
1462 }
1463 dst[0] |= 0x80;
1464}
1465
1466fn numeric_extended_from(src: &[u8]) -> u64 {
1467 let mut dst: u64 = 0;
1468 let mut b_to_skip = 1;
1469 if src.len() == 8 {
1470 dst = (src[0] ^ 0x80) as u64;
1472 } else {
1473 b_to_skip = src.len() - 8;
1475 }
1476 for byte in src.iter().skip(b_to_skip) {
1477 dst <<= 8;
1478 dst |= *byte as u64;
1479 }
1480 dst
1481}
1482
1483fn truncate(slice: &[u8]) -> &[u8] {
1484 match slice.iter().position(|i| *i == 0) {
1485 Some(i) => &slice[..i],
1486 None => slice,
1487 }
1488}
1489
1490fn copy_into(slot: &mut [u8], bytes: &[u8]) -> io::Result<()> {
1493 if bytes.len() > slot.len() {
1494 Err(other("provided value is too long"))
1495 } else if bytes.iter().any(|b| *b == 0) {
1496 Err(other("provided value contains a nul byte"))
1497 } else {
1498 for (slot, val) in slot.iter_mut().zip(bytes.iter().chain(Some(&0))) {
1499 *slot = *val;
1500 }
1501 Ok(())
1502 }
1503}
1504
1505fn copy_path_into(mut slot: &mut [u8], path: &Path, is_link_name: bool) -> io::Result<()> {
1514 let mut emitted = false;
1515 let mut needs_slash = false;
1516 for component in path.components() {
1517 let bytes = path2bytes(Path::new(component.as_os_str()))?;
1518 match (component, is_link_name) {
1519 (Component::Prefix(..), false) | (Component::RootDir, false) => {
1520 return Err(other("paths in archives must be relative"));
1521 }
1522 (Component::ParentDir, false) => {
1523 return Err(other("paths in archives must not have `..`"));
1524 }
1525 (Component::CurDir, false) if path.components().count() == 1 => {}
1527 (Component::CurDir, false) => continue,
1528 (Component::Normal(_), _) | (_, true) => {}
1529 };
1530 if needs_slash {
1531 copy(&mut slot, b"/")?;
1532 }
1533 if bytes.contains(&b'/') {
1534 if let Component::Normal(..) = component {
1535 return Err(other("path component in archive cannot contain `/`"));
1536 }
1537 }
1538 copy(&mut slot, &*bytes)?;
1539 if &*bytes != b"/" {
1540 needs_slash = true;
1541 }
1542 emitted = true;
1543 }
1544 if !emitted {
1545 return Err(other("paths in archives must have at least one component"));
1546 }
1547 if ends_with_slash(path) {
1548 copy(&mut slot, &[b'/'])?;
1549 }
1550 return Ok(());
1551
1552 fn copy(slot: &mut &mut [u8], bytes: &[u8]) -> io::Result<()> {
1553 copy_into(*slot, bytes)?;
1554 let tmp = mem::replace(slot, &mut []);
1555 *slot = &mut tmp[bytes.len()..];
1556 Ok(())
1557 }
1558}
1559
1560#[cfg(target_arch = "wasm32")]
1561fn ends_with_slash(p: &Path) -> bool {
1562 p.to_string_lossy().ends_with('/')
1563}
1564
1565#[cfg(windows)]
1566fn ends_with_slash(p: &Path) -> bool {
1567 let last = p.as_os_str().encode_wide().last();
1568 last == Some(b'/' as u16) || last == Some(b'\\' as u16)
1569}
1570
1571#[cfg(unix)]
1572fn ends_with_slash(p: &Path) -> bool {
1573 p.as_os_str().as_bytes().ends_with(&[b'/'])
1574}
1575
1576#[cfg(any(windows, target_arch = "wasm32"))]
1577pub fn path2bytes(p: &Path) -> io::Result<Cow<[u8]>> {
1578 p.as_os_str()
1579 .to_str()
1580 .map(|s| s.as_bytes())
1581 .ok_or_else(|| other(&format!("path {} was not valid Unicode", p.display())))
1582 .map(|bytes| {
1583 if bytes.contains(&b'\\') {
1584 let mut bytes = bytes.to_owned();
1586 for b in &mut bytes {
1587 if *b == b'\\' {
1588 *b = b'/';
1589 }
1590 }
1591 Cow::Owned(bytes)
1592 } else {
1593 Cow::Borrowed(bytes)
1594 }
1595 })
1596}
1597
1598#[cfg(unix)]
1599pub fn path2bytes(p: &Path) -> io::Result<Cow<[u8]>> {
1601 Ok(p.as_os_str().as_bytes()).map(Cow::Borrowed)
1602}
1603
1604#[cfg(windows)]
1605pub fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
1608 return match bytes {
1609 Cow::Borrowed(bytes) => {
1610 let s = str::from_utf8(bytes).map_err(|_| not_unicode(bytes))?;
1611 Ok(Cow::Borrowed(Path::new(s)))
1612 }
1613 Cow::Owned(bytes) => {
1614 let s = String::from_utf8(bytes).map_err(|uerr| not_unicode(&uerr.into_bytes()))?;
1615 Ok(Cow::Owned(PathBuf::from(s)))
1616 }
1617 };
1618
1619 fn not_unicode(v: &[u8]) -> io::Error {
1620 other(&format!(
1621 "only Unicode paths are supported on Windows: {}",
1622 String::from_utf8_lossy(v)
1623 ))
1624 }
1625}
1626
1627#[cfg(unix)]
1628pub fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
1630 use std::ffi::{OsStr, OsString};
1631
1632 Ok(match bytes {
1633 Cow::Borrowed(bytes) => Cow::Borrowed(Path::new(OsStr::from_bytes(bytes))),
1634 Cow::Owned(bytes) => Cow::Owned(PathBuf::from(OsString::from_vec(bytes))),
1635 })
1636}
1637
1638#[cfg(target_arch = "wasm32")]
1639pub fn bytes2path(bytes: Cow<[u8]>) -> io::Result<Cow<Path>> {
1640 Ok(match bytes {
1641 Cow::Borrowed(bytes) => {
1642 Cow::Borrowed({ Path::new(str::from_utf8(bytes).map_err(invalid_utf8)?) })
1643 }
1644 Cow::Owned(bytes) => {
1645 Cow::Owned({ PathBuf::from(String::from_utf8(bytes).map_err(invalid_utf8)?) })
1646 }
1647 })
1648}
1649
1650#[cfg(target_arch = "wasm32")]
1651fn invalid_utf8<T>(_: T) -> io::Error {
1652 io::Error::new(io::ErrorKind::InvalidData, "Invalid utf-8")
1653}