18680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o/*
28680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o * make-sparse.c --- make a sparse file from stdin
38680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o *
48680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o * Copyright 2004 by Theodore Ts'o.
58680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o *
68680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o * %Begin-Header%
78680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
88680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o * License.
98680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o * %End-Header%
108680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o */
118680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o
128680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o#define _LARGEFILE_SOURCE
138680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o#define _LARGEFILE64_SOURCE
148680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o
158680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o#include <stdio.h>
168680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o#include <unistd.h>
178680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o#include <stdlib.h>
188680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o#include <sys/types.h>
198680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o#include <sys/stat.h>
208680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o#include <fcntl.h>
218680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o#include <errno.h>
228680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o
238680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'oint full_read(int fd, char *buf, size_t count)
248680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o{
258680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	int got, total = 0;
268680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	int pass = 0;
278680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o
288680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	while (count > 0) {
298680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		got = read(fd, buf, count);
308680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		if (got == -1) {
318680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o			if ((errno == EINTR) || (errno == EAGAIN))
328680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o				continue;
338680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o			return total ? total : -1;
348680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		}
358680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		if (got == 0) {
368680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o			if (pass++ >= 3)
378680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o				return total;
388680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o			continue;
398680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		}
408680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		pass = 0;
418680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		buf += got;
428680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		total += got;
438680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		count -= got;
448680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	}
458680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	return total;
468680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o}
478680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o
488680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'oint main(int argc, char **argv)
498680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o{
508680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	int fd, got, i;
514087bbd68bc129c19f0130ba36679e3e8c80c617Theodore Ts'o	int zflag = 0;
528680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	char buf[1024];
538680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o
548680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	if (argc != 2) {
558680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		fprintf(stderr, "Usage: make-sparse out-file\n");
568680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		exit(1);
578680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	}
588680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	fd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0777);
598680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	if (fd < 0) {
608680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		perror(argv[1]);
618680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		exit(1);
628680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	}
638680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	while (1) {
648680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		got = full_read(0, buf, sizeof(buf));
658680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		if (got == 0)
668680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o			break;
678680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		if (got == sizeof(buf)) {
688680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o			for (i=0; i < sizeof(buf); i++)
698680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o				if (buf[i])
708680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o					break;
718680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o			if (i == sizeof(buf)) {
728680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o				lseek(fd, sizeof(buf), SEEK_CUR);
734087bbd68bc129c19f0130ba36679e3e8c80c617Theodore Ts'o				zflag = 1;
748680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o				continue;
758680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o			}
768680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		}
774087bbd68bc129c19f0130ba36679e3e8c80c617Theodore Ts'o		zflag = 0;
788680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o		write(fd, buf, got);
798680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	}
804087bbd68bc129c19f0130ba36679e3e8c80c617Theodore Ts'o	if (zflag) {
814087bbd68bc129c19f0130ba36679e3e8c80c617Theodore Ts'o		lseek(fd, -1, SEEK_CUR);
824087bbd68bc129c19f0130ba36679e3e8c80c617Theodore Ts'o		buf[0] = 0;
834087bbd68bc129c19f0130ba36679e3e8c80c617Theodore Ts'o		write(fd, buf, 1);
844087bbd68bc129c19f0130ba36679e3e8c80c617Theodore Ts'o	}
858680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o	return 0;
868680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o}
878680b4e6805ac9c19980c2348b6cc88b90f5225aTheodore Ts'o
88