Merge branch 'relibc' into 'master'
Implement 'tar.h' See merge request redox-os/relibc!588
This commit is contained in:
+1
-1
@@ -102,7 +102,7 @@ pub mod sys_un;
|
||||
pub mod sys_utsname;
|
||||
pub mod sys_wait;
|
||||
// TODO: syslog.h
|
||||
// TODO: tar.h
|
||||
pub mod tar;
|
||||
// TODO: term.h (deprecated)
|
||||
pub mod termios;
|
||||
// TODO: tgmath.h (likely C implementation)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
sys_includes = ["sys/types.h"]
|
||||
include_guard = "_TAR_H"
|
||||
trailer = "#include <bits/tar.h>"
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
no_includes = true
|
||||
cpp_compat = true
|
||||
|
||||
[enum]
|
||||
prefix_with_name = true
|
||||
@@ -0,0 +1,147 @@
|
||||
//! tar.h implementation for Redox, following POSIX.1-1990 specification
|
||||
//! and https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/tar.h.html
|
||||
|
||||
use core::slice;
|
||||
|
||||
/// Block size for tar archives (512 bytes).
|
||||
pub const BLOCKSIZE: usize = 512;
|
||||
|
||||
/// Default record size for tar archives (10KB, consisting of 20 blocks).
|
||||
pub const RECORDSIZE: usize = BLOCKSIZE * 20; // 10KB (default for tar archives)
|
||||
|
||||
/// Field lengths in tar headers
|
||||
pub const NAME_SIZE: usize = 100; // File name
|
||||
pub const MODE_SIZE: usize = 8; // File mode
|
||||
pub const UID_SIZE: usize = 8; // Owner's numeric user ID
|
||||
pub const GID_SIZE: usize = 8; // Group's numeric user ID
|
||||
pub const SIZE_SIZE: usize = 12; // File size in bytes
|
||||
pub const MTIME_SIZE: usize = 12; // Modification time
|
||||
pub const CHKSUM_SIZE: usize = 8; // Checksum
|
||||
pub const LINKNAME_SIZE: usize = 100; // Name of linked file
|
||||
pub const MAGIC_SIZE: usize = 6; // Magic string size
|
||||
pub const VERSION_SIZE: usize = 2; // Version string size
|
||||
pub const UNAME_SIZE: usize = 32; // Owner user name
|
||||
pub const GNAME_SIZE: usize = 32; // Owner group name
|
||||
pub const DEVMAJOR_SIZE: usize = 8; // Major device number
|
||||
pub const DEVMINOR_SIZE: usize = 8; // Minor device number
|
||||
pub const PREFIX_SIZE: usize = 155; // Prefix for file name
|
||||
pub const HEADER_SIZE: usize = 512; // Total header size
|
||||
|
||||
/// Bits used in the mode field - value in octal
|
||||
pub const TSUID: u16 = 0o4000; // Set user ID on execution
|
||||
pub const TSGID: u16 = 0o2000; // Set group ID on execution
|
||||
pub const TSVTX: u16 = 0o1000; // Sticky bit
|
||||
pub const TUREAD: u16 = 0o0400; // Read permission, owner
|
||||
pub const TUWRITE: u16 = 0o0200; // Write permission, owner
|
||||
pub const TUEXEC: u16 = 0o0100; // Execute/search permission, owner
|
||||
pub const TGREAD: u16 = 0o0040; // Read permission, group
|
||||
pub const TGWRITE: u16 = 0o0020; // Write permission, group
|
||||
pub const TGEXEC: u16 = 0o0010; // Execute/search permission, group
|
||||
pub const TOREAD: u16 = 0o0004; // Read permission, others
|
||||
pub const TOWRITE: u16 = 0o0002; // Write permission, others
|
||||
pub const TOEXEC: u16 = 0o0001; // Execute/search permission, others
|
||||
|
||||
/// Values used in typeflag field
|
||||
pub const REGTYPE: u8 = b'0'; // Regular file
|
||||
pub const AREGTYPE: u8 = b'\0'; // Regular file (old format)
|
||||
pub const LNKTYPE: u8 = b'1'; // Link
|
||||
pub const SYMTYPE: u8 = b'2'; // Symbolic link
|
||||
pub const CHRTYPE: u8 = b'3'; // Character special
|
||||
pub const BLKTYPE: u8 = b'4'; // Block special
|
||||
pub const DIRTYPE: u8 = b'5'; // Directory
|
||||
pub const FIFOTYPE: u8 = b'6'; // FIFO special
|
||||
pub const CONTTYPE: u8 = b'7'; // Contiguous file
|
||||
|
||||
/// tar format magic and version
|
||||
pub const TMAGIC: &str = "ustar"; // Magic string : ustar and a null
|
||||
pub const TMAGLEN: usize = 6; // Length of the magic string
|
||||
pub const TVERSION: &str = "00"; // Version string
|
||||
pub const TVERSLEN: usize = 2; // Length of the version string
|
||||
|
||||
/// Reserved for future standards
|
||||
pub const XHDRTYPE: u8 = b'x'; // Extended header referring to the next file in the archive
|
||||
pub const XGLTYPE: u8 = b'g'; // Global extended header
|
||||
|
||||
/// Reserved values for GNU tar extensions
|
||||
// pub const GNUTYPE_DUMPDIR: u8 = b'D'; // Directory dump
|
||||
// pub const GNUTYPE_MULTIVOL: u8 = b'M'; // Multi-volume file
|
||||
// pub const GNUTYPE_LONGNAME: u8 = b'L'; // Long file name
|
||||
// pub const GNUTYPE_LONGLINK: u8 = b'K'; // Long link name
|
||||
// pub const GNUTYPE_SPARSE: u8 = b'S'; // Sparse file
|
||||
|
||||
/// Represents a tar archive header following the POSIX ustar format.
|
||||
///
|
||||
/// The header contains metadata about a file in a tar archive, including
|
||||
/// its name, size, permissions, and other attributes. All text fields are
|
||||
/// null-terminated.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TarHeader {
|
||||
// Byte offset - usage
|
||||
pub name: [u8; NAME_SIZE], // 0 - File name
|
||||
pub mode: [u8; MODE_SIZE], // 100 - Permissions
|
||||
pub uid: [u8; UID_SIZE], // 108 - User ID
|
||||
pub gid: [u8; GID_SIZE], // 116 - Group ID
|
||||
pub size: [u8; SIZE_SIZE], // 124 - File size in bytes
|
||||
pub mtime: [u8; MTIME_SIZE], // 136 - Modification time
|
||||
pub chksum: [u8; CHKSUM_SIZE], // 148 - Header checksum
|
||||
pub typeflag: u8, // 156 - File type
|
||||
pub linkname: [u8; LINKNAME_SIZE], // 157 - Linked file name
|
||||
pub magic: [u8; MAGIC_SIZE], // 257 - UStar magic
|
||||
pub version: [u8; VERSION_SIZE], // 263 - UStar version
|
||||
pub uname: [u8; UNAME_SIZE], // 265 - Owner user name
|
||||
pub gname: [u8; GNAME_SIZE], // 297 - Owner group name
|
||||
pub devmajor: [u8; DEVMAJOR_SIZE], // 329 - Major device number
|
||||
pub devminor: [u8; DEVMINOR_SIZE], // 337 - Minor device number
|
||||
pub prefix: [u8; PREFIX_SIZE], // 345 - Prefix for file name
|
||||
pub padding: [u8; 12], // 500 - Padding to make 512 bytes
|
||||
}
|
||||
|
||||
impl Default for TarHeader {
|
||||
fn default() -> Self {
|
||||
let mut header = Self {
|
||||
name: [0; NAME_SIZE],
|
||||
mode: [0; MODE_SIZE],
|
||||
uid: [0; UID_SIZE],
|
||||
gid: [0; GID_SIZE],
|
||||
size: [0; SIZE_SIZE],
|
||||
mtime: [0; MTIME_SIZE],
|
||||
chksum: [0; CHKSUM_SIZE],
|
||||
typeflag: AREGTYPE,
|
||||
linkname: [0; LINKNAME_SIZE],
|
||||
magic: [0; MAGIC_SIZE],
|
||||
version: [0; VERSION_SIZE],
|
||||
uname: [0; UNAME_SIZE],
|
||||
gname: [0; GNAME_SIZE],
|
||||
devmajor: [0; DEVMAJOR_SIZE],
|
||||
devminor: [0; DEVMINOR_SIZE],
|
||||
prefix: [0; PREFIX_SIZE],
|
||||
padding: [0; 12],
|
||||
};
|
||||
|
||||
// Set default magic ("ustar") and version ("00")
|
||||
let magic_bytes = TMAGIC.as_bytes(); // "ustar"
|
||||
header.magic[..magic_bytes.len()].copy_from_slice(magic_bytes);
|
||||
// tar specification often expects "ustar\0"
|
||||
if MAGIC_SIZE >= 6 && TMAGIC.len() < MAGIC_SIZE {
|
||||
header.magic[TMAGIC.len()] = 0;
|
||||
}
|
||||
|
||||
let version_bytes = TVERSION.as_bytes(); // "00"
|
||||
header.version[..version_bytes.len()].copy_from_slice(version_bytes);
|
||||
|
||||
header
|
||||
}
|
||||
}
|
||||
|
||||
impl TarHeader {
|
||||
/// Calculates the checksum of the tar header as required by the specification.
|
||||
/// Before computing, the checksum field is treated as if it contained all spaces (0x20).
|
||||
pub fn calculate_checksum(&self) -> usize {
|
||||
let mut header_copy = *self;
|
||||
header_copy.chksum.fill(b' ');
|
||||
let bytes =
|
||||
unsafe { slice::from_raw_parts(&header_copy as *const _ as *const u8, HEADER_SIZE) };
|
||||
bytes.iter().map(|&b| b as usize).sum()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user