VirtualBox

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

Last change on this file since 77994 was 77825, checked in by vboxsync, 6 years ago

IPRT: Split RTFileCopyEx and RTFileCopyByHandlesEx out of r3/fileio.cpp so we can do platform specific implementations of these. bugref:9172

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

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