VirtualBox

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

Last change on this file since 92258 was 90803, checked in by vboxsync, 3 years ago

Runtime: More VALID_PTR -> RT_VALID_PTR/AssertPtr.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.8 KB
Line 
1/* $Id: fileio.cpp 90803 2021-08-23 19:08:38Z vboxsync $ */
2/** @file
3 * IPRT - File I/O.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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
223RTR3DECL(RTFOFF) RTFileGetMaxSize(RTFILE File)
224{
225 RTFOFF cbMax;
226 int rc = RTFileQueryMaxSizeEx(File, &cbMax);
227 return RT_SUCCESS(rc) ? cbMax : -1;
228}
229
230
231RTDECL(int) RTFileCopyByHandles(RTFILE FileSrc, RTFILE FileDst)
232{
233 return RTFileCopyByHandlesEx(FileSrc, FileDst, NULL, NULL);
234}
235
236
237RTDECL(int) RTFileCompare(const char *pszFile1, const char *pszFile2)
238{
239 return RTFileCompareEx(pszFile1, pszFile2, 0 /*fFlags*/, NULL, NULL);
240}
241
242
243RTDECL(int) RTFileCompareByHandles(RTFILE hFile1, RTFILE hFile2)
244{
245 return RTFileCompareByHandlesEx(hFile1, hFile2, 0 /*fFlags*/, NULL, NULL);
246}
247
248
249RTDECL(int) RTFileCompareEx(const char *pszFile1, const char *pszFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
250{
251 /*
252 * Validate input.
253 */
254 AssertPtrReturn(pszFile1, VERR_INVALID_POINTER);
255 AssertReturn(*pszFile1, VERR_INVALID_PARAMETER);
256 AssertPtrReturn(pszFile2, VERR_INVALID_POINTER);
257 AssertReturn(*pszFile2, VERR_INVALID_PARAMETER);
258 AssertPtrNullReturn(pfnProgress, VERR_INVALID_POINTER);
259 AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
260
261 /*
262 * Open the files.
263 */
264 RTFILE hFile1;
265 int rc = RTFileOpen(&hFile1, pszFile1,
266 RTFILE_O_READ | RTFILE_O_OPEN
267 | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE1 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
268 if (RT_SUCCESS(rc))
269 {
270 RTFILE hFile2;
271 rc = RTFileOpen(&hFile2, pszFile2,
272 RTFILE_O_READ | RTFILE_O_OPEN
273 | (fFlags & RTFILECOMP_FLAGS_NO_DENY_WRITE_FILE2 ? RTFILE_O_DENY_NONE : RTFILE_O_DENY_WRITE));
274 if (RT_SUCCESS(rc))
275 {
276 /*
277 * Call the ByHandles version and let it do the job.
278 */
279 rc = RTFileCompareByHandlesEx(hFile1, hFile2, fFlags, pfnProgress, pvUser);
280
281 /* Clean up */
282 int rc2 = RTFileClose(hFile2);
283 AssertRC(rc2);
284 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
285 rc = rc2;
286 }
287
288 int rc2 = RTFileClose(hFile1);
289 AssertRC(rc2);
290 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
291 rc = rc2;
292 }
293 return rc;
294}
295
296
297RTDECL(int) RTFileCompareByHandlesEx(RTFILE hFile1, RTFILE hFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser)
298{
299 /*
300 * Validate input.
301 */
302 AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);
303 AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE);
304 AssertPtrNullReturn(pfnProgress, VERR_INVALID_POINTER);
305 AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
306
307 /*
308 * Compare the file sizes first.
309 */
310 uint64_t cbFile1;
311 int rc = RTFileQuerySize(hFile1, &cbFile1);
312 if (RT_FAILURE(rc))
313 return rc;
314
315 uint64_t cbFile2;
316 rc = RTFileQuerySize(hFile1, &cbFile2);
317 if (RT_FAILURE(rc))
318 return rc;
319
320 if (cbFile1 != cbFile2)
321 return VERR_NOT_EQUAL;
322
323
324 /*
325 * Allocate buffer.
326 */
327 size_t cbBuf;
328 uint8_t *pbBuf1Free = NULL;
329 uint8_t *pbBuf1;
330 uint8_t *pbBuf2Free = NULL;
331 uint8_t *pbBuf2;
332 if (cbFile1 < _512K)
333 {
334 cbBuf = 8*_1K;
335 pbBuf1 = (uint8_t *)alloca(cbBuf);
336 pbBuf2 = (uint8_t *)alloca(cbBuf);
337 }
338 else
339 {
340 cbBuf = _128K;
341 pbBuf1 = pbBuf1Free = (uint8_t *)RTMemTmpAlloc(cbBuf);
342 pbBuf2 = pbBuf2Free = (uint8_t *)RTMemTmpAlloc(cbBuf);
343 }
344 if (pbBuf1 && pbBuf2)
345 {
346 /*
347 * Seek to the start of each file
348 * and set the size of the destination file.
349 */
350 rc = RTFileSeek(hFile1, 0, RTFILE_SEEK_BEGIN, NULL);
351 if (RT_SUCCESS(rc))
352 {
353 rc = RTFileSeek(hFile2, 0, RTFILE_SEEK_BEGIN, NULL);
354 if (RT_SUCCESS(rc) && pfnProgress)
355 rc = pfnProgress(0, pvUser);
356 if (RT_SUCCESS(rc))
357 {
358 /*
359 * Compare loop.
360 */
361 unsigned uPercentage = 0;
362 RTFOFF off = 0;
363 RTFOFF cbPercent = cbFile1 / 100;
364 RTFOFF offNextPercent = cbPercent;
365 while (off < (RTFOFF)cbFile1)
366 {
367 /* read the blocks */
368 RTFOFF cbLeft = cbFile1 - off;
369 size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft;
370 rc = RTFileRead(hFile1, pbBuf1, cbBlock, NULL);
371 if (RT_FAILURE(rc))
372 break;
373 rc = RTFileRead(hFile2, pbBuf2, cbBlock, NULL);
374 if (RT_FAILURE(rc))
375 break;
376
377 /* compare */
378 if (memcmp(pbBuf1, pbBuf2, cbBlock))
379 {
380 rc = VERR_NOT_EQUAL;
381 break;
382 }
383
384 /* advance */
385 off += cbBlock;
386 if (pfnProgress && offNextPercent < off)
387 {
388 while (offNextPercent < off)
389 {
390 uPercentage++;
391 offNextPercent += cbPercent;
392 }
393 rc = pfnProgress(uPercentage, pvUser);
394 if (RT_FAILURE(rc))
395 break;
396 }
397 }
398
399#if 0
400 /*
401 * Compare OS specific data (EAs and stuff).
402 */
403 if (RT_SUCCESS(rc))
404 rc = rtFileCompareOSStuff(hFile1, hFile2);
405#endif
406
407 /* 100% */
408 if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc))
409 rc = pfnProgress(100, pvUser);
410 }
411 }
412 }
413 else
414 rc = VERR_NO_MEMORY;
415 RTMemTmpFree(pbBuf2Free);
416 RTMemTmpFree(pbBuf1Free);
417
418 return rc;
419}
420
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