[ 
https://issues.apache.org/jira/browse/CAMEL-24089?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Federico Mariani updated CAMEL-24089:
-------------------------------------
    Attachment: FileConsumerFileLockHugeFileTruncationIssueTest.java

> camel-file: file-to-file copy with readLock=fileLock silently truncates files 
> larger than 2 GB on Linux (single transferTo, return value ignored)
> -------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-24089
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24089
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-file
>    Affects Versions: 4.21.0
>            Reporter: Federico Mariani
>            Priority: Critical
>              Labels: code-review
>         Attachments: FileConsumerFileLockHugeFileTruncationIssueTest.java
>
>
> h3. Problem
> Route {{from("file:in?readLock=fileLock").to("file:out")}} keeps the 
> read-lock {{FileChannel}} in an exchange property; 
> {{FileOperations.writeFileByFile}} (FileOperations.java:515-532) then copies 
> via:
> {code:java}
> channel.transferTo(0, channel.size(), out);   // single call, return value 
> discarded
> {code}
> {{FileChannel.transferTo}} is documented to possibly transfer fewer bytes 
> than requested, and the JDK caps each call at {{Integer.MAX_VALUE}} bytes (~2 
> 147 479 552 with sendfile on Linux). Any source file larger than ~2 GB 
> produces a silently truncated target while the producer reports success - the 
> done file is still written and the commit deletes/moves the source.
> *Platform note:* the truncation manifests on Linux, where the JDK takes the 
> direct sendfile/copy_file_range path capped at {{Integer.MAX_VALUE}}-ish 
> bytes per call ({{sun.nio.ch.FileChannelImpl.transferTo}}: {{int icount = 
> (int) Math.min(count, nd.maxDirectTransferSize())}}). On macOS the direct 
> transfer is unsupported for file-to-file targets and the JDK falls back to 
> {{transferToTrustedChannel}}, an internal loop that copies the full count - 
> verified empirically (a single {{transferTo}} of a 3 GB file returned 
> 3221225472 on macOS). Relying on that fallback is still a contract violation: 
> {{transferTo}} is documented to possibly transfer fewer bytes than requested.
> h3. Failure scenario
> {{readLock=fileLock}} consumer + file producer + source file > 2 GB on Linux: 
> target is truncated at ~2 GB, no exception, source is gone after commit. The 
> non-locked path ({{Files.copy}}) is unaffected.
> h3. History
> Introduced by CAMEL-13680 (2019). Notably the pre-2017 code this area evolved 
> from *did* loop: {{while (position < size) position += 
> in.transferTo(position, bufferSize, out);}} (removed in d8c0a53b6787).
> h3. Suggested fix
> Loop until {{channel.size()}} bytes are transferred (standard transferTo 
> loop).
> h3. Reproducer
> Attached JUnit test (place in 
> {{core/camel-core/src/test/java/org/apache/camel/component/file/}}, where the 
> file component tests live). Uses a sparse 3 GB source file; needs ~3 GB free 
> transient disk space. Asserts target length equals source length. It FAILS on 
> Linux (target truncated to ~2147483647 bytes) and passes on macOS due to the 
> JDK fallback described above. The fix - the standard loop until all bytes are 
> transferred - is correct on all platforms.
> ----
> _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 JUnit reproducer is attached; it fails deterministically on Linux on 
> current main (4.22.0-SNAPSHOT)._



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

Reply via email to