VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/fileio.cpp@ 108150

最後變更 在這個檔案從108150是 107803,由 vboxsync 提交於 2 月 前

Runtime/r3/fileio.cpp: Make the parameters of RTFileSetForceFlags() 64-bit like all the other RTFile* APIs for the mode flags, bugref:3409

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 13.9 KB
 
1/* $Id: fileio.cpp 107803 2025-01-16 09:08:31Z vboxsync $ */
2/** @file
3 * IPRT - File I/O.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.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 "internal/iprt.h"
42#include <iprt/file.h>
43
44#include <iprt/mem.h>
45#include <iprt/assert.h>
46#include <iprt/alloca.h>
47#include <iprt/string.h>
48#include <iprt/err.h>
49#include "internal/file.h"
50
51
52/*********************************************************************************************************************************
53* Global Variables *
54*********************************************************************************************************************************/
55/** Set of forced set open flags for files opened read-only. */
56static uint64_t g_fOpenReadSet = 0;
57
58/** Set of forced cleared open flags for files opened read-only. */
59static uint64_t g_fOpenReadMask = 0;
60
61/** Set of forced set open flags for files opened write-only. */
62static uint64_t g_fOpenWriteSet = 0;
63
64/** Set of forced cleared open flags for files opened write-only. */
65static uint64_t g_fOpenWriteMask = 0;
66
67/** Set of forced set open flags for files opened read-write. */
68static uint64_t g_fOpenReadWriteSet = 0;
69
70/** Set of forced cleared open flags for files opened read-write. */
71static uint64_t g_fOpenReadWriteMask = 0;
72
73
74/**
75 * Force the use of open flags for all files opened after the setting is
76 * changed. The caller is responsible for not causing races with RTFileOpen().
77 *
78 * @returns iprt status code.
79 * @param fOpenForAccess Access mode to which the set/mask settings apply.
80 * @param fSet Open flags to be forced set.
81 * @param fMask Open flags to be masked out.
82 */
83RTR3DECL(int) RTFileSetForceFlags(uint64_t fOpenForAccess, uint64_t fSet, uint64_t fMask)
84{
85 /*
86 * For now allow only RTFILE_O_WRITE_THROUGH. The other flags either
87 * make no sense in this context or are not useful to apply to all files.
88 */
89 if ((fSet | fMask) & ~RTFILE_O_WRITE_THROUGH)
90 return VERR_INVALID_PARAMETER;
91 switch (fOpenForAccess)
92 {
93 case RTFILE_O_READ:
94 g_fOpenReadSet = fSet;
95 g_fOpenReadMask = fMask;
96 break;
97 case RTFILE_O_WRITE:
98 g_fOpenWriteSet = fSet;
99 g_fOpenWriteMask = fMask;
100 break;
101 case RTFILE_O_READWRITE:
102 g_fOpenReadWriteSet = fSet;
103 g_fOpenReadWriteMask = fMask;
104 break;
105 default:
106 AssertMsgFailed(("Invalid access mode %d\n", fOpenForAccess));
107 return VERR_INVALID_PARAMETER;
108 }
109 return VINF_SUCCESS;
110}
111
112
113/**
114 * Adjusts and validates the flags.
115 *
116 * The adjustments are made according to the wishes specified using the RTFileSetForceFlags API.
117 *
118 * @returns IPRT status code.
119 * @param pfOpen Pointer to the user specified flags on input.
120 * Updated on successful return.
121 * @internal
122 */
123int rtFileRecalcAndValidateFlags(uint64_t *pfOpen)
124{
125 /*
126 * Recalc.
127 */
128 uint32_t fOpen = *pfOpen;
129 switch (fOpen & RTFILE_O_ACCESS_MASK)
130 {
131 case RTFILE_O_READ:
132 fOpen |= g_fOpenReadSet;
133 fOpen &= ~g_fOpenReadMask;
134 break;
135 case RTFILE_O_WRITE:
136 fOpen |= g_fOpenWriteSet;
137 fOpen &= ~g_fOpenWriteMask;
138 break;
139 case RTFILE_O_READWRITE:
140 fOpen |= g_fOpenReadWriteSet;
141 fOpen &= ~g_fOpenReadWriteMask;
142 break;
143#ifdef RT_OS_WINDOWS
144 case RTFILE_O_ATTR_ONLY:
145 if (fOpen & RTFILE_O_ACCESS_ATTR_MASK)
146 break;
147#endif
148 default:
149 AssertMsgFailed(("Invalid access mode value, fOpen=%#llx\n", fOpen));
150 return VERR_INVALID_PARAMETER;
151 }
152
153 /*
154 * Validate .
155 */
156#ifdef RT_OS_WINDOWS
157 AssertMsgReturn((fOpen & RTFILE_O_ACCESS_MASK) || (fOpen & RTFILE_O_ACCESS_ATTR_MASK),
158 ("Missing RTFILE_O_READ/WRITE/ACCESS_ATTR: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER);
159#else
160 AssertMsgReturn(fOpen & RTFILE_O_ACCESS_MASK, ("Missing RTFILE_O_READ/WRITE: fOpen=%#llx\n", fOpen), VERR_INVALID_PARAMETER);
161#endif
162#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
163 AssertMsgReturn(!(fOpen & (~(uint64_t)RTFILE_O_VALID_MASK | RTFILE_O_NON_BLOCK)), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
164#else
165 AssertMsgReturn(!(fOpen & ~(uint64_t)RTFILE_O_VALID_MASK), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
166#endif
167 AssertMsgReturn((fOpen & (RTFILE_O_TRUNCATE | RTFILE_O_WRITE)) != RTFILE_O_TRUNCATE, ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
168
169 switch (fOpen & RTFILE_O_ACTION_MASK)
170 {
171 case 0: /* temporarily */
172 AssertMsgFailed(("Missing RTFILE_O_OPEN/CREATE*! (continuable assertion)\n"));
173 fOpen |= RTFILE_O_OPEN;
174 break;
175 case RTFILE_O_OPEN:
176 AssertMsgReturn(!(RTFILE_O_NOT_CONTENT_INDEXED & fOpen), ("%#llx\n", fOpen), VERR_INVALID_PARAMETER);
177 RT_FALL_THROUGH();
178 case RTFILE_O_OPEN_CREATE:
179 case RTFILE_O_CREATE:
180 case RTFILE_O_CREATE_REPLACE:
181 break;
182 default:
183 AssertMsgFailed(("Invalid action value: fOpen=%#llx\n", fOpen));
184 return VERR_INVALID_PARAMETER;
185 }
186
187 switch (fOpen & RTFILE_O_DENY_MASK)
188 {
189 case 0: /* temporarily */
190 AssertMsgFailed(("Missing RTFILE_O_DENY_*! (continuable assertion)\n"));
191 fOpen |= RTFILE_O_DENY_NONE;
192 break;
193 case RTFILE_O_DENY_NONE:
194 case RTFILE_O_DENY_READ:
195 case RTFILE_O_DENY_WRITE:
196 case RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
197 case RTFILE_O_DENY_NOT_DELETE:
198 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_READ:
199 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE:
200 case RTFILE_O_DENY_NOT_DELETE | RTFILE_O_DENY_WRITE | RTFILE_O_DENY_READ:
201 break;
202 default:
203 AssertMsgFailed(("Invalid deny value: fOpen=%#llx\n", fOpen));
204 return VERR_INVALID_PARAMETER;
205 }
206
207 /* done */
208 *pfOpen = fOpen;
209 return VINF_SUCCESS;
210}
211
212
213RTR3DECL(uint64_t) RTFileTell(RTFILE File)
214{
215 /*
216 * Call the seek api to query the stuff.
217 */
218 uint64_t off = 0;
219 int rc = RTFileSeek(File, 0, RTFILE_SEEK_CURRENT, &off);
220 if (RT_SUCCESS(rc))
221 return off;
222 AssertMsgFailed(("RTFileSeek(%d) -> %d\n", File, rc));
223 return ~0ULL;
224}
225
226
227RTR3DECL(RTFOFF) RTFileGetMaxSize(RTFILE File)
228{
229 RTFOFF cbMax;
230 int rc = RTFileQueryMaxSizeEx(File, &cbMax);
231 return RT_SUCCESS(rc) ? cbMax : -1;
232}
233
234
235RTDECL(int) RTFileCopyByHandles(RTFILE FileSrc, RTFILE FileDst)
236{
237 return RTFileCopyByHandlesEx(FileSrc, FileDst, NULL, NULL);
238}
239
240
241RTDECL(int) RTFileCompare(const char *pszFile1, const char *pszFile2)
242{
243 return RTFileCompareEx(pszFile1, pszFile2, 0 /*fFlags*/, NULL, NULL);
244}
245
246
247RTDECL(int) RTFileCompareByHandles(RTFILE hFile1, RTFILE hFile2)
248{
249 return RTFileCompareByHandlesEx(hFile1, hFile2, 0 /*fFlags*/, NULL, NULL);
250}
251
252
253RTDECL(int) RTFileCompareEx(const char *pszFile1, const char *pszFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
254{
255 /*
256 * Validate input.
257 */
258 AssertPtrReturn(pszFile1, VERR_INVALID_POINTER);
259 AssertReturn(*pszFile1, VERR_INVALID_PARAMETER);
260 AssertPtrReturn(pszFile2, VERR_INVALID_POINTER);
261 AssertReturn(*pszFile2, VERR_INVALID_PARAMETER);
262 AssertPtrNullReturn(pfnProgress, VERR_INVALID_POINTER);
263 AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
264
265 /*
266 * Open the files.
267 */
268 RTFILE hFile1;
269 int rc = RTFileOpen(&hFile1, pszFile1,
270 RTFILE_O_READ | RTFILE_O_OPEN
271 | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE1 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
272 if (RT_SUCCESS(rc))
273 {
274 RTFILE hFile2;
275 rc = RTFileOpen(&hFile2, pszFile2,
276 RTFILE_O_READ | RTFILE_O_OPEN
277 | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE2 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
278 if (RT_SUCCESS(rc))
279 {
280 /*
281 * Call the ByHandles version and let it do the job.
282 */
283 rc = RTFileCompareByHandlesEx(hFile1, hFile2, fFlags, pfnProgress, pvUser);
284
285 /* Clean up */
286 int rc2 = RTFileClose(hFile2);
287 AssertRC(rc2);
288 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
289 rc = rc2;
290 }
291
292 int rc2 = RTFileClose(hFile1);
293 AssertRC(rc2);
294 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
295 rc = rc2;
296 }
297 return rc;
298}
299
300
301RTDECL(int) RTFileCompareByHandlesEx(RTFILE hFile1, RTFILE hFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
302{
303 /*
304 * Validate input.
305 */
306 AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);
307 AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);
308 AssertPtrNullReturn(pfnProgress, VERR_INVALID_POINTER);
309 AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
310
311 /*
312 * Compare the file sizes first.
313 */
314 uint64_t cbFile1;
315 int rc = RTFileQuerySize(hFile1, &cbFile1);
316 if (RT_FAILURE(rc))
317 return rc;
318
319 uint64_t cbFile2;
320 rc = RTFileQuerySize(hFile1, &cbFile2);
321 if (RT_FAILURE(rc))
322 return rc;
323
324 if (cbFile1 != cbFile2)
325 return VERR_NOT_EQUAL;
326
327
328 /*
329 * Allocate buffer.
330 */
331 size_t cbBuf;
332 uint8_t *pbBuf1Free = NULL;
333 uint8_t *pbBuf1;
334 uint8_t *pbBuf2Free = NULL;
335 uint8_t *pbBuf2;
336 if (cbFile1 < _512K)
337 {
338 cbBuf = 8*_1K;
339 pbBuf1 = (uint8_t *)alloca(cbBuf);
340 pbBuf2 = (uint8_t *)alloca(cbBuf);
341 }
342 else
343 {
344 cbBuf = _128K;
345 pbBuf1 = pbBuf1Free = (uint8_t *)RTMemTmpAlloc(cbBuf);
346 pbBuf2 = pbBuf2Free = (uint8_t *)RTMemTmpAlloc(cbBuf);
347 }
348 if (pbBuf1 && pbBuf2)
349 {
350 /*
351 * Seek to the start of each file
352 * and set the size of the destination file.
353 */
354 rc = RTFileSeek(hFile1, 0, RTFILE_SEEK_BEGIN, NULL);
355 if (RT_SUCCESS(rc))
356 {
357 rc = RTFileSeek(hFile2, 0, RTFILE_SEEK_BEGIN, NULL);
358 if (RT_SUCCESS(rc) && pfnProgress)
359 rc = pfnProgress(0, pvUser);
360 if (RT_SUCCESS(rc))
361 {
362 /*
363 * Compare loop.
364 */
365 unsigned uPercentage = 0;
366 RTFOFF off = 0;
367 RTFOFF cbPercent = cbFile1 / 100;
368 RTFOFF offNextPercent = cbPercent;
369 while (off < (RTFOFF)cbFile1)
370 {
371 /* read the blocks */
372 RTFOFF cbLeft = cbFile1 - off;
373 size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;
374 rc = RTFileRead(hFile1, pbBuf1, cbBlock, NULL);
375 if (RT_FAILURE(rc))
376 break;
377 rc = RTFileRead(hFile2, pbBuf2, cbBlock, NULL);
378 if (RT_FAILURE(rc))
379 break;
380
381 /* compare */
382 if (memcmp(pbBuf1, pbBuf2, cbBlock))
383 {
384 rc = VERR_NOT_EQUAL;
385 break;
386 }
387
388 /* advance */
389 off += cbBlock;
390 if (pfnProgress && offNextPercent < off)
391 {
392 while (offNextPercent < off)
393 {
394 uPercentage++;
395 offNextPercent += cbPercent;
396 }
397 rc = pfnProgress(uPercentage, pvUser);
398 if (RT_FAILURE(rc))
399 break;
400 }
401 }
402
403#if 0
404 /*
405 * Compare OS specific data (EAs and stuff).
406 */
407 if (RT_SUCCESS(rc))
408 rc = rtFileCompareOSStuff(hFile1, hFile2);
409#endif
410
411 /* 100% */
412 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))
413 rc = pfnProgress(100, pvUser);
414 }
415 }
416 }
417 else
418 rc = VERR_NO_MEMORY;
419 RTMemTmpFree(pbBuf2Free);
420 RTMemTmpFree(pbBuf1Free);
421
422 return rc;
423}
424
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette