aboutsummaryrefslogtreecommitdiff
path: root/s2slib.py
diff options
context:
space:
mode:
Diffstat (limited to 's2slib.py')
-rw-r--r--s2slib.py145
1 files changed, 145 insertions, 0 deletions
diff --git a/s2slib.py b/s2slib.py
new file mode 100644
index 0000000..409157e
--- /dev/null
+++ b/s2slib.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python3
+# File: s2slib.py
+# Locations:
+# /mnt/public/Support/Programs/shortcuts/
+# https://gitlab.com/bgstack15/s2s
+# Author: bgstack15@gmail.com
+# SPDX-License-Identifier: GPL-3.0
+# Startdate: 2021-02-11 20:00
+# Title: Shortcut To Symlink library
+# Purpose: Convert .lnk files to POSIX symlinks within a single filesystem
+# History:
+# Usage:
+# see s2s.py
+# Reference:
+# https://stackoverflow.com/questions/25146960/python-convert-back-slashes-to-forward-slashes/25147093#25147093
+# https://github.com/libyal/liblnk/blob/main/documentation/Windows%20Shortcut%20File%20(LNK)%20format.asciidoc#file_attribute_flags
+# Improve:
+# Handle absolute paths when relative paths are absent?
+# Add a force=True option to overwrite existing symlink that points to something else
+# Dependencies:
+# devuan-req: python3-liblnk
+import pylnk # python3-liblnk
+import os, re, posixpath
+from sys import stderr
+
+debuglevel = 8
+
+# Functions
+def eprint(*args, **kwargs):
+ print(*args, file=stderr, **kwargs)
+
+# to benefit from caching outside of the function, maybe
+lnkregex = re.compile(".*\.lnk$")
+
+def replace_one_symlink(
+ lnkfile
+ , delete = False
+ , debuglevel = debuglevel
+ , dryrun = False
+ ):
+
+ thislnk = pylnk.file()
+ basename = os.path.basename(lnkfile)
+ #workdir = os.path.dirname(lnkfile) # not used
+
+ # Exit if this is not a .lnk file
+ if not re.match(lnkregex,basename):
+ eprint(f"Cannot operate on {lnkfile}")
+ return -1
+
+ thislnk.open(lnkfile)
+
+ # Get relative path
+ # we are really expecting a relative path for every single one, because we are dealing with Windows shortcuts to files all on the same network share.
+ # Although I suppose a symlink could work if you could somehow map the expected SMB path to a POSIX filesystem
+ try:
+ relative_path = thislnk.relative_path
+ except:
+ eprint(f"No relative path for {lnkfile}, and abs path not yet implemented.")
+ return -1
+ # and make it a Unix-style path
+ relative_path = posixpath.join(*thislnk.relative_path.split('\\'))
+
+ # Not used for anything, but here if we want it.
+ linktype = "file"
+ if thislnk.file_attribute_flags & 0x10:
+ linktype = "dir"
+
+ # Get preferred name, and strip any " - Shortcut"
+ pn = os.path.splitext(lnkfile)[:-1][0] # remove the .lnk part, but preserve any other dots
+ symlink_path = re.sub(' - Shortcut$', "",pn)
+
+ # take action
+ if debuglevel >= 5:
+ eprint(f"Want symlink \"{symlink_path}\" ({linktype})--> \"{relative_path}\"")
+
+ ready_to_delete = False
+
+ if os.path.exists(symlink_path):
+ current_source = ""
+ try:
+ current_source = os.path.realpath(symlink_path)
+ except:
+ eprint(f"Unable to determine current_source for {symlink_path} which already exists.")
+ normpath = os.path.normpath(os.path.join(os.path.dirname(symlink_path),relative_path))
+ #eprint(f"Please ensure {current_source} matches {relative_path} which is {normpath}")
+ if normpath != current_source:
+ # The existing symlink points to something else. Not sure how to proceed.
+ # probably need to add a --force option to overwrite
+ eprint(f"Warning: Existing symlink {symlink_path} points to {current_source} and not {normpath} as requested")
+ else:
+ # it exists and already points to what we want it to point to.
+ if debuglevel >= 3:
+ eprint(f"symlink {symlink_path} already points to {current_source} which is {normpath}")
+ ready_to_delete = True
+ else:
+ # symlink does not exist, so make it!
+ if debuglevel >= 1:
+ eprint(f"ln -s {relative_path} {symlink_path}")
+ if not dryrun:
+ try:
+ os.symlink(relative_path,symlink_path)
+ ready_to_delete = True
+ except Exception as e:
+ eprint(e)
+
+ if delete:
+ if ready_to_delete:
+ if debuglevel >= 2:
+ eprint(f"rm {lnkfile}")
+ if not dryrun:
+ os.remove(lnkfile)
+ return 0
+
+def list_all_child_lnk_files(indir):
+ mylist = []
+ for root, dirs, files in os.walk(indir):
+ for name in files:
+ if ".lnk" in name:
+ mylist.append(os.path.join(root,name))
+ #eprint(os.path.join(root,name))
+ return mylist
+
+def replace_all_symlinks(
+ indir
+ , delete = False
+ , debuglevel = debuglevel
+ , dryrun = False
+ ):
+ result = 0
+
+ # get list of all lnk files
+ mylist = list_all_child_lnk_files(indir)
+ for lnkfile in mylist:
+ replace_one_symlink(
+ lnkfile
+ , delete = delete
+ , debuglevel = debuglevel
+ , dryrun = dryrun
+ )
+
+ return result
+
+if __name__ == "__main__":
+ print("running the main loop")
bgstack15