/*-
 * Copyright (c) 2001-2004
 *	HATANOU Tomomi.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef	lint
static char sccsid[] = "@(#)mkfile.c	1.3 (HATANOU Tomomi) 2004/01/21";
#endif	/* !lint */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

#define	MKFILE_WBUF	(1048576)	/* XXX - is 1M an reasonable value? */

/*
 * Try settting "sticky bit" for compatibility with SunOS's mkfile(8).
 */
#define	MKFILE_MODE	(S_IRUSR | S_IWUSR | S_ISVTX)

static char	buf[MKFILE_WBUF];
static int	nofill = 0;
static int	verbose = 0;

static void
usage()
{
	fprintf(stderr, "\
Usage: mkfile [-nv] <size>[e|p|t|g|m|k|b] <filename> ...\n");
	exit(0);
}

/*
 * NOTE: On many *BSD systems, size_t is still 32bit width.
 *       We use `off_t' instead here.
 *       This may also be okay for LP64 systems.
 */
static off_t
getsize(s)
	char *s;
{
	int sft;
	off_t length;
	char *suffix;

	length = (off_t)strtoll(s, &suffix, 10);
	sft = 0;
	switch (*suffix) {
	case 'e':
	case 'E':	/* exabytes */
		sft = 60;
		break;
	case 'p':
	case 'P':	/* petabytes */
		sft = 50;
		break;
	case 't':
	case 'T':	/* terabytes */
		sft = 40;
		break;
	case 'g':
	case 'G':	/* gigabytes */
		sft = 30;
		break;
	case 'm':
	case 'M':	/* megabytes */
		sft = 20;
		break;
	case 'k':
	case 'K':	/* kilobytes */
		sft = 10;
		break;
	case 'b':
	case 'B':	/* blocks */
		sft = 9;
		break;
	}
	if (sft) {
		off_t len;

		len = length;
		length <<= sft;
		/* check overflow */
		if ((length >> sft) != len) {
			printf("Size too large.\n");
			exit(0);
		}
	}

	return length;
}

static void
init_buf()
{
	bzero(buf, MKFILE_WBUF);
}

static void
create_file(f, s)
	char *f;
	off_t s;
{
	int fd, i;
	size_t bk, ix;

	if (verbose) {
		fprintf(stdout, "%s %qu bytes\n", f, s);
		fflush(stdout);
	}
	if ((fd = open(f, O_WRONLY | O_CREAT | O_TRUNC, MKFILE_MODE)) < 0) {
		perror(f);
	} else {
		lseek(fd, s - (off_t)1, SEEK_SET);
		write(fd, buf, (size_t)1);
		if (!nofill) {
			lseek(fd, (off_t)0, SEEK_SET);
			bk = (size_t)(s / (off_t)MKFILE_WBUF);
			ix = (size_t)(s % (off_t)MKFILE_WBUF);
			for (i = 0; i < bk; i++) {
				write(fd, buf, (size_t)MKFILE_WBUF);
			}
			if (ix) {
				write(fd, buf, (size_t)ix);
			}
		}
		close(fd);
	}
}

int
main(argc, argv)
	int argc;
	char **argv;
{
	off_t fsize;
	char *p;

	if (argc < 3) {
		usage();
	}
	argv++;
	init_buf();
	for (fsize = 0; *argv != NULL; argv++) {
		switch (**argv) {
		case '-':
			for (p = *argv + 1; *p; p++) {
				switch (*p) {
				case 'n':		/* no filling */
					nofill = 1;
					break;
				case 'v':		/* verbose */
					verbose = 1;
					break;
				}
			}
			break;
		default:
			if (!fsize) {
				fsize = getsize(*argv);
			} else {
				create_file(*argv, fsize);
			}
		}
	}

	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1