[file_utils] unln: handle exceptions, list errors
This commit is contained in:
parent
7879f04f15
commit
eb37c52e8c
|
@ -25,6 +25,11 @@ equivalent of (cp -p file tmp && mv tmp file). Checks are done in order
|
|||
to work only on regular files which have more than one hard link, so the
|
||||
minimal amount of copies are done.
|
||||
|
||||
A summary of the file names on which error were raised is displayed at
|
||||
the end of the execution. Note that if a file is under a directory which
|
||||
is not executable (i.e. the program can't cd in), it will be considered
|
||||
as inexistant and ignored, and its name won't be displayed.
|
||||
|
||||
/!\ Warning: the copy function used is shutil.copy2(), which tries to
|
||||
preserve all the metadata it can, but as of Python 3.3 it is not
|
||||
guaranteed that extended attributes will be preserved. See the
|
||||
|
|
|
@ -29,10 +29,8 @@
|
|||
# inodes by doing the equivalent of (cp -p file tmp && mv tmp file).
|
||||
#
|
||||
# TODO:
|
||||
# - Handle exceptions (permission denied on copy, etc.)
|
||||
# - Option verbose
|
||||
# - Option to follow symlinks
|
||||
# - Summarise skipped regular files with more than one link
|
||||
|
||||
|
||||
import sys
|
||||
|
@ -90,6 +88,10 @@ usage_string = "Usage:\n\t{} <file1> [file2 ...]".format(progname)
|
|||
# Error codes
|
||||
ERR_BAD_USAGE = 1
|
||||
|
||||
# List of filenames that were supposed to be worked on but could not because of
|
||||
# an error
|
||||
error_filenames = []
|
||||
|
||||
|
||||
# Check command-line arguments
|
||||
if len(sys.argv) < 2:
|
||||
|
@ -123,17 +125,31 @@ for filename in sys.argv[1:]:
|
|||
|
||||
# Reserve a temporary file name
|
||||
dirname = os.path.dirname(filename)
|
||||
handle, tmpfilename = tempfile.mkstemp(
|
||||
prefix="{}-".format(filename),
|
||||
suffix="-{}.tmp".format(progname),
|
||||
dir=dirname)
|
||||
try:
|
||||
handle, tmpfilename = tempfile.mkstemp(
|
||||
prefix="{}-".format(filename),
|
||||
suffix="-{}.tmp".format(progname),
|
||||
dir=dirname)
|
||||
except:
|
||||
warn("Cannot create temporary file to copy {}:".format(quote(filename)),
|
||||
sys.exc_info()[1])
|
||||
error_filenames.append(filename)
|
||||
continue
|
||||
os.close(handle) # we just need a temporary file name
|
||||
|
||||
# Copy the original file to the temporary file
|
||||
verbose("Copying to temporary file", quote(tmpfilename), end="... ")
|
||||
shutil.copy2(filename, tmpfilename) # cp -p
|
||||
try:
|
||||
shutil.copy2(filename, tmpfilename) # cp -p
|
||||
except:
|
||||
warn("Cannot copy {} to {}:".format(quote(filename), quote(tmpfilename)),
|
||||
sys.exc_info()[1])
|
||||
error_filenames.append(filename)
|
||||
# Delete temporary file
|
||||
os.remove(tmpfilename)
|
||||
continue
|
||||
|
||||
# Try to sync if we are running Python >= 3.3
|
||||
# Sync (if we are running Python >= 3.3)
|
||||
if sys.version_info.minor >= 3:
|
||||
verbose("Syncing", end="... ")
|
||||
os.sync()
|
||||
|
@ -141,4 +157,18 @@ for filename in sys.argv[1:]:
|
|||
# Rename the temporary file with the original file name
|
||||
verbose("Moving back {} to {}...".format(
|
||||
quote(tmpfilename), quote(filename)))
|
||||
os.rename(tmpfilename, filename)
|
||||
try:
|
||||
os.rename(tmpfilename, filename)
|
||||
except:
|
||||
warn("Cannot move {} to {}:".format(
|
||||
quote(tmpfilename), quote(filename)),
|
||||
sys.exc_info()[1], "Deleting temporary file", quote(tmpfilename))
|
||||
error_filenames.append(filename)
|
||||
# Delete temporary file
|
||||
os.remove(tmpfilename)
|
||||
|
||||
|
||||
# Display the list of files in error
|
||||
if len(error_filenames):
|
||||
warn("The following regular files still have more than one hard link:")
|
||||
print(*error_filenames, sep="\n", file=sys.stderr)
|
||||
|
|
Loading…
Reference in New Issue