commit 5ab84dfd1b077a945e263c51bd8d60e853846522
Author: Brian Swetland <swetland@frotz.net>
Date: Wed, 11 Dec 2013 23:28:37 -0800
initial checkin
Diffstat:
A | Makefile | | | 11 | +++++++++++ |
A | README | | | 30 | ++++++++++++++++++++++++++++++ |
A | mksparse.c | | | 76 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | unsparse.c | | | 65 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | util.c | | | 69 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | util.h | | | 30 | ++++++++++++++++++++++++++++++ |
6 files changed, 281 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,11 @@
+
+all: mksparse unsparse
+
+mksparse: mksparse.c util.c util.h
+ gcc -Wall -O2 -o mksparse mksparse.c util.c
+
+unsparse: unsparse.c util.c util.h
+ gcc -Wall -O2 -o unsparse unsparse.c util.c
+
+clean:
+ rm -f unsparse mksparse
diff --git a/README b/README
@@ -0,0 +1,30 @@
+
+Tools to "compress" linux files that have holes in them and "decompress" the results.
+
+mksparse <infile> <outfile> # infile may be - for stdin
+unsparse <infile> <outfile> # outfile may be - for stdout
+
+
+$ truncate -s 1G image.bin
+
+$ du -k image.bin
+0 image.bin
+
+$ mkfs.ext4 -F image.bin
+...
+$ du -k image.bin
+33184 image.bin
+
+$ mksparse image.bin image.sparse
+$ mksparse image.bin - | gzip -9 > image.sparse.gz
+
+$ zcat image.sparse.gz | ./unsparse - image.new
+
+$ ls -la image.*
+-rw-rw-r-- 1 swetland swetland 1073741824 Dec 11 23:16 image.bin
+-rw------- 1 swetland swetland 1073741824 Dec 11 23:19 image.new
+-rw------- 1 swetland swetland 33976528 Dec 11 23:17 image.sparse
+-rw-rw-r-- 1 swetland swetland 34887 Dec 11 23:17 image.sparse.gz
+
+$ du -k image.new
+33184
diff --git a/mksparse.c b/mksparse.c
@@ -0,0 +1,76 @@
+/* Copyright 2013 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE /* for SEEK_HOLE */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "util.h"
+
+static u8 buffer[1024*1024];
+
+int main(int argc, char **argv) {
+ struct chunk c;
+ off_t a, b = 0;
+ int fin, fout;
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: mksparse <infile> <outfile>");
+ return -1;
+ }
+
+ if ((fin = open(argv[1], O_RDONLY)) < 0) {
+ fprintf(stderr, "error: cannot open '%s' for reading\n", argv[1]);
+ return -1;
+ }
+
+ if (!strcmp(argv[2], "-")) {
+ fout = 1;
+ } else if ((fout = open(argv[2], O_WRONLY | O_CREAT, 0600)) < 0) {
+ fprintf(stderr, "error: cannot open '%s' for writing\n", argv[2]);
+ return -1;
+ }
+
+ while ((a = lseek(fin, b, SEEK_DATA)) >= 0) {
+ b = lseek(fin, a, SEEK_HOLE);
+ c.start = a;
+ c.length = b - a;
+ if (lseek(fin, a, SEEK_SET) != a)
+ goto fail;
+ if (writex(fout, &c, sizeof(c)))
+ goto fail;
+ if (copyx(fin, fout, c.length, buffer, sizeof(buffer)))
+ goto fail;
+ /* fprintf(stderr, "%lu bytes at %lu\n", c.length, c.start); */
+ }
+
+ c.start = c.length = 0;
+ if (writex(fout, &c, sizeof(c)))
+ goto fail;
+
+ if (close(fout))
+ goto fail;
+
+ return 0;
+
+fail:
+ fprintf(stderr, "error: %s\n", strerror(errno));
+ return -1;
+}
+
diff --git a/unsparse.c b/unsparse.c
@@ -0,0 +1,65 @@
+/* Copyright 2013 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "util.h"
+
+static u8 buffer[1024*1024];
+
+int main(int argc, char **argv) {
+ struct chunk c;
+ int fin = 0;
+ int fout = 0;
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: unsparse <infile> <outfile>\n");
+ return -1;
+ }
+
+ if (!strcmp(argv[1], "-")) {
+ fin = 0;
+ } else if ((fin = open(argv[1], O_RDONLY)) < 0) {
+ fprintf(stderr, "error: cannot open '%s' for reading\n", argv[1]);
+ return -1;
+ }
+
+ if ((fout = open(argv[2], O_WRONLY | O_CREAT, 0600)) < 0) {
+ fprintf(stderr, "error: cannot open '%s' for writing\n", argv[2]);
+ return -1;
+ }
+
+ for (;;) {
+ if (readx(fin, &c, sizeof(c)))
+ break;
+ if ((c.start == 0) && (c.length == 0)) {
+ if (close(fout))
+ break;
+ return 0;
+ }
+ if (lseek(fout, c.start, SEEK_SET) != c.start)
+ break;
+ if (copyx(fin, fout, c.length, buffer, sizeof(buffer)))
+ break;
+ }
+
+ fprintf(stderr, "error: %s\n", strerror(errno));
+ return -1;
+}
+
diff --git a/util.c b/util.c
@@ -0,0 +1,69 @@
+/* Copyright 2013 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "util.h"
+
+int readx(int fd, void *_data, size_t len) {
+ ssize_t r;
+ u8 *data = _data;
+ while (len > 0) {
+ r = read(fd, data, len);
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ len -= r;
+ data += r;
+ }
+ return 0;
+}
+
+int writex(int fd, void *_data, size_t len) {
+ ssize_t r;
+ u8 *data = _data;
+ while (len > 0) {
+ r = write(fd, data, len);
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ len -= r;
+ data += r;
+ }
+ return 0;
+}
+
+int copyx(int fin, int fout, size_t len, u8 *buf, size_t max) {
+ ssize_t r;
+ while (len > 0) {
+ r = read(fin, buf, max > len ? len : max);
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+ if (writex(fout, buf, r))
+ return -1;
+ len -= r;
+ }
+ return 0;
+}
diff --git a/util.h b/util.h
@@ -0,0 +1,30 @@
+/* Copyright 2013 Brian Swetland <swetland@frotz.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+typedef unsigned char u8;
+
+struct chunk {
+ off_t start;
+ off_t length;
+};
+
+int readx(int fd, void *_data, size_t len);
+int writex(int fd, void *_data, size_t len);
+int copyx(int fin, int fout, size_t len, u8 *buf, size_t max);
+
+#endif