Esempio n. 1
0
def migrate_folder(source, target):
    try:
        create_link = False
        if not os.path.isdir(source):
            logger.error(f"[{source}] does not exist or is not a directory.")
            return

        source_backup = f"{source}.sav"
        # seems Python does not support dictory junction well (os.path.islink is always False)
        # use isdir AND !exists to guess dictory junction condition
        if os.path.exists(source):
            # not a junction, rename source first before copying
            logger.info(f"Renaming {source} to {source_backup}...")
            os.rename(source, source_backup)
            create_link = True

        # copy folder content only if target not created yet
        if not os.path.exists(target):
            logger.info(f"Copying content from {source_backup} to {target}...")
            shutil.copytree(source_backup, target, copy_function=shutil.copy)

        if create_link:
            logger.info(f"Creating link from {source} to {source_backup}...")
            #win32api.CreateSymbolicLink(source, target)
            _winapi.CreateJunction(target, source)

    except Exception:
        logger.error("Failed to migrate from {source} to {target}.",
                     exc_info=True)
Esempio n. 2
0
def SymlinkAction(target, source, env):
    target = target if is_List(target) else [target]
    source = source if is_List(source) else [source]

    if len(target) != 1 or len(source) != 1:
        raise UserError("Symlink only takes a single target and source")

    abs_src = os.path.abspath(str(source[0]))
    abs_trg = os.path.abspath(str(target[0]))

    if not os.path.isdir(abs_src):
        raise UserError(
            "Only folder symlink are allowed due to Windows limitation")

    try:
        os.unlink(abs_trg)
    except Exception:
        pass

    if env["HOST_OS"] == "win32":
        try:
            import _winapi

            _winapi.CreateJunction(abs_src, abs_trg)
        except Exception as e:
            raise UserError(
                f"Can't do a NTFS junction as symlink fallback ({abs_src} -> {abs_trg})"
            ) from e

    else:
        try:
            os.symlink(abs_src, abs_trg)
        except Exception as e:
            raise UserError(
                f"Can't create symlink ({abs_src} -> {abs_trg})") from e
Esempio n. 3
0
def make_directory_symlink(new_symlink_file_path: Path,
                           existing_dir: Path) -> Path:
    gflogging.log(
        f"symlink: from {str(new_symlink_file_path)} to {str(existing_dir)}")
    check(existing_dir.is_dir(),
          AssertionError(f"Not a directory: {existing_dir}"))
    file_mkdirs_parent(new_symlink_file_path)

    # symlink_to takes a path relative to the location of the new file (or an absolute path, but we avoid this).
    symlink_contents = os.path.relpath(str(existing_dir),
                                       start=str(new_symlink_file_path.parent))
    try:
        new_symlink_file_path.symlink_to(symlink_contents,
                                         target_is_directory=True)
    except OSError:
        if get_platform() != "Windows":
            raise
        # Retry using junctions under Windows.
        try:
            # noinspection PyUnresolvedReferences
            import _winapi  # pylint: disable=import-error,import-outside-toplevel;

            # Unlike symlink_to, CreateJunction takes a path relative to the current directory.
            _winapi.CreateJunction(str(existing_dir),
                                   str(new_symlink_file_path))
            return new_symlink_file_path
        except ModuleNotFoundError:
            pass
        raise

    return new_symlink_file_path
Esempio n. 4
0
def symlink(target, link):
    """os.symlink() but use a junction point on Windows."""
    if islink(link):
        unlink(link)
    if platform.system() == "Windows":
        _winapi.CreateJunction(target, link)
    else:
        os.symlink(target, link)  # pylint: disable=no-member
def _symlink_compat(conanfile, src, dst):
    """On Windows, symlinks require admin privileges, so we use a directory junction instead"""
    if conanfile.settings.os == "Windows":
        import _winapi

        _winapi.CreateJunction(str(src), str(dst))
    else:
        os.symlink(src, dst)
Esempio n. 6
0
def make_link(point_from, point_to):
    if os.path.exists(point_from):
        print('Already linked:', point_from, '<--->', point_to)
        return
    if platform.system() == 'Windows':
        import _winapi
        _winapi.CreateJunction(point_to, point_from)
    else:
        os.symlink(point_to, point_from, True)
Esempio n. 7
0
def create_link_in_user_addon_directory(directory, link_path):
    if os.path.exists(link_path):
        os.remove(link_path)

    if sys.platform == "win32":
        import _winapi
        _winapi.CreateJunction(str(directory), str(link_path))
    else:
        os.symlink(str(directory), str(link_path), target_is_directory=True)
    def __init__(self, *args: str, **kwargs: str) -> None:
        # https://stackoverflow.com/a/19102520
        super().__init__(*args, **kwargs)

        self.windows = platform.system() == "Windows"
        if self.windows:
            self.exeext = ".exe"
        else:
            self.exeext = ""

        self.repository_root_dir = os.path.dirname(
            os.path.dirname(os.path.realpath(__file__)))
        self.user_scripts_dir = tempfile.mkdtemp()
        os.mkdir(os.path.join(self.user_scripts_dir, "addons"))
        addon_dir = os.path.join(self.user_scripts_dir, "addons",
                                 "io_scene_vrm_saturday06")
        if self.windows:
            import _winapi

            _winapi.CreateJunction(self.repository_root_dir, addon_dir)
        else:
            os.symlink(self.repository_root_dir, addon_dir)

        test_vrm_dir = os.environ.get(
            "BLENDER_VRM_TEST_VRM_DIR",
            os.path.join(self.repository_root_dir, "tests", "vrm"),
        )

        command = [self.find_blender_command(), "--version"]
        completed_process = subprocess.run(
            command,
            check=False,
            capture_output=True,
        )
        stdout_str = self.process_output_to_str(completed_process.stdout)
        stderr_str = self.process_output_to_str(completed_process.stderr)
        output = ("\n  ".join(command) + "\n===== stdout =====\n" +
                  stdout_str + "===== stderr =====\n" + stderr_str +
                  "==================")
        if completed_process.returncode != 0:
            raise Exception("Failed to execute command:\n" + output)
        major_minor = ".".join(
            stdout_str.splitlines()[0].split(" ")[1].split(".")[:2])

        self.test_temp_vrm_dir = os.path.join(test_vrm_dir, major_minor,
                                              "temp")
        self.test_in_vrm_dir = os.path.join(test_vrm_dir, "in")
        self.test_out_vrm_dir = os.path.join(test_vrm_dir, major_minor, "out")
        self.test_out2_vrm_dir = os.path.join(test_vrm_dir, major_minor,
                                              "out2")
        self.test_out3_vrm_dir = os.path.join(test_vrm_dir, major_minor,
                                              "out3")
        os.makedirs(self.test_temp_vrm_dir, exist_ok=True)
        os.makedirs(self.test_out_vrm_dir, exist_ok=True)
        os.makedirs(self.test_out2_vrm_dir, exist_ok=True)
        os.makedirs(self.test_out3_vrm_dir, exist_ok=True)
Esempio n. 9
0
def CreateJunctionFromPackage(source, destination):
    # Before creating a junction, clean the destionation path first
    if not PBTools.PurgeDestionation(destination):
        LogError(
            "Can't clean existing files in destionation junction point: " +
            destination)

    # Create junction from package contents to destination
    try:
        _winapi.CreateJunction(source, destination)
    except:
        LogError("Can't create junction point from " + source + " to " +
                 destination)
Esempio n. 10
0
def create_junction_from_package(source, destination):
    # Before creating a junction, clean the destionation path first
    if not PBTools.purge_destination(destination):
        log_error(
            "Can't clean existing files in destionation junction point: " +
            destination)

    # Create junction from package contents to destination
    try:
        _winapi.CreateJunction(source, destination)
    except:
        log_error("Can't create junction point from " + source + " to " +
                  destination)
Esempio n. 11
0
    def link(self):
        if self.config.create_dirs:
            if not os.path.exists(self.config.source_dir):
                os.makedirs(self.config.source_dir)
            if not os.path.exists(self.config.target_dir):
                os.makedirs(self.config.target_dir)

        self.game = self._get_game()
        if not self.game:
            sys.exit("no game to link")
        self.fix_paths()
        link_msg = "unlink" if self.config.reverse else "link"
        if not ask_yes_no(f'Are you sure you want to {link_msg} "{self.game}"',
                          default="n"):
            sys.exit("Exiting...")

        source_exists = os.path.exists(self.source_path)
        target_exists = os.path.exists(self.target_path)

        if not source_exists and not target_exists:
            sys.exit("Game folder does not exist in either location")
        if self.config.reverse:
            if source_exists and target_exists:
                # this remove directory will fail if not a link, unless the directory is empty
                # if the dir is empty, then it's not a big deal if the directory is accidentally deleted
                os.rmdir(self.source_path)
                CopyProgress.move(self.target_path, self.source_path)
                print(
                    f"Junction removed: {self.source_path} <== {self.target_path}"
                )
            elif not target_exists:
                sys.exit("Target does not exist")
            else:
                CopyProgress.move(self.target_path, self.source_path)
                print(
                    f"Junction removed: {self.source_path} <== {self.target_path}"
                )
        else:
            if source_exists and target_exists:
                sys.exit("Game folder exists in both locations")
            elif source_exists:
                if not os.path.isdir(self.source_path):
                    sys.exit(f"{self.source_path} is not a directory")
                CopyProgress.move(self.source_path, self.target_path)
            if not os.path.isdir(self.target_path):
                sys.exit(f"{self.target_path} is not a directory")
            _winapi.CreateJunction(self.target_path, self.source_path)
            print(
                f"Junction created: {self.source_path} ==> {self.target_path}")
Esempio n. 12
0
def symlink(target, link):
    """os.symlink() but use a junction point on Windows.
    """
    if islink(link):
        unlink(link)
    if platform.system() == "Windows":
        if sys.version_info[:2] < (3, 5):
            with open(os.devnull, "w") as nul:
                subprocess.check_call(["mklink", "/J", link, target],
                                      shell=True,
                                      stdout=nul)
        else:
            _winapi.CreateJunction(target, link)
    else:
        os.symlink(target, link)  # pylint: disable=no-member
Esempio n. 13
0
def create_link(src, link, is_dir):
    src_abs = os.path.abspath(src)
    link_abs = os.path.abspath(link)

    if os.path.exists(src_abs):
        if not os.path.exists(link_abs):
            if is_dir:
                if is_windows:
                    _winapi.CreateJunction(src_abs, link_abs)
                else:
                    os.symlink(src_abs, link_abs, True)
            else:
                os.link(src_abs, link_abs)
            log("Link created: {0} => {1}".format(src_abs, link_abs))
        else:
            log("Link already exists".format(link_abs))
    else:
        log("Invalid link source: {0}".format(src_abs))
Esempio n. 14
0
def symlink(src, dest, *args, **kwargs):
    if os.name == "nt":
        # Try to use junctions first.
        try:
            import _winapi
            _winapi.CreateJunction(src, dest)
            return
        except KeyboardInterrupt as e:
            raise e
        except Exception:
            # Ok, probably linking a file and not a directory
            # trying a regular symlink.
            try:
                os.symlink(src, dest, *args, **kwargs)
            except OSError as e:
                raise_error_if(
                    "symbolic link privilege not held" in str(e),
                    "Permission denied while attempting to create a symlink: {}\n"
                    "Please ensure the 'Create symbolic links' right is granted "
                    "to your user in the 'Local Security Policy'.", dest)
                raise e
    else:
        os.symlink(src, dest, *args, **kwargs)
Esempio n. 15
0
    def __init__(self, *args: str, **kwargs: str) -> None:
        # https://stackoverflow.com/a/19102520
        super().__init__(*args, **kwargs)

        self.windows = platform.system() == "Windows"
        if self.windows:
            self.exeext = ".exe"
        else:
            self.exeext = ""

        self.repository_root_dir = os.path.dirname(
            os.path.dirname(os.path.realpath(__file__)))
        self.user_scripts_dir = tempfile.mkdtemp()
        os.mkdir(os.path.join(self.user_scripts_dir, "addons"))
        addon_dir = os.path.join(self.user_scripts_dir, "addons",
                                 "io_scene_vrm_saturday06")
        if self.windows:
            import _winapi

            _winapi.CreateJunction(self.repository_root_dir, addon_dir)
        else:
            os.symlink(self.repository_root_dir, addon_dir)

        test_vrm_dir = os.environ.get(
            "BLENDER_VRM_TEST_VRM_DIR",
            os.path.join(self.repository_root_dir, "tests", "vrm"),
        )
        self.test_temp_vrm_dir = os.path.join(test_vrm_dir, "temp")
        self.test_in_vrm_dir = os.path.join(test_vrm_dir, "in")
        self.test_out_vrm_dir = os.path.join(test_vrm_dir, "out")
        self.test_out2_vrm_dir = os.path.join(test_vrm_dir, "out2")
        self.test_out3_vrm_dir = os.path.join(test_vrm_dir, "out3")
        os.makedirs(self.test_temp_vrm_dir, exist_ok=True)
        os.makedirs(self.test_out_vrm_dir, exist_ok=True)
        os.makedirs(self.test_out2_vrm_dir, exist_ok=True)
        os.makedirs(self.test_out3_vrm_dir, exist_ok=True)
Esempio n. 16
0
    def extract(self,
                path: Optional[Any] = None,
                targets: Optional[List[str]] = None,
                return_dict: bool = False) -> Optional[Dict[str, IO[Any]]]:
        target_junction = []  # type: List[pathlib.Path]
        target_sym = []  # type: List[pathlib.Path]
        target_files = []  # type: List[Tuple[pathlib.Path, Dict[str, Any]]]
        target_dirs = []  # type: List[pathlib.Path]
        if path is not None:
            if isinstance(path, str):
                path = pathlib.Path(path)
            try:
                if not path.exists():
                    path.mkdir(parents=True)
                else:
                    pass
            except OSError as e:
                if e.errno == errno.EEXIST and path.is_dir():
                    pass
                else:
                    raise e
        fnames = [
        ]  # type: List[str]  # check duplicated filename in one archive?
        for f in self.files:
            # TODO: sanity check
            # check whether f.filename with invalid characters: '../'
            if f.filename.startswith('../'):
                raise Bad7zFile
            # When archive has a multiple files which have same name.
            # To guarantee order of archive, multi-thread decompression becomes off.
            # Currently always overwrite by latter archives.
            # TODO: provide option to select overwrite or skip.
            if f.filename not in fnames:
                outname = f.filename
            else:
                i = 0
                while True:
                    outname = f.filename + '_%d' % i
                    if outname not in fnames:
                        break
            fnames.append(outname)
            if path is not None:
                outfilename = path.joinpath(outname)
            else:
                outfilename = pathlib.Path(outname)
            if targets is not None and f.filename not in targets:
                self.worker.register_filelike(f.id, None)
                continue
            if f.is_directory:
                if not outfilename.exists():
                    target_dirs.append(outfilename)
                    target_files.append((outfilename, f.file_properties()))
                else:
                    pass
            elif f.is_socket:
                pass
            elif f.is_symlink:
                target_sym.append(outfilename)
                self.worker.register_filelike(f.id, outfilename)
            elif f.is_junction:
                target_junction.append(outfilename)
                self.worker.register_filelike(f.id, outfilename)
            else:
                self.worker.register_filelike(f.id, outfilename)
                target_files.append((outfilename, f.file_properties()))
        for target_dir in sorted(target_dirs):
            try:
                target_dir.mkdir()
            except FileExistsError:
                if target_dir.is_dir():
                    # skip rare case
                    pass
                elif target_dir.is_file():
                    raise Exception(
                        "Directory name is existed as a normal file.")
                else:
                    raise Exception(
                        "Directory making fails on unknown condition.")

        self.worker.extract(self.fp,
                            parallel=(not self.password_protected
                                      and not self._filePassed),
                            return_dict=return_dict)
        if return_dict:
            return self.worker._dict

        # create symbolic links on target path as a working directory.
        # if path is None, work on current working directory.
        for t in target_sym:
            sym_dst = t.resolve()
            with sym_dst.open('rb') as b:
                sym_src = b.read().decode(
                    encoding='utf-8')  # symlink target name stored in utf-8
            sym_dst.unlink()  # unlink after close().
            sym_dst.symlink_to(pathlib.Path(sym_src))

        # create junction point only on windows platform
        if sys.platform.startswith('win'):
            for t in target_junction:
                junction_dst = t.resolve()
                with junction_dst.open('rb') as b:
                    junction_target = pathlib.Path(
                        b.read().decode(encoding='utf-8'))
                    junction_dst.unlink()
                    _winapi.CreateJunction(
                        junction_target,
                        str(junction_dst))  # type: ignore  # noqa

        for o, p in target_files:
            self._set_file_property(o, p)
        return None
Esempio n. 17
0
# Load Addon
########################################

addon_directory = bpy.utils.user_resource('SCRIPTS', "addons")
addon_folder_name = os.path.basename(external_addon_directory)
symlink_path = os.path.join(addon_directory, addon_folder_name)

if not os.path.exists(addon_directory):
    os.makedirs(addon_directory)
if os.path.exists(symlink_path):
    os.remove(symlink_path)

if sys.platform == "win32":
    import _winapi
    _winapi.CreateJunction(external_addon_directory, symlink_path)
else:
    os.symlink(external_addon_directory,
               symlink_path,
               target_is_directory=True)

bpy.ops.wm.addon_enable(module=addon_folder_name)

# Operators
########################################


class UpdateAddonOperator(bpy.types.Operator):
    bl_idname = "dev.update_addon"
    bl_label = "Update Addon"
Esempio n. 18
0
import os, sys, platform
from os.path import join, abspath
import pathlib

_, assetsDir, binAssetsDir = sys.argv
try:
    binDir = abspath(join(binAssetsDir, os.pardir))
    pathlib.Path(assetsDir).mkdir(parents=True, exist_ok=True)
    pathlib.Path(binDir).mkdir(parents=True, exist_ok=True)
    if platform.system() == 'Windows':
        import _winapi

        _winapi.CreateJunction(assetsDir, binAssetsDir)
    else:
        os.symlink(assetsDir, binAssetsDir)
    print(f"Created Symlink {binAssetsDir} -> {assetsDir}")
except FileExistsError:
    print(f"Symlink already exists: {binAssetsDir}")
except Exception as e:
    print(f"{sys.argv}\n{e}")
Esempio n. 19
0
    def extractall(self, path: Optional[Any] = 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.
        """
        target_junction = []  # type: List[Tuple[BinaryIO, str]]
        target_sym = []  # type: List[Tuple[BinaryIO, str]]
        target_files = []  # type: List[Tuple[pathlib.Path, Dict[str, Any]]]
        target_dirs = []  # type: List[pathlib.Path]
        self.reset()
        if path is not None:
            if isinstance(path, str):
                path = pathlib.Path(path)
            try:
                if not path.exists():
                    path.mkdir(parents=True)
                else:
                    pass
            except OSError as e:
                if e.errno == errno.EEXIST and path.is_dir():
                    pass
                else:
                    raise e

        multi_thread = self.header.main_streams is not None and self.header.main_streams.unpackinfo.numfolders > 1 and \
            self.header.main_streams.packinfo.numstreams == self.header.main_streams.unpackinfo.numfolders
        fnames = []  # type: List[str]
        for f in self.files:
            # TODO: sanity check
            # check whether f.filename with invalid characters: '../'
            if f.filename.startswith('../'):
                raise Bad7zFile
            # When archive has a multiple files which have same name.
            # To guarantee order of archive, multi-thread decompression becomes off.
            # Currently always overwrite by latter archives.
            # TODO: provide option to select overwrite or skip.
            if f.filename in fnames:
                multi_thread = False
            fnames.append(f.filename)
            if path is not None:
                outfilename = path.joinpath(f.filename)
            else:
                outfilename = pathlib.Path(f.filename)
            if f.is_directory:
                if not outfilename.exists():
                    target_dirs.append(outfilename)
                    target_files.append((outfilename, f.file_properties()))
                else:
                    pass
            elif f.is_socket:
                pass
            elif f.is_symlink:
                buf = io.BytesIO()
                pair = (buf, f.filename)
                target_sym.append(pair)
                self.worker.register_filelike(f.id, buf)
            elif f.is_junction:
                buf = io.BytesIO()
                pair = (buf, f.filename)
                target_junction.append(pair)
                self.worker.register_filelike(f.id, buf)
            else:
                self.worker.register_filelike(f.id, outfilename)
                target_files.append((outfilename, f.file_properties()))
        for target_dir in sorted(target_dirs):
            try:
                target_dir.mkdir()
            except FileExistsError:
                if target_dir.is_dir():
                    # skip rare case
                    pass
                elif target_dir.is_file():
                    raise Exception(
                        "Directory name is existed as a normal file.")
                else:
                    raise Exception(
                        "Directory making fails on unknown condition.")
        self.worker.extract(self.fp, multithread=multi_thread)
        for b, t in target_sym:
            b.seek(0)
            sym_src_org = b.read().decode(
                encoding='utf-8')  # symlink target name stored in utf-8
            dirname = os.path.dirname(t)
            if path:
                sym_src = path.joinpath(dirname, sym_src_org)
                sym_dst = path.joinpath(t)
            else:
                sym_src = pathlib.Path(dirname).joinpath(sym_src_org)
                sym_dst = pathlib.Path(t)
            sym_dst.symlink_to(sym_src)

        # create junction point only on windows platform
        if sys.platform.startswith('win'):
            for b, t in target_junction:
                b.seek(0)
                junction_target = pathlib.Path(
                    b.read().decode(encoding='utf-8'))
                dirname = os.path.dirname(t)
                if path:
                    junction_point = path.joinpath(t)
                else:
                    junction_point = pathlib.Path(dirname).joinpath(t)
                _winapi.CreateJunction(junction_target,
                                       junction_point)  # type: ignore  # noqa

        for o, p in target_files:
            self._set_file_property(o, p)
Esempio n. 20
0
if platform.system() == "Windows":
    import _winapi

    exeext = ".exe"
else:
    exeext = ""

blender_command = sys.argv[1] if len(sys.argv) > 1 else "blender" + exeext
repository_root_dir = os.path.dirname(
    os.path.dirname(os.path.realpath(__file__)))
user_scripts_dir = tempfile.mkdtemp()
os.mkdir(os.path.join(user_scripts_dir, "addons"))
addon_dir = os.path.join(user_scripts_dir, "addons", "io_scene_vrm_saturday06")
if platform.system() == "Windows":
    _winapi.CreateJunction(repository_root_dir, addon_dir)
else:
    os.symlink(repository_root_dir, addon_dir)

env = os.environ.copy()
env["BLENDER_USER_SCRIPTS"] = user_scripts_dir
subprocess.run(
    [
        blender_command,
        "-noaudio",  # sound system to None (less output on stdout)
        "--factory-startup",  # factory settings
        "--addons",
        "io_scene_vrm_saturday06",  # enable the addon
        "--python-exit-code",
        "1",
        "--background",
Esempio n. 21
0
    def _extract(
        self,
        path: Optional[Any] = None,
        targets: Optional[List[str]] = None,
        return_dict: bool = False,
        callback: Optional[ExtractCallback] = None
    ) -> Optional[Dict[str, IO[Any]]]:
        if callback is not None and not isinstance(callback, ExtractCallback):
            raise ValueError(
                'Callback specified is not a subclass of py7zr.callbacks.ExtractCallback class'
            )
        elif callback is not None:
            self.reporterd = threading.Thread(target=self.reporter,
                                              args=(callback, ),
                                              daemon=True)
            self.reporterd.start()
        target_junction = []  # type: List[pathlib.Path]
        target_sym = []  # type: List[pathlib.Path]
        target_files = []  # type: List[Tuple[pathlib.Path, Dict[str, Any]]]
        target_dirs = []  # type: List[pathlib.Path]
        if path is not None:
            if isinstance(path, str):
                path = pathlib.Path(path)
            try:
                if not path.exists():
                    path.mkdir(parents=True)
                else:
                    pass
            except OSError as e:
                if e.errno == errno.EEXIST and path.is_dir():
                    pass
                else:
                    raise e
        fnames = [
        ]  # type: List[str]  # check duplicated filename in one archive?
        self.q.put(('pre', None, None))
        for f in self.files:
            # TODO: sanity check
            # check whether f.filename with invalid characters: '../'
            if f.filename.startswith('../'):
                raise Bad7zFile
            # When archive has a multiple files which have same name
            # To guarantee order of archive, multi-thread decompression becomes off.
            # Currently always overwrite by latter archives.
            # TODO: provide option to select overwrite or skip.
            if f.filename not in fnames:
                outname = f.filename
            else:
                i = 0
                while True:
                    outname = f.filename + '_%d' % i
                    if outname not in fnames:
                        break
            fnames.append(outname)
            if path is not None:
                outfilename = path.joinpath(outname)
            else:
                outfilename = pathlib.Path(outname)
            if os.name == 'nt':
                if outfilename.is_absolute():
                    # hack for microsoft windows path length limit < 255
                    outfilename = pathlib.WindowsPath('\\\\?\\' +
                                                      str(outfilename))
            if targets is not None and f.filename not in targets:
                self.worker.register_filelike(f.id, None)
                continue
            if f.is_directory:
                if not outfilename.exists():
                    target_dirs.append(outfilename)
                    target_files.append((outfilename, f.file_properties()))
                else:
                    pass
            elif f.is_socket:
                pass
            elif return_dict:
                fname = outfilename.as_posix()
                _buf = io.BytesIO()
                self._dict[fname] = _buf
                self.worker.register_filelike(f.id, MemIO(_buf))
            elif f.is_symlink:
                target_sym.append(outfilename)
                try:
                    if outfilename.exists():
                        outfilename.unlink()
                except OSError as ose:
                    if ose.errno not in [errno.ENOENT]:
                        raise
                self.worker.register_filelike(f.id, outfilename)
            elif f.is_junction:
                target_junction.append(outfilename)
                self.worker.register_filelike(f.id, outfilename)
            else:
                self.worker.register_filelike(f.id, outfilename)
                target_files.append((outfilename, f.file_properties()))
        for target_dir in sorted(target_dirs):
            try:
                target_dir.mkdir()
            except FileExistsError:
                if target_dir.is_dir():
                    # skip rare case
                    pass
                elif target_dir.is_file():
                    raise Exception(
                        "Directory name is existed as a normal file.")
                else:
                    raise Exception(
                        "Directory making fails on unknown condition.")

        if callback is not None:
            self.worker.extract(self.fp,
                                parallel=(not self.password_protected
                                          and not self._filePassed),
                                q=self.q)
        else:
            self.worker.extract(self.fp,
                                parallel=(not self.password_protected
                                          and not self._filePassed))

        self.q.put(('post', None, None))
        if return_dict:
            return self._dict
        else:
            # create symbolic links on target path as a working directory.
            # if path is None, work on current working directory.
            for t in target_sym:
                sym_dst = t.resolve()
                with sym_dst.open('rb') as b:
                    sym_src = b.read().decode(
                        encoding='utf-8'
                    )  # symlink target name stored in utf-8
                sym_dst.unlink()  # unlink after close().
                sym_dst.symlink_to(pathlib.Path(sym_src))
            # create junction point only on windows platform
            if sys.platform.startswith('win'):
                for t in target_junction:
                    junction_dst = t.resolve()
                    with junction_dst.open('rb') as b:
                        junction_target = pathlib.Path(
                            b.read().decode(encoding='utf-8'))
                        junction_dst.unlink()
                        _winapi.CreateJunction(
                            junction_target,
                            str(junction_dst))  # type: ignore  # noqa
            # set file properties
            for o, p in target_files:
                self._set_file_property(o, p)
            return None