Skip to content

Instantly share code, notes, and snippets.

@divinity76
Last active January 28, 2021 02:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save divinity76/e0f22d6da40fd2b78b7f3888a037533f to your computer and use it in GitHub Desktop.
Save divinity76/e0f22d6da40fd2b78b7f3888a037533f to your computer and use it in GitHub Desktop.
<?php
declare (strict_types = 1);
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
// INSTEAD USE https://gist.github.com/divinity76/605547aa19d244c5bd6016cc5d7f2402
const SECTOR_SIZE=512;
if ($argc !== 2) {
die("usage: {$argv[0]} '/dev/usb'\n");
}
$handle = fopen($argv[1], "r+b");
if (!$handle) {
die("error: unable to open input file \"{$argv[1]}\"");
}
$error_count = 0;
$size = get_size($argv[1]);
$mb = $size / 1024 / 1024;
$gb = $mb / 1024;
echo "apparent size: {$mb} megabytes aka {$gb} gigabytes, i hope that is correct. - ", PHP_EOL;
if (true) {
echo "first running overwrite-everything:\n";
mt_srand(1337);
$starttime=microtime(true);
for ($i = 0; $i < $size;) {
$start=microtime(true);
$buf = '';
for ($bsize = 0, $count = min(SECTOR_SIZE, $size - $i); $bsize < $count; ++$bsize) {
$buf .= chr(mt_rand(0, 255));
}
fwrite_all($handle, $buf);
$i += strlen($buf);
echo "\r",number_format($i/1024/1024,3),"MB total, ",number_format(($i/$size)*100,5),"% - right now: ", number_format((strlen($buf)/(microtime(true)-$start)) /1024/1024,3),"MB/s, total average: ",number_format(($i/(microtime(true)-$starttime))/1024/1024,3),"MB/s";
}
echo "\n";
}
echo "all data written! ... flushing..";
fflush($handle);
rewind($handle);
echo ". done. attempting dropcaches..";
if (!is_writable('/proc/sys/vm/drop_caches')) {
echo " failed because /proc/sys/vm/drop_caches is not writable.\n";
} elseif (2 !== file_put_contents("/proc/sys/vm/drop_caches", "3\n")) {
echo "failed because could not write 3.\n";
} else {
echo ". success!\n";
}
if (true) {
echo "now verifying..";
mt_srand(1337);
$starttime=microtime(true);
$corrupted_bytes=0;
$corrupted_bytes_total=0;
$corrupted_sectors=array();
for ($i = 0; $i < $size;) {
$start=microtime(true);
$buf = '';
for ($bsize = 0, $count = min(SECTOR_SIZE, $size - $i); $bsize < $count; ++$bsize) {
$buf .= chr(mt_rand(0, 255));
}
$read = fread_all($handle, strlen($buf));
if (!my_compare($buf,$read,$corrupted_bytes)) {
echo "\rERROR at sector ".floor($i/512).": {$corrupted_bytes} corrupted bytes! \n";
++$error_count;
$corrupted_bytes_total+=$corrupted_bytes;
$corrupted_sectors[(int)floor($i/512)]=true;
}
$i += strlen($read);
assert(strlen($read) === strlen($buf));
echo "\r",number_format($i/1024/1024,3),"MB total, ",number_format(($i/$size)*100,5),"% - right now: ", number_format((strlen($buf)/(microtime(true)-$start)) /1024/1024,3),"MB/s, total average: ",number_format(($i/(microtime(true)-$starttime))/1024/1024,3),"MB/s";
}
echo "\n";
}
$corrupted_sectors=array_keys($corrupted_sectors);
echo "verification finished! total corrupted sectors: {$error_count} total corrupted bytes: {$corrupted_bytes}\n";
echo "list of corrupted sectors: ";
print_r($corrupted_sectors);
var_dump($error_count);
function my_compare(string $s1,string $s2, int &$incorrect_bytes=0):bool{
$incorrect_bytes=0;
$s1len=strlen($s1);
$s2len=strlen($s2);
$max=min($s1len,$s2len);
if($s1len!==$s2len){
$incorrect_bytes+=abs($s1len-$s2len);
}
for($i=0;$i<$max;++$i){
if($s1[$i]!==$s2[$i]){
++$incorrect_bytes;
}
}
return ($incorrect_bytes===0);
}
/**
* writes all data or throws
*
* @param mixed $handle
* @param string $data
* @throws \RuntimeException when fwrite returned <1 but still more data to write
* @return void
*/
function fwrite_all($handle, string $data): void
{
$original_len = strlen($data);
if ($original_len > 0) {
$len = $original_len;
$written_total = 0;
for (;;) {
$written_now = fwrite($handle, $data);
if ($written_now === $len) {
return;
}
if ($written_now < 1) {
throw new \RuntimeException("could only write {$written_total}/{$original_len} bytes!");
}
$written_total += $written_now;
$data = substr($data, $written_now);
$len -= $written_now;
// assert($len > 0);
// assert($len === strlen($data));
}
}
}
function get_size(string $path): int
{
$fp = fopen($path, "rb");
if (!$fp) {
throw new \RuntimeException("error: unable to open input file \"{$path[1]}\" for reading!");
}
fseek($fp, 0, SEEK_END);
$ret = ftell($fp);
fclose($fp);
if (empty($ret) || $ret < 2) {
throw new \RuntimeException("unable to get size of file! (ftell() returned bogus value {$ret})");
}
return $ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment