mkfs : add boundary-align option

This allow to align fat and start of cluster on a boundary.
This may usefull for some media like sdcard.

Signed-off-by: Matthieu CASTET <castet.matthieu@free.fr>
diff --git a/README.md b/README.md
index 958fe48..2e5f2dc 100644
--- a/README.md
+++ b/README.md
@@ -42,6 +42,10 @@
         mkfs.exfat -f /dev/sda1
     4. For set volume label, use -l option with string user want.
         mkfs.exfat -L "my usb" /dev/sda1
+    5. To change boundary alignement(KB or MB or Byte) user want
+        mkfs.exfat -b 16777216 /dev/sda1
+        mkfs.exfat -b 16384K /dev/sda1
+        mkfs.exfat -b 16M /dev/sda1
 
 - fsck.exfat:
     Check the consistency of your exfat filesystem and optionally repair a corrupted device formatted by exfat.
diff --git a/include/libexfat.h b/include/libexfat.h
index 9c25b7e..6a3ecb8 100644
--- a/include/libexfat.h
+++ b/include/libexfat.h
@@ -28,6 +28,8 @@
 
 #define EXFAT_MAX_NUM_CLUSTER		(0xFFFFFFF5)
 
+#define DEFAULT_BOUNDARY_ALIGNMENT	(1024*1024)
+
 #define DEFAULT_SECTOR_SIZE	(512)
 
 #define VOLUME_LABEL_BUFFER_SIZE	(VOLUME_LABEL_MAX_LEN*MB_LEN_MAX+1)
@@ -59,6 +61,7 @@
 	bool writeable;
 	unsigned int cluster_size;
 	unsigned int sec_per_clu;
+	unsigned int boundary_align;
 	bool quick;
 	__u16 volume_label[VOLUME_LABEL_MAX_LEN];
 	int volume_label_len;
diff --git a/lib/libexfat.c b/lib/libexfat.c
index cc840ec..1c0bbc0 100644
--- a/lib/libexfat.c
+++ b/lib/libexfat.c
@@ -165,6 +165,9 @@
 	if (!ui->cluster_size)
 		exfat_set_default_cluster_size(bd, ui);
 
+	if (!ui->boundary_align)
+		ui->boundary_align = DEFAULT_BOUNDARY_ALIGNMENT;
+
 	if (ioctl(fd, BLKSSZGET, &bd->sector_size) < 0)
 		bd->sector_size = DEFAULT_SECTOR_SIZE;
 	bd->sector_size_bits = sector_size_bits(bd->sector_size);
diff --git a/manpages/mkfs.exfat.8 b/manpages/mkfs.exfat.8
index bc7ab4d..0c28f03 100644
--- a/manpages/mkfs.exfat.8
+++ b/manpages/mkfs.exfat.8
@@ -4,6 +4,9 @@
 .SH SYNOPSIS
 .B mkfs.exfat
 [
+.B \-b
+.I boundary_alignement
+] [
 .B \-c
 .I cluster_size
 ] [
@@ -36,6 +39,12 @@
 .PP
 .SH OPTIONS
 .TP
+.BI \-b " boundary_alignement"
+Specify the aligment for FAT and start of cluster.
+Boundary alignement can be specified in m/M for megabytes
+and k/K for kilobytes. It should be a power of two.
+Some media like sdcard need this.
+.TP
 .BI \-c " cluster_size"
 Specify the cluster size. Cluster size can be specified in m/M for megabytes
 and k/K for kilobytes.
diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c
index 4abcc41..60999b1 100644
--- a/mkfs/mkfs.c
+++ b/mkfs/mkfs.c
@@ -405,6 +405,7 @@
 	fprintf(stderr, "Usage: mkfs.exfat\n");
 	fprintf(stderr, "\t-L | --volume-label=label                              Set volume label\n");
 	fprintf(stderr, "\t-c | --cluster-size=size(or suffixed by 'K' or 'M')    Specify cluster size\n");
+	fprintf(stderr, "\t-b | --boundary-align=size(or suffixed by 'K' or 'M')  Specify boundary alignement\n");
 	fprintf(stderr, "\t-f | --full-format                                     Full format\n");
 	fprintf(stderr, "\t-V | --version                                         Show version\n");
 	fprintf(stderr, "\t-v | --verbose                                         Print debug\n");
@@ -416,6 +417,7 @@
 static struct option opts[] = {
 	{"volume-label",	required_argument,	NULL,	'L' },
 	{"cluster-size",	required_argument,	NULL,	'c' },
+	{"boundary-align",	required_argument,	NULL,	'b' },
 	{"full-format",		no_argument,		NULL,	'f' },
 	{"version",		no_argument,		NULL,	'V' },
 	{"verbose",		no_argument,		NULL,	'v' },
@@ -427,14 +429,22 @@
 static int exfat_build_mkfs_info(struct exfat_blk_dev *bd,
 		struct exfat_user_input *ui)
 {
-	if (ui->cluster_size > DEFAULT_BOUNDARY_ALIGNMENT)
-		finfo.fat_byte_off = ui->cluster_size;
-	else
-		finfo.fat_byte_off = DEFAULT_BOUNDARY_ALIGNMENT;
+	int clu_len;
+	if (ui->boundary_align < bd->sector_size) {
+		exfat_err("boundary alignement is too small (min %d)\n",
+				bd->sector_size);
+		return -1;
+	}
+	finfo.fat_byte_off = round_up(24 * bd->sector_size,
+			ui->boundary_align);
 	finfo.fat_byte_len = round_up((bd->num_clusters * sizeof(int)),
 		ui->cluster_size);
 	finfo.clu_byte_off = round_up(finfo.fat_byte_off + finfo.fat_byte_len,
-		DEFAULT_BOUNDARY_ALIGNMENT);
+		ui->boundary_align);
+	if (bd->size <= finfo.clu_byte_off) {
+		exfat_err("boundary alignement is too big\n");
+		return -1;
+	}
 	finfo.total_clu_cnt = (bd->size - finfo.clu_byte_off) /
 		ui->cluster_size;
 	if (finfo.total_clu_cnt > EXFAT_MAX_NUM_CLUSTER) {
@@ -444,16 +454,15 @@
 
 	finfo.bitmap_byte_off = finfo.clu_byte_off;
 	finfo.bitmap_byte_len = round_up(finfo.total_clu_cnt, 8) / 8;
-	finfo.ut_start_clu = round_up(EXFAT_REVERVED_CLUSTERS *
-		ui->cluster_size + finfo.bitmap_byte_len, ui->cluster_size) /
-		ui->cluster_size;
-	finfo.ut_byte_off = round_up(finfo.bitmap_byte_off +
-		finfo.bitmap_byte_len, ui->cluster_size);
+	clu_len = round_up(finfo.bitmap_byte_len, ui->cluster_size);
+
+	finfo.ut_start_clu = EXFAT_FIRST_CLUSTER + clu_len / ui->cluster_size;
+	finfo.ut_byte_off = finfo.bitmap_byte_off + clu_len;
 	finfo.ut_byte_len = EXFAT_UPCASE_TABLE_SIZE;
-	finfo.root_start_clu = round_up(finfo.ut_start_clu * ui->cluster_size
-		+ finfo.ut_byte_len, ui->cluster_size) / ui->cluster_size;
-	finfo.root_byte_off = round_up(finfo.ut_byte_off + finfo.ut_byte_len,
-		ui->cluster_size);
+	clu_len = round_up(finfo.ut_byte_len, ui->cluster_size);
+
+	finfo.root_start_clu = finfo.ut_start_clu + clu_len / ui->cluster_size;
+	finfo.root_byte_off = finfo.ut_byte_off + clu_len;
 	finfo.root_byte_len = sizeof(struct exfat_dentry) * 3;
 	finfo.volume_serial = get_new_serial();
 
@@ -544,7 +553,7 @@
 	return 0;
 }
 
-static long long parse_cluster_size(const char *size)
+static long long parse_size(const char *size)
 {
 	char *data_unit;
 	unsigned long long byte_size = strtoull(size, &data_unit, 0);
@@ -561,7 +570,7 @@
 	case '\0':
 		break;
 	default:
-		exfat_err("Wrong unit input('%c') for cluster size\n",
+		exfat_err("Wrong unit input('%c') for size\n",
 				*data_unit);
 		return -EINVAL;
 	}
@@ -583,7 +592,7 @@
 		exfat_err("failed to init locale/codeset\n");
 
 	opterr = 0;
-	while ((c = getopt_long(argc, argv, "n:L:c:fVvh", opts, NULL)) != EOF)
+	while ((c = getopt_long(argc, argv, "n:L:c:b:fVvh", opts, NULL)) != EOF)
 		switch (c) {
 		/*
 		 * Make 'n' option fallthrough to 'L' option for for backward
@@ -601,7 +610,7 @@
 			break;
 		}
 		case 'c':
-			ret = parse_cluster_size(optarg);
+			ret = parse_size(optarg);
 			if (ret < 0)
 				goto out;
 			else if (ret & (ret - 1)) {
@@ -615,6 +624,17 @@
 			}
 			ui.cluster_size = ret;
 			break;
+		case 'b':
+			ret = parse_size(optarg);
+			if (ret < 0)
+				goto out;
+			else if (ret & (ret - 1)) {
+				exfat_err("boundary align(%d) is not a power of 2)\n",
+					ret);
+				goto out;
+			}
+			ui.boundary_align = ret;
+			break;
 		case 'f':
 			ui.quick = false;
 			break;
diff --git a/mkfs/mkfs.h b/mkfs/mkfs.h
index e4724ea..ffd56e3 100644
--- a/mkfs/mkfs.h
+++ b/mkfs/mkfs.h
@@ -5,7 +5,6 @@
 
 #ifndef _MKFS_H
 
-#define DEFAULT_BOUNDARY_ALIGNMENT	(1024*1024)
 #define MIN_NUM_SECTOR			(2048)
 #define EXFAT_MAX_CLUSTER_SIZE		(32*1024*1024)