<repo_name>asheplyakov/gzipsplit<file_sep>/test/test_ab.sh
#!/bin/sh
set -e
rm -f s_*.gz
./gzipsplit test/ab.img

if [ ! -f s_0.gz ]; then
       echo "file s_0.gz is not found" >&2
       exit 1
fi

if [ ! -f s_1.gz ]; then
	echo "file s_1.gz is not found" >&2
	exit 1
fi

if [ -f s_2.gz ]; then
	echo "extra file s_2.gz has been found" >&2
fi

zcat s_0.gz > s_0.txt
if ! cmp -s s_0.txt test/a.txt; then
	echo "1st file does not match expected test/a.txt" >&2
	exit 1
fi
zcat s_1.gz > s_1.txt

if ! cmp -s s_1.txt test/b.txt; then
	echo "1st file does not match expected test/b.txt" >&2
	exit 1
fi

exit 0
<file_sep>/gzipsplit.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void switch_file(FILE **current, int *count) {
	char buf[sizeof("s_1234567890.gz")];
	memset(buf, 0, sizeof(buf));
	if (*current) {
		if (fflush(*current) != 0)
			exit(2);
		if (fclose(*current) != 0)
			exit(3);
		*current = NULL;
	}
	sprintf(buf, "s_%d.gz", *count);
	++(*count);
	*current = fopen(buf, "w");
	if (!*current)
		exit(5);
}

static int can_be_flg(char c) {
	const char flg_mask = 0x1f;
	if ((c & ~flg_mask) == 0)
		return 1;
	else
		return 0;
}

static void process(FILE *in) {
	int count = 0;
	FILE* current = NULL;
	int c1, c2, c3, c4;
	size_t off = 0;
	while (1) {
		c1 = c2 = c3 = c4 = EOF;

		c1 = fgetc(in);
		if (c1 == EOF)
			break;
		off++;
		if (!current) {
			printf("writing file #1\n");
			switch_file(&current, &count);
			if (fputc(c1, current) == EOF)
				exit(11);
			continue;
		}

		if ((char)c1 == '\x1F') {
			c2 = fgetc(in);
			if (c2 == EOF) {
				if (fputc(c1, current) == EOF)
					exit(11);
				break;
			}
			off++;
			if ((char)c2 == '\x8B') {
				c3 = getc(in);
				if (c3 == EOF) {
					if (fputc(c1, current) == EOF)
						exit(11);
					if (fputc(c2, current) == EOF)
						exit(11);
					break;
				}
				off++;
				if ((char)c3 == '\x08') {
					c4 = getc(in);
					if (c4 == EOF) {
						if (fputc(c1, current) == EOF)
							exit(11);
						if (fputc(c2, current) == EOF)
							exit(11);
						if (fputc(c3, current) == EOF)
							exit(11);
						break;
					}
					off++;
					if (can_be_flg((char)c4)) {
						printf("writing file #%d\n", count + 1);
						switch_file(&current, &count);
					}
					if (fputc(c1, current) == EOF)
						exit(11);
					if (fputc(c2, current) == EOF)
						exit(11);
					if (fputc(c3, current) == EOF)
						exit(11);
					if (fputc(c4, current) == EOF)
						exit(11);
				} else {
					/* c3 != '\x08' */
					if (fputc(c1, current) == EOF)
						exit(11);
					if (fputc(c2, current) == EOF)
						exit(11);
					if (fputc(c3, current) == EOF)
						exit(11);
				}
			} else {
				/* c2 != '\x8B' */
				if (fputc(c1, current) == EOF)
					exit(11);
				if (fputc(c2, current) == EOF)
					exit(11);
			}
		} else {
			/* c1 != '\x1F' */
			if (fputc(c1, current) == EOF)
				exit(11);
		}
	}
	if (current) {
		fflush(current);
		fclose(current);
		current = NULL;
	}
}

int main(int argc, char **argv) {
	FILE* in;
	in = fopen(argv[1], "r");
	if (!in) {
		exit(7);
	}
	process(in);
	fclose(in);
	return 0;
}

<file_sep>/README.md
# Split concatenated gzip archives


## What?

Some Linux distributions (in particular [ALT Linux](http://www.altlinux.org))
use tricky initramfs images which consist of concatenated gzip archives.
This little program helps to split such initramfs images into individual
gzip files.

## Usage

```bash
$ gzipsplit /path/to/full.cz
  writing file #1
  writing file #2
  writing file #3
```

The output will be written to files `s_N.gz` (with N = 0, 1, 2 in
this example). This naming is hard coded, sorry.

## Building

```bash
$ make check
```
<file_sep>/Makefile

CFLAGS ?= -O2 -g -Wall

gzipsplit: gzipsplit.c Makefile
	$(CC) $(CFLAGS) -o $@ $<

check: gzipsplit test/ab.img
	./test/test_ab.sh

test/ab.img: test/a.txt test/b.txt
	gzip -c < test/a.txt > $@.tmp
	gzip -c < test/b.txt >> $@.tmp
	mv $@.tmp $@

clean:
	@rm -f gzipsplit

.PHONY: clean
