"""Read from and write to tar format archives."""

import bz2
import io
import sys
from _typeshed import StrOrBytesPath, StrPath
from builtins import list as _list  # aliases to avoid name clashes with fields named "type" or "list"
from collections.abc import Callable, Iterable, Iterator, Mapping
from gzip import _ReadableFileobj as _GzipReadableFileobj, _WritableFileobj as _GzipWritableFileobj
from types import TracebackType
from typing import IO, ClassVar, Literal, Protocol, overload
from typing_extensions import Self, TypeAlias

__all__ = [
    "TarFile",
    "TarInfo",
    "is_tarfile",
    "TarError",
    "ReadError",
    "CompressionError",
    "StreamError",
    "ExtractError",
    "HeaderError",
    "ENCODING",
    "USTAR_FORMAT",
    "GNU_FORMAT",
    "PAX_FORMAT",
    "DEFAULT_FORMAT",
    "open",
]
if sys.version_info >= (3, 12):
    __all__ += [
        "fully_trusted_filter",
        "data_filter",
        "tar_filter",
        "FilterError",
        "AbsoluteLinkError",
        "OutsideDestinationError",
        "SpecialFileError",
        "AbsolutePathError",
        "LinkOutsideDestinationError",
    ]

_FilterFunction: TypeAlias = Callable[[TarInfo, str], TarInfo | None]
_TarfileFilter: TypeAlias = Literal["fully_trusted", "tar", "data"] | _FilterFunction

class _Fileobj(Protocol):
    def read(self, size: int, /) -> bytes: ...
    def write(self, b: bytes, /) -> object: ...
    def tell(self) -> int: ...
    def seek(self, pos: int, /) -> object: ...
    def close(self) -> object: ...
    # Optional fields:
    # name: str | bytes
    # mode: Literal["rb", "r+b", "wb", "xb"]

class _Bz2ReadableFileobj(bz2._ReadableFileobj):
    def close(self) -> object: ...

class _Bz2WritableFileobj(bz2._WritableFileobj):
    def close(self) -> object: ...

# tar constants
NUL: bytes
BLOCKSIZE: int
RECORDSIZE: int
GNU_MAGIC: bytes
POSIX_MAGIC: bytes

LENGTH_NAME: int
LENGTH_LINK: int
LENGTH_PREFIX: int

REGTYPE: bytes
AREGTYPE: bytes
LNKTYPE: bytes
SYMTYPE: bytes
CONTTYPE: bytes
BLKTYPE: bytes
DIRTYPE: bytes
FIFOTYPE: bytes
CHRTYPE: bytes

GNUTYPE_LONGNAME: bytes
GNUTYPE_LONGLINK: bytes
GNUTYPE_SPARSE: bytes

XHDTYPE: bytes
XGLTYPE: bytes
SOLARIS_XHDTYPE: bytes

USTAR_FORMAT: int
GNU_FORMAT: int
PAX_FORMAT: int
DEFAULT_FORMAT: int

# tarfile constants

SUPPORTED_TYPES: tuple[bytes, ...]
REGULAR_TYPES: tuple[bytes, ...]
GNU_TYPES: tuple[bytes, ...]
PAX_FIELDS: tuple[str, ...]
PAX_NUMBER_FIELDS: dict[str, type]
PAX_NAME_FIELDS: set[str]

ENCODING: str

@overload
def open(
    name: StrOrBytesPath | None = None,
    mode: Literal["r", "r:*", "r:", "r:gz", "r:bz2", "r:xz"] = "r",
    fileobj: IO[bytes] | None = None,
    bufsize: int = 10240,
    *,
    format: int | None = ...,
    tarinfo: type[TarInfo] | None = ...,
    dereference: bool | None = ...,
    ignore_zeros: bool | None = ...,
    encoding: str | None = ...,
    errors: str = ...,
    pax_headers: Mapping[str, str] | None = ...,
    debug: int | None = ...,
    errorlevel: int | None = ...,
) -> TarFile:
    """
    Open a tar archive for reading, writing or appending. Return
    an appropriate TarFile class.

    mode:
    'r' or 'r:*' open for reading with transparent compression
    'r:'         open for reading exclusively uncompressed
    'r:gz'       open for reading with gzip compression
    'r:bz2'      open for reading with bzip2 compression
    'r:xz'       open for reading with lzma compression
    'a' or 'a:'  open for appending, creating the file if necessary
    'w' or 'w:'  open for writing without compression
    'w:gz'       open for writing with gzip compression
    'w:bz2'      open for writing with bzip2 compression
    'w:xz'       open for writing with lzma compression

    'x' or 'x:'  create a tarfile exclusively without compression, raise
                 an exception if the file is already created
    'x:gz'       create a gzip compressed tarfile, raise an exception
                 if the file is already created
    'x:bz2'      create a bzip2 compressed tarfile, raise an exception
                 if the file is already created
    'x:xz'       create an lzma compressed tarfile, raise an exception
                 if the file is already created

    'r|*'        open a stream of tar blocks with transparent compression
    'r|'         open an uncompressed stream of tar blocks for reading
    'r|gz'       open a gzip compressed stream of tar blocks
    'r|bz2'      open a bzip2 compressed stream of tar blocks
    'r|xz'       open an lzma compressed stream of tar blocks
    'w|'         open an uncompressed stream for writing
    'w|gz'       open a gzip compressed stream for writing
    'w|bz2'      open a bzip2 compressed stream for writing
    'w|xz'       open an lzma compressed stream for writing
    """
    ...
@overload
def open(
    name: StrOrBytesPath | None,
    mode: Literal["x", "x:", "a", "a:", "w", "w:"],
    fileobj: _Fileobj | None = None,
    bufsize: int = 10240,
    *,
    format: int | None = ...,
    tarinfo: type[TarInfo] | None = ...,
    dereference: bool | None = ...,
    ignore_zeros: bool | None = ...,
    encoding: str | None = ...,
    errors: str = ...,
    pax_headers: Mapping[str, str] | None = ...,
    debug: int | None = ...,
    errorlevel: int | None = ...,
) -> TarFile:
    """
    Open a tar archive for reading, writing or appending. Return
    an appropriate TarFile class.

    mode:
    'r' or 'r:*' open for reading with transparent compression
    'r:'         open for reading exclusively uncompressed
    'r:gz'       open for reading with gzip compression
    'r:bz2'      open for reading with bzip2 compression
    'r:xz'       open for reading with lzma compression
    'a' or 'a:'  open for appending, creating the file if necessary
    'w' or 'w:'  open for writing without compression
    'w:gz'       open for writing with gzip compression
    'w:bz2'      open for writing with bzip2 compression
    'w:xz'       open for writing with lzma compression

    'x' or 'x:'  create a tarfile exclusively without compression, raise
                 an exception if the file is already created
    'x:gz'       create a gzip compressed tarfile, raise an exception
                 if the file is already created
    'x:bz2'      create a bzip2 compressed tarfile, raise an exception
                 if the file is already created
    'x:xz'       create an lzma compressed tarfile, raise an exception
                 if the file is already created

    'r|*'        open a stream of tar blocks with transparent compression
    'r|'         open an uncompressed stream of tar blocks for reading
    'r|gz'       open a gzip compressed stream of tar blocks
    'r|bz2'      open a bzip2 compressed stream of tar blocks
    'r|xz'       open an lzma compressed stream of tar blocks
    'w|'         open an uncompressed stream for writing
    'w|gz'       open a gzip compressed stream for writing
    'w|bz2'      open a bzip2 compressed stream for writing
    'w|xz'       open an lzma compressed stream for writing
    """
    ...
@overload
def open(
    name: StrOrBytesPath | None = None,
    *,
    mode: Literal["x", "x:", "a", "a:", "w", "w:"],
    fileobj: _Fileobj | None = None,
    bufsize: int = 10240,
    format: int | None = ...,
    tarinfo: type[TarInfo] | None = ...,
    dereference: bool | None = ...,
    ignore_zeros: bool | None = ...,
    encoding: str | None = ...,
    errors: str = ...,
    pax_headers: Mapping[str, str] | None = ...,
    debug: int | None = ...,
    errorlevel: int | None = ...,
) -> TarFile:
    """
    Open a tar archive for reading, writing or appending. Return
    an appropriate TarFile class.

    mode:
    'r' or 'r:*' open for reading with transparent compression
    'r:'         open for reading exclusively uncompressed
    'r:gz'       open for reading with gzip compression
    'r:bz2'      open for reading with bzip2 compression
    'r:xz'       open for reading with lzma compression
    'a' or 'a:'  open for appending, creating the file if necessary
    'w' or 'w:'  open for writing without compression
    'w:gz'       open for writing with gzip compression
    'w:bz2'      open for writing with bzip2 compression
    'w:xz'       open for writing with lzma compression

    'x' or 'x:'  create a tarfile exclusively without compression, raise
                 an exception if the file is already created
    'x:gz'       create a gzip compressed tarfile, raise an exception
                 if the file is already created
    'x:bz2'      create a bzip2 compressed tarfile, raise an exception
                 if the file is already created
    'x:xz'       create an lzma compressed tarfile, raise an exception
                 if the file is already created

    'r|*'        open a stream of tar blocks with transparent compression
    'r|'         open an uncompressed stream of tar blocks for reading
    'r|gz'       open a gzip compressed stream of tar blocks
    'r|bz2'      open a bzip2 compressed stream of tar blocks
    'r|xz'       open an lzma compressed stream of tar blocks
    'w|'         open an uncompressed stream for writing
    'w|gz'       open a gzip compressed stream for writing
    'w|bz2'      open a bzip2 compressed stream for writing
    'w|xz'       open an lzma compressed stream for writing
    """
    ...
@overload
def open(
    name: StrOrBytesPath | None,
    mode: Literal["x:gz", "x:bz2", "w:gz", "w:bz2"],
    fileobj: _Fileobj | None = None,
    bufsize: int = 10240,
    *,
    format: int | None = ...,
    tarinfo: type[TarInfo] | None = ...,
    dereference: bool | None = ...,
    ignore_zeros: bool | None = ...,
    encoding: str | None = ...,
    errors: str = ...,
    pax_headers: Mapping[str, str] | None = ...,
    debug: int | None = ...,
    errorlevel: int | None = ...,
    compresslevel: int = 9,
) -> TarFile:
    """
    Open a tar archive for reading, writing or appending. Return
    an appropriate TarFile class.

    mode:
    'r' or 'r:*' open for reading with transparent compression
    'r:'         open for reading exclusively uncompressed
    'r:gz'       open for reading with gzip compression
    'r:bz2'      open for reading with bzip2 compression
    'r:xz'       open for reading with lzma compression
    'a' or 'a:'  open for appending, creating the file if necessary
    'w' or 'w:'  open for writing without compression
    'w:gz'       open for writing with gzip compression
    'w:bz2'      open for writing with bzip2 compression
    'w:xz'       open for writing with lzma compression

    'x' or 'x:'  create a tarfile exclusively without compression, raise
                 an exception if the file is already created
    'x:gz'       create a gzip compressed tarfile, raise an exception
                 if the file is already created
    'x:bz2'      create a bzip2 compressed tarfile, raise an exception
                 if the file is already created
    'x:xz'       create an lzma compressed tarfile, raise an exception
                 if the file is already created

    'r|*'        open a stream of tar blocks with transparent compression
    'r|'         open an uncompressed stream of tar blocks for reading
    'r|gz'       open a gzip compressed stream of tar blocks
    'r|bz2'      open a bzip2 compressed stream of tar blocks
    'r|xz'       open an lzma compressed stream of tar blocks
    'w|'         open an uncompressed stream for writing
    'w|gz'       open a gzip compressed stream for writing
    'w|bz2'      open a bzip2 compressed stream for writing
    'w|xz'       open an lzma compressed stream for writing
    """
    ...
@overload
def open(
    name: StrOrBytesPath | None = None,
    *,
    mode: Literal["x:gz", "x:bz2", "w:gz", "w:bz2"],
    fileobj: _Fileobj | None = None,
    bufsize: int = 10240,
    format: int | None = ...,
    tarinfo: type[TarInfo] | None = ...,
    dereference: bool | None = ...,
    ignore_zeros: bool | None = ...,
    encoding: str | None = ...,
    errors: str = ...,
    pax_headers: Mapping[str, str] | None = ...,
    debug: int | None = ...,
    errorlevel: int | None = ...,
    compresslevel: int = 9,
) -> TarFile:
    """
    Open a tar archive for reading, writing or appending. Return
    an appropriate TarFile class.

    mode:
    'r' or 'r:*' open for reading with transparent compression
    'r:'         open for reading exclusively uncompressed
    'r:gz'       open for reading with gzip compression
    'r:bz2'      open for reading with bzip2 compression
    'r:xz'       open for reading with lzma compression
    'a' or 'a:'  open for appending, creating the file if necessary
    'w' or 'w:'  open for writing without compression
    'w:gz'       open for writing with gzip compression
    'w:bz2'      open for writing with bzip2 compression
    'w:xz'       open for writing with lzma compression

    'x' or 'x:'  create a tarfile exclusively without compression, raise
                 an exception if the file is already created
    'x:gz'       create a gzip compressed tarfile, raise an exception
                 if the file is already created
    'x:bz2'      create a bzip2 compressed tarfile, raise an exception
                 if the file is already created
    'x:xz'       create an lzma compressed tarfile, raise an exception
                 if the file is already created

    'r|*'        open a stream of tar blocks with transparent compression
    'r|'         open an uncompressed stream of tar blocks for reading
    'r|gz'       open a gzip compressed stream of tar blocks
    'r|bz2'      open a bzip2 compressed stream of tar blocks
    'r|xz'       open an lzma compressed stream of tar blocks
    'w|'         open an uncompressed stream for writing
    'w|gz'       open a gzip compressed stream for writing
    'w|bz2'      open a bzip2 compressed stream for writing
    'w|xz'       open an lzma compressed stream for writing
    """
    ...
@overload
def open(
    name: StrOrBytesPath | None,
    mode: Literal["x:xz", "w:xz"],
    fileobj: _Fileobj | None = None,
    bufsize: int = 10240,
    *,
    format: int | None = ...,
    tarinfo: type[TarInfo] | None = ...,
    dereference: bool | None = ...,
    ignore_zeros: bool | None = ...,
    encoding: str | None = ...,
    errors: str = ...,
    pax_headers: Mapping[str, str] | None = ...,
    debug: int | None = ...,
    errorlevel: int | None = ...,
    preset: Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | None = ...,
) -> TarFile:
    """
    Open a tar archive for reading, writing or appending. Return
    an appropriate TarFile class.

    mode:
    'r' or 'r:*' open for reading with transparent compression
    'r:'         open for reading exclusively uncompressed
    'r:gz'       open for reading with gzip compression
    'r:bz2'      open for reading with bzip2 compression
    'r:xz'       open for reading with lzma compression
    'a' or 'a:'  open for appending, creating the file if necessary
    'w' or 'w:'  open for writing without compression
    'w:gz'       open for writing with gzip compression
    'w:bz2'      open for writing with bzip2 compression
    'w:xz'       open for writing with lzma compression

    'x' or 'x:'  create a tarfile exclusively without compression, raise
                 an exception if the file is already created
    'x:gz'       create a gzip compressed tarfile, raise an exception
                 if the file is already created
    'x:bz2'      create a bzip2 compressed tarfile, raise an exception
                 if the file is already created
    'x:xz'       create an lzma compressed tarfile, raise an exception
                 if the file is already created

    'r|*'        open a stream of tar blocks with transparent compression
    'r|'         open an uncompressed stream of tar blocks for reading
    'r|gz'       open a gzip compressed stream of tar blocks
    'r|bz2'      open a bzip2 compressed stream of tar blocks
    'r|xz'       open an lzma compressed stream of tar blocks
    'w|'         open an uncompressed stream for writing
    'w|gz'       open a gzip compressed stream for writing
    'w|bz2'      open a bzip2 compressed stream for writing
    'w|xz'       open an lzma compressed stream for writing
    """
    ...
@overload
def open(
    name: StrOrBytesPath | None = None,
    *,
    mode: Literal["x:xz", "w:xz"],
    fileobj: _Fileobj | None = None,
    bufsize: int = 10240,
    format: int | None = ...,
    tarinfo: type[TarInfo] | None = ...,
    dereference: bool | None = ...,
    ignore_zeros: bool | None = ...,
    encoding: str | None = ...,
    errors: str = ...,
    pax_headers: Mapping[str, str] | None = ...,
    debug: int | None = ...,
    errorlevel: int | None = ...,
    preset: Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | None = ...,
) -> TarFile:
    """
    Open a tar archive for reading, writing or appending. Return
    an appropriate TarFile class.

    mode:
    'r' or 'r:*' open for reading with transparent compression
    'r:'         open for reading exclusively uncompressed
    'r:gz'       open for reading with gzip compression
    'r:bz2'      open for reading with bzip2 compression
    'r:xz'       open for reading with lzma compression
    'a' or 'a:'  open for appending, creating the file if necessary
    'w' or 'w:'  open for writing without compression
    'w:gz'       open for writing with gzip compression
    'w:bz2'      open for writing with bzip2 compression
    'w:xz'       open for writing with lzma compression

    'x' or 'x:'  create a tarfile exclusively without compression, raise
                 an exception if the file is already created
    'x:gz'       create a gzip compressed tarfile, raise an exception
                 if the file is already created
    'x:bz2'      create a bzip2 compressed tarfile, raise an exception
                 if the file is already created
    'x:xz'       create an lzma compressed tarfile, raise an exception
                 if the file is already created

    'r|*'        open a stream of tar blocks with transparent compression
    'r|'         open an uncompressed stream of tar blocks for reading
    'r|gz'       open a gzip compressed stream of tar blocks
    'r|bz2'      open a bzip2 compressed stream of tar blocks
    'r|xz'       open an lzma compressed stream of tar blocks
    'w|'         open an uncompressed stream for writing
    'w|gz'       open a gzip compressed stream for writing
    'w|bz2'      open a bzip2 compressed stream for writing
    'w|xz'       open an lzma compressed stream for writing
    """
    ...

# TODO: Temporary fallback for modes containing pipe characters. These don't
# work with mypy 1.10, but this should be fixed with mypy 1.11.
# https://github.com/python/typeshed/issues/12182
@overload
def open(
    name: StrOrBytesPath | None = None,
    *,
    mode: str,
    fileobj: IO[bytes] | None = None,
    bufsize: int = 10240,
    format: int | None = ...,
    tarinfo: type[TarInfo] | None = ...,
    dereference: bool | None = ...,
    ignore_zeros: bool | None = ...,
    encoding: str | None = ...,
    errors: str = ...,
    pax_headers: Mapping[str, str] | None = ...,
    debug: int | None = ...,
    errorlevel: int | None = ...,
    preset: int | None = ...,
) -> TarFile:
    """
    Open a tar archive for reading, writing or appending. Return
    an appropriate TarFile class.

    mode:
    'r' or 'r:*' open for reading with transparent compression
    'r:'         open for reading exclusively uncompressed
    'r:gz'       open for reading with gzip compression
    'r:bz2'      open for reading with bzip2 compression
    'r:xz'       open for reading with lzma compression
    'a' or 'a:'  open for appending, creating the file if necessary
    'w' or 'w:'  open for writing without compression
    'w:gz'       open for writing with gzip compression
    'w:bz2'      open for writing with bzip2 compression
    'w:xz'       open for writing with lzma compression

    'x' or 'x:'  create a tarfile exclusively without compression, raise
                 an exception if the file is already created
    'x:gz'       create a gzip compressed tarfile, raise an exception
                 if the file is already created
    'x:bz2'      create a bzip2 compressed tarfile, raise an exception
                 if the file is already created
    'x:xz'       create an lzma compressed tarfile, raise an exception
                 if the file is already created

    'r|*'        open a stream of tar blocks with transparent compression
    'r|'         open an uncompressed stream of tar blocks for reading
    'r|gz'       open a gzip compressed stream of tar blocks
    'r|bz2'      open a bzip2 compressed stream of tar blocks
    'r|xz'       open an lzma compressed stream of tar blocks
    'w|'         open an uncompressed stream for writing
    'w|gz'       open a gzip compressed stream for writing
    'w|bz2'      open a bzip2 compressed stream for writing
    'w|xz'       open an lzma compressed stream for writing
    """
    ...

class ExFileObject(io.BufferedReader):
    def __init__(self, tarfile: TarFile, tarinfo: TarInfo) -> None: ...

class TarFile:
    """
    The TarFile Class provides an interface to tar archives.
    
    """
    OPEN_METH: ClassVar[Mapping[str, str]]
    name: StrOrBytesPath | None
    mode: Literal["r", "a", "w", "x"]
    fileobj: _Fileobj | None
    format: int | None
    tarinfo: type[TarInfo]
    dereference: bool | None
    ignore_zeros: bool | None
    encoding: str | None
    errors: str
    fileobject: type[ExFileObject]
    pax_headers: Mapping[str, str] | None
    debug: int | None
    errorlevel: int | None
    offset: int  # undocumented
    extraction_filter: _FilterFunction | None
    if sys.version_info >= (3, 13):
        stream: bool
        def __init__(
            self,
            name: StrOrBytesPath | None = None,
            mode: Literal["r", "a", "w", "x"] = "r",
            fileobj: _Fileobj | None = None,
            format: int | None = None,
            tarinfo: type[TarInfo] | None = None,
            dereference: bool | None = None,
            ignore_zeros: bool | None = None,
            encoding: str | None = None,
            errors: str = "surrogateescape",
            pax_headers: Mapping[str, str] | None = None,
            debug: int | None = None,
            errorlevel: int | None = None,
            copybufsize: int | None = None,  # undocumented
            stream: bool = False,
        ) -> None:
            """
            Open an (uncompressed) tar archive `name'. `mode' is either 'r' to
            read from an existing archive, 'a' to append data to an existing
            file or 'w' to create a new file overwriting an existing one. `mode'
            defaults to 'r'.
            If `fileobj' is given, it is used for reading or writing data. If it
            can be determined, `mode' is overridden by `fileobj's mode.
            `fileobj' is not closed, when TarFile is closed.
            """
            ...
    else:
        def __init__(
            self,
            name: StrOrBytesPath | None = None,
            mode: Literal["r", "a", "w", "x"] = "r",
            fileobj: _Fileobj | None = None,
            format: int | None = None,
            tarinfo: type[TarInfo] | None = None,
            dereference: bool | None = None,
            ignore_zeros: bool | None = None,
            encoding: str | None = None,
            errors: str = "surrogateescape",
            pax_headers: Mapping[str, str] | None = None,
            debug: int | None = None,
            errorlevel: int | None = None,
            copybufsize: int | None = None,  # undocumented
        ) -> None: ...

    def __enter__(self) -> Self: ...
    def __exit__(
        self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None
    ) -> None: ...
    def __iter__(self) -> Iterator[TarInfo]:
        """
        Provide an iterator object.
        
        """
        ...
    @classmethod
    def open(
        cls,
        name: StrOrBytesPath | None = None,
        mode: str = "r",
        fileobj: IO[bytes] | None = None,  # depends on mode
        bufsize: int = 10240,
        *,
        format: int | None = ...,
        tarinfo: type[TarInfo] | None = ...,
        dereference: bool | None = ...,
        ignore_zeros: bool | None = ...,
        encoding: str | None = ...,
        errors: str = ...,
        pax_headers: Mapping[str, str] | None = ...,
        debug: int | None = ...,
        errorlevel: int | None = ...,
    ) -> Self:
        """
        Open a tar archive for reading, writing or appending. Return
        an appropriate TarFile class.

        mode:
        'r' or 'r:*' open for reading with transparent compression
        'r:'         open for reading exclusively uncompressed
        'r:gz'       open for reading with gzip compression
        'r:bz2'      open for reading with bzip2 compression
        'r:xz'       open for reading with lzma compression
        'a' or 'a:'  open for appending, creating the file if necessary
        'w' or 'w:'  open for writing without compression
        'w:gz'       open for writing with gzip compression
        'w:bz2'      open for writing with bzip2 compression
        'w:xz'       open for writing with lzma compression

        'x' or 'x:'  create a tarfile exclusively without compression, raise
                     an exception if the file is already created
        'x:gz'       create a gzip compressed tarfile, raise an exception
                     if the file is already created
        'x:bz2'      create a bzip2 compressed tarfile, raise an exception
                     if the file is already created
        'x:xz'       create an lzma compressed tarfile, raise an exception
                     if the file is already created

        'r|*'        open a stream of tar blocks with transparent compression
        'r|'         open an uncompressed stream of tar blocks for reading
        'r|gz'       open a gzip compressed stream of tar blocks
        'r|bz2'      open a bzip2 compressed stream of tar blocks
        'r|xz'       open an lzma compressed stream of tar blocks
        'w|'         open an uncompressed stream for writing
        'w|gz'       open a gzip compressed stream for writing
        'w|bz2'      open a bzip2 compressed stream for writing
        'w|xz'       open an lzma compressed stream for writing
        """
        ...
    @classmethod
    def taropen(
        cls,
        name: StrOrBytesPath | None,
        mode: Literal["r", "a", "w", "x"] = "r",
        fileobj: _Fileobj | None = None,
        *,
        compresslevel: int = ...,
        format: int | None = ...,
        tarinfo: type[TarInfo] | None = ...,
        dereference: bool | None = ...,
        ignore_zeros: bool | None = ...,
        encoding: str | None = ...,
        pax_headers: Mapping[str, str] | None = ...,
        debug: int | None = ...,
        errorlevel: int | None = ...,
    ) -> Self:
        """
        Open uncompressed tar archive name for reading or writing.
        
        """
        ...
    @overload
    @classmethod
    def gzopen(
        cls,
        name: StrOrBytesPath | None,
        mode: Literal["r"] = "r",
        fileobj: _GzipReadableFileobj | None = None,
        compresslevel: int = 9,
        *,
        format: int | None = ...,
        tarinfo: type[TarInfo] | None = ...,
        dereference: bool | None = ...,
        ignore_zeros: bool | None = ...,
        encoding: str | None = ...,
        pax_headers: Mapping[str, str] | None = ...,
        debug: int | None = ...,
        errorlevel: int | None = ...,
    ) -> Self:
        """
        Open gzip compressed tar archive name for reading or writing.
        Appending is not allowed.
        """
        ...
    @overload
    @classmethod
    def gzopen(
        cls,
        name: StrOrBytesPath | None,
        mode: Literal["w", "x"],
        fileobj: _GzipWritableFileobj | None = None,
        compresslevel: int = 9,
        *,
        format: int | None = ...,
        tarinfo: type[TarInfo] | None = ...,
        dereference: bool | None = ...,
        ignore_zeros: bool | None = ...,
        encoding: str | None = ...,
        pax_headers: Mapping[str, str] | None = ...,
        debug: int | None = ...,
        errorlevel: int | None = ...,
    ) -> Self:
        """
        Open gzip compressed tar archive name for reading or writing.
        Appending is not allowed.
        """
        ...
    @overload
    @classmethod
    def bz2open(
        cls,
        name: StrOrBytesPath | None,
        mode: Literal["w", "x"],
        fileobj: _Bz2WritableFileobj | None = None,
        compresslevel: int = 9,
        *,
        format: int | None = ...,
        tarinfo: type[TarInfo] | None = ...,
        dereference: bool | None = ...,
        ignore_zeros: bool | None = ...,
        encoding: str | None = ...,
        pax_headers: Mapping[str, str] | None = ...,
        debug: int | None = ...,
        errorlevel: int | None = ...,
    ) -> Self:
        """
        Open bzip2 compressed tar archive name for reading or writing.
        Appending is not allowed.
        """
        ...
    @overload
    @classmethod
    def bz2open(
        cls,
        name: StrOrBytesPath | None,
        mode: Literal["r"] = "r",
        fileobj: _Bz2ReadableFileobj | None = None,
        compresslevel: int = 9,
        *,
        format: int | None = ...,
        tarinfo: type[TarInfo] | None = ...,
        dereference: bool | None = ...,
        ignore_zeros: bool | None = ...,
        encoding: str | None = ...,
        pax_headers: Mapping[str, str] | None = ...,
        debug: int | None = ...,
        errorlevel: int | None = ...,
    ) -> Self:
        """
        Open bzip2 compressed tar archive name for reading or writing.
        Appending is not allowed.
        """
        ...
    @classmethod
    def xzopen(
        cls,
        name: StrOrBytesPath | None,
        mode: Literal["r", "w", "x"] = "r",
        fileobj: IO[bytes] | None = None,
        preset: int | None = None,
        *,
        format: int | None = ...,
        tarinfo: type[TarInfo] | None = ...,
        dereference: bool | None = ...,
        ignore_zeros: bool | None = ...,
        encoding: str | None = ...,
        pax_headers: Mapping[str, str] | None = ...,
        debug: int | None = ...,
        errorlevel: int | None = ...,
    ) -> Self:
        """
        Open lzma compressed tar archive name for reading or writing.
        Appending is not allowed.
        """
        ...
    def getmember(self, name: str) -> TarInfo:
        """
        Return a TarInfo object for member `name'. If `name' can not be
        found in the archive, KeyError is raised. If a member occurs more
        than once in the archive, its last occurrence is assumed to be the
        most up-to-date version.
        """
        ...
    def getmembers(self) -> _list[TarInfo]:
        """
        Return the members of the archive as a list of TarInfo objects. The
        list has the same order as the members in the archive.
        """
        ...
    def getnames(self) -> _list[str]:
        """
        Return the members of the archive as a list of their names. It has
        the same order as the list returned by getmembers().
        """
        ...
    def list(self, verbose: bool = True, *, members: _list[TarInfo] | None = None) -> None:
        """
        Print a table of contents to sys.stdout. If `verbose' is False, only
        the names of the members are printed. If it is True, an `ls -l'-like
        output is produced. `members' is optional and must be a subset of the
        list returned by getmembers().
        """
        ...
    def next(self) -> TarInfo | None:
        """
        Return the next member of the archive as a TarInfo object, when
        TarFile is opened for reading. Return None if there is no more
        available.
        """
        ...
    # Calling this method without `filter` is deprecated, but it may be set either on the class or in an
    # individual call, so we can't mark it as @deprecated here.
    def extractall(
        self,
        path: StrOrBytesPath = ".",
        members: Iterable[TarInfo] | None = None,
        *,
        numeric_owner: bool = False,
        filter: _TarfileFilter | None = ...,
    ) -> None:
        """
        Extract all members from the archive to the current working
        directory and set owner, modification time and permissions on
        directories afterwards. `path' specifies a different directory
        to extract to. `members' is optional and must be a subset of the
        list returned by getmembers(). If `numeric_owner` is True, only
        the numbers for user/group names are used and not the names.

        The `filter` function will be called on each member just
        before extraction.
        It can return a changed TarInfo or None to skip the member.
        String names of common filters are accepted.
        """
        ...
    # Same situation as for `extractall`.
    def extract(
        self,
        member: str | TarInfo,
        path: StrOrBytesPath = "",
        set_attrs: bool = True,
        *,
        numeric_owner: bool = False,
        filter: _TarfileFilter | None = ...,
    ) -> None:
        """
        Extract a member from the archive to the current working directory,
        using its full name. Its file information is extracted as accurately
        as possible. `member' may be a filename or a TarInfo object. You can
        specify a different directory using `path'. File attributes (owner,
        mtime, mode) are set unless `set_attrs' is False. If `numeric_owner`
        is True, only the numbers for user/group names are used and not
        the names.

        The `filter` function will be called before extraction.
        It can return a changed TarInfo or None to skip the member.
        String names of common filters are accepted.
        """
        ...
    def _extract_member(
        self, tarinfo: TarInfo, targetpath: str, set_attrs: bool = True, numeric_owner: bool = False
    ) -> None:
        """
        Extract the TarInfo object tarinfo to a physical
        file called targetpath.
        """
        ...
    def extractfile(self, member: str | TarInfo) -> IO[bytes] | None:
        """
        Extract a member from the archive as a file object. `member' may be
        a filename or a TarInfo object. If `member' is a regular file or
        a link, an io.BufferedReader object is returned. For all other
        existing members, None is returned. If `member' does not appear
        in the archive, KeyError is raised.
        """
        ...
    def makedir(self, tarinfo: TarInfo, targetpath: StrOrBytesPath) -> None:
        """
        Make a directory called targetpath.
        
        """
        ...
    def makefile(self, tarinfo: TarInfo, targetpath: StrOrBytesPath) -> None:
        """
        Make a file called targetpath.
        
        """
        ...
    def makeunknown(self, tarinfo: TarInfo, targetpath: StrOrBytesPath) -> None:
        """
        Make a file from a TarInfo object with an unknown type
        at targetpath.
        """
        ...
    def makefifo(self, tarinfo: TarInfo, targetpath: StrOrBytesPath) -> None:
        """
        Make a fifo called targetpath.
        
        """
        ...
    def makedev(self, tarinfo: TarInfo, targetpath: StrOrBytesPath) -> None:
        """
        Make a character or block device called targetpath.
        
        """
        ...
    def makelink(self, tarinfo: TarInfo, targetpath: StrOrBytesPath) -> None:
        """
        Make a (symbolic) link called targetpath. If it cannot be created
        (platform limitation), we try to make a copy of the referenced file
        instead of a link.
        """
        ...
    def chown(self, tarinfo: TarInfo, targetpath: StrOrBytesPath, numeric_owner: bool) -> None:
        """
        Set owner of targetpath according to tarinfo. If numeric_owner
        is True, use .gid/.uid instead of .gname/.uname. If numeric_owner
        is False, fall back to .gid/.uid when the search based on name
        fails.
        """
        ...
    def chmod(self, tarinfo: TarInfo, targetpath: StrOrBytesPath) -> None:
        """
        Set file permissions of targetpath according to tarinfo.
        
        """
        ...
    def utime(self, tarinfo: TarInfo, targetpath: StrOrBytesPath) -> None:
        """
        Set modification time of targetpath according to tarinfo.
        
        """
        ...
    def add(
        self,
        name: StrPath,
        arcname: StrPath | None = None,
        recursive: bool = True,
        *,
        filter: Callable[[TarInfo], TarInfo | None] | None = None,
    ) -> None:
        """
        Add the file `name' to the archive. `name' may be any type of file
        (directory, fifo, symbolic link, etc.). If given, `arcname'
        specifies an alternative name for the file in the archive.
        Directories are added recursively by default. This can be avoided by
        setting `recursive' to False. `filter' is a function
        that expects a TarInfo object argument and returns the changed
        TarInfo object, if it returns None the TarInfo object will be
        excluded from the archive.
        """
        ...
    def addfile(self, tarinfo: TarInfo, fileobj: IO[bytes] | None = None) -> None:
        """
        Add the TarInfo object `tarinfo' to the archive. If `tarinfo' represents
        a non zero-size regular file, the `fileobj' argument should be a binary file,
        and tarinfo.size bytes are read from it and added to the archive.
        You can create TarInfo objects directly, or by using gettarinfo().
        """
        ...
    def gettarinfo(
        self, name: StrOrBytesPath | None = None, arcname: str | None = None, fileobj: IO[bytes] | None = None
    ) -> TarInfo:
        """
        Create a TarInfo object from the result of os.stat or equivalent
        on an existing file. The file is either named by `name', or
        specified as a file object `fileobj' with a file descriptor. If
        given, `arcname' specifies an alternative name for the file in the
        archive, otherwise, the name is taken from the 'name' attribute of
        'fileobj', or the 'name' argument. The name should be a text
        string.
        """
        ...
    def close(self) -> None:
        """
        Close the TarFile. In write-mode, two finishing zero blocks are
        appended to the archive.
        """
        ...

if sys.version_info >= (3, 9):
    def is_tarfile(name: StrOrBytesPath | IO[bytes]) -> bool:
        """
        Return True if name points to a tar archive that we
        are able to handle, else return False.

        'name' should be a string, file, or file-like object.
        """
        ...

else:
    def is_tarfile(name: StrOrBytesPath) -> bool: ...

class TarError(Exception):
    """Base exception."""
    ...
class ReadError(TarError):
    """Exception for unreadable tar archives."""
    ...
class CompressionError(TarError):
    """Exception for unavailable compression methods."""
    ...
class StreamError(TarError):
    """Exception for unsupported operations on stream-like TarFiles."""
    ...
class ExtractError(TarError):
    """General exception for extract errors."""
    ...
class HeaderError(TarError):
    """Base exception for header errors."""
    ...

class FilterError(TarError):
    # This attribute is only set directly on the subclasses, but the documentation guarantees
    # that it is always present on FilterError.
    tarinfo: TarInfo

class AbsolutePathError(FilterError):
    def __init__(self, tarinfo: TarInfo) -> None: ...

class OutsideDestinationError(FilterError):
    def __init__(self, tarinfo: TarInfo, path: str) -> None: ...

class SpecialFileError(FilterError):
    def __init__(self, tarinfo: TarInfo) -> None: ...

class AbsoluteLinkError(FilterError):
    def __init__(self, tarinfo: TarInfo) -> None: ...

class LinkOutsideDestinationError(FilterError):
    def __init__(self, tarinfo: TarInfo, path: str) -> None: ...

def fully_trusted_filter(member: TarInfo, dest_path: str) -> TarInfo: ...
def tar_filter(member: TarInfo, dest_path: str) -> TarInfo: ...
def data_filter(member: TarInfo, dest_path: str) -> TarInfo: ...

class TarInfo:
    """
    Informational class which holds the details about an
    archive member given by a tar header block.
    TarInfo objects are returned by TarFile.getmember(),
    TarFile.getmembers() and TarFile.gettarinfo() and are
    usually created internally.
    """
    name: str
    path: str
    size: int
    mtime: int | float
    chksum: int
    devmajor: int
    devminor: int
    offset: int
    offset_data: int
    sparse: bytes | None
    tarfile: TarFile | None
    mode: int
    type: bytes
    linkname: str
    uid: int
    gid: int
    uname: str
    gname: str
    pax_headers: Mapping[str, str]
    def __init__(self, name: str = "") -> None:
        """
        Construct a TarInfo object. name is the optional name
        of the member.
        """
        ...
    @classmethod
    def frombuf(cls, buf: bytes | bytearray, encoding: str, errors: str) -> Self:
        """
        Construct a TarInfo object from a 512 byte bytes object.
        
        """
        ...
    @classmethod
    def fromtarfile(cls, tarfile: TarFile) -> Self:
        """
        Return the next TarInfo object from TarFile object
        tarfile.
        """
        ...
    @property
    def linkpath(self) -> str:
        """In pax headers, "linkname" is called "linkpath"."""
        ...
    @linkpath.setter
    def linkpath(self, linkname: str) -> None:
        """In pax headers, "linkname" is called "linkpath"."""
        ...
    def replace(
        self,
        *,
        name: str = ...,
        mtime: int = ...,
        mode: int = ...,
        linkname: str = ...,
        uid: int = ...,
        gid: int = ...,
        uname: str = ...,
        gname: str = ...,
        deep: bool = True,
    ) -> Self:
        """
        Return a deep copy of self with the given attributes replaced.
        
        """
        ...
    def get_info(self) -> Mapping[str, str | int | bytes | Mapping[str, str]]:
        """
        Return the TarInfo's attributes as a dictionary.
        
        """
        ...
    def tobuf(self, format: int | None = 2, encoding: str | None = "utf-8", errors: str = "surrogateescape") -> bytes:
        """
        Return a tar header as a string of 512 byte blocks.
        
        """
        ...
    def create_ustar_header(
        self, info: Mapping[str, str | int | bytes | Mapping[str, str]], encoding: str, errors: str
    ) -> bytes:
        """
        Return the object as a ustar header block.
        
        """
        ...
    def create_gnu_header(
        self, info: Mapping[str, str | int | bytes | Mapping[str, str]], encoding: str, errors: str
    ) -> bytes:
        """
        Return the object as a GNU header block sequence.
        
        """
        ...
    def create_pax_header(self, info: Mapping[str, str | int | bytes | Mapping[str, str]], encoding: str) -> bytes:
        """
        Return the object as a ustar header block. If it cannot be
        represented this way, prepend a pax extended header sequence
        with supplement information.
        """
        ...
    @classmethod
    def create_pax_global_header(cls, pax_headers: Mapping[str, str]) -> bytes:
        """
        Return the object as a pax global header block sequence.
        
        """
        ...
    def isfile(self) -> bool:
        """Return True if the Tarinfo object is a regular file."""
        ...
    def isreg(self) -> bool:
        """Return True if the Tarinfo object is a regular file."""
        ...
    def issparse(self) -> bool: ...
    def isdir(self) -> bool:
        """Return True if it is a directory."""
        ...
    def issym(self) -> bool:
        """Return True if it is a symbolic link."""
        ...
    def islnk(self) -> bool:
        """Return True if it is a hard link."""
        ...
    def ischr(self) -> bool:
        """Return True if it is a character device."""
        ...
    def isblk(self) -> bool:
        """Return True if it is a block device."""
        ...
    def isfifo(self) -> bool:
        """Return True if it is a FIFO."""
        ...
    def isdev(self) -> bool:
        """Return True if it is one of character device, block device or FIFO."""
        ...
