// 2>/dev/null; set -e; X=${0%.c} ; [ "$X" -nt "$0" ] || gcc -s -o "$X" -D_FILE_OFFSET_BITS=64 -Wall -O3 "$0" && hide "$X"; exec "$X" "$@" #include #include #include #include #include #include #include #include #include #include // Yeah ... I really need a C library like libb. // Use ccan and contribute to ccan. size_t bs = 4096; #define check_need_nl() if (need_nl) { fprintf(stderr, "\n"); need_nl = 0; } int main(int argc, char **argv) { if (argc != 2 || argv[1][0] == '-') { char *prog = basename(strdup(argv[0])); fprintf(stderr, "usage: %s badfile\n", prog); exit(1); } char *file = argv[1]; int fd = open(file, O_RDWR); if (fd == -1) { perror("open"); exit(1); } struct stat st; if (fstat(fd, &st) == -1) { perror("fstat"); exit(1); } off_t size = st.st_size; char buf[bs]; char zero[bs]; memset(zero, 0, bs); int mod = 0; off_t pos = 0; int perc, perc0 = -1; int need_nl = 0; for(;;) { perc = (int)(100*pos/size); if (perc != perc0) { fprintf(stderr, "\r%d%% ", perc); perc0 = perc; need_nl = 1; } if (pos+bs > size) { bs = size - pos; } size_t len = read(fd, buf, bs); if (len == 0) break; if (len == -1) { if (errno != EIO) { check_need_nl(); perror("read"); exit(1); } check_need_nl(); fprintf(stderr, "bad block at offset %jd, overwriting with %zd byte zero block\n", (intmax_t)pos, bs); if (lseek(fd, pos, SEEK_SET) == -1) { check_need_nl(); perror("lseek"); exit(1); } if (write(fd, zero, bs) == -1) { check_need_nl(); perror("write"); exit(1); } mod = 1; len = bs; } if (len != bs) { check_need_nl(); fprintf(stderr, "read did not return expected number of bytes: %zd vs %zd at %jd - quitting\n", len, bs, (intmax_t)pos); } pos += len; } check_need_nl(); if (mod && fsync(fd) == -1) { perror("fsync"); exit(1); } exit(0); }