#ifndef __SPAD__
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS	64
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
#include <sys/stat.h>
#if defined(__GLIBC__) && __GLIBC__ >= 2
#define HAVE_ERROR_H
#else
#define loff_t __loff_t
#endif
#ifdef HAVE_ERROR_H
#include <error.h>
#endif
#include <unistd.h>
#include "SPAD-API.H"
#include <fcntl.h>
#include <string.h>
#else
#include <STDIO.H>
#include <STDLIB.H>
#include <ERRNO.H>
#include <TIME.H>
#include <SYS/STAT.H>
#include <SPAD/LIBC.H>
#define HAVE_ERROR_H
#include <ERROR.H>
#include <UNISTD.H>
#include <FCNTL.H>
#include <STRING.H>
#include <ARCH/MOV.H>
#include <SPAD/DEV.H>
#include <SPAD/IOCTL.H>
#include <SPAD/SYNC.H>
#endif

#include "STRUCT.H"

typedef __u64 __d_off;

#include "SFSAPAGE.H"

#ifndef HAVE_ERROR_H
static void error(int x, int y, char *m, ...)
{
	va_list va;
	va_start(va, m);
	vfprintf(stderr, m, va);
	va_end(va);
	if (y) fprintf(stderr, ": %s", strerror(y));
	fprintf(stderr, "\n");
	exit(x);
}
#endif

/* FILESYSTEM LAYOUT:
	sector, no of sectors
	4000,1 (SUPERBLOCK_SECTOR) -- superblock
	4001,1 (TXBLOCK_SECTOR) -- tx block
	4002,apage_index_sectors (apage_index_0_sector) -- apage index 0
	4002+apage_index_sectors,apage_index_sectors (apage_index_1_sector) -- apage index 1
	4002+2*apage_index_sectors,n_apages*page_size (apages_sector) -- apages
	apages_sector+n_apages*page_size,512 (cct_sector) -- txc table
	cct_sector+512,1 -- root fnode
	64 (ROOT_DIR) -- root directory
	-- free space
*/

#define BUFFER_SIZE		CCT_SIZE

#define CCT_SECTORS		(CCT_SIZE / 512)
/*#define ROOT_DIR_SECTORS	fnode_sectors*/
#define ROOT_DIR_SECTORS	block_sectors

static __s64 size = -1;
static __s64 reserve = -1;
static int block_size = -1;
static int block_bits;
static int fnode_size = -1;
static int fnode_bits;
static int page_size = -1;
static int page_bits;
static int cluster_size = -1;
static int cluster_bits;
static int cluster_threshold = -1;
static __s64 group_size = -1;
static int group_bits;
static __s64 metadata_groupsize = -1;
static __s64 smallfile_groupsize = -1;

static __u64 groups;
static int metadata_groups;
static int smallfile_groups;

static int unix_names =
#ifdef __SPAD__
	0
#else
	1
#endif
;
static int no_checksums = 0;

#define MAX_PAGE_BITS	17
#define MAX_BLOCK_SIZE	65536

#define block_sectors	(1 << (block_bits - 9))
#define page_sectors	(1 << (page_bits - 9))
#define fnode_sectors	(1 << (fnode_bits - 9))
#define block_align(x)	(((x) + block_sectors - 1) & ~(__u64)(block_sectors - 1))
#define page_align(x)	(((x) + page_sectors - 1) & ~(__u64)(page_sectors - 1))
#define fnode_align(x, o) ((block_align(x) & (fnode_sectors - 1)) + (o) <= fnode_sectors ? block_align(x) : ((x) + fnode_sectors - 1) & ~(__u64)(fnode_sectors - 1))

static int n_apages;
static int apage_index_sectors;

static __u64 superblock_sector = SUPERBLOCK_SECTOR;
static __u64 txblock_sector;
static __u64 apage_index_0_sector;
static __u64 apage_index_1_sector;
static __u64 apages_sector;
static __u64 cct_sector;
static __u64 root_fnode_sector;
static __u64 root_dir_sector;

#define SIZE_ARRAY	4096
static __u64 size_array[SIZE_ARRAY];	/* used_apages entries are valid */
static int used_apages;

static char *file = NULL;
static int h;

static char buffer_[BUFFER_SIZE + (1 << MAX_PAGE_BITS)];
static char *buffer;

#define sb ((struct superblock *)buffer)
#define txb ((struct txblock *)buffer)
#define apg ((struct apage_head *)buffer)
#define fx ((struct fixed_fnode_block *)buffer)

#ifdef __linux__
#if !defined(__GLIBC__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1)
#include <asm/unistd.h>
#ifdef __NR__llseek
#define use_llseek
static _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh);
#endif
#endif
#endif

#ifndef __NOT_FROM_SPAD_TREE
#include <KERNEL/GETHSIZE.I>
#else
#include "GETHSIZE.I"
#endif

static void check_valid(void)
{
	if (block_size == -1) {
#if defined(__SPAD__)
		IOCTLRQ io;
		io.h = h;
		io.ioctl = IOCTL_BIO_PHYSICAL_BLOCKSIZE;
		io.param = 0;
		io.v.ptr = 0;
		io.v.len = 0;
		io.v.vspace = &KERNEL$VIRTUAL;
		SYNC_IO(&io, KERNEL$IOCTL);
		if (io.status >= 0) {
			block_size = io.status;
		} else {
			block_size = 512;
		}
#else
		if (unix_names) {
			block_size = getpagesize();
		} else {
			block_size = 512;
		}
#endif
		if (block_size > MAX_BLOCK_SIZE) block_size = MAX_BLOCK_SIZE;
		if (block_size < 512) block_size = 512;
	}
	if (block_size < 512 || block_size > MAX_BLOCK_SIZE || block_size & (block_size - 1)) error(2, 0, "invalid block size");
	block_bits = ffs(block_size) - 1;

	if (size == -1) {
		size = gethsize(h);
		if (!size) error(1, errno, "cannot access %s", file);
	}
	size >>= 9;
	size &= ~(__u64)(block_sectors - 1);
	if (size < MIN_SIZE || size > MAX_SIZE) error(2, 0, "bad size");

	if (reserve == -1) reserve = get_default_reserved(size);
	else reserve >>= 9;
	reserve &= ~(__u64)(block_sectors - 1);
	if (reserve > size) error(2, 0, "bad reserve");

	if (page_size == -1) {
#ifdef __SPAD__
		page_size = getpagesize();
#else
		page_size = 32768;
#endif
		while (page_size < block_size || page_size < 1024 || page_size < fnode_size) page_size *= 2;
	}
	if (page_size < 1024 || page_size > 1 << MAX_PAGE_BITS || page_size & (page_size - 1)) error(2, 0, "invalid page_size");
	page_bits = ffs(page_size) - 1;
	if (page_bits < block_bits) error(2, 0, "page size is less than block size");

	if (fnode_size == -1) {
		fnode_size = 8192;
		if (fnode_size < block_size) fnode_size = block_size;
		if (fnode_size > page_size) fnode_size = page_size;
	}
	if (fnode_size < 512 || fnode_size > 1 << MAX_PAGE_BITS || fnode_size & (fnode_size - 1)) error(2, 0, "invalid fnode size");
	fnode_bits = ffs(fnode_size) - 1;
	if (fnode_bits < block_bits) error(2, 0, "fnode size is less than page size");
	if (fnode_bits > page_bits) error(2, 0, "fnode size is greater than page size");

	if (cluster_size == -1) {
		cluster_size = 32768;
		if (cluster_size < block_size) cluster_size = block_size;
	}
	if (cluster_size < 512 || (cluster_size > 512 << MAX_ALLOC_MASK_BITS) || cluster_size & (cluster_size - 1)) error(2, 0, "invalid cluster size");
	cluster_bits = ffs(cluster_size) - 1;
	if (cluster_bits < block_bits) error(2, 0, "cluster size is less than block size");

	if (cluster_threshold == -1) {
		cluster_threshold = 4 * cluster_size;
	}
	cluster_threshold = ((unsigned)cluster_threshold + cluster_size - 1) & -cluster_size;
	if ((unsigned)cluster_threshold >= 1 << 31) error(2, 0, "cluster threshold is greater than 1 << 31");
	if ((unsigned)cluster_threshold >= (__u64)cluster_size << 16) error(2, 0, "cluster threshold is greater than cluster size * 65536");

	if (group_size == -1) {
		group_bits = get_default_group_bits(size, cluster_bits - 9) + 9;
	} else {
		group_bits = 9;
		while (((__u64)3 << group_bits) >> 1 < group_size && group_bits < 48) {
			group_bits++;
		}
	}
	group_size = (__u64)1 << group_bits;
	if (group_bits < cluster_bits) error(2, 0, "group size is less than cluster size");
	groups = (size + ((__u64)1 << (group_bits - 9)) - 1) >> (group_bits - 9);
	if (groups > 0xffff) error(2, 0, "more than 65535 groups (too small group size)");

	if (metadata_groupsize == -1) {
		metadata_groups = get_default_metadata_groups(group_bits - 9, groups);
	} else {
		metadata_groups = (metadata_groupsize + (1 << (group_bits - 1))) >> group_bits;
	}
	if (metadata_groups > groups) error(2, 0, "metadata group size too high");
	if (smallfile_groupsize == -1) {
		smallfile_groups = get_default_smallfile_groups(group_bits - 9, groups, metadata_groups);
	} else {
		smallfile_groups = (smallfile_groupsize + (1 << (group_bits - 1))) >> group_bits;
	}
	if (smallfile_groups + metadata_groups >= groups) error(2, 0, "metadata group size + smallfile group size too high");

	n_apages = N_APAGES(size, page_bits, block_bits);
	apage_index_sectors = APAGE_INDEX_SECTORS(n_apages, block_size);

	txblock_sector = block_align(superblock_sector + block_sectors);
	apage_index_0_sector = block_align(txblock_sector + block_sectors);
	apage_index_1_sector = block_align(apage_index_0_sector + apage_index_sectors);
	apages_sector = page_align(apage_index_1_sector + apage_index_sectors);
	cct_sector = block_align(apages_sector + (n_apages << (page_bits - 9)));
	root_fnode_sector = block_align(cct_sector + 512);
	root_dir_sector = fnode_align(root_fnode_sector + block_sectors, ROOT_DIR_SECTORS);
}

static void print_progress(int total, int partial)
{
	static time_t lt = 0;
	time_t t = time(NULL);
	if (t == lt) return;
	lt = t;
	fprintf(stderr, "\r%d%%", partial * 100 / total);
}

static void zerobuf(void)
{
	memset(buffer, 0, BUFFER_SIZE);
}

static void write_blocks(void *ptr, __u64 sec, int num)
{
	__u64 r;
#ifdef use_llseek
	loff_t l;
#endif
	sec *= 512;
#ifdef use_llseek
	r = _llseek(h, sec >> 32, sec, &l, SEEK_SET);
#else
	r = lseek(h, sec, SEEK_SET);
#endif
	if (r == -1) error(1, errno, "llseek %08x%08x", (unsigned)(sec >> 32), (unsigned)(sec & 0xffffffffu));
	r = write(h, ptr, num * 512);
	if (r == -1) error(1, errno, "write %08x%08x", (unsigned)(sec >> 32), (unsigned)(sec & 0xffffffffu));
	if (r != num * 512) error(1, 0, "write: %d < %d", (int)r, num * 512);
}

static void write_super(void)
{
	char *val;
	zerobuf();
	strcpy((char *)sb->signature, SUPERBLOCK_SIGNATURE);
	sb->byte_sex = 0x0123456789ABCDEFLL;
	sb->version_major = SPADFS_VERSION_MAJOR;
	sb->version_middle = SPADFS_VERSION_MIDDLE;
	sb->version_minor = SPADFS_VERSION_MINOR;
	sb->sectors_per_block_bits = block_bits - 9;
	sb->sectors_per_fnodepage_bits = fnode_bits - 9;
	sb->sectors_per_page_bits = page_bits - 9;
	sb->sectors_per_cluster_bits = cluster_bits - 9;
	sb->sectors_per_group_bits = group_bits - 9;
	sb->cluster_threshold = cluster_threshold / (1 << cluster_bits);
	sb->small_file_group = metadata_groups;
	sb->large_file_group = metadata_groups + smallfile_groups;
	sb->size = size;
	sb->reserve_sectors = reserve;
	sb->txblock = txblock_sector;
	sb->apage_index[0] = apage_index_0_sector;
	sb->apage_index[1] = apage_index_1_sector;
	sb->cct = cct_sector;
	sb->root = root_fnode_sector;
	if (unix_names) sb->flags_compat_none |= FLAG_COMPAT_NONE_UNIX_NAMES;
	if (no_checksums) sb->flags_compat_fsck |= FLAG_COMPAT_FSCK_NO_CHECKSUMS;
	sb->checksum = CHECKSUM_BASE ^ __byte_sum(sb, 512);
	if ((val = validate_super(sb))) {
		fprintf(stderr, "error: %s\n", val);
		error(4, 0, "internal error, validate_super failed. Report all arguments that you passed to MKSPADFS");
	}
	write_blocks(sb, SUPERBLOCK_SECTOR, block_sectors);
}

static void write_txbl(void)
{
	zerobuf();
	txb->magic = TXBLOCK_MAGIC;
	txb->cc = 0;
	txb->a_cc = 0;
	txb->a_txc = 0;
	txb->txflags = 0;
	txb->checksum = CHECKSUM_BASE ^ __byte_sum(txb, 512);
	write_blocks(sb, txblock_sector, block_sectors);
}

static void write_txct(void)
{
	int i;
	zerobuf();
	for (i = 0; i < CCT_SECTORS; i += block_sectors) {
		print_progress(CCT_SECTORS, i);
		write_blocks(buffer, cct_sector + i, block_sectors);
	}
}

static void write_root_fixed_fnode(void)
{
#define fn	((struct fnode *)fx->fnode0)
	zerobuf();
	fx->magic = FIXED_FNODE_BLOCK_MAGIC;
	fx->flags = FIXED_FNODE_BLOCK_CHECKSUM_VALID;
	fx->cc = 0;
	fx->txc = 0;
	fx->nlink0 = 1;
	fx->hint_small = metadata_groups;	/* these two are not really used or changed ... hints in the following root fnode are appropriate */
	fx->hint_large = metadata_groups + smallfile_groups;

	fn->next = FNODE_SIZE(0, 0) & FNODE_NEXT_SIZE;
	fn->cc = 0;
	fn->txc = 0;
	fn->size0 = 0;
	fn->ctime = fn->mtime = time(NULL);
	fn->run10 = root_dir_sector;
	fn->run11 = root_dir_sector >> 32;
	fn->run1n = metadata_groups;
	fn->run2n = metadata_groups + smallfile_groups;
	fn->flags = FNODE_FLAGS_DIR;
	fn->namelen = 0;
	fx->checksum = CHECKSUM_BASE ^ __byte_sum(fx, FIXED_FNODE_BLOCK_SIZE);
	write_blocks(buffer, root_fnode_sector, FIXED_FNODE_BLOCK_SIZE);
#undef fn
}

static void write_root_dir(void)
{
	int i;
	zerobuf();
	for (i = 0; i < ROOT_DIR_SECTORS * 512; i += FNODE_BLOCK_SIZE) {
		struct fnode_block *b = (void *)&buffer[i];
		struct fnode *f;
		b->magic = FNODE_BLOCK_MAGIC;
		b->flags = FNODE_BLOCK_CHECKSUM_VALID | FNODE_BLOCK_FIRST * !i | FNODE_BLOCK_LAST * (i + FNODE_BLOCK_SIZE >= ROOT_DIR_SECTORS * 512);
		b->prev0 = b->prev1 = 0;
		b->txc = TXC_INVALID(0);
		b->cc = 0;
		f = b->fnodes;
		f->next = (FNODE_MAX_SIZE & FNODE_NEXT_SIZE) | FNODE_NEXT_FREE;
		f->cc = 0;
		f->txc = 0;
		b->checksum = CHECKSUM_BASE ^ __byte_sum(b, FNODE_BLOCK_SIZE);
	}
	write_blocks(buffer, root_dir_sector, ROOT_DIR_SECTORS);
}

static void write_apage_index(__u64 ai)
{
	struct apage_index_entry *aind = NULL;	/* warning go away */
	int i;
	__u64 ap = apages_sector + (n_apages - 1) * page_sectors;
	for (i = 0; i < n_apages; i++) {
		print_progress(n_apages, i);
		if (!(i * sizeof(struct apage_index_entry) & ((1 << block_bits) - 1))) {
			if (i) write_blocks(buffer, ai, block_sectors), ai += block_sectors;
			zerobuf();
			aind = (void *)buffer;
		}
		aind->apage = ap, ap -= page_sectors;
		aind->end_block = i < used_apages ? size_array[i] : 0;
		aind++;
	}
	write_blocks(buffer, ai, block_sectors);
}

static void write_apages(void)
{
	__u32 s;
	__u64 ptr;
	int r;
	int a_sector, n_e;
	int wrote_apages;
	a_sector = apages_sector;
	wrote_apages = 0;
	while (wrote_apages < n_apages) {
		print_progress(n_apages, wrote_apages++);
		zerobuf();
		apg->magic = APAGE_MAGIC;
		apg->cc = 0;
		apg->txc = 0;
		/* write_blocks(buffer, a_sector, page_sectors); this is good for raid but worse for normal disks */
		write_blocks(buffer, a_sector, block_sectors);
		a_sector += page_sectors;
	}
	a_sector = apages_sector + (n_apages - 1) * page_sectors;
	n_e = (1 << page_bits) / 2 / sizeof(struct aentry);
	used_apages = 0;
	zerobuf();
	*APAGE_ERROR = 0;
	if (SPAD_APAGE_MAKE(apg, n_e, block_bits - 9)) goto err;
	if (apage_index_1_sector + apage_index_sectors < apages_sector)
		if (SPAD_APAGE_FREE(apg, apage_index_1_sector + apage_index_sectors, apages_sector - (apage_index_1_sector + apage_index_sectors))) goto err;
	if (root_fnode_sector + block_sectors < root_dir_sector)
		if (SPAD_APAGE_FREE(apg, root_fnode_sector + block_sectors, root_dir_sector - (root_fnode_sector + block_sectors))) goto err;
	if (cct_sector + 512 < root_fnode_sector)
		if (SPAD_APAGE_FREE(apg, cct_sector + 512, root_fnode_sector - (cct_sector + 512))) goto err;
	ptr = root_dir_sector + ROOT_DIR_SECTORS;
	next_block:
	if (ptr > size) error(2, 0, "too small filesystem");
	if (ptr + 0xffffffffu > size) s = size - ptr;
	else s = 0xffffffffu;
	r = SPAD_APAGE_FREE(apg, ptr, s);
	if (r < 0) goto err;
	if (!r) {
		ptr += s;
		if (ptr < size) goto next_block;
	}
	apg->magic = APAGE_MAGIC;
	apg->s.u.l.flags |= APAGE_CHECKSUM_VALID;
	apg->s.u.l.checksum = CHECKSUM_BASE ^ __byte_sum(&apg->s, sizeof(struct apage_subhead) + sizeof(struct aentry) * (n_e - 1));
	write_blocks(buffer, a_sector, page_sectors / 2 < block_sectors ? block_sectors : page_sectors / 2);
	size_array[used_apages++] = ptr;
	if (ptr < size) {
		if (used_apages >= SIZE_ARRAY) error(4, 0, "INTERNAL ERROR: SIZE_ARRAY OVERFLOW");
		a_sector -= page_sectors;
		if (a_sector < apages_sector)
			error(4, 0, "INTERNAL ERROR: APAGE OVERFLOW");
		zerobuf();
		if (SPAD_APAGE_MAKE(apg, n_e, block_bits - 9)) goto err;
		goto next_block;
	}
	return;
	err:
	error(4, 0, "INTERNAL ERROR IN APAGE OPERATION: %s", APAGE_ERROR);
}

#ifndef __SPAD__

/*
static __u64 xstrtoull(char *a, char **b)
{
	__u64 x = 0;
	while (*a >= '0' && *a <= '9') {
		__u64 y = x * 10 + *a - '0';
		if (x != (y - (*a - '0')) / 10) break;
		x = y;
		a++;
	}
	*b = a;
	return x;
}
*/

static __s64 get_number(char *a, char *num_error)
{
	__s64 n, mult;
	*num_error = 0;
	if (!a || !*a) goto err;
#if !defined(__linux__) || defined(__GLIBC__)
	n = strtoll(a, &a, 10);
#else
	n = strtod(a, &a);
#endif
	mult = 1;
	if (*a == 'k' || *a == 'K') mult = 1000, a++;
	else if (*a == 'm' || *a == 'M') mult = 1000000, a++;
	else if (*a == 'g' || *a == 'G') mult = 1000000000, a++;
	else if (*a == 't' || *a == 'T') mult = (__s64)1000000000 * 1000, a++;
	if (*a) goto err;
	if ((__s64)((__u64)n * mult) / mult != n) goto err;
	return (__u64)n * mult;
	err:
	*num_error = 1;
	return 0;
}

#endif

#ifdef __SPAD__
static __const__ struct __param_table params[] = {
	"", __PARAM_STRING, 1, __MAX_STR_LEN, &file,
	"", __PARAM_INT64, MIN_SIZE << 9, 1, &size,
	"UNIX_NAMES", __PARAM_BOOL, ~0, 1, &unix_names,
	"SPAD_NAMES", __PARAM_BOOL, ~0, 0, &unix_names,
	"NO_CHECKSUMS", __PARAM_BOOL, ~0, 1, &no_checksums,
	"CHECKSUMS", __PARAM_BOOL, ~0, 0, &no_checksums,
	"RESERVE", __PARAM_INT64, 0, 1, &reserve,
	"BLOCK_SIZE", __PARAM_INT, 512, MAX_BLOCK_SIZE + 1, &block_size,
	"FNODE_SIZE", __PARAM_INT, 512, (1 << MAX_PAGE_BITS) + 1, &fnode_size,
	"PAGE_SIZE", __PARAM_INT, 1024, (1 << MAX_PAGE_BITS) + 1, &page_size,
	"CLUSTER_SIZE", __PARAM_INT, 512, 512 << MAX_ALLOC_MASK_BITS, &cluster_size,
	"GROUP_SIZE", __PARAM_INT64, 512, 1, &group_size,
	"METADATA_GROUP_SIZE", __PARAM_INT64, 0, 1, &metadata_groupsize,
	"SMALLFILE_GROUP_SIZE", __PARAM_INT64, 0, 1, &smallfile_groupsize,
	"CLUSTER_THRESHOLD", __PARAM_INT, 0, (1U << 31) - 511, &cluster_threshold,
	NULL, 0, 0, 0, NULL,
};
#endif

int main(int argc, char *argv[])
{
	char **arg = argv;
#ifdef __SPAD__
	int state = 0;
	if (__unlikely(__parse_params(&arg, &state, params, NULL, NULL, NULL))) goto syn;
#else
	int skip = 0;
	while (*++arg) {
		__s64 num;
		char num_error;
		if (skip) goto is_file;
		if (!strcasecmp(*arg, "--unix-names")) {
			unix_names = 1;
		} else if (!strcasecmp(*arg, "--spad-names")) {
			unix_names = 0;
		} else if (!strcasecmp(*arg, "--no-checksums")) {
			no_checksums = 1;
		} else if (!strcasecmp(*arg, "--checksums")) {
			no_checksums = 0;
		} else if (!strcasecmp(*arg, "--reserve")) {
			num = get_number(*++arg, &num_error);
			if (num_error || num < 0) goto syn;
			reserve = num;
		} else if (!strcasecmp(*arg, "--block-size")) {
			num = get_number(*++arg, &num_error);
			if (num_error || num < 512 || num > MAX_BLOCK_SIZE || num & (num - 1)) goto syn;
			block_size = num;
		} else if (!strcasecmp(*arg, "--fnode-size")) {
			num = get_number(*++arg, &num_error);
			if (num_error || num < 512 || num > 1 << MAX_PAGE_BITS || num & (num - 1)) goto syn;
			fnode_size = num;
		} else if (!strcasecmp(*arg, "--page-size")) {
			num = get_number(*++arg, &num_error);
			if (num_error || num < 1024 || num > 1 << MAX_PAGE_BITS || num & (num - 1)) goto syn;
			page_size = num;
		} else if (!strcasecmp(*arg, "--cluster-size")) {
			num = get_number(*++arg, &num_error);
			if (num_error || num < 512 || num >= 512 << MAX_ALLOC_MASK_BITS || num & (num - 1)) goto syn;
			cluster_size = num;
		} else if (!strcasecmp(*arg, "--group-size")) {
			num = get_number(*++arg, &num_error);
			if (num_error || num < 512) goto syn;
			group_size = num;
		} else if (!strcasecmp(*arg, "--metadata-group-size")) {
			num = get_number(*++arg, &num_error);
			if (num_error || num < 0) goto syn;
			metadata_groupsize = num;
		} else if (!strcasecmp(*arg, "--smallfile-group-size")) {
			num = get_number(*++arg, &num_error);
			if (num_error || num < 0) goto syn;
			smallfile_groupsize = num;
		} else if (!strcasecmp(*arg, "--cluster-threshold")) {
			num = get_number(*++arg, &num_error);
			if (num_error || num < 0 || num > (1U << 31) - 511) goto syn;
			cluster_threshold = num;
		} else if (!strcasecmp(*arg, "--")) {
			skip = 1;
		} else if (**arg == '-') {
			goto syn;
		} else {
			is_file:
			if (!file) {
				file = *arg;
			} else if (size == -1) {
				num = get_number(*arg, &num_error);
				if (num_error || num < MIN_SIZE << 9) goto syn;
				size = num;
			} else {
				goto syn;
			}
		}
	}
#endif
	if (!file) {
		syn:
		error(2, 0, "syntax error");
	}

	buffer = (char *)((unsigned long)(buffer_ + (1 << MAX_PAGE_BITS) - 1) & ~(unsigned long)((1 << MAX_PAGE_BITS) - 1));

	h = open(file, O_RDWR);
	if (h < 0) error(1, errno, "error opening %s", file);
	check_valid();
	fprintf(stderr, "\rwriting super block...\n");
	write_super();
	fprintf(stderr, "\rwriting tx block...\n");
	write_txbl();
	fprintf(stderr, "\rwriting apages...\n");
	write_apages();
	fprintf(stderr, "\rwriting apage index...\n");
	write_apage_index(apage_index_0_sector);
	/*no need to write index 1 */
	/*write_apage_index(apage_index_1_sector);*/
	fprintf(stderr, "\rwriting crash count table...\n");
	write_txct();
	fprintf(stderr, "\rwriting root fixed fnode...\n");
	write_root_fixed_fnode();
	fprintf(stderr, "\rwriting root directory...\n");
	write_root_dir();
	fprintf(stderr, "\rsyncing...\n");
	if (fsync(h)) error(1, errno, "can't fsync");
	close(h);
	return 0;
}
