HEX
Server: Apache
System: Linux server2.voipitup.com.au 4.18.0-553.109.1.lve.el8.x86_64 #1 SMP Thu Mar 5 20:23:46 UTC 2026 x86_64
User: posscale (1027)
PHP: 8.2.30
Disabled: exec,passthru,shell_exec,system
Upload Files
File: //opt/saltstack/salt/lib/python3.10/site-packages/salt/states/__pycache__/archive.cpython-310.pyc
o

�N�g=�@s*dZddlZddlZddlZddlZddlZddlZddlZddlZddl	m
Z
ddlmZddl
ZddlZddlZddlZddlZddlZddlmZmZe�e�Zdd�Zdd	�Zd
d�Zdd
�Zdd�Zddd�Zdd�Z dd�Z!dd�Z"																						ddd�Z#dS)z0
Extract an archive

.. versionadded:: 2014.1.0
�N)�closing)�urlparse)�CommandExecutionError�CommandNotFoundErrorcCs0|durdSztj�|�WStyYdSw)z�
    Return a bool telling whether or ``path`` is absolute. If ``path`` is None,
    return ``True``. This function is designed to validate variables which
    optionally contain a file path.
    NTF)�os�path�isabs�AttributeError�r�r�G/opt/saltstack/salt/lib/python3.10/site-packages/salt/states/archive.py�_path_is_abss�r
cCs4|r|dd7<dS|r|dd7<dSdS)zq
    Common code to add additional explanation to the state's comment field,
    both when test=True and not
    �commentz, due to source_hash updatez*, due to absence of one or more files/dirsNr)�ret�source_hash_trigger�contents_missingrrr�_add_explanation,s
�rcCs tjjj|tdd�tdd�S)N�	hash_type��form)�hsumr)�salt�utilsZ	hashutilsZget_hash�__opts__r
rrr�
_gen_checksum7s�rc
Cs�z'd�tj�|td�df�}t�d|�r&tjj�dtj�	|�d�
d��}WnBtyi}z6t|��
d�rNtj�	|�\}}tjj�d|�d	�|�
d��}nt|��
d
�r^tjj�d|�}n�WYd}~nd}~wwtjj�tdd|�}t�d
||�|S)N�.�cachedir�hashz..[/\\]�local���z/\z
path is on�:zCannot mix UNCZuncZarchive_hashz1Using checksum file %s for cached archive file %s)�joinrr�relpathr�re�matchrr�
splitdrive�lstrip�
ValueError�str�
startswith�rstrip�log�debug)rr"�exc�driverrrr�_checksum_file_path>s0�����
r/c

Cs�t|�}tj�|�}tj�|�st�|�t|�}|�d�}|�d�}|r�|r�g}z�z6tj	j
�|d��$}|D]}z|�|�
d��dd��Wq6tyOYq6wWd�n1sZwYWntyy}	z
|	jtjkro�WYd}	~	nd}	~	wwtj	j
�|d��>}|D]}|d|kr�||d<|�d	j|��q�|d
d�|D�vr�|�|�d|�d��Wd�WdSWd�WdS1s�wYWdSty�}	ztjd||	d
d�WYd}	~	dSd}	~	wwdSdS)Nrr�r�
r ��wrz{}:{}
cSsg|]}|d�qS)rr��.0�xrrr�
<listcomp>tsz$_update_checksum.<locals>.<listcomp>z$Failed to update checksum for %s: %sT)�exc_info)r/rr�dirname�isdir�makedirsr�getrr�files�fopen�appendr*�splitr'�OSError�errno�ENOENT�write�formatr+�warning)
r�
checksum_fileZchecksum_dir�
source_sumrr�lines�fp_�liner-rrr�_update_checksumYs^


��������&�����rLc	Cs�|durtd}t|�}z:tjj�|d��(}|D]}|�d��dd�\}}||kr+nq	Wd�WdSWd�n1s@wYWntt	fyRYdSw||d�S)Nrr0r1r r2)rr)
rr/rrr=r>r*r@rAr')rrrGrJrKrrrrr�_read_cached_checksums&����	�
rMcCs t||�dtd�d�}||kS)Nrr)rMr<r)�cachedrHZ
cached_sumrrr�_compare_checksum�s�rOcCsdtdddgdd�vS)NZbsdtarzcmd.run�tarz	--versionF)�python_shell)�__salt__rrrr�
_is_bsdtar�srScCs&zt�|�WdStyYdSw)z3
    Attempt to remove the specified directory
    N)r�rmdirrA)�namerrr�_cleanup_destdir�s
�rVFTcWKsx|didd�}tjjjd�i|��}|r|rd|d<|Sd|vr9d|vr9|�dg��d	�t|�d��}|�d�nd|vrEt|�d��}nd|vrQt|�d��}nd
}t|�s`|�d�|d<|S|shd|d<|S|�	t
j�}t
j�
|�r}|�d
�|d<|S|t
j7}t|�s�d|d<|St|�s�d|d<|S|dur�zt
j�||��dt
j�}Wnty�d
}Ynw|r�d|��|d<|S|dur�t
j�|�r�d
|d<d|�d�|d<|S|s�|�r tjj��r�d|d<|S|�rtd|�}|dk�rd|�d�|d<|Snd}|�rtd|�}|dk�rd|�d�|d<|Snd}nd}}|�r3|�s3|�dg��d�ztd||t�d}Wnt�y]}zd|d<|j|d<|WYd}~Sd}~ww|�sod|d<d |�d!�|d<|St|�} | j}!t
j�| j| j��	t
j�}"|!�r�|!��tjv�r�d"�|!|"g�}"d#}!|"�p�| j}#|!tjjj v}$|$�r�t
j�!t
j�"|"��}t
j�
|��s�d$�#tjj$�%|��|d<|Sd%}%|�s�tjj�&|#�}|du�r�d&�#d'�|%��|d<|Sz|��}Wn
t'�y�Ynw||%v�rd(�#|d'�|%��|d<|S|du�rt(|t)��st)|�}d}&|�r9|d)k�r9z
t*t+�,d*|��-d+��}&Wnt't.f�y8Ynw|d,k�r�|�rf|du�rOt/�0d-|�d
}n	|�sXd.|d<|S|�rfd/tv�rfd0|d<|S|�r�|du�rwt/�0d1|�d}n|�r�|�dg��d2�n	|�r�d3|d<|S|d4k�r�d5tv�r�d6|d<|Sd7}'|�r�||'v�r�d8�#d'�|'��|d<|S|�r�|d
u�r�d9}nt(|tt*f��s�zt*|�}Wnt1�y�d:|d<|YSw|�rztd;|||td<�}(Wnt�y}z
|j|d<|WYd}~Sd}~wwi}(|�ro|$�r|})ntd=|td>�})|)�r)t2|)�}*t/�3d?|*|(�nt|�}+tjj�t4d@dAt|+j|+j�},t2|,�}*|(�ri|*�ri|*dB|(dBk�rht4dC�rVdnd
|d<dD�#tjj$�%|��|d<|Snt/�3dE|�|$�ru|})n�t4dC�r�d|d<dF�#tjj$�%|��|d<|SdGt5v�r�dH�#tjj$�%|��|d<|Szt5dG||||t|dI�}-Wn)t�y�}zdJ�#tjj$�%|�|�}.t/�6|.�|.|d<|WYd}~Sd}~wwt/�3dK|-�|-d�r�td=|td>�})n
t/�3dLtjj$�%|��|-St2|)�}*|�r	|�r	|�s	t7|)�|d,k�r?|�s?t/�3dM|�ztdN|)dt|dO�}/Wn
t�y-Ynw|/�r?dP�#tjj$�%|��|d<|SztdQ|)||	|&dd
|dR�}0Wn_t�y�}zRd}0g}1|�sc|1�dS�|�sq|�sl|�rq|1�dT�|j}.|1�r�|.dU7}.|d)k�r�|.dV7}.n|.dW7}.|.dX�#|�7}.|1D]
}2|.dY|2��7}.�q�|.|d<|WYd}~Sd}~ww|�r�|0du�r�t8|0dZ�d+k�s�t8|0d[�dk�r�d\�#|t
j�|d]�|�|d<|S|�r�|
�r�d^|d<d|d<|S|}3d}4zt
j�|�}5Wnt1�yd}5Ynw|5�s�|0du�rBz
t
�9|�d}3W�nrt:�yA}z!|j;t;j<k�r&d
}3nd_�#||�|d<|WYd}~SWYd}~�nId}~wwg}6|0d`t=j>f|0dadbdc�f|0ddt=j?ffD]b\}7}8|7D]Z}9tjj�||9�}:zt
�9|:�	t
j��j@};|8|;��s~|6�|9�W�q_t:�y�}z,|j;t;j<k�r�d
}3d
}4n|j;t;jAk�r�t)|�|d<|WYd}~SWYd}~�q_d}~ww�qY|6�r�dUde�dfdg�|6D��}<dh�#|�|d<t4dC�r�|�r�|0du�r�d|d<|ddi�#|<�7<|St4dC�r|
�r|0du�rd|d<|ddj7<|S|�r|0du�s�|
�s#|ddk�#|<�7<|Sg}1|6D]F}9t
j�||9�}:ztjj�B|:�	t
j��|dl�dmg��|:�d
}3W�q't:�ym}z|j;t;j<k�rb|1�t)|��WYd}~�q'd}~ww|1�r�dn}.|1D]
}2|.dY|2��7}.�qu|.|d<|S|3�s�|�r�|*du�r�tC|)|*��s�d
}3d
}=nd}=d}>|3�
r|$�r�|�r�|�s�tdo||(dB�|d<|d�s�dp�#tjj$�%|�|(dB�|d<|St4dC�r�d|d<dq�#tjj$�%|�|�|d<|�r�|0du�r�|ddr7<tD||=|4�|S|
�ra|0du�rag}1t/�3ds|�ztjj�B|�	t
j��|dl�dmdt|�du��Wn!t:�yE}z|j;t;j<k�r;|1�t)|��WYd}~nd}~ww|1�radv�#|�}.|1D]
}2|.dY|2��7}.�qP|.|d<|S|�r�|0du�r�g}1t/�3dw|�|0dZ|0d[D]J}9t
j�||9�}:zt/�3dx|:�tjj�B|:�	t
j��|dl�dmg��|:�W�qyt:�y�}z|j;t;j<k�r�|1�t)|��WYd}~�qyd}~ww|1�r�dy}.|1D]
}2|.dY|2��7}.�q�|.|d<|St
j�E|��s�t5dz||d
d{�d
}>t/�3d||)|��z�|d,k�rA|�r/ztd/|)|f|||d}�|��}?W�n�ttFf�y.}z|j|d<|WYd}~WSd}~wwtd~|)|f||||d�|��}?�n�|d4k�rtztd5|)|fd�|i|��}?W�n�ttFf�ys}z|j|d<|WYd}~WSd}~ww|du�	r6z3tGtH�I|)d����}@|@�JtjjK�L|��|@�M�}?|�r�|?d|�}?Wd�n	1�s�wYW�n?tHjN�	y5tjj�Od���	rtd�d�d�|)gdd
d��dk�	rt/�3d��d�}Atd�|A�#tP�Q|)��|d
d��}B|Bd�dk�r�|>�r�tR|�d|d<|B|dl<|YWStS��	r|Bd�}?n-|Bd�}?n(|>�	rtR|�d|d<d�|d<|YWS|>�	r&tR|�d|d<d�|d<|YWSYn�wtjj�Od)��	sEd�|d<|WSd�dg�tP�T|�D�}Cd)g}Dd�}Eg}FtU|C�D]0\}G}H|H�d���	rk|F�|H��	qZ|Gdk�	rw|F�|H��	qZ|H}I|I�Vd�d�}I|I�Vd�d�}I|E|I}E�	qZtWd���d�k�	r�d�|E}E|D�|E�|D�X|F�|D�Xd�|)g�td�|D|dd��}B|Bd�dk�	r�d|d<|B|dl<|WStS��	r�|Bd��Y�}?|�	r�|?d|�}?n|Bd��Y�}?|�	r�|?d|�}?|?�	s�d�}?Wnt�
y}z
|j|d<|WYd}~Sd}~wwg}Jg}K|�
s|�rQ|�
r,t
j�E|��
r$|g}Lg}Mg}Nng}L|g}Mg}Nn|0du�
r=|0dZ}L|0d[}M|0d�}Ng}O|�
rG|O�d��|�
rO|O�d��d'�|O�}Pd�d��d�|fd�|ffD�}Q|LD]h}Rt
j�||R�}:t
j�E|:��
st4dC�
s}|J�|:��
qct/�3d�|P|Rt4dC�
r�d�nd�t5dz|:|||Od��}St/�3d�|S�|S�Zdl��
r�d
|dld�<z
|Sd�
s�|K�|:�W�
qct[t1f�
y�t/�\d�|S|R�Y�
qcw|M|ND]�}Tt
j�||T�}:zt
�9|:�}UWn*t:�y
}zt4dC�
s�|j;t;j<k�
r�|J�|:�|K�|:�WYd}~�
q�d}~ww|dk�r||Uj]k�s!|dk�rO||Uj^k�rOt4dC�r.d
|dld�<�
q�zt
�_|:||�d
|dld�<W�
q�t:�yN|K�|T�Y�
q�w�
q�|3�r�t8|?�dk�r�|>�re|g|dld�<|?|dld�<d��#tjj$�%|�|�|d<tD||=|4�|dd��#|�7<d
|d<n=d|d<d��#tjj$�%|��|d<n,d
|d<|5�r�|�d�|d<nd�|d<t4dC�r�|dl�Zd���r�d|d<|dd�7<|J�r�|�s�d|d<|dd�7<|JD]}V|ddY|V��7<�q�|K�rd|d<|dd�7<|KD]}V|ddY|V��7<�q�|$�s:|�rt/�3d�|)�|St/�3d�|)�t5d�|td>�}-|-d�s:|�dg��|-d�|S)�aaW
    .. versionadded:: 2014.1.0
    .. versionchanged:: 2016.11.0,3005
        This state has been rewritten. Some arguments are new to this release
        and will not be available in the 2016.3 release cycle (and earlier).
        Additionally, the **ZIP Archive Handling** section below applies
        specifically to the 2016.11.0 release (and newer).

    Ensure that an archive is extracted to a specific directory.

    .. important::
        **Changes for 2016.11.0**

        In earlier releases, this state would rely on the ``if_missing``
        argument to determine whether or not the archive needed to be
        extracted. When this argument was not passed, then the state would just
        assume ``if_missing`` is the same as the ``name`` argument (i.e. the
        parent directory into which the archive would be extracted).

        This caused a number of annoyances. One such annoyance was the need to
        know beforehand a path that would result from the extraction of the
        archive, and setting ``if_missing`` to that directory, like so:

        .. code-block:: yaml

            extract_myapp:
              archive.extracted:
                - name: /var/www
                - source: salt://apps/src/myapp-16.2.4.tar.gz
                - user: www
                - group: www
                - if_missing: /var/www/myapp-16.2.4

        If ``/var/www`` already existed, this would effectively make
        ``if_missing`` a required argument, just to get Salt to extract the
        archive.

        Some users worked around this by adding the top-level directory of the
        archive to the end of the ``name`` argument, and then used ``--strip``
        or ``--strip-components`` to remove that top-level dir when extracting:

        .. code-block:: yaml

            extract_myapp:
              archive.extracted:
                - name: /var/www/myapp-16.2.4
                - source: salt://apps/src/myapp-16.2.4.tar.gz
                - user: www
                - group: www

        With the rewrite for 2016.11.0, these workarounds are no longer
        necessary. ``if_missing`` is still a supported argument, but it is no
        longer required. The equivalent SLS in 2016.11.0 would be:

        .. code-block:: yaml

            extract_myapp:
              archive.extracted:
                - name: /var/www
                - source: salt://apps/src/myapp-16.2.4.tar.gz
                - user: www
                - group: www

        Salt now uses a function called :py:func:`archive.list
        <salt.modules.archive.list>` to get a list of files/directories in the
        archive. Using this information, the state can now check the minion to
        see if any paths are missing, and know whether or not the archive needs
        to be extracted. This makes the ``if_missing`` argument unnecessary in
        most use cases.

    .. important::
        **ZIP Archive Handling**

        *Note: this information applies to 2016.11.0 and later.*

        Salt has two different functions for extracting ZIP archives:

        1. :py:func:`archive.unzip <salt.modules.archive.unzip>`, which uses
           Python's zipfile_ module to extract ZIP files.
        2. :py:func:`archive.cmd_unzip <salt.modules.archive.cmd_unzip>`, which
           uses the ``unzip`` CLI command to extract ZIP files.

        Salt will prefer the use of :py:func:`archive.cmd_unzip
        <salt.modules.archive.cmd_unzip>` when CLI options are specified (via
        the ``options`` argument), and will otherwise prefer the
        :py:func:`archive.unzip <salt.modules.archive.unzip>` function. Use
        of :py:func:`archive.cmd_unzip <salt.modules.archive.cmd_unzip>` can be
        forced however by setting the ``use_cmd_unzip`` argument to ``True``.
        By contrast, setting this argument to ``False`` will force usage of
        :py:func:`archive.unzip <salt.modules.archive.unzip>`. For example:

        .. code-block:: yaml

            /var/www:
              archive.extracted:
                - source: salt://foo/bar/myapp.zip
                - use_cmd_unzip: True

        When ``use_cmd_unzip`` is omitted, Salt will choose which extraction
        function to use based on the source archive and the arguments passed to
        the state. When in doubt, simply do not set this argument; it is
        provided as a means of overriding the logic Salt uses to decide which
        function to use.

        There are differences in the features available in both extraction
        functions. These are detailed below.

        - *Command-line options* (only supported by :py:func:`archive.cmd_unzip
          <salt.modules.archive.cmd_unzip>`) - When the ``options`` argument is
          used, :py:func:`archive.cmd_unzip <salt.modules.archive.cmd_unzip>`
          is the only function that can be used to extract the archive.
          Therefore, if ``use_cmd_unzip`` is specified and set to ``False``,
          and ``options`` is also set, the state will not proceed.

        - *Permissions* - Due to an `upstream bug in Python`_, permissions are
          not preserved when the zipfile_ module is used to extract an archive.
          As of the 2016.11.0 release, :py:func:`archive.unzip
          <salt.modules.archive.unzip>` (as well as this state) has an
          ``extract_perms`` argument which, when set to ``True`` (the default),
          will attempt to match the permissions of the extracted
          files/directories to those defined within the archive. To disable
          this functionality and have the state not attempt to preserve the
          permissions from the ZIP archive, set ``extract_perms`` to ``False``:

          .. code-block:: yaml

              /var/www:
                archive.extracted:
                  - source: salt://foo/bar/myapp.zip
                  - extract_perms: False

    .. _`upstream bug in Python`: https://bugs.python.org/issue15795

    name
        Directory into which the archive should be extracted

    source
        Archive to be extracted

        .. note::
            This argument uses the same syntax as its counterpart in the
            :py:func:`file.managed <salt.states.file.managed>` state.

    source_hash
        Hash of source file, or file with list of hash-to-file mappings

        .. note::
            This argument uses the same syntax as its counterpart in the
            :py:func:`file.managed <salt.states.file.managed>` state.

        .. versionchanged:: 2016.11.0
            If this argument specifies the hash itself, instead of a URI to a
            file containing hashes, the hash type can now be omitted and Salt
            will determine the hash type based on the length of the hash. For
            example, both of the below states are now valid, while before only
            the second one would be:

        .. code-block:: yaml

            foo_app:
              archive.extracted:
                - name: /var/www
                - source: https://mydomain.tld/foo.tar.gz
                - source_hash: 3360db35e682f1c5f9c58aa307de16d41361618c

            bar_app:
              archive.extracted:
                - name: /var/www
                - source: https://mydomain.tld/bar.tar.gz
                - source_hash: sha1=5edb7d584b82ddcbf76e311601f5d4442974aaa5

    source_hash_name
        When ``source_hash`` refers to a hash file, Salt will try to find the
        correct hash by matching the filename part of the ``source`` URI. When
        managing a file with a ``source`` of ``salt://files/foo.tar.gz``, then
        the following line in a hash file would match:

        .. code-block:: text

            acbd18db4cc2f85cedef654fccc4a4d8    foo.tar.gz

        This line would also match:

        .. code-block:: text

            acbd18db4cc2f85cedef654fccc4a4d8    ./dir1/foo.tar.gz

        However, sometimes a hash file will include multiple similar paths:

        .. code-block:: text

            37b51d194a7513e45b56f6524f2d51f2    ./dir1/foo.txt
            acbd18db4cc2f85cedef654fccc4a4d8    ./dir2/foo.txt
            73feffa4b7f6bb68e44cf984c85f6e88    ./dir3/foo.txt

        In cases like this, Salt may match the incorrect hash. This argument
        can be used to tell Salt which filename to match, to ensure that the
        correct hash is identified. For example:

        .. code-block:: yaml

            /var/www:
              archive.extracted:
                - source: https://mydomain.tld/dir2/foo.tar.gz
                - source_hash: https://mydomain.tld/hashes
                - source_hash_name: ./dir2/foo.tar.gz

        .. note::
            This argument must contain the full filename entry from the
            checksum file, as this argument is meant to disambiguate matches
            for multiple files that have the same basename. So, in the
            example above, simply using ``foo.txt`` would not match.

        .. versionadded:: 2016.11.0

    source_hash_update : False
        Set this to ``True`` if archive should be extracted if source_hash has
        changed and there is a difference between the archive and the local files.
        This would extract regardless of the ``if_missing`` parameter.

        Note that this is only checked if the ``source`` value has not changed.
        If it has (e.g. to increment a version number in the path) then the
        archive will not be extracted even if the hash has changed.

        .. note::
            Setting this to ``True`` along with ``keep_source`` set to ``False``
            will result the ``source`` re-download to do a archive file list check.
            If it's not desirable please consider the ``skip_files_list_verify``
            argument.

        .. versionadded:: 2016.3.0

    skip_files_list_verify : False
        Set this to ``True`` if archive should be extracted if ``source_hash`` has
        changed but only checksums of the archive will be checked to determine if
        the extraction is required.

        It will try to find a local cache of the ``source`` and check its hash against
        the ``source_hash``. If there is no local cache available, for example if you
        set the ``keep_source`` to ``False``,  it will try to find a cached source hash
        file in the Minion archives cache directory.

        .. note::
            The current limitation of this logic is that you have to set
            minions ``hash_type`` config option to the same one that you're going
            to pass via ``source_hash`` argument.

        .. warning::
            With this argument set to ``True`` Salt will only check for the ``source_hash``
            against the local hash of the ``sourse``. So if you, for example, remove extracted
            files without clearing the Salt Minion cache next time you execute the state Salt
            will not notice that extraction is required if the hashes are still match.

        .. versionadded:: 3000

    skip_verify : False
        If ``True``, hash verification of remote file sources (``http://``,
        ``https://``, ``ftp://``) will be skipped, and the ``source_hash``
        argument will be ignored.

        .. versionadded:: 2016.3.4

    keep_source : True
        For ``source`` archives not local to the minion (i.e. from the Salt
        fileserver or a remote source such as ``http(s)`` or ``ftp``), Salt
        will need to download the archive to the minion cache before they can
        be extracted. To remove the downloaded archive after extraction, set
        this argument to ``False``.

        .. versionadded:: 2017.7.3

    keep : True
        Same as ``keep_source``, kept for backward-compatibility.

        .. note::
            If both ``keep_source`` and ``keep`` are used, ``keep`` will be
            ignored.

    password
        **For ZIP archives only.** Password used for extraction.

        .. versionadded:: 2016.3.0
        .. versionchanged:: 2016.11.0
          The newly-added :py:func:`archive.is_encrypted
          <salt.modules.archive.is_encrypted>` function will be used to
          determine if the archive is password-protected. If it is, then the
          ``password`` argument will be required for the state to proceed.

    options
        **For tar and zip archives only.**  This option can be used to specify
        a string of additional arguments to pass to the tar/zip command.

        If this argument is not used, then the minion will attempt to use
        Python's native tarfile_/zipfile_ support to extract it. For zip
        archives, this argument is mostly used to overwrite existing files with
        ``o``.

        Using this argument means that the ``tar`` or ``unzip`` command will be
        used, which is less platform-independent, so keep this in mind when
        using this option; the CLI options must be valid options for the
        ``tar``/``unzip`` implementation on the minion's OS.

        .. versionadded:: 2016.11.0
        .. versionchanged:: 2015.8.11,2016.3.2
            XZ-compressed tar archives no longer require ``J`` to manually be
            set in the ``options``, they are now detected automatically and
            decompressed using the xz_ CLI command and extracted using ``tar
            xvf``. This is a more platform-independent solution, as not all tar
            implementations support the ``J`` argument for extracting archives.

        .. note::
            For tar archives, main operators like ``-x``, ``--extract``,
            ``--get``, ``-c`` and ``-f``/``--file`` should *not* be used here.

    list_options
        **For tar archives only.** This state uses :py:func:`archive.list
        <salt.modules.archive.list_>` to discover the contents of the source
        archive so that it knows which file paths should exist on the minion if
        the archive has already been extracted. For the vast majority of tar
        archives, :py:func:`archive.list <salt.modules.archive.list_>` "just
        works". Archives compressed using gzip, bzip2, and xz/lzma (with the
        help of the xz_ CLI command) are supported automatically. However, for
        archives compressed using other compression types, CLI options must be
        passed to :py:func:`archive.list <salt.modules.archive.list_>`.

        This argument will be passed through to :py:func:`archive.list
        <salt.modules.archive.list_>` as its ``options`` argument, to allow it
        to successfully list the archive's contents. For the vast majority of
        archives, this argument should not need to be used, it should only be
        needed in cases where the state fails with an error stating that the
        archive's contents could not be listed.

        .. versionadded:: 2016.11.0

    force : False
        If a path that should be occupied by a file in the extracted result is
        instead a directory (or vice-versa), the state will fail. Set this
        argument to ``True`` to force these paths to be removed in order to
        allow the archive to be extracted.

        .. warning::
            Use this option *very* carefully.

        .. versionadded:: 2016.11.0

    overwrite : False
        Set this to ``True`` to force the archive to be extracted. This is
        useful for cases where the filenames/directories have not changed, but
        the content of the files have.

        .. versionadded:: 2016.11.1

    clean : False
        Set this to ``True`` to remove any top-level files and recursively
        remove any top-level directory paths before extracting.

        .. note::
            Files will only be cleaned first if extracting the archive is
            deemed necessary, either by paths missing on the minion, or if
            ``overwrite`` is set to ``True``.

        .. versionadded:: 2016.11.1

    clean_parent : False
        If ``True``, and the archive is extracted, delete the parent
        directory (i.e. the directory into which the archive is extracted), and
        then re-create that directory before extracting. Note that ``clean``
        and ``clean_parent`` are mutually exclusive.

        .. versionadded:: 3000

    user
        The user to own each extracted file. Not available on Windows.

        .. versionadded:: 2015.8.0
        .. versionchanged:: 2016.3.0
            When used in combination with ``if_missing``, ownership will only
            be enforced if ``if_missing`` is a directory.
        .. versionchanged:: 2016.11.0
            Ownership will be enforced only on the file/directory paths found
            by running :py:func:`archive.list <salt.modules.archive.list_>` on
            the source archive. An alternative root directory on which to
            enforce ownership can be specified using the
            ``enforce_ownership_on`` argument.

    group
        The group to own each extracted file. Not available on Windows.

        .. versionadded:: 2015.8.0
        .. versionchanged:: 2016.3.0
            When used in combination with ``if_missing``, ownership will only
            be enforced if ``if_missing`` is a directory.
        .. versionchanged:: 2016.11.0
            Ownership will be enforced only on the file/directory paths found
            by running :py:func:`archive.list <salt.modules.archive.list_>` on
            the source archive. An alternative root directory on which to
            enforce ownership can be specified using the
            ``enforce_ownership_on`` argument.

    if_missing
        If specified, this path will be checked, and if it exists then the
        archive will not be extracted. This path can be either a directory or a
        file, so this option can also be used to check for a semaphore file and
        conditionally skip extraction.

        .. versionchanged:: 2016.3.0
            When used in combination with either ``user`` or ``group``,
            ownership will only be enforced when ``if_missing`` is a directory.
        .. versionchanged:: 2016.11.0
            Ownership enforcement is no longer tied to this argument, it is
            simply checked for existence and extraction will be skipped if
            if is present.

    trim_output : False
        Useful for archives with many files in them. This can either be set to
        ``True`` (in which case only the first 100 files extracted will be
        in the state results), or it can be set to an integer for more exact
        control over the max number of files to include in the state results.

        .. versionadded:: 2016.3.0

    use_cmd_unzip : False
        Set to ``True`` for zip files to force usage of the
        :py:func:`archive.cmd_unzip <salt.modules.archive.cmd_unzip>` function
        to extract.

        .. versionadded:: 2016.11.0

    extract_perms : True
        **For ZIP archives only.** When using :py:func:`archive.unzip
        <salt.modules.archive.unzip>` to extract ZIP archives, Salt works
        around an `upstream bug in Python`_ to set the permissions on extracted
        files/directories to match those encoded into the ZIP archive. Set this
        argument to ``False`` to skip this workaround.

        .. versionadded:: 2016.11.0

    enforce_toplevel : True
        This option will enforce a single directory at the top level of the
        source archive, to prevent extracting a 'tar-bomb'. Set this argument
        to ``False`` to allow archives with files (or multiple directories) at
        the top level to be extracted.

        .. versionadded:: 2016.11.0

    enforce_ownership_on
        When ``user`` or ``group`` is specified, Salt will default to enforcing
        permissions on the file/directory paths detected by running
        :py:func:`archive.list <salt.modules.archive.list_>` on the source
        archive. Use this argument to specify an alternate directory on which
        ownership should be enforced.

        .. note::
            This path must be within the path specified by the ``name``
            argument.

        .. versionadded:: 2016.11.0

    archive_format
        One of ``tar``, ``zip``, or ``rar``.

        .. versionchanged:: 2016.11.0
            If omitted, the archive format will be guessed based on the value
            of the ``source`` argument. If the minion is running a release
            older than 2016.11.0, this option is required.

    .. _tarfile: https://docs.python.org/2/library/tarfile.html
    .. _zipfile: https://docs.python.org/2/library/zipfile.html
    .. _xz: http://tukaani.org/xz/

    use_etag
        If ``True``, remote http/https file sources will attempt to use the
        ETag header to determine if the remote file needs to be downloaded.
        This provides a lightweight mechanism for promptly refreshing files
        changed on a web server without requiring a full hash comparison via
        the ``source_hash`` parameter.

        .. versionadded:: 3005

    **Examples**

    1. tar with lmza (i.e. xz) compression:

       .. code-block:: yaml

           graylog2-server:
             archive.extracted:
               - name: /opt/
               - source: https://github.com/downloads/Graylog2/graylog2-server/graylog2-server-0.9.6p1.tar.lzma
               - source_hash: md5=499ae16dcae71eeb7c3a30c75ea7a1a6

    2. tar archive with flag for verbose output, and enforcement of user/group
       ownership:

       .. code-block:: yaml

           graylog2-server:
             archive.extracted:
               - name: /opt/
               - source: https://github.com/downloads/Graylog2/graylog2-server/graylog2-server-0.9.6p1.tar.gz
               - source_hash: md5=499ae16dcae71eeb7c3a30c75ea7a1a6
               - options: v
               - user: foo
               - group: foo

    3. tar archive, with ``source_hash_update`` set to ``True`` to prevent
       state from attempting extraction unless the ``source_hash`` differs
       from the previous time the archive was extracted:

       .. code-block:: yaml

           graylog2-server:
             archive.extracted:
               - name: /opt/
               - source: https://github.com/downloads/Graylog2/graylog2-server/graylog2-server-0.9.6p1.tar.lzma
               - source_hash: md5=499ae16dcae71eeb7c3a30c75ea7a1a6
               - source_hash_update: True
    F�)rU�result�changesrzIOnly one of "skip_files_list_verify" and "skip_verify" can be set to Truer�keep_sourceZkeep�warningsz`Both 'keep_source' and 'keep' were used. Since these both do the same thing, 'keep' was ignored.Tz is not an absolute pathz0Name of the directory path needs to be specifiedz exists and is not a directoryz.Value for 'if_missing' is not an absolute pathz8Value for 'enforce_ownership_on' is not an absolute pathNz..z0Value for 'enforce_ownership_on' must be within rXzPath z existsz:User/group ownership cannot be enforced on Windows minionszfile.user_to_uidzUser z does not existrzfile.group_to_gidzGroup zVThe 'source_hash_update' argument is ignored when 'source_hash' is not also specified.zfile.source_listrzInvalid source "�"r �filezSource file '{}' does not exist)rP�rar�zipz�Could not guess archive_format from the value of the 'source' argument. Please set this archive_format to one of the following: {}z, z�Invalid archive_format '{}'. Either set it to a supported value ({}) or remove this argument and the archive format will be guessed based on file extension.rPz/--strip(?:-components)?(?:\s+|=)["']?(\d+)["']?r2r_zfPresence of CLI options in archive.extracted state for '%s' implies that use_cmd_unzip is set to True.z�'use_cmd_unzip' cannot be set to False if CLI options are being specified (via the 'options' argument). Either remove 'use_cmd_unzip', or set it to True.zarchive.cmd_unzipzParchive.cmd_unzip function not available, unzip might not be installed on minionzfPresence of a password in archive.extracted state for '%s' implies that use_cmd_unzip is set to False.z�Using a password in combination with setting 'use_cmd_unzip' to True is considered insecure. It is recommended to remove the 'use_cmd_unzip' argument (or set it to False) and allow Salt to extract the archive using Python's built-in ZIP file support.z:The 'password' argument is only supported for zip archivesr^z
archive.unrarzParchive.unrar function not available, rar/unrar might not be installed on minion)rPr_zPThe 'options' argument is only compatible with the following archive formats: {}�dz?Invalid value for trim_output, must be True/False or an integerzfile.get_source_sum)�source�source_hash�source_hash_name�saltenvzcp.is_cached)rdz9Existing source sum is: "%s". Expected source sum is "%s"rZextrn_filesr�testz�Archive {} existing source sum is the same as the expected one and skip_files_list_verify argument was set to True. Extraction is not neededz0There is no cached source %s available on minionzYArchive {} would be cached (if necessary) and checked to discover if extraction is neededzfile.cachedz3Unable to cache {}, file.cached state not available)rbrc�skip_verifyrd�use_etagzFailed to cache {}: {}zfile.cached: %szfailed to download %sz.Checking %s to see if it is password-protectedzarchive.is_encrypted)�cleanrdrgzdArchive {} is password-protected, but no password was specified. Please set the 'password' argument.zarchive.list)�archive_format�options�strip_componentsrh�verbosergz'if_missing' must be setzCOwnership cannot be managed without setting 'enforce_ownership_on'.z

a_If the source archive is a tar archive compressed using a compression type not natively supported by the tar command, then setting the 'list_options' argument may allow the contents to be listed. Otherwise, if Salt is unable to determine the files/directories in the archive, the following workaround(s) would need to be used for this state to proceedz@The following workarounds must be used for this state to proceedz3 (assuming the source file is a valid {} archive):
z
- Ztop_level_dirsZtop_level_filesaArchive does not have a single top-level directory. To allow this archive to be extracted, set 'enforce_toplevel' to False. To avoid a '{}-bomb' it may also be advisable to set a top-level directory by adding it to the 'name' value (for example, setting 'name' to {} instead of {}).Zsome_dirz9Only one of 'clean' and 'clean_parent' can be set to Truez9Failed to check for existence of if_missing path ({}): {}�dirsr=cSst�|�ot�|�S�N)�stat�S_ISLNK�S_ISDIR)r6rrr�<lambda>�szextracted.<locals>.<lambda>Zlinksr1cSsg|]}d|���qS)z- rr4rrrr7�szextracted.<locals>.<listcomp>z~The below paths (relative to {}) exist, but are the incorrect type (file instead of directory, symlink instead of file, etc.).zr Since the 'clean' option is enabled, the destination paths would be cleared and the archive would be extracted.{}z� Since the 'clean_parent' option is enabled, the destination parent directory would be removed first and then re-created and the archive would be extractedzm To proceed with extraction, set 'force' to True. Note that this will remove these paths before extracting.{}rYZremovedz�One or more paths existed by were the incorrect type (i.e. file instead of directory or vice-versa), but could not be removed. The following errors were observed:
zfile.check_hashz,{} does not match the desired source_hash {}z#Archive {} would be extracted to {}z$, after cleaning destination path(s)z5Removing directory %s due to clean_parent set to Truez
Directory z$ was removed prior to the extractionzGUnable to remove the directory {}. The following errors were observed:
z%Cleaning archive paths from within %szRemoving %szLOne or more paths could not be cleaned. The following errors were observed:
zfile.directory)�userr;zExtracting %s to %s)rj�trim_output�passwordz
archive.unzip)rjrtru�
extract_permsrtr0�xzzcmd.retcodez-t)rQZignore_retcodezeTar file is XZ-compressed, attempting decompression and extraction using XZ Utils and the tar commandz(xz --decompress --stdout {0} | tar xvf -zcmd.run_all)�cwdrQ�retcode�stderr�stdoutaFailed to read from tar archive using Python's native tar file support. If archive is compressed using something other than gzip or bzip2, the 'options' argument may be required to pass the correct options to the tar command in order to extract the archive.z`Failed to read from tar archive. If it is XZ-compressed, install xz-utils to attempt extraction.z>tar command not available, it might not be installed on minioncSsg|]}|dvr|�qS))�vz-vz	--verboserr4rrrr7�s
�Zxv�-r6�frZopenbsdz-fzno tar output so farZtop_level_linksrs�groupcSsi|]	\}}|r||�qSrr)r5r6�yrrr�
<dictcomp>)szextracted.<locals>.<dictcomp>z;Enforcing %s ownership on %s using a file.directory state%sz (dry-run only))rsr�recursezfile.directory: %szupdated ownershipz2Bad state return %s for file.directory state on %sZdirectories_createdZextracted_filesz{} extracted to {}z*. Output was trimmed to {} number of lineszNo files were extracted from {}z(All files in archive are already presentz>. Ownership would be updated on one or more files/directories.zR

While trying to enforce user/group ownership, the following paths were missing:
zl

While trying to enforce user/group ownership, Salt was unable to change ownership on the following paths:
zKeeping cached source file %szCleaning cached source file %szfile.not_cachedr)`rr�argsZclean_kwargs�
setdefaultr?�bool�popr
r*r�sepr�isfiler"r)�	Exception�exists�platformZ
is_windowsrRZ__env__r�strerrorr�schemer!�netloc�lower�string�ascii_lowercaser=ZLOCAL_PROTOS�realpath�
expanduserrE�urlZredact_http_basic_authZguess_archive_typer	�
isinstancer(�intr#�searchrr'r+�info�	TypeErrorrMr,rZ
__states__�	exceptionrL�len�lstatrArBrCrorqrp�st_mode�ENOTDIRZrm_rfrOrr:rr�tarfile�open�
extractallZstringutilsZto_str�getnames�	ReadError�which�shlex�quoterVrSr@�	enumerate�replaceZ
__grains__�extend�
splitlinesr<�KeyErrorrF�st_uid�st_gid�lchown)WrUrarbrcZsource_hash_updateZskip_files_list_verifyrfrurjZlist_options�forceZ	overwriterhZclean_parentrsrZ
if_missingrtZ
use_cmd_unziprvZenforce_toplevelZenforce_ownership_onrirg�kwargsrrZZnot_rel�uid�gidZsource_matchr-Zurlparsed_sourceZurlparsed_schemeZurlparsed_pathZsource_hash_basenameZsource_is_localZvalid_archive_formatsrkZsupports_optionsrHrNZexisting_cached_source_sum�parsedZexpected_cached_pathrX�msgZ
encrypted_zip�contents�errors�errorZextraction_neededrZif_missing_path_existsZincorrect_type�	path_list�funcr�	full_pathZ	path_modeZincorrect_pathsrZcreated_destdirr=rP�cmd�resultsZtar_optsZtar_cmdZ
tar_shortoptsZtar_longopts�position�optZ
append_optZenforce_missingZenforce_failedZenforce_dirsZ
enforce_filesZ
enforce_linksr�Zrecurse_strZ
owner_changesr9Z
dir_result�filenameZ	file_stat�itemrrr�	extracted�s4%��

���
�
�
��
�����
��
�����

��
�
����

��
��
�
���	����
��
��
��
��
�
����
�	
�
�
����$�
$��
�


����
��

���������
�����
��
�
�
�������
���
����
�
	���
��
������
�


�
	�
��@��


���
��





���

�
��


��
����

�
����	�
r�rn)NNFFFNNNFFFFNNNFNTTNNF)$�__doc__rB�loggingrr#r�ror�r��
contextlibr�urllib.parserZsalt.utils.argsrZsalt.utils.filesZsalt.utils.hashutilsZsalt.utils.pathZsalt.utils.platformZsalt.utils.urlZsalt.exceptionsrr�	getLogger�__name__r+r
rrr/rLrMrOrSrVr�rrrr�<module>sf

&
�