- Timestamp:
- Nov 8, 2016 6:27:27 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/ValidationKit/testboxscript/TestBoxHelper.cpp
r62484 r64605 31 31 #include <iprt/buildconfig.h> 32 32 #include <iprt/env.h> 33 #include <iprt/file.h> 34 #include <iprt/path.h> 35 #include <iprt/getopt.h> 33 36 #include <iprt/initterm.h> 37 #include <iprt/mem.h> 34 38 #include <iprt/message.h> 35 39 #include <iprt/mp.h> … … 47 51 # include <sys/sysctl.h> 48 52 #endif 53 54 55 56 /** 57 * Does one free space wipe, using the given filename. 58 * 59 * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE on failure (fully 60 * bitched). 61 * @param pszFilename The filename to use for wiping free space. Will be 62 * replaced and afterwards deleted. 63 * @param pvFiller The filler block buffer. 64 * @param cbFiller The size of the filler block buffer. 65 * @param cbMinLeftOpt When to stop wiping. 66 */ 67 static RTEXITCODE doOneFreeSpaceWipe(const char *pszFilename, void const *pvFiller, size_t cbFiller, uint64_t cbMinLeftOpt) 68 { 69 /* 70 * Open the file. 71 */ 72 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 73 RTFILE hFile = NIL_RTFILE; 74 int rc = RTFileOpen(&hFile, pszFilename, 75 RTFILE_O_WRITE | RTFILE_O_DENY_NONE | RTFILE_O_CREATE_REPLACE | (0775 << RTFILE_O_CREATE_MODE_SHIFT)); 76 if (RT_SUCCESS(rc)) 77 { 78 /* 79 * Query the amount of available free space. Figure out which API we should use. 80 */ 81 RTFOFF cbTotal = 0; 82 RTFOFF cbFree = 0; 83 rc = RTFileQueryFsSizes(hFile, &cbTotal, &cbFree, NULL, NULL); 84 bool const fFileHandleApiSupported = rc != VERR_NOT_SUPPORTED && rc != VERR_NOT_IMPLEMENTED; 85 if (!fFileHandleApiSupported) 86 rc = RTFsQuerySizes(pszFilename, &cbTotal, &cbFree, NULL, NULL); 87 if (RT_SUCCESS(rc)) 88 { 89 RTPrintf("%s: %'RTfoff bytes out of %'RTfoff are free\n", pszFilename, cbFree, cbTotal); 90 91 /* 92 * Start filling up the free space, down to the last 32MB. 93 */ 94 RTFOFF const cbMinLeft = RT_MAX(cbMinLeftOpt, cbFiller * 2); 95 RTFOFF cbLeftToWrite = cbFree - cbMinLeft; 96 uint64_t cbWritten = 0; 97 uint32_t iLoop = 0; 98 while (cbLeftToWrite >= (RTFOFF)cbFiller) 99 { 100 rc = RTFileWrite(hFile, pvFiller, cbFiller, NULL); 101 if (RT_FAILURE(rc)) 102 { 103 if (rc == VERR_DISK_FULL) 104 RTPrintf("%s: Disk full after writing %'RU64 bytes\n", pszFilename, cbWritten); 105 else 106 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Write error after %'RU64 bytes: %Rrc\n", 107 pszFilename, cbWritten, rc); 108 break; 109 } 110 111 /* Flush every now and then as we approach a completely full disk. */ 112 if (cbLeftToWrite <= _1G && (iLoop & (cbLeftToWrite > _128M ? 15 : 3)) == 0) 113 RTFileFlush(hFile); 114 115 /* 116 * Advance and maybe recheck the amount of free space. 117 */ 118 cbWritten += cbFiller; 119 cbLeftToWrite -= (ssize_t)cbFiller; 120 iLoop++; 121 if ((iLoop & (16 - 1)) == 0 || cbLeftToWrite < _256M) 122 { 123 RTFOFF cbFreeUpdated; 124 if (fFileHandleApiSupported) 125 rc = RTFsQuerySizes(pszFilename, NULL, &cbFreeUpdated, NULL, NULL); 126 else 127 rc = RTFileQueryFsSizes(hFile, NULL, &cbFreeUpdated, NULL, NULL); 128 if (RT_SUCCESS(rc)) 129 { 130 cbFree = cbFreeUpdated; 131 cbLeftToWrite = cbFree - cbMinLeft; 132 } 133 else 134 { 135 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Failed to query free space after %'RU64 bytes: %Rrc\n", 136 pszFilename, cbWritten, rc); 137 break; 138 } 139 if ((iLoop & (512 - 1)) == 0) 140 RTPrintf("%s: %'RTfoff bytes out of %'RTfoff are free after writing %'RU64 bytes\n", 141 pszFilename, cbFree, cbTotal, cbWritten); 142 } 143 } 144 145 /* 146 * Now flush the file and then reduce the size a little before closing 147 * it so the system won't entirely run out of space. The flush should 148 * ensure the data has actually hit the disk. 149 */ 150 rc = RTFileFlush(hFile); 151 if (RT_FAILURE(rc)) 152 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Flush failed at %'RU64 bytes: %Rrc\n", pszFilename, cbWritten, rc); 153 154 uint64_t cbReduced = cbWritten > _512M ? cbWritten - _512M : cbWritten / 2; 155 rc = RTFileSetAllocationSize(hFile, cbReduced, RTFILE_ALLOC_SIZE_F_DEFAULT); 156 if (RT_FAILURE(rc)) 157 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Failed to reduce file size from %'RU64 to %'RU64 bytes: %Rrc\n", 158 pszFilename, cbWritten, cbReduced, rc); 159 } 160 else 161 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Initial free space query failed: %Rrc \n", pszFilename, rc); 162 163 RTFileClose(hFile); 164 165 /* 166 * Delete the file. 167 */ 168 rc = RTFileDelete(pszFilename); 169 if (RT_FAILURE(rc)) 170 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Delete failed: %Rrc !!\n", pszFilename, rc); 171 } 172 else 173 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Open failed: %Rrc\n", pszFilename, rc); 174 return rcExit; 175 } 176 177 178 /** 179 * Wipes free space on one or more volumes by creating large files. 180 */ 181 static RTEXITCODE handlerWipeFreeSpace(int argc, char **argv) 182 { 183 /* 184 * Parse arguments. 185 */ 186 const char *apszDefFiles[2] = { "./wipefree.spc", NULL }; 187 bool fAll = false; 188 uint32_t u32Filler = UINT32_C(0xf6f6f6f6); 189 uint64_t cbMinLeftOpt = _32M; 190 191 static RTGETOPTDEF const s_aOptions[] = 192 { 193 { "--all", 'a', RTGETOPT_REQ_NOTHING }, 194 { "--filler", 'f', RTGETOPT_REQ_UINT32 }, 195 { "--min-free", 'm', RTGETOPT_REQ_UINT64 }, 196 }; 197 RTGETOPTSTATE State; 198 RTGetOptInit(&State, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); 199 RTGETOPTUNION ValueUnion; 200 int chOpt; 201 while ( (chOpt = RTGetOpt(&State, &ValueUnion)) != 0 202 && chOpt != VINF_GETOPT_NOT_OPTION) 203 { 204 switch (chOpt) 205 { 206 case 'a': 207 fAll = true; 208 break; 209 case 'f': 210 u32Filler = ValueUnion.u32; 211 break; 212 case 'm': 213 cbMinLeftOpt = ValueUnion.u64; 214 break; 215 case 'h': 216 RTPrintf("usage: wipefrespace [options] [filename1 [..]]\n", 217 "\n" 218 "Options:\n" 219 " -a, --all\n" 220 " Try do the free space wiping on all seemingly relevant file systems.\n" 221 " Changes the meaning of the filenames " 222 " This is not yet implemented\n" 223 " -p, --filler <32-bit value>\n" 224 " What to fill the blocks we write with. Default: 0xf6f6f6f6\n" 225 " -m, --min-free <64-bit byte count>\n" 226 " Specifies when to stop in terms of free disk space (in bytes).\n" 227 " Default: 32MB\n" 228 "\n" 229 "Zero or more names of files to do the free space wiping thru can be given.\n" 230 "When --all is NOT used, each of the files are used to do free space wiping on\n" 231 "the volume they will live on. However, when --all is in effect the files are\n" 232 "appended to the volume mountpoints and only the first that can be created will\n" 233 "be used. Files (used ones) will be removed when done.\n" 234 ); 235 return RTEXITCODE_SUCCESS; 236 237 default: 238 return RTGetOptPrintError(chOpt, &ValueUnion); 239 } 240 } 241 242 char **papszFiles; 243 if (chOpt == 0) 244 papszFiles = (char **)apszDefFiles; 245 else 246 papszFiles = RTGetOptNonOptionArrayPtr(&State); 247 248 /* 249 * Allocate and prep a memory which we'll write over and over again. 250 */ 251 uint32_t cbFiller = _2M; 252 uint32_t *pu32Filler = (uint32_t *)RTMemPageAlloc(cbFiller); 253 while (!pu32Filler) 254 { 255 cbFiller <<= 1; 256 if (cbFiller >= _4K) 257 pu32Filler = (uint32_t *)RTMemPageAlloc(cbFiller); 258 else 259 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTMemPageAlloc failed for sizes between 4KB and 2MB!\n"); 260 } 261 for (uint32_t i = 0; i < cbFiller / sizeof(pu32Filler[0]); i++) 262 pu32Filler[i] = u32Filler; 263 264 /* 265 * Do the requested work. 266 */ 267 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 268 if (!fAll) 269 { 270 for (uint32_t iFile = 0; papszFiles[iFile] != NULL; iFile++) 271 { 272 RTEXITCODE rcExit2 = doOneFreeSpaceWipe(papszFiles[iFile], pu32Filler, cbFiller, cbMinLeftOpt); 273 if (rcExit2 != RTEXITCODE_SUCCESS && rcExit == RTEXITCODE_SUCCESS) 274 rcExit = rcExit2; 275 } 276 } 277 else 278 { 279 /* 280 * Reject --all for now. 281 */ 282 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "The --all option is not yet implemented!\n"); 283 } 284 285 RTMemPageFree(pu32Filler, cbFiller); 286 return rcExit; 287 } 49 288 50 289 … … 395 634 { "longmode", handlerCpuLongMode, true }, 396 635 { "memsize", handlerMemSize, true }, 397 { "report", handlerReport, true } 636 { "report", handlerReport, true }, 637 { "wipefreespace", handlerWipeFreeSpace, false } 398 638 }; 399 639
Note:
See TracChangeset
for help on using the changeset viewer.