Source code for llnl.util.symlink

# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import errno
import os
import shutil
import tempfile
from os.path import exists, join
from sys import platform as _platform

from llnl.util import lang

is_windows = _platform == 'win32'

if is_windows:
    from win32file import CreateHardLink

# '_win32' functions based on
def _win32_junction(path, link):
    # junctions require absolute paths
    if not os.path.isabs(link):
        link = os.path.abspath(link)

    # os.symlink will fail if link exists, emulate the behavior here
    if exists(link):
        raise OSError(errno.EEXIST, 'File  exists: %s -> %s' % (link, path))

    if not os.path.isabs(path):
        parent = os.path.join(link, os.pardir)
        path = os.path.join(parent, path)
        path = os.path.abspath(path)

    CreateHardLink(link, path)

def _win32_can_symlink():
    tempdir = tempfile.mkdtemp()

    dpath = join(tempdir, 'dpath')
    fpath = join(tempdir, 'fpath.txt')

    dlink = join(tempdir, 'dlink')
    flink = join(tempdir, 'flink.txt')

    import llnl.util.filesystem as fs

        os.symlink(dpath, dlink)
        can_symlink_directories = os.path.islink(dlink)
    except OSError:
        can_symlink_directories = False

        os.symlink(fpath, flink)
        can_symlink_files = os.path.islink(flink)
    except OSError:
        can_symlink_files = False

    # Cleanup the test directory

    return can_symlink_directories and can_symlink_files

def _win32_is_junction(path):
    Determines if a path is a win32 junction
    if os.path.islink(path):
        return False

    if is_windows:
        import ctypes.wintypes

        GetFileAttributes = ctypes.windll.kernel32.GetFileAttributesW
        GetFileAttributes.argtypes = (ctypes.wintypes.LPWSTR,)
        GetFileAttributes.restype = ctypes.wintypes.DWORD


        res = GetFileAttributes(path)
        return res != INVALID_FILE_ATTRIBUTES and \
            bool(res & FILE_ATTRIBUTE_REPARSE_POINT)

    return False