VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/linux/RTFileCopyPartEx-linux.cpp

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.5 KB
Line 
1/* $Id: RTFileCopyPartEx-linux.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - RTFileCopyPartEx, linux specific implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/file.h>
42#include "internal/iprt.h"
43
44#include <iprt/asm.h>
45#include <iprt/assert.h>
46#include <iprt/err.h>
47
48#include <errno.h>
49#include <unistd.h>
50#include <sys/syscall.h>
51
52#ifndef __NR_copy_file_range
53# if defined(RT_ARCH_X86)
54# define __NR_copy_file_range 377
55# elif defined(RT_ARCH_AMD64)
56# define __NR_copy_file_range 326
57# endif
58#endif
59
60
61#ifndef __NR_copy_file_range
62# include "../../generic/RTFileCopyPartEx-generic.cpp"
63#else /* __NR_copy_file_range - whole file */
64/* Include the generic code as a fallback since copy_file_range is rather new . */
65# define IPRT_FALLBACK_VERSION
66# include "../../generic/RTFileCopyPartEx-generic.cpp"
67# undef IPRT_FALLBACK_VERSION
68
69
70/*********************************************************************************************************************************
71* Global Variables *
72*********************************************************************************************************************************/
73static int32_t volatile g_fCopyFileRangeSupported = -1;
74
75
76DECLINLINE(loff_t)
77MyCopyFileRangeSysCall(int fdIn, loff_t *poffIn, int fdOut, loff_t *poffOut, size_t cbChunk, unsigned int fFlags)
78{
79 return syscall(__NR_copy_file_range, fdIn, poffIn, fdOut, poffOut, cbChunk, fFlags);
80}
81
82
83DECL_NO_INLINE(static, bool) HasCopyFileRangeSyscallSlow(void)
84{
85 errno = 0;
86 MyCopyFileRangeSysCall(-1, NULL, -1, NULL, 4096, 0);
87 if (errno != ENOSYS)
88 {
89 ASMAtomicWriteS32(&g_fCopyFileRangeSupported, 1);
90 return true;
91 }
92 ASMAtomicWriteS32(&g_fCopyFileRangeSupported, 0);
93 return false;
94}
95
96DECLINLINE(bool) HasCopyFileRangeSyscall(void)
97{
98 int32_t i = ASMAtomicUoReadS32(&g_fCopyFileRangeSupported);
99 if (i != -1)
100 return i == 1;
101 return HasCopyFileRangeSyscallSlow();
102}
103
104
105
106RTDECL(int) RTFileCopyPartPrep(PRTFILECOPYPARTBUFSTATE pBufState, uint64_t cbToCopy)
107{
108 if (HasCopyFileRangeSyscall())
109 {
110 pBufState->iAllocType = -42;
111 pBufState->pbBuf = NULL;
112 pBufState->cbBuf = 0;
113 pBufState->uMagic = RTFILECOPYPARTBUFSTATE_MAGIC;
114 return VINF_SUCCESS;
115 }
116 return rtFileCopyPartPrepFallback(pBufState, cbToCopy);
117}
118
119
120RTDECL(void) RTFileCopyPartCleanup(PRTFILECOPYPARTBUFSTATE pBufState)
121{
122 return rtFileCopyPartCleanupFallback(pBufState);
123}
124
125
126RTDECL(int) RTFileCopyPartEx(RTFILE hFileSrc, RTFOFF offSrc, RTFILE hFileDst, RTFOFF offDst, uint64_t cbToCopy,
127 uint32_t fFlags, PRTFILECOPYPARTBUFSTATE pBufState, uint64_t *pcbCopied)
128{
129 /*
130 * Validate input.
131 */
132 if (pcbCopied)
133 *pcbCopied = 0;
134 AssertReturn(pBufState->uMagic == RTFILECOPYPARTBUFSTATE_MAGIC, VERR_INVALID_FLAGS);
135 if (pBufState->iAllocType == -42)
136 { /* more and more likely as time goes */ }
137 else
138 return rtFileCopyPartExFallback(hFileSrc, offSrc, hFileDst, offDst, cbToCopy, fFlags, pBufState, pcbCopied);
139 AssertReturn(offSrc >= 0, VERR_NEGATIVE_SEEK);
140 AssertReturn(offDst >= 0, VERR_NEGATIVE_SEEK);
141 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
142
143 /*
144 * If nothing to copy, return right away.
145 */
146 if (!cbToCopy)
147 return VINF_SUCCESS;
148
149 /*
150 * Do the copying.
151 */
152 uint64_t cbCopied = 0;
153 int rc = VINF_SUCCESS;
154 do
155 {
156 size_t cbThisCopy = (size_t)RT_MIN(cbToCopy - cbCopied, _1G);
157 loff_t offThisDst = offSrc + cbCopied;
158 loff_t offThisSrc = offDst + cbCopied;
159 ssize_t cbActual = MyCopyFileRangeSysCall((int)RTFileToNative(hFileSrc), &offThisSrc,
160 (int)RTFileToNative(hFileDst), &offThisDst,
161 cbThisCopy, 0);
162 if (cbActual < 0)
163 {
164 rc = errno;
165 Assert(rc != 0);
166 rc = rc != 0 ? RTErrConvertFromErrno(rc) : VERR_READ_ERROR;
167 if (rc != VERR_NOT_SAME_DEVICE || cbCopied != 0)
168 break;
169
170 /* Fall back to generic implementation if the syscall refuses to handle the case. */
171 rc = rtFileCopyPartPrepFallback(pBufState, cbToCopy);
172 if (RT_SUCCESS(rc))
173 return rtFileCopyPartExFallback(hFileSrc, offSrc, hFileDst, offDst, cbToCopy, fFlags, pBufState, pcbCopied);
174 return rc;
175 }
176 Assert(offThisSrc == offSrc + (int64_t)cbCopied + cbActual);
177 Assert(offThisDst == offDst + (int64_t)cbCopied + cbActual);
178
179 if (cbActual == 0)
180 {
181 if (!pcbCopied)
182 rc = VERR_EOF;
183 break;
184 }
185
186 cbCopied += cbActual;
187 } while (cbCopied < cbToCopy);
188
189 if (pcbCopied)
190 *pcbCopied = cbCopied;
191
192 return rc;
193}
194
195#endif /* __NR_copy_file_range */
196
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use