Skip to content

Commit 8f5fb99

Browse files
committed
glusterfs/ghetto-purge.py: handle symlinks
I had some issues with symlinks and finally decided to handle them instead of skipping. Now I am sure that we can just remove them w- ithout worrying that os.remove() will remove the link target. Also, we don't need to try to get the xattrs because symlinks don't have them, and we don't need to remove the .glusterfs hard link because there isn't one.
1 parent 4dbda72 commit 8f5fb99

File tree

1 file changed

+23
-15
lines changed

1 file changed

+23
-15
lines changed

glusterfs/ghetto-purge.py

+23-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# SPDX-License-Identifier: GPL-3.0-only
44
#
5-
# ghetto-purge.py v0.0.2
5+
# ghetto-purge.py v0.0.3
66
#
77
# Read files and directories from an input file, one per line, and attempt to
88
# remove them from the GlusterFS brick along with their .glusterfs links. This
@@ -32,18 +32,12 @@ def main():
3232
# Note that we have to remove \n from the line
3333
path_to_analyze = f"{brick_path}/{line.strip()}"
3434

35-
# To be safe I check if this is a symlink first, because we only
36-
# want to process entries named in our input file and not follow them
37-
# all over the file system. I am not sure how to deal with these yet...
38-
# pathlib's exists() will follow symlinks and return False if they are
39-
# broken, for example (note that pathlib's is_dir() is different than
40-
# os.is_dir(), and the latter has follow_symlinks(false)).
41-
if Path(f"{path_to_analyze}").is_symlink():
42-
print(f"Skipping symlink: {path_to_analyze}")
43-
44-
continue
45-
46-
if Path(f"{path_to_analyze}").exists():
35+
# Pathlib's Path.exists() will return false if the path is a broken
36+
# symlink so we need to check for the symlink case here as well.
37+
if (
38+
Path(f"{path_to_analyze}").exists()
39+
or Path(f"{path_to_analyze}").is_symlink()
40+
):
4741
if Path(f"{path_to_analyze}").is_dir():
4842
if args.debug:
4943
print(f"Descend into: {path_to_analyze}")
@@ -122,8 +116,22 @@ def process_file(brick_path, path):
122116
if args.debug:
123117
print(f"Processing file: {path}")
124118

125-
# Get a string representation of the xattr from hex bytes
126-
file_gfid = os.getxattr(path, "trusted.gfid").hex()
119+
# Try to get a string representation of the xattr from hex bytes. We need
120+
# to try/except because os.getxattr() returns FileNotFoundError when the
121+
# file is a broken symlink, and OSError when the link goes somewhere that
122+
# does not have GlusterFS metadata. This happens in the case of eg Python
123+
# virtual environments in user's home directories and it is not a problem
124+
# to remove it and return without trying to remove a .glusterfs hard link.
125+
try:
126+
file_gfid = os.getxattr(path, "trusted.gfid").hex()
127+
except (FileNotFoundError, OSError):
128+
if not args.dry_run:
129+
os.remove(path)
130+
131+
print(f'{"(DRY RUN) " if args.dry_run else ""}Removed symlink: {path}')
132+
133+
return
134+
127135
file_glusterfs_path = dot_glusterfs_path(brick_path, file_gfid)
128136

129137
if Path(path).exists():

0 commit comments

Comments
 (0)