Merge remote-tracking branch 'toybox/master' into HEAD
diff --git a/toys/other/shred.c b/toys/other/shred.c
new file mode 100644
index 0000000..07d62c3
--- /dev/null
+++ b/toys/other/shred.c
@@ -0,0 +1,104 @@
+/* shred.c - Overwrite a file to securely delete
+ *
+ * Copyright 2014 Rob Landley <rob@landley.net>
+ *
+ * No standard
+
+USE_SHRED(NEWTOY(shred, "<1zxus#<1n#<1o#<0f", TOYFLAG_USR|TOYFLAG_BIN))
+
+config SHRED
+ bool "shred"
+ default n
+ help
+ usage: shred [-fuz] [-n COUNT] [-s SIZE] FILE...
+
+ Securely delete a file by overwriting its contents with random data.
+
+ -f Force (chmod if necessary)
+ -n COUNT Random overwrite iterations (default 1)
+ -o OFFSET Start at OFFSET
+ -s SIZE Use SIZE instead of detecting file size
+ -u unlink (actually delete file when done)
+ -x Use exact size (default without -s rounds up to next 4k)
+ -z zero at end
+
+ Note: data journaling filesystems render this command useless, you must
+ overwrite all free space (fill up disk) to erase old data on those.
+*/
+
+#define FOR_shred
+#include "toys.h"
+
+GLOBALS(
+ long offset;
+ long iterations;
+ long size;
+
+ int ufd;
+)
+
+void shred_main(void)
+{
+ char **try;
+
+ if (!(toys.optflags & FLAG_n)) TT.iterations++;
+ TT.ufd = xopen("/dev/urandom", O_RDONLY);
+
+ // We don't use loopfiles() here because "-" isn't stdin, and want to
+ // respond to files we can't open via chmod.
+
+ for (try = toys.optargs; *try; try++) {
+ off_t pos = 0, len = TT.size;
+ int fd = open(*try, O_RDWR), iter = 0, throw;
+
+ // do -f chmod if necessary
+ if (fd == -1 && (toys.optflags & FLAG_f)) {
+ chmod(*try, 0600);
+ fd = open(*try, O_RDWR);
+ }
+ if (fd == -1) {
+ perror_msg("%s", *try);
+ continue;
+ }
+
+ // determine length
+ if (!len) len = fdlength(fd);
+ if (len<1) {
+ error_msg("%s: needs -s", *try);
+ close(fd);
+ continue;
+ }
+
+ // Loop through, writing to this file
+ for (;;) {
+ // Advance to next -n or -z?
+
+ if (pos >= len) {
+ pos = -1;
+ if (++iter == TT.iterations && (toys.optargs && FLAG_z)) {
+ memset(toybuf, 0, sizeof(toybuf));
+ continue;
+ }
+ if (iter >= TT.iterations) break;
+ }
+
+ if (pos < TT.offset) {
+ if (TT.offset != lseek(fd, TT.offset, SEEK_SET)) {
+ perror_msg("%s", *try);
+ break;
+ }
+ pos = TT.offset;
+ }
+
+ // Determine length, read random data if not zeroing, write.
+
+ throw = sizeof(toybuf);
+ if (toys.optflags & FLAG_x)
+ if (len-pos < throw) throw = len-pos;
+
+ if (iter != TT.iterations) xread(TT.ufd, toybuf, throw);
+ if (throw != writeall(fd, toybuf, throw)) perror_msg("%s");
+ pos += throw;
+ }
+ }
+}
diff --git a/toys/other/vmstat.c b/toys/other/vmstat.c
index 49c7cc7..eed7945 100644
--- a/toys/other/vmstat.c
+++ b/toys/other/vmstat.c
@@ -84,11 +84,13 @@
if (toys.optc) loop_delay = atolx_range(toys.optargs[0], 0, INT_MAX);
if (toys.optc > 1) loop_max = atolx_range(toys.optargs[1], 1, INT_MAX) - 1;
- for (loop = 0; loop <= loop_max; loop++) {
+ for (loop = 0; !loop_max || loop <= loop_max; loop++) {
unsigned idx = loop&1, offset = 0, expected = 0;
uint64_t units, total_hz, *ptr = (uint64_t *)(top+idx),
*oldptr = (uint64_t *)(top+!idx);
+ if (loop && loop_delay) sleep(loop_delay);
+
// Print headers
if (rows>3 && !(loop % (rows-3))) {
if (isatty(1)) terminal_size(0, &rows);
@@ -147,7 +149,6 @@
}
xputc('\n');
- if (loop_delay) sleep(loop_delay);
- else break;
+ if (!loop_delay) break;
}
}
diff --git a/toys/pending/compress.c b/toys/pending/compress.c
index b79699d..45251fc 100644
--- a/toys/pending/compress.c
+++ b/toys/pending/compress.c
@@ -130,10 +130,10 @@
// Compressed data buffer
char *data;
unsigned pos, len;
- int fd;
+ int infd, outfd;
// Tables only used for deflation
- unsigned short *head, *chain;
+ unsigned short *hashhead, *hashchain;
)
// little endian bit buffer
@@ -145,9 +145,8 @@
// malloc a struct bitbuf
struct bitbuf *bitbuf_init(int fd, int size)
{
- struct bitbuf *bb = xmalloc(sizeof(struct bitbuf)+size);
+ struct bitbuf *bb = xzalloc(sizeof(struct bitbuf)+size);
- memset(bb, 0, sizeof(struct bitbuf));
bb->max = size;
bb->fd = fd;
@@ -204,13 +203,42 @@
return result;
}
+void bitbuf_flush(struct bitbuf *bb)
+{
+ if (!bb->bitpos) return;
+
+ xwrite(bb->fd, bb->buf, (bb->bitpos+7)/8);
+ memset(bb->buf, 0, bb->max);
+ bb->bitpos = 0;
+}
+
+void bitbuf_put(struct bitbuf *bb, int data, int len)
+{
+ while (len) {
+ int click = bb->bitpos >> 3, blow, blen;
+
+ // Flush buffer if necessary
+ if (click == bb->max) {
+ bitbuf_flush(bb);
+ click = 0;
+ }
+ blow = bb->bitpos & 7;
+ blen = 8-blow;
+ if (blen > len) blen = len;
+ bb->buf[click] |= data << blow;
+ bb->bitpos += blen;
+ data >>= blen;
+ len -= blen;
+ }
+}
+
static void data_crc(char sym)
{
TT.data[TT.pos++ & 32767] = sym;
if (!(TT.pos & 32767)) {
- xwrite(TT.fd, TT.data, 32768);
- if (TT.crcfunc) TT.crcfunc(0, 32768);
+ xwrite(TT.outfd, TT.data, 32768);
+ if (TT.crcfunc) TT.crcfunc(TT.data, 32768);
}
}
@@ -245,9 +273,9 @@
}
// Fetch and decode next huffman coded symbol from bitbuf.
-// This takes advantage of the the sorting to navigate the tree as an array:
+// This takes advantage of the sorting to navigate the tree as an array:
// each time we fetch a bit we have all the codes at that bit level in
-// order with no gaps..
+// order with no gaps.
static unsigned huff_and_puff(struct bitbuf *bb, struct huff *huff)
{
unsigned short *length = huff->length;
@@ -264,36 +292,7 @@
return huff->symbol[start + offset];
}
-// Deflate from TT.fd to bitbuf
-// For deflate, TT.len = input read, TT.pos = input consumed
-static void deflate(struct bitbuf *bb)
-{
- char *data = TT.data;
- int len, end = 0;
-
- TT.crc = ~0;
-
- while (!end) {
- // Read next half-window of data if we haven't hit EOF yet.
- len = readall(TT.fd, data + (TT.len & 32768), 32768);
-fprintf(stderr, "read %d@%d\n", len, TT.pos);
- if (len < 0) perror_exit("read"); // todo: add filename
- if (len != 32768) end++;
- TT.len += len;
-
- // repeat until spanked
- while (TT.pos != TT.len) {
- unsigned pos = TT.pos & 65535;
-
- if (!(pos & 32767) && !end) break;
-
- TT.pos++;
- }
- }
-fprintf(stderr, "total %d\n", TT.pos);
-}
-
-// Decompress deflated data from bitbuf to TT.fd.
+// Decompress deflated data from bitbuf to TT.outfd.
static void inflate(struct bitbuf *bb)
{
TT.crc = ~0;
@@ -408,23 +407,60 @@
}
if (TT.pos & 32767) {
- xwrite(TT.fd, TT.data, TT.pos & 32767);
- if (TT.crcfunc) TT.crcfunc(0, TT.pos & 32767);
+ xwrite(TT.outfd, TT.data, TT.pos & 32767);
+ if (TT.crcfunc) TT.crcfunc(TT.data, TT.pos & 32767);
}
}
+// Deflate from TT.infd to bitbuf
+// For deflate, TT.len = input read, TT.pos = input consumed
+static void deflate(struct bitbuf *bb)
+{
+ char *data = TT.data;
+ int len, final = 0;
+
+ TT.crc = ~0;
+
+ while (!final) {
+ // Read next half-window of data if we haven't hit EOF yet.
+ len = readall(TT.infd, data+(TT.len&32768), 32768);
+ if (len < 0) perror_exit("read"); // todo: add filename
+ if (len != 32768) final++;
+ if (TT.crcfunc) TT.crcfunc(data+(TT.len&32768), len);
+ // TT.len += len; crcfunc advances len
+
+ // store block as literal
+ bitbuf_put(bb, final, 1);
+ bitbuf_put(bb, 0, 1);
+
+ bitbuf_put(bb, 0, (8-bb->bitpos)&7);
+ bitbuf_put(bb, len, 16);
+ bitbuf_put(bb, 0xffff & ~len, 16);
+
+ // repeat until spanked
+ while (TT.pos != TT.len) {
+ unsigned pos = TT.pos & 65535;
+
+ bitbuf_put(bb, data[pos], 8);
+
+ // need to refill buffer?
+ if (!(32767 & ++TT.pos) && !final) break;
+ }
+ }
+ bitbuf_flush(bb);
+}
+
// Allocate memory for deflate/inflate.
static void init_deflate(int compress)
{
int i, n = 1;
-// only supporting HASH_SIZE = 1 << 15, I.E. size = 32768
-
- // Ye olde deflate window
- TT.data = xmalloc(32768*(compress+1));
+ // compress needs 64k data and 32k each for hashhead and hashchain.
+ // decompress just needs 32k data.
+ TT.data = xmalloc(32768*(compress ? 4 : 1));
if (compress) {
- TT.head = (unsigned short *)(TT.data+65536);
- TT.chain = TT.head + 0;
+ TT.hashhead = (unsigned short *)(TT.data + 65536);
+ TT.hashchain = (unsigned short *)(TT.data + 65536 + 32768);
}
// Calculate lenbits, lenbase, distbits, distbase
@@ -480,12 +516,12 @@
unsigned crc, *crc_table = (unsigned *)(toybuf+sizeof(toybuf)-1024);
crc = TT.crc;
- for (i=0; i<len; i++) crc = crc_table[(crc^TT.data[i])&0xff] ^ (crc>>8);
+ for (i=0; i<len; i++) crc = crc_table[(crc^data[i])&0xff] ^ (crc>>8);
TT.crc = crc;
TT.len += len;
}
-static void do_compress(int fd, char *name)
+static void do_gzip(int fd, char *name)
{
struct bitbuf *bb = bitbuf_init(1, sizeof(toybuf));
@@ -494,10 +530,22 @@
// 4 byte MTIME (zeroed), Extra Flags (2=maximum compression),
// Operating System (FF=unknown)
- xwrite(1, "\x1f\x8b\x08\0\0\0\0\0\x02\xff", 10);
+ TT.infd = fd;
+ xwrite(bb->fd, "\x1f\x8b\x08\0\0\0\0\0\x02\xff", 10);
+
+ // Use last 1k of toybuf for little endian crc table
+ crc_init((unsigned *)(toybuf+sizeof(toybuf)-1024), 1);
+ TT.crcfunc = gzip_crc;
deflate(bb);
+ // tail: crc32, len32
+
+ bitbuf_put(bb, 0, (8-bb->bitpos)&7);
+ bitbuf_put(bb, ~TT.crc, 32);
+ bitbuf_put(bb, TT.len, 32);
+
+ bitbuf_flush(bb);
free(bb);
}
@@ -506,7 +554,7 @@
struct bitbuf *bb = bitbuf_init(fd, sizeof(toybuf));
if (!is_gzip(bb)) error_exit("not gzip");
- TT.fd = 1;
+ TT.outfd = 1;
// Use last 1k of toybuf for little endian crc table
crc_init((unsigned *)(toybuf+sizeof(toybuf)-1024), 1);
@@ -548,16 +596,9 @@
loopfiles(toys.optargs, do_zcat);
}
-void do_deflate(int fd, char *name)
-{
- struct bitbuf *bb = bitbuf_init(1, sizeof(toybuf));
-
- deflate(bb);
-}
-
void gzip_main(void)
{
init_deflate(1);
- loopfiles(toys.optargs, do_compress);
+ loopfiles(toys.optargs, do_gzip);
}