Federico Mariani created CAMEL-24095:
----------------------------------------

             Summary: camel-file: tempFileName + fileExist=Move + 
eagerDeleteTargetFile=false silently overwrites the existing target instead of 
moving it (no Move branch in handleExistingTarget)
                 Key: CAMEL-24095
                 URL: https://issues.apache.org/jira/browse/CAMEL-24095
             Project: Camel
          Issue Type: Bug
          Components: camel-ftp, camel-file
    Affects Versions: 4.21.0
            Reporter: Federico Mariani
         Attachments: FileProducerTempFileMoveExistingNonEagerIssueTest.java

h3. Problem
{{GenericFileProducer.handleExistingTarget}} (GenericFileProducer.java:249-266) 
- the non-eager exists handler used when writing via 
{{tempFileName}}/{{tempPrefix}} with {{eagerDeleteTargetFile=false}} - covers 
{{Ignore}}, {{Fail}} and {{Override}} but has *no Move branch*, unlike its 
eager twin {{handleExistingTargetEager}} (line 235-237) which calls the 
{{moveExistingFileStrategy}}. It returns false and {{renameFile(tempTarget, 
target)}} proceeds: {{FileUtil.renameFile}} uses {{Files.move(..., 
ATOMIC_MOVE)}} (or copy with {{REPLACE_EXISTING}} as fallback), so the 
pre-existing target is overwritten and lost - never archived to the 
{{moveExisting}} destination, which is the entire point of {{fileExist=Move}}.

h3. Failure scenario
{{to("file:out?tempFileName=inprogress-${file:name}&fileExist=Move&moveExisting=archive/&eagerDeleteTargetFile=false")}}
 with an existing target: the old file is destroyed instead of moved to 
{{archive/}}. This combination is deliberate usage - per the 
{{eagerDeleteTargetFile}} javadoc, non-eager is exactly how you get "fail if a 
file already exists at the move destination" semantics for the moveExisting 
operation.

h3. History
CAMEL-15822 (235a0a5f3d15, 2020) was titled "fileExist=Move doesn't use 
FileMoveExistingStrategy when tempFile is also configured" but patched only the 
eager branch; the non-eager branch has lacked Move handling since the logic's 
inception and through the 2023 helper-extraction refactor (1bcab0700cd9).

h3. Suggested fix
Add the Move branch to {{handleExistingTarget}}, mirroring 
{{handleExistingTargetEager}}.

Adjacent defect in the same code path: with {{eagerDeleteTargetFile=false}}, 
the temp file is fully written before the exists check, and the 
{{Ignore}}-return / {{Fail}}-throw / failed-rename paths all leave the temp 
file orphaned on disk (unbounded accumulation with date/UUID-bearing 
{{tempFileName}} expressions).

h3. Note for the fix
Existing test 
{{FileProducerMoveExistingTest.testFailOnMoveExistingFileExistsEagerDeleteFalseTempFileName}}
 currently *asserts the buggy behavior* (it expects the pre-existing 
move-target to keep its old content, i.e. no move happened) and will need 
updating together with the fix.

h3. Reproducer
Attached failing JUnit test (place in 
{{core/camel-core/src/test/java/org/apache/camel/component/file/}}, where the 
file component tests live). Pre-creates the target with content OLD, produces 
NEW through the tempFileName+Move+non-eager endpoint, and asserts the OLD 
content was archived to {{archive/}} - on current main the archive file does 
not exist and OLD is destroyed.

----
_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