Federico Mariani created CAMEL-24092:
----------------------------------------

             Summary: camel-file: readLock=fileLock claims the lock after an 
IOException - file processed with no lock held and marker file deleted 
(possible duplicate consumption)
                 Key: CAMEL-24092
                 URL: https://issues.apache.org/jira/browse/CAMEL-24092
             Project: Camel
          Issue Type: Bug
          Components: camel-file
    Affects Versions: 4.21.0
            Reporter: Federico Mariani
         Attachments: FileLockReadLockIOExceptionShouldNotAcquireIssueTest.java

h3. Problem
In {{FileLockExclusiveReadLockStrategy.acquireExclusiveReadLock}} 
(FileLockExclusiveReadLockStrategy.java:114-140), with the default 
{{readLockTimeout=10000}}: if {{new RandomAccessFile(target, "rw")}} or 
{{channel.tryLock()}} throws {{IOException}} (file deleted between poll and 
lock, permission error, Windows AV/MS-Office special locks), 
{{handleIOException}} logs "Cannot acquire read lock. Will try again.", sleeps 
once, returns false - and control *falls out of the catch block*: the 
{{finally}} (since {{exclusive == false}}) closes channel/RAF and calls 
{{super.releaseExclusiveReadLockOnAbort(...)}} which *deletes the .camelLock 
marker file*, then the method stores {{lock = null}} and *returns true*.

h3. Failure scenario
The consumer processes the file with (a) no OS file lock and (b) the marker 
protection removed - a competing consumer in another JVM watching the same 
directory can acquire the marker and process the same file concurrently -> 
duplicate consumption. There is also no actual retry despite the "Will try 
again" log, and the {{timeout == 0}} branch correctly returns false - the two 
branches contradict each other.

h3. History
The fall-through-to-true dates to CAMEL-1195 (2008, deliberate "process anyway 
on Windows-AV IOE" degradation). But CAMEL-5324 (2012) later layered marker 
files into this strategy, and the finally releasing that marker before 
returning true cannot be intentional - it silently drops the exact cross-JVM 
protection CAMEL-5324 added. CAMEL-7988 changed the {{timeout==0}} branch from 
throw to return-false, leaving the branches contradictory.

h3. Suggested fix
Return false from the IOException path (consistent with the {{timeout==0}} 
branch). If the degraded consume-anyway behavior must be preserved for the 
Windows-AV case, at minimum the marker must not be released and the retry log 
fixed.

Adjacent nit found in the same class: {{doReleaseExclusiveReadLock}} (line 
164-165) fetches the {{RandomAccessFile}} under the 
{{FILE_LOCK_EXCLUSIVE_LOCK}} key instead of {{FILE_LOCK_RANDOM_ACCESS_FILE}}, 
so {{rac}} is always null (no fd leak today only because closing the channel 
closes the shared fd).

h3. Reproducer
Attached failing JUnit test (place in 
{{core/camel-core/src/test/java/org/apache/camel/component/file/strategy/}}, 
where the file component tests live). Makes the target file unwritable so 
{{RandomAccessFile("rw")}} throws, and asserts {{acquireExclusiveReadLock}} 
returns false; on current main it returns true (and has deleted the marker).

----
_This issue was researched and filed by Claude Code on behalf of [~croway] 
(GitHub: Croway), as part of a deep code review of camel-file and camel-ftp. A 
failing JUnit reproducer is attached; it fails deterministically on current 
main (4.22.0-SNAPSHOT)._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to