/** * Does one free space wipe, using the given filename. * * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE on failure (fully * bitched). * @param pszFilename The filename to use for wiping free space. Will be * replaced and afterwards deleted. * @param pvFiller The filler block buffer. * @param cbFiller The size of the filler block buffer. * @param cbMinLeftOpt When to stop wiping. */ static RTEXITCODE doOneFreeSpaceWipe(const char *pszFilename, void const *pvFiller, size_t cbFiller, uint64_t cbMinLeftOpt) { /* * Open the file. */ RTEXITCODE rcExit = RTEXITCODE_SUCCESS; RTFILE hFile = NIL_RTFILE; int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_WRITE | RTFILE_O_DENY_NONE | RTFILE_O_CREATE_REPLACE | (0775 << RTFILE_O_CREATE_MODE_SHIFT)); if (RT_SUCCESS(rc)) { /* * Query the amount of available free space. Figure out which API we should use. */ RTFOFF cbTotal = 0; RTFOFF cbFree = 0; rc = RTFileQueryFsSizes(hFile, &cbTotal, &cbFree, NULL, NULL); bool const fFileHandleApiSupported = rc != VERR_NOT_SUPPORTED && rc != VERR_NOT_IMPLEMENTED; if (!fFileHandleApiSupported) rc = RTFsQuerySizes(pszFilename, &cbTotal, &cbFree, NULL, NULL); if (RT_SUCCESS(rc)) { RTPrintf("%s: %'9RTfoff MiB out of %'9RTfoff are free\n", pszFilename, cbFree / _1M, cbTotal / _1M); /* * Start filling up the free space, down to the last 32MB. */ uint64_t const nsStart = RTTimeNanoTS(); /* for speed calcs */ uint64_t nsStat = nsStart; /* for speed calcs */ uint64_t cbStatWritten = 0; /* for speed calcs */ RTFOFF const cbMinLeft = RT_MAX(cbMinLeftOpt, cbFiller * 2); RTFOFF cbLeftToWrite = cbFree - cbMinLeft; uint64_t cbWritten = 0; uint32_t iLoop = 0; while (cbLeftToWrite >= (RTFOFF)cbFiller) { rc = RTFileWrite(hFile, pvFiller, cbFiller, NULL); if (RT_FAILURE(rc)) { if (rc == VERR_DISK_FULL) RTPrintf("%s: Disk full after writing %'9RU64 MiB\n", pszFilename, cbWritten / _1M); else rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Write error after %'RU64 bytes: %Rrc\n", pszFilename, cbWritten, rc); break; } /* Flush every now and then as we approach a completely full disk. */ if (cbLeftToWrite <= _1G && (iLoop & (cbLeftToWrite > _128M ? 15 : 3)) == 0) RTFileFlush(hFile); /* * Advance and maybe recheck the amount of free space. */ cbWritten += cbFiller; cbLeftToWrite -= (ssize_t)cbFiller; iLoop++; if ((iLoop & (16 - 1)) == 0 || cbLeftToWrite < _256M) { RTFOFF cbFreeUpdated; if (fFileHandleApiSupported) rc = RTFileQueryFsSizes(hFile, NULL, &cbFreeUpdated, NULL, NULL); else rc = RTFsQuerySizes(pszFilename, NULL, &cbFreeUpdated, NULL, NULL); if (RT_SUCCESS(rc)) { cbFree = cbFreeUpdated; cbLeftToWrite = cbFree - cbMinLeft; } else { rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Failed to query free space after %'RU64 bytes: %Rrc\n", pszFilename, cbWritten, rc); break; } if ((iLoop & (512 - 1)) == 0) { uint64_t const nsNow = RTTimeNanoTS(); uint64_t cNsInterval = nsNow - nsStat; uint64_t cbInterval = cbWritten - cbStatWritten; uint64_t cbIntervalPerSec = cbInterval ? (uint64_t)(cbInterval / (cNsInterval / (double)RT_NS_1SEC)) : 0; RTPrintf("%s: %'9RTfoff MiB out of %'9RTfoff are free after writing %'9RU64 MiB (%'5RU64 MiB/s)\n", pszFilename, cbFree / _1M, cbTotal / _1M, cbWritten / _1M, cbIntervalPerSec / _1M); nsStat = nsNow; cbStatWritten = cbWritten; } } } /* * Now flush the file and then reduce the size a little before closing * it so the system won't entirely run out of space. The flush should * ensure the data has actually hit the disk. */ rc = RTFileFlush(hFile); if (RT_FAILURE(rc)) rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Flush failed at %'RU64 bytes: %Rrc\n", pszFilename, cbWritten, rc); uint64_t cbReduced = cbWritten > _512M ? cbWritten - _512M : cbWritten / 2; rc = RTFileSetSize(hFile, cbReduced); if (RT_FAILURE(rc)) rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Failed to reduce file size from %'RU64 to %'RU64 bytes: %Rrc\n", pszFilename, cbWritten, cbReduced, rc); /* Issue a summary statements. */ uint64_t cNsElapsed = RTTimeNanoTS() - nsStart; uint64_t cbPerSec = cbWritten ? (uint64_t)(cbWritten / (cNsElapsed / (double)RT_NS_1SEC)) : 0; RTPrintf("%s: Wrote %'RU64 MiB in %'RU64 s, avg %'RU64 MiB/s.\n", pszFilename, cbWritten / _1M, cNsElapsed / RT_NS_1SEC, cbPerSec / _1M); } else rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Initial free space query failed: %Rrc \n", pszFilename, rc); RTFileClose(hFile); /* * Delete the file. */ rc = RTFileDelete(pszFilename); if (RT_FAILURE(rc)) rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Delete failed: %Rrc !!\n", pszFilename, rc); } else rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Open failed: %Rrc\n", pszFilename, rc); return rcExit; }
int main(int argc, char **argv) { RTR3InitExe(argc, &argv, 0); /* * Process all arguments (including the executable). */ int cErrors = 0; for (int i = 0; i < argc; i++) { RTPrintf("tstRTFsQueries: '%s'...\n", argv[i]); uint32_t u32Serial; int rc = RTFsQuerySerial(argv[i], &u32Serial); if (RT_SUCCESS(rc)) RTPrintf("tstRTFsQueries: u32Serial=%#010RX32\n", u32Serial); else { RTPrintf("tstRTFsQueries: RTFsQuerySerial failed, rc=%Rrc\n", rc); cErrors++; } RTFOFF cbTotal = 42; RTFOFF cbFree = 42; uint32_t cbBlock = 42; uint32_t cbSector = 42; rc = RTFsQuerySizes(argv[i], &cbTotal, &cbFree, &cbBlock, &cbSector); if (RT_SUCCESS(rc)) RTPrintf("tstRTFsQueries: cbTotal=%RTfoff cbFree=%RTfoff cbBlock=%d cbSector=%d\n", cbTotal, cbFree, cbBlock, cbSector); else { RTPrintf("tstRTFsQueries: RTFsQuerySerial failed, rc=%Rrc\n", rc); cErrors++; } rc = RTFsQuerySizes(argv[i], NULL, NULL, NULL, NULL); if (RT_FAILURE(rc)) { RTPrintf("tstRTFsQueries: RTFsQuerySizes(nop) failed, rc=%Rrc\n", rc); cErrors++; } RTFSTYPE enmType; rc = RTFsQueryType(argv[i], &enmType); if (RT_SUCCESS(rc)) RTPrintf("tstRTFsQueries: file system type is '%s'\n", RTFsTypeName(enmType)); else { RTPrintf("tstRTFsQueries: RTFsQueryType failed, rc=%Rrc\n", rc); cErrors++; } RTFSPROPERTIES Props; rc = RTFsQueryProperties(argv[i], &Props); if (RT_SUCCESS(rc)) RTPrintf("tstRTFsQueries: cbMaxComponent=%u %s %s %s %s %s %s\n", Props.cbMaxComponent, Props.fCaseSensitive ? "case" : "not-case", Props.fCompressed ? "compressed" : "not-compressed", Props.fFileCompression ? "file-compression" : "no-file-compression", Props.fReadOnly ? "readonly" : "readwrite", Props.fRemote ? "remote" : "not-remote", Props.fSupportsUnicode ? "supports-unicode" : "doesn't-support-unicode"); else { RTPrintf("tstRTFsQueries: RTFsQueryProperties failed, rc=%Rrc\n", rc); cErrors++; } } if (!cErrors) RTPrintf("tstRTFsQueries: SUCCESS\n"); else RTPrintf("tstRTFsQueries: FAIlURE - %u errors\n", cErrors); return !!cErrors; }