pax_global_header00006660000000000000000000000064132066305040014511gustar00rootroot0000000000000052 comment=dee2a93a34c4342eb91b131c8a6c12409f502604 holes-0.1/000077500000000000000000000000001320663050400124635ustar00rootroot00000000000000holes-0.1/Makefile000066400000000000000000000006671320663050400141340ustar00rootroot00000000000000ALL=holes CFLAGS=-g -O2 -Wall -Wno-switch -Wextra -Wwrite-strings DESTDIR= PREFIX=/usr/local BINDIR=$(PREFIX)/bin MANDIR=$(PREFIX)/share/man all: $(ALL) README: holes.1 mandoc -Tutf8 $< | col -bx >$@ clean: FRC rm -f $(ALL) check: FRC all prove -v ./tests install: FRC all mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1 install -m0755 $(ALL) $(DESTDIR)$(BINDIR) install -m0644 $(ALL:=.1) $(DESTDIR)$(MANDIR)/man1 FRC: holes-0.1/README000066400000000000000000000025721320663050400133510ustar00rootroot00000000000000HOLES(1) General Commands Manual HOLES(1) NAME holes – find runs of zero bytes SYNOPSIS holes [-b byte] [-n minlen] [-s] [files ...] DESCRIPTION holes looks for runs of zero bytes (a.k.a. holes) in the specified input files (or the standard input), and prints the start addresses (in hexadecimal) as well as the lengths (in decimal). When multiple input files are specified, holes prefixes each line with the file name. The options are as follows: -b byte Count runs of byte, a number between 0 and 255, instead of zero bytes. -n minlen Change minimum size of holes reported. By default, only holes of at least 64 bytes are reported. -s Print a summary at the end how many percent of the file are runs of zeroes. EXIT STATUS The holes utility exits 0 on success, and >0 if an error occurs. SEE ALSO fallocate(1), truncate(1), virt-sparsify(1) AUTHORS Leah Neukirchen LICENSE holes is in the public domain. To the extent possible under law, the creator of this work has waived all copyright and related or neighboring rights to this work. http://creativecommons.org/publicdomain/zero/1.0/ Void Linux November 8, 2017 Void Linux holes-0.1/holes.1000066400000000000000000000022341320663050400136600ustar00rootroot00000000000000.Dd November 8, 2017 .Dt HOLES 1 .Os .Sh NAME .Nm holes .Nd find runs of zero bytes .Sh SYNOPSIS .Nm .Op Fl b Ar byte .Op Fl n Ar minlen .Op Fl s .Op Ar files\ ... .Sh DESCRIPTION .Nm looks for runs of zero bytes (a.k.a. holes) in the specified input files (or the standard input), and prints the start addresses (in hexadecimal) as well as the lengths (in decimal). When multiple input files are specified, .Nm prefixes each line with the file name. .Pp The options are as follows: .Bl -tag -width Ds .It Fl b Ar byte Count runs of .Ar byte , a number between 0 and 255, instead of zero bytes. .It Fl n Ar minlen Change minimum size of holes reported. By default, only holes of at least 64 bytes are reported. .It Fl s Print a summary at the end how many percent of the file are runs of zeroes. .El .Sh EXIT STATUS .Ex -std .Sh SEE ALSO .Xr fallocate 1 , .Xr truncate 1 , .Xr virt-sparsify 1 .Sh AUTHORS .An Leah Neukirchen Aq Mt leah@vuxu.org .Sh LICENSE .Nm is in the public domain. .Pp To the extent possible under law, the creator of this work has waived all copyright and related or neighboring rights to this work. .Pp .Lk http://creativecommons.org/publicdomain/zero/1.0/ holes-0.1/holes.c000066400000000000000000000050141320663050400137410ustar00rootroot00000000000000/* holes - find holes (= runs of zero bytes) in input files */ #include #include #include #include #include ssize_t minlen = 64; char byte = 0; int ret = 0; char *argv0; ssize_t total, totalz; void holes(FILE *input, char *filename) { off_t offset = 0; off_t run = 0; static char buf[16384]; int len; int i; char *d; while ((len = fread(buf, 1, sizeof buf, input)) >= 1) { if (run == 0) { d = memchr(buf, byte, len); if (!d) { offset += len; continue; } i = d - buf; offset += i; } else { i = 0; } for (; i < len; i++) { if (buf[i] == byte) { run++; } else { if (run >= minlen) { if (filename) printf("%s: ", filename); printf("%08lx %ld\n", offset - run, run); totalz += run; } run = 0; } offset++; } } if (ferror(input)) { fprintf(stderr, "%s: can't read '%s': %s\n", argv0, filename ? filename : "-", strerror(errno)); ret = 1; return; } if (offset == 0 || // empty file run >= minlen) { if (filename) printf("%s: ", filename); printf("%08lx %ld\n", offset - run, run); totalz += run; } total += offset; } int main(int argc, char *argv[]) { int c, i; long b; char *e; int sflag = 0; argv0 = argv[0]; while ((c = getopt(argc, argv, "b:n:s")) != -1) switch (c) { case 'b': errno = 0; b = strtol(optarg, &e, 0); if (errno != 0 || *e || b < 0 || b > 256) { fprintf(stderr, "%s: can't parse byte '%s'.\n", argv0, optarg); exit(2); } byte = b; break; case 'n': errno = 0; minlen = strtoll(optarg, &e, 0); if (errno != 0 || *e) { fprintf(stderr, "%s: can't parse length '%s'.\n", argv0, optarg); exit(2); } if (minlen < 1) { fprintf(stderr, "%s: MINLEN must not be smaller than 1.\n", argv0); exit(2); } break; case 's': sflag++; break; default: fprintf(stderr, "Usage: %s [-b BYTE] [-n MINLEN] [-s] [FILES...]\n", argv0); exit(2); } if (optind == argc) holes(stdin, 0); else for (i = optind; i < argc; i++) { FILE *input = (strcmp(argv[i], "-") == 0) ? stdin : fopen(argv[i], "rb"); if (!input) { fprintf(stderr, "%s: can't open file '%s': %s\n", argv0, argv[i], strerror(errno)); ret = 1; } else { holes(input, argc - optind > 1 ? argv[i] : 0); } } if (sflag) printf("total %jd/%jd (%.2f%%)\n", totalz, total, total == 0 ? 0.0 : 100.0*totalz / total); return ret; } holes-0.1/tests000066400000000000000000000034101320663050400135460ustar00rootroot00000000000000#!/bin/sh printf '1..10\n' set -e holes() { "${HOLES:-./holes}" "$@"; } zeroes() { dd if=/dev/zero bs=${2:-1} count=$1 2>/dev/null; } nonzeroes() { zeroes $1 $2 | tr '\0' x; } check_output() { msg=$1 expected="$(cat)" shift if output="$(eval "$@" 2>&1)"; then if [ "$output" = "$expected" ]; then printf 'ok - %s\n' "$msg" return fi fi printf 'not ok - %s\n' "$msg" if [ "$output" != "$expected" ]; then printf 'Unexpected output:\n%s\n' "$output" | sed 's/^/# /' fi } check_output 'no hole' 'echo foobar | holes' <