From e1c2703de51e749de85a8b2f4e8202fca462c286 Mon Sep 17 00:00:00 2001 From: Thomas Couchoud Date: Wed, 19 Jul 2023 21:10:37 +0200 Subject: [PATCH] Add file locking to prevent concurrency issues Added a file lock before performing a move or copy action in the FileDifference class to ensure that no concurrent modifications can happen during operation. With this, we can prevent potential data integrity issues when the file is accessed by another process at the same time. Two additional exceptions are added to handle the cases where the file is locked by another process or other unexpected situations occur. --- .../filesecure/files/FileDifference.java | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/main/java/fr/rakambda/filesecure/files/FileDifference.java b/src/main/java/fr/rakambda/filesecure/files/FileDifference.java index 2d8770c..dc1a620 100644 --- a/src/main/java/fr/rakambda/filesecure/files/FileDifference.java +++ b/src/main/java/fr/rakambda/filesecure/files/FileDifference.java @@ -5,8 +5,12 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; +import java.nio.channels.FileChannel; +import java.nio.channels.OverlappingFileLockException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Objects; import java.util.Optional; /** @@ -40,22 +44,34 @@ public void applyStrategy(@NotNull BackupStrategy backupStrategy){ var targetPath = desiredTarget.getTargetFolder().resolve(finalName); log.info("{} file {} to {}", backupStrategy.name(), sourcePath, targetPath); if(!Main.parameters.isDryRun()){ - try{ - switch(backupStrategy){ - case MOVE -> { - Files.createDirectories(desiredTarget.getTargetFolder()); - if(Files.isDirectory(desiredTarget.getTargetFolder())){ - Files.move(sourcePath, targetPath); + + try(var channel = FileChannel.open(sourcePath, StandardOpenOption.WRITE, StandardOpenOption.READ)){ + var fileLock = channel.tryLock(); + if(Objects.isNull(fileLock)){ + log.warn("Failed to get lock for {}", sourcePath); + return; + } + + try(fileLock){ + switch(backupStrategy){ + case MOVE -> { + Files.createDirectories(desiredTarget.getTargetFolder()); + if(Files.isDirectory(desiredTarget.getTargetFolder())){ + Files.move(sourcePath, targetPath); + } } - } - case COPY -> { - Files.createDirectories(desiredTarget.getTargetFolder()); - if(Files.isDirectory(desiredTarget.getTargetFolder())){ - Files.copy(sourcePath, targetPath); + case COPY -> { + Files.createDirectories(desiredTarget.getTargetFolder()); + if(Files.isDirectory(desiredTarget.getTargetFolder())){ + Files.copy(sourcePath, targetPath); + } } } } } + catch(OverlappingFileLockException e){ + log.warn("File {} is locked, skipping", sourcePath); + } catch(Exception e){ log.warn("Error applying strategy {} on file {}", backupStrategy, sourcePath, e); }