sparse

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 5ab84dfd1b077a945e263c51bd8d60e853846522
Author: Brian Swetland <swetland@frotz.net>
Date:   Wed, 11 Dec 2013 23:28:37 -0800

initial checkin

Diffstat:
AMakefile | 11+++++++++++
AREADME | 30++++++++++++++++++++++++++++++
Amksparse.c | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aunsparse.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autil.c | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autil.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