[file_utils] unln: option --dereference

This commit is contained in:
Matteo Cypriani 2013-04-09 20:04:00 -04:00
parent 4533f40d58
commit 199ebd9d68
1 changed files with 28 additions and 8 deletions

View File

@ -27,9 +27,6 @@
#
# This script separates file names given as arguments from their respective
# inodes by doing the equivalent of (cp -p file tmp && mv tmp file).
#
# TODO:
# - Option to follow symlinks
import argparse
@ -64,12 +61,28 @@ def quote(string):
""" Quotes a string. """
return "``{}´´".format(string)
def dereference(path):
"""Follows a symbolic link recursively.
Returns the final target's path, that may or may not exist in the file
system. If 'path' is not a symbolic link, it is returned as is.
"""
if not os.path.islink(path):
return path
dereferenced = os.readlink(path)
# If it's a relative link we must convert it to an absolute path
if not os.path.isabs(dereferenced):
dereferenced = os.path.join(os.path.dirname(path), dereferenced)
return dereference(dereferenced)
# Parse command-line arguments
arg_parser = argparse.ArgumentParser(
description="Separate a file name from its other hard links",
epilog="For more information about this program, see the README file \
provided with the distribution.")
arg_parser.add_argument("-L", "--dereference", action="store_true",
help="follow symbolic links")
arg_parser.add_argument("-s", "--sync", action="store_true",
help="sync files after a copy to be more fail safe \
(requires Python 3.3 or above, will be ignored with lower versions)")
@ -87,16 +100,23 @@ error_filenames = []
# Main loop
for filename in options.filenames:
# Is a symbolic link?
if os.path.islink(filename):
if not options.dereference:
warn(quote(filename), "is a symbolic link, ignoring.")
continue
# Dereference the link
dereferenced = dereference(filename)
verbose("Dereferenced {} -> {}.".format(
quote(filename), quote(dereferenced)))
filename = dereferenced
# Exists?
if not os.path.exists(filename):
warn(quote(filename), "does not exist, ignoring.")
continue
# Is a symbolic link?
if os.path.islink(filename):
warn(quote(filename), "is a symbolic link, ignoring.")
continue
# Is a regular file?
if not os.path.isfile(filename):
warn(quote(filename), "is not a regular file, ignoring.")