ext2/3 is hard, use find as backup

This commit is contained in:
Darryl Nixon 2023-07-16 12:20:57 -07:00
parent 155b3e2006
commit 068d47703a
2 changed files with 36 additions and 3 deletions

View file

@ -35,6 +35,7 @@ class ShredDir(AsyncObject):
self.mount_points.add(self.mount_point)
self.fs_handler = await mount_to_fs_handler(self.mount_point)
self.byte_size = sum(item.byte_size for item in self.contents)
self.inode = path.stat().st_ino
async def _get_contents(self) -> List:
contents = []
@ -63,13 +64,30 @@ class ShredDir(AsyncObject):
def __hash__(self) -> int:
return hash(self.absolute_path)
async def delete_hardlinks_by_inode(self) -> None:
logger.info(f"Finding and deleting hardlinks inside {self.absolute_path.name}")
for path in self.contents:
await path.delete_hardlinks_by_inode()
proc = await asyncio.create_subprocess_exec("find", str(self.mount_point), "-inum", self.get_inode(), "-delete")
stdout, _ = await proc.communicate()
if proc.returncode != 0:
err = f"Unable to delete hardlinks for {self.absolute_path.name}"
logger.error(err)
raise RuntimeError(err)
logger.info(f"Deleted hardlink for {self.absolute_path.name}")
class ShredFile(AsyncObject):
"""Class for tracking each file to be shredded."""
async def __init__(self, path: Path) -> None:
self.absolute_path = path.resolve().absolute()
self.byte_size = path.stat().st_size
stat = path.stat()
self.byte_size = stat.st_size
self.inode = stat.st_ino
self.mount_point = find_mount(self.absolute_path)
self.fs_handler = await mount_to_fs_handler(self.mount_point)
self.hardlinks = None
@ -145,6 +163,17 @@ class ShredFile(AsyncObject):
def __hash__(self) -> int:
return hash(self.absolute_path)
async def delete_hardlinks_by_inode(self) -> None:
proc = await asyncio.create_subprocess_exec("find", str(self.mount_point), "-inum", self.get_inode(), "-delete")
stdout, _ = await proc.communicate()
if proc.returncode != 0:
err = f"Unable to delete hardlinks for {self.absolute_path.name}"
logger.error(err)
raise RuntimeError(err)
logger.info("Deleted hardlink for {self.absolute_path.name}")
async def get_all_hardlinks(paths: Set[Union[ShredFile, ShredDir]]) -> None:
for path in paths:

View file

@ -12,7 +12,6 @@ async def main(job: argparse.Namespace) -> bool:
It is called by the CLI and builds a job queue based on the arguments passed.
"""
new_paths = set()
logger.info(f"job type is {type(job)}")
# Expand all directories and files, and collect mount point information
for path in job.paths:
@ -28,9 +27,14 @@ async def main(job: argparse.Namespace) -> bool:
else:
raise TypeError(f"Not a file or directory: {path}")
# Get hardlinks to subsequently unlink for all files
# Try to delete hardlinks based on the filesystem type
job.paths = await get_all_hardlinks(new_paths)
# Just in case, use "find" to delete any remaining hardlinks
# from the mount point
for path in job.paths:
await path.delete_hardlinks_by_inode()
# Shred all physical files including hardlinks
for path in job.paths:
if isinstance(path, ShredFile):