Ensure that the parent directory containing this path is available.

    Args:

        path (str):
            The full path to the directory.

            .. note::

                The path must end with a trailing slash otherwise the
                directory(s) will be created up to the parent directory. For
                example if path is ``C:\\temp\\test``, then it would be treated
                as ``C:\\temp\\`` but if the path ends with a trailing slash
                like ``C:\\temp\\test\\``, then it would be treated as
                ``C:\\temp\\test\\``.

        owner (str):
            The owner of the directory. If not passed, it will be the account
            that created the directory, likely SYSTEM.

        grant_perms (dict):
            A dictionary containing the user/group and the basic permissions to
            grant, ie: ``{'user': {'perms': 'basic_permission'}}``. You can also
            set the ``applies_to`` setting here. The default is
            ``this_folder_subfolders_files``. Specify another ``applies_to``
            setting like this:

            .. code-block:: yaml

                {'user': {'perms': 'full_control', 'applies_to': 'this_folder'}}

            To set advanced permissions use a list for the ``perms`` parameter, ie:

            .. code-block:: yaml

                {'user': {'perms': ['read_attributes', 'read_ea'], 'applies_to': 'this_folder'}}

        deny_perms (dict):
            A dictionary containing the user/group and permissions to deny along
            with the ``applies_to`` setting. Use the same format used for the
            ``grant_perms`` parameter. Remember, deny permissions supersede
            grant permissions.

        inheritance (bool):
            If True the object will inherit permissions from the parent, if
            False, inheritance will be disabled. Inheritance setting will not
            apply to parent directories if they must be created.

        reset (bool):
            If ``True`` the existing DACL will be cleared and replaced with the
            settings defined in this function. If ``False``, new entries will be
            appended to the existing DACL. Default is ``False``.

            .. versionadded:: 2018.3.0

    Returns:
        bool: True if successful

    Raises:
        CommandExecutionError: If unsuccessful

    CLI Example:

    .. code-block:: bash

        # To grant the 'Users' group 'read & execute' permissions.
        salt '*' file.makedirs C:\\Temp\\ Administrators "{'Users': {'perms': 'read_execute'}}"

        # Locally using salt call
        salt-call file.makedirs C:\\Temp\\ Administrators "{'Users': {'perms': 'read_execute', 'applies_to': 'this_folder_only'}}"

        # Specify advanced attributes with a list
        salt '*' file.makedirs C:\\Temp\\ Administrators "{'jsnuffy': {'perms': ['read_attributes', 'read_ea'], 'applies_to': 'this_folder_only'}}"

def makedirs_(path,
              owner=None,
              grant_perms=None,
              deny_perms=None,
              inheritance=True,
              reset=False):
    '''
    Ensure that the parent directory containing this path is available.

    Args:

        path (str):
            The full path to the directory.

            .. note::

                The path must end with a trailing slash otherwise the
                directory(s) will be created up to the parent directory. For
                example if path is ``C:\\temp\\test``, then it would be treated
                as ``C:\\temp\\`` but if the path ends with a trailing slash
                like ``C:\\temp\\test\\``, then it would be treated as
                ``C:\\temp\\test\\``.

        owner (str):
            The owner of the directory. If not passed, it will be the account
            that created the directory, likely SYSTEM.

        grant_perms (dict):
            A dictionary containing the user/group and the basic permissions to
            grant, ie: ``{'user': {'perms': 'basic_permission'}}``. You can also
            set the ``applies_to`` setting here. The default is
            ``this_folder_subfolders_files``. Specify another ``applies_to``
            setting like this:

            .. code-block:: yaml

                {'user': {'perms': 'full_control', 'applies_to': 'this_folder'}}

            To set advanced permissions use a list for the ``perms`` parameter, ie:

            .. code-block:: yaml

                {'user': {'perms': ['read_attributes', 'read_ea'], 'applies_to': 'this_folder'}}

        deny_perms (dict):
            A dictionary containing the user/group and permissions to deny along
            with the ``applies_to`` setting. Use the same format used for the
            ``grant_perms`` parameter. Remember, deny permissions supersede
            grant permissions.

        inheritance (bool):
            If True the object will inherit permissions from the parent, if
            False, inheritance will be disabled. Inheritance setting will not
            apply to parent directories if they must be created.

        reset (bool):
            If ``True`` the existing DACL will be cleared and replaced with the
            settings defined in this function. If ``False``, new entries will be
            appended to the existing DACL. Default is ``False``.

            .. versionadded:: 2018.3.0

    Returns:
        bool: True if successful

    Raises:
        CommandExecutionError: If unsuccessful

    CLI Example:

    .. code-block:: bash

        # To grant the 'Users' group 'read & execute' permissions.
        salt '*' file.makedirs C:\\Temp\\ Administrators "{'Users': {'perms': 'read_execute'}}"

        # Locally using salt call
        salt-call file.makedirs C:\\Temp\\ Administrators "{'Users': {'perms': 'read_execute', 'applies_to': 'this_folder_only'}}"

        # Specify advanced attributes with a list
        salt '*' file.makedirs C:\\Temp\\ Administrators "{'jsnuffy': {'perms': ['read_attributes', 'read_ea'], 'applies_to': 'this_folder_only'}}"
    '''
    path = os.path.expanduser(path)

    # walk up the directory structure until we find the first existing
    # directory
    dirname = os.path.normpath(os.path.dirname(path))

    if os.path.isdir(dirname):
        # There's nothing for us to do
        msg = 'Directory \'{0}\' already exists'.format(dirname)
        log.debug(msg)
        return msg

    if os.path.exists(dirname):
        msg = 'The path \'{0}\' already exists and is not a directory'.format(
            dirname
        )
        log.debug(msg)
        return msg

    directories_to_create = []
    while True:
        if os.path.isdir(dirname):
            break

        directories_to_create.append(dirname)
        current_dirname = dirname
        dirname = os.path.dirname(dirname)

        if current_dirname == dirname:
            raise SaltInvocationError(
                'Recursive creation for path \'{0}\' would result in an '
                'infinite loop. Please use an absolute path.'.format(dirname)
            )

    # create parent directories from the topmost to the most deeply nested one
    directories_to_create.reverse()
    for directory_to_create in directories_to_create:
        # all directories have the user, group and mode set!!
        log.debug('Creating directory: %s', directory_to_create)
        mkdir(
            path=directory_to_create,
            owner=owner,
            grant_perms=grant_perms,
            deny_perms=deny_perms,
            inheritance=inheritance,
            reset=reset)

    return True