Skip to content

Getting the lnk target; did I miss something? #33

@suedunham

Description

@suedunham

My problem is solved; my script is run; my Windows lnks are converted. There is no fire to put out, but I'm a bit ashamed of how I did it, and I wonder if there is a better way than I found to get the whole target value of the lnk_file object.

Mine is a simple use case. I only have links to other files and directories on my local filesystem, and there are no commands or flags to open them with,

I first tried combining the string_data.working_directory() and string_data.relative_path() methods. This has some wrinkles with . or .. terms in the middle, but pathlib.Path().resolve() could tidy those up. More fatal were at least one case where the lnk pointed to a directory; the relative_path() was simply "./DirName" and the working_directory() was None.

Then I tried an approach based on lnk_file.targets.primary_name(). This got me most of the way there, except that I could not get the initial root slash or the Windows volume letter at the beginning of the path. Those two elements in the targets don't have primary_name() methods.

I stuck with that though, and hacked up something in the except clause leaning on _raw_target.

    def get_target(self) -> Path | None:
        """Get target from Windows lnk via targets.

        The constituents of the lnk_file.targets property do not have
        a property_name method in the case of the root_folder and the
        my_computer types. This means that the initial / and the drive
        letter are not accessible cleanly this way, so we descend into
        hackery then.
        """

        def get_primary_name(target):
            """Get primary name of target."""
            try:
                return target.primary_name()
            except AttributeError:
                # Return slash if target is root_folder.
                # Yes, my_computer starts with a slash too. It is needed
                # here as well. When Path is done with it, it's three.
                return_value = '/'
                # my_computer._raw_target starts with "/D:", etc.
                if chr(target._raw_target[0]) == '/':
                    return_value = target._raw_target[:3].decode(UTF8)
                return return_value

        target = None
        if self.lnk.targets is not None:
            target = Path('/'.join(get_primary_name(target)
                                   for target in self.lnk.targets))
        return target

That self.lnk part is set thusly:

    def read_windows_lnk(self) -> LnkParse3.lnk_file:
        """Read Windows lnk file with LnkParse3."""
        with open(self.windows_file, "rb") as win:
            return LnkParse3.lnk_file(win)

So, yeah, yuck. Still, that was the best I could find. Is there something better that I'm not seeing?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions