VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstFile.cpp@ 95841

Last change on this file since 95841 was 95001, checked in by vboxsync, 3 years ago

IPRT/testcase: Made tstFile more flexible by querying file system properties (free space, ++) before we actually perform any tests and clamp accordingly, plus making it more random (for beyond 2GB writes). This is needed because we have test VMs which have less disk space configured than 2GB [SCM fix].

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.5 KB
Line 
1/* $Id: tstFile.cpp 95001 2022-05-13 09:43:20Z vboxsync $ */
2/** @file
3 * IPRT Testcase - File I/O.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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 <iprt/test.h>
32#include <iprt/file.h>
33#include <iprt/errcore.h>
34#include <iprt/path.h>
35#include <iprt/rand.h>
36#include <iprt/string.h>
37#include <iprt/stream.h>
38
39
40/*********************************************************************************************************************************
41* Global Variables *
42*********************************************************************************************************************************/
43static const char g_szTestStr[] = "Sausages and bacon for breakfast again!\n";
44static char g_szTestStr2[] =
45"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
46"enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor "
47"in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non "
48"proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n"
49"\n"
50"Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum "
51"elit, nec luctus magna felis sollicitudin mauris. Integer in mauris eu nibh euismod gravida. Duis ac tellus et risus "
52"vulputate vehicula. Donec lobortis risus a elit. Etiam tempor. Ut ullamcorper, ligula eu tempor congue, eros est euismod "
53"turpis, id tincidunt sapien risus a quam. Maecenas fermentum consequat mi. Donec fermentum. Pellentesque malesuada nulla a mi. "
54"Duis sapien sem, aliquet nec, commodo eget, consequat quis, neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl "
55"adipiscing sapien, sed malesuada diam lacus eget erat. Cras mollis scelerisque nunc. Nullam arcu. Aliquam consequat. Curabitur "
56"augue lorem, dapibus quis, laoreet et, pretium ac, nisi. Aenean magna nisl, mollis quis, molestie eu, feugiat in, orci. In hac "
57"habitasse platea dictumst.\n";
58
59/**
60 * Structure holding queried file system properties we're performing our tests on.
61 */
62typedef struct FsProps
63{
64 RTFOFF cbTotal;
65 RTFOFF cbFree;
66 uint32_t cbBlock;
67 uint32_t cbSector;
68} FsProps;
69/** Queried file system properties we're performing our tests on. */
70static FsProps s_FsProps;
71
72
73static void tstAppend(RTFILE hFile)
74{
75 char achBuf[sizeof(g_szTestStr2) * 4];
76
77 /*
78 * Write some stuff and read it back.
79 */
80 size_t const cbWrite1 = sizeof(g_szTestStr2) / 4;
81 RTTESTI_CHECK_RC_RETV(RTFileWrite(hFile, g_szTestStr2, sizeof(g_szTestStr2) - 1, NULL), VINF_SUCCESS);
82
83 size_t const offWrite2 = cbWrite1;
84 size_t const cbWrite2 = sizeof(g_szTestStr2) / 2;
85 RTTESTI_CHECK_RC_RETV(RTFileSeek(hFile, 0, RTFILE_SEEK_BEGIN, NULL), VINF_SUCCESS);
86 RTTESTI_CHECK_RC_RETV(RTFileWrite(hFile, &g_szTestStr2[offWrite2], cbWrite2, NULL), VINF_SUCCESS);
87
88 RTTESTI_CHECK_RC_RETV(RTFileSeek(hFile, 0, RTFILE_SEEK_BEGIN, NULL), VINF_SUCCESS);
89 RTTESTI_CHECK_RC_RETV(RTFileRead(hFile, achBuf, cbWrite1 + cbWrite2, NULL), VINF_SUCCESS);
90 if (memcmp(achBuf, g_szTestStr2, cbWrite1 + cbWrite2) != 0)
91 RTTestIFailed("Read back #1 failed (%#zx + %#zx)", cbWrite1, cbWrite2);
92
93#if 1 //ndef RT_OS_WINDOWS
94 /*
95 * Truncate the file and write some more. This is problematic on windows,
96 * we currently have a questionable hack in place to make this work.
97 */
98 RTTESTI_CHECK_RC_RETV(RTFileSetSize(hFile, 0), VINF_SUCCESS);
99
100 size_t const offWrite3 = cbWrite1 + cbWrite2;
101 size_t const cbWrite3 = sizeof(g_szTestStr2) - 1 - offWrite3;
102 RTTESTI_CHECK_RC_RETV(RTFileSeek(hFile, 0, RTFILE_SEEK_BEGIN, NULL), VINF_SUCCESS);
103 RTTESTI_CHECK_RC_RETV(RTFileWrite(hFile, &g_szTestStr2[offWrite3], cbWrite3, NULL), VINF_SUCCESS);
104
105 RTTESTI_CHECK_RC_RETV(RTFileSeek(hFile, 0, RTFILE_SEEK_BEGIN, NULL), VINF_SUCCESS);
106 RTTESTI_CHECK_RC_RETV(RTFileRead(hFile, achBuf, cbWrite3, NULL), VINF_SUCCESS);
107 if (memcmp(achBuf, &g_szTestStr2[offWrite3], cbWrite3) != 0)
108 RTTestIFailed("Read back #2 failed (%#zx)", cbWrite3);
109#endif
110}
111
112
113static void tstBasics(RTFILE hFile)
114{
115 RTFOFF cbMax = -2;
116 int rc = RTFileQueryMaxSizeEx(hFile, &cbMax);
117 if (rc != VERR_NOT_IMPLEMENTED)
118 {
119 if (rc != VINF_SUCCESS)
120 RTTestIFailed("RTFileQueryMaxSizeEx failed: %Rrc", rc);
121 else
122 {
123 RTTESTI_CHECK_MSG(cbMax > 0, ("cbMax=%RTfoff", cbMax));
124 RTTESTI_CHECK_MSG(cbMax == RTFileGetMaxSize(hFile),
125 ("cbMax=%RTfoff, RTFileGetMaxSize->%RTfoff", cbMax, RTFileGetMaxSize(hFile)));
126 }
127 }
128
129 uint64_t cbFileSize = _2G + RTRandU32Ex(_1K, _1M); /* Try growing file beyond 2G by default. */
130 if ((uint64_t)s_FsProps.cbFree <= cbFileSize)
131 {
132 RTTestIPrintf(RTTESTLVL_ALWAYS, "Warning: Free disk space less than testcase file size (%RTfoff vs. %RU64), limiting\n",
133 s_FsProps.cbFree, cbFileSize);
134 cbFileSize = s_FsProps.cbFree - _1M; /* Leave a bit of space on the fs. */
135 }
136 /** @todo Also check and clamp for fs max file size limits? */
137 RTTESTI_CHECK_MSG_RETV(cbFileSize, ("No space left on file system (disk full)"));
138
139 rc = RTFileSetSize(hFile, cbFileSize);
140 if (RT_FAILURE(rc))
141 RTTestIFailed("Failed to grow file #1 to %RU64. rc=%Rrc", cbFileSize, rc);
142 else
143 {
144 uint64_t cb;
145 RTTESTI_CHECK_RC(RTFileQuerySize(hFile, &cb), VINF_SUCCESS);
146 RTTESTI_CHECK_MSG(cb == cbFileSize, ("RTFileQuerySize return %RX64 bytes, expected %RX64.", cb, cbFileSize));
147
148 /*
149 * Try some writes at the beginning of the file.
150 */
151 uint64_t offFile = RTFileTell(hFile);
152 RTTESTI_CHECK_MSG(offFile == 0, ("RTFileTell -> %#RX64, expected 0 (#1)", offFile));
153
154 size_t cbWritten = 0;
155 while (cbWritten < sizeof(g_szTestStr))
156 {
157 size_t cbWrittenPart;
158 rc = RTFileWrite(hFile, &g_szTestStr[cbWritten], sizeof(g_szTestStr) - cbWritten, &cbWrittenPart);
159 if (RT_FAILURE(rc))
160 break;
161 cbWritten += cbWrittenPart;
162 }
163 if (RT_FAILURE(rc))
164 RTTestIFailed("Failed to write to file #1 at offset 0. rc=%Rrc\n", rc);
165 else
166 {
167 /* check that it was written correctly. */
168 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_BEGIN, NULL);
169 if (RT_FAILURE(rc))
170 RTTestIFailed("Failed to seek offset 0 in file #1. rc=%Rrc\n", rc);
171 else
172 {
173 char szReadBuf[sizeof(g_szTestStr)];
174 size_t cbRead = 0;
175 while (cbRead < sizeof(g_szTestStr))
176 {
177 size_t cbReadPart;
178 rc = RTFileRead(hFile, &szReadBuf[cbRead], sizeof(g_szTestStr) - cbRead, &cbReadPart);
179 if (RT_FAILURE(rc))
180 break;
181 cbRead += cbReadPart;
182 }
183 if (RT_FAILURE(rc))
184 RTTestIFailed("Failed to read from file #1 at offset 0. rc=%Rrc\n", rc);
185 else
186 {
187 if (!memcmp(szReadBuf, g_szTestStr, sizeof(g_szTestStr)))
188 RTPrintf("tstFile: head write ok\n");
189 else
190 RTTestIFailed("Data read from file #1 at offset 0 differs from what we wrote there.\n");
191 }
192 }
193 }
194
195 /*
196 * Try some writes at the end of the file.
197 */
198 rc = RTFileSeek(hFile, cbFileSize, RTFILE_SEEK_BEGIN, NULL);
199 if (RT_FAILURE(rc))
200 RTTestIFailed("Failed to seek to %RU64 in file #1. rc=%Rrc\n", cbFileSize, rc);
201 else
202 {
203 offFile = RTFileTell(hFile);
204 if (offFile != cbFileSize)
205 RTTestIFailed("RTFileTell -> %#llx, expected %#llx (#2)\n", offFile, cbFileSize);
206 else
207 {
208 cbWritten = 0;
209 while (cbWritten < sizeof(g_szTestStr))
210 {
211 size_t cbWrittenPart;
212 rc = RTFileWrite(hFile, &g_szTestStr[cbWritten], sizeof(g_szTestStr) - cbWritten, &cbWrittenPart);
213 if (RT_FAILURE(rc))
214 break;
215 cbWritten += cbWrittenPart;
216 }
217 if (RT_FAILURE(rc))
218 RTTestIFailed("Failed to write to file #1 at offset %RU64. rc=%Rrc\n", cbFileSize, rc);
219 else
220 {
221 rc = RTFileSeek(hFile, offFile, RTFILE_SEEK_BEGIN, NULL);
222 if (RT_FAILURE(rc))
223 RTTestIFailed("Failed to seek offset %RX64 in file #1. rc=%Rrc\n", offFile, rc);
224 else
225 {
226 char szReadBuf[sizeof(g_szTestStr)];
227 size_t cbRead = 0;
228 while (cbRead < sizeof(g_szTestStr))
229 {
230 size_t cbReadPart;
231 rc = RTFileRead(hFile, &szReadBuf[cbRead], sizeof(g_szTestStr) - cbRead, &cbReadPart);
232 if (RT_FAILURE(rc))
233 break;
234 cbRead += cbReadPart;
235 }
236 if (RT_FAILURE(rc))
237 RTTestIFailed("Failed to read from file #1 at offset %RU64. rc=%Rrc\n", cbFileSize, rc);
238 else
239 {
240 if (!memcmp(szReadBuf, g_szTestStr, sizeof(g_szTestStr)))
241 RTPrintf("tstFile: tail write ok\n");
242 else
243 RTTestIFailed("Data read from file #1 at offset %RU64 differs from what we wrote there.\n",
244 cbFileSize);
245 }
246 }
247 }
248 }
249 }
250
251 /*
252 * Some general seeking around.
253 */
254 RTFOFF offSeek = RTRandS64Ex(0, cbFileSize);
255 rc = RTFileSeek(hFile, offSeek, RTFILE_SEEK_BEGIN, NULL);
256 if (RT_FAILURE(rc))
257 RTTestIFailed("Failed to seek to %RTfoff in file #1. rc=%Rrc\n", offSeek, rc);
258 else
259 {
260 offFile = RTFileTell(hFile);
261 if (offFile != (uint64_t)offSeek)
262 RTTestIFailed("RTFileTell -> %#RTfoff, expected %RTfoff (#3)\n", offFile, offSeek);
263 }
264
265 /* seek end */
266 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL);
267 if (RT_FAILURE(rc))
268 RTTestIFailed("Failed to seek to end of file #1. rc=%Rrc\n", rc);
269 else
270 {
271 offFile = RTFileTell(hFile);
272 if (offFile != cbFileSize + sizeof(g_szTestStr)) /* assuming tail write was ok. */
273 RTTestIFailed("RTFileTell -> %RTfoff, expected %#RX64 (#4)\n", offFile, cbFileSize + sizeof(g_szTestStr));
274 }
275
276 /* seek start */
277 rc = RTFileSeek(hFile, 0, RTFILE_SEEK_BEGIN, NULL);
278 if (RT_FAILURE(rc))
279 RTTestIFailed("Failed to seek to end of file #1. rc=%Rrc\n", rc);
280 else
281 {
282 offFile = RTFileTell(hFile);
283 if (offFile != 0)
284 RTTestIFailed("RTFileTell -> %RTfoff, expected 0 (#5)\n", offFile);
285 }
286 }
287}
288
289int main()
290{
291 RTTEST hTest;
292 RTEXITCODE rcExit = RTTestInitAndCreate("tstRTFile", &hTest);
293 if (rcExit != RTEXITCODE_SUCCESS)
294 return rcExit;
295 RTTestBanner(hTest);
296
297 /*
298 * Query file system sizes first.
299 * This is needed beforehand, so that we don't perform tests which cannot succeed because of known limitations
300 * (too little space, file system maximum file size restrictions, ++).
301 */
302 char szCWD[RTPATH_MAX];
303 int rc = RTPathGetCurrent(szCWD, sizeof(szCWD));
304 RTTESTI_CHECK_MSG(RT_SUCCESS(rc), ("Unable to query current directory, rc=%Rrc", rc));
305 rc = RTFsQuerySizes(szCWD, &s_FsProps.cbTotal, &s_FsProps.cbFree, &s_FsProps.cbBlock, &s_FsProps.cbSector);
306 RTTESTI_CHECK_MSG(RT_SUCCESS(rc), ("Unable to query file system sizes of '%s', rc=%Rrc", szCWD, rc));
307
308 /*
309 * Some basic tests.
310 */
311 RTTestSub(hTest, "Basics");
312 RTFILE hFile = NIL_RTFILE;
313 RTTESTI_CHECK_RC(rc = RTFileOpen(&hFile, "tstFile#1.tst", RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE),
314 VINF_SUCCESS);
315 if (RT_SUCCESS(rc))
316 {
317 tstBasics(hFile);
318 RTTESTI_CHECK_RC(RTFileClose(hFile), VINF_SUCCESS);
319 RTTESTI_CHECK_RC(RTFileDelete("tstFile#1.tst"), VINF_SUCCESS);
320 }
321
322 /*
323 * Test appending & truncation.
324 */
325 RTTestSub(hTest, "Append");
326 hFile = NIL_RTFILE;
327 RTTESTI_CHECK_RC(rc = RTFileOpen(&hFile, "tstFile#2.tst",
328 RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE | RTFILE_O_APPEND),
329 VINF_SUCCESS);
330 if (RT_SUCCESS(rc))
331 {
332 tstAppend(hFile);
333 RTTESTI_CHECK_RC(RTFileClose(hFile), VINF_SUCCESS);
334 RTTESTI_CHECK_RC(RTFileDelete("tstFile#2.tst"), VINF_SUCCESS);
335 }
336
337 /*
338 * Done.
339 */
340 return RTTestSummaryAndDestroy(hTest);
341}
342
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