summaryrefslogtreecommitdiffstats
path: root/toolbox
diff options
context:
space:
mode:
authorDaniel Rosenberg <drosen@google.com>2014-07-15 16:56:20 -0700
committerDaniel Rosenberg <drosen@google.com>2014-07-16 16:56:00 -0700
commit052f27562154d175267999106bd6bf18fc8c363e (patch)
treeabc81422ee754042badd0a46d58c98f9927613b8 /toolbox
parentcadd5bb70eae200d744f115fd63c3ebe17069db8 (diff)
downloadsystem_core-052f27562154d175267999106bd6bf18fc8c363e.zip
system_core-052f27562154d175267999106bd6bf18fc8c363e.tar.gz
system_core-052f27562154d175267999106bd6bf18fc8c363e.tar.bz2
newfs_msdos: Added option to cluster-align the start of the root directory
This follows the recommendations of the SD-card association. Change-Id: Ie89a5972d086b3df9d92e631c394a521f807b016 Signed-off-by: Daniel Rosenberg <drosen@google.com>
Diffstat (limited to 'toolbox')
-rw-r--r--toolbox/newfs_msdos.c100
1 files changed, 69 insertions, 31 deletions
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 5fbca8d..f69987c 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -238,11 +238,12 @@ static void usage(void);
*/
int newfs_msdos_main(int argc, char *argv[])
{
- static const char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
+ static const char opts[] = "@:NAB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
const char *opt_B = NULL, *opt_L = NULL, *opt_O = NULL, *opt_f = NULL;
u_int opt_F = 0, opt_I = 0, opt_S = 0, opt_a = 0, opt_b = 0, opt_c = 0;
u_int opt_e = 0, opt_h = 0, opt_i = 0, opt_k = 0, opt_m = 0, opt_n = 0;
u_int opt_o = 0, opt_r = 0, opt_s = 0, opt_u = 0;
+ u_int opt_A = 0;
int opt_N = 0;
int Iflag = 0, mflag = 0, oflag = 0;
char buf[MAXPATHLEN];
@@ -260,6 +261,7 @@ int newfs_msdos_main(int argc, char *argv[])
ssize_t n;
time_t now;
u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
+ u_int extra_res, alignment=0, set_res, set_spf, set_spc, tempx, attempts=0;
int ch, fd, fd1;
off_t opt_create = 0, opt_ofs = 0;
@@ -271,6 +273,9 @@ int newfs_msdos_main(int argc, char *argv[])
case 'N':
opt_N = 1;
break;
+ case 'A':
+ opt_A = 1;
+ break;
case 'B':
opt_B = optarg;
break;
@@ -359,6 +364,12 @@ int newfs_msdos_main(int argc, char *argv[])
err(1, "%s", buf);
}
dtype = *argv;
+ if (opt_A) {
+ if (opt_r)
+ errx(1, "align (-A) is incompatible with -r");
+ if (opt_N)
+ errx(1, "align (-A) is incompatible with -N");
+ }
if (opt_create) {
if (opt_N)
errx(1, "create (-C) is incompatible with -N");
@@ -536,36 +547,62 @@ int newfs_msdos_main(int argc, char *argv[])
if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
x = bpb.bkbs + 1;
}
- if (!bpb.res)
- bpb.res = fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x;
- else if (bpb.res < x)
- errx(1, "too few reserved sectors");
- if (fat != 32 && !bpb.rde)
- bpb.rde = DEFRDE;
- rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
- if (!bpb.spc)
- for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
- bpb.spc < MAXSPC &&
- bpb.res +
- howmany((RESFTE + maxcls(fat)) * (fat / BPN),
- bpb.bps * NPB) * bpb.nft +
- rds +
- (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
- bpb.spc <<= 1);
- if (fat != 32 && bpb.bspf > MAXU16)
- errx(1, "too many sectors/FAT for FAT12/16");
- x1 = bpb.res + rds;
- x = bpb.bspf ? bpb.bspf : 1;
- if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
- errx(1, "meta data exceeds file system size");
- x1 += x * bpb.nft;
- x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
- (bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
- x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), bpb.bps * NPB);
- if (!bpb.bspf) {
- bpb.bspf = x2;
- x1 += (bpb.bspf - 1) * bpb.nft;
- }
+
+ extra_res = 0;
+ set_res = !bpb.res;
+ set_spf = !bpb.bspf;
+ set_spc = !bpb.spc;
+ tempx = x;
+ /*
+ * Attempt to align if opt_A is set. This is done by increasing the number
+ * of reserved blocks. This can cause other factors to change, which can in
+ * turn change the alignment. This should take at most 2 iterations, as
+ * increasing the reserved amount may cause the FAT size to decrease by 1,
+ * requiring another nft reserved blocks. If spc changes, it will
+ * be half of its previous size, and thus will not throw off alignment.
+ */
+ do {
+ x = tempx;
+ if (set_res)
+ bpb.res = (fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x) + extra_res;
+ else if (bpb.res < x)
+ errx(1, "too few reserved sectors");
+ if (fat != 32 && !bpb.rde)
+ bpb.rde = DEFRDE;
+ rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
+ if (set_spc)
+ for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
+ bpb.spc < MAXSPC &&
+ bpb.res +
+ howmany((RESFTE + maxcls(fat)) * (fat / BPN),
+ bpb.bps * NPB) * bpb.nft +
+ rds +
+ (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
+ bpb.spc <<= 1);
+ if (fat != 32 && bpb.bspf > MAXU16)
+ errx(1, "too many sectors/FAT for FAT12/16");
+ x1 = bpb.res + rds;
+ x = bpb.bspf ? bpb.bspf : 1;
+ if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
+ errx(1, "meta data exceeds file system size");
+ x1 += x * bpb.nft;
+ x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
+ (bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
+ x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), bpb.bps * NPB);
+ if (set_spf) {
+ bpb.bspf = x2;
+ x1 += (bpb.bspf - 1) * bpb.nft;
+ }
+ if(set_res) {
+ /* attempt to align root directory */
+ alignment = (bpb.res + bpb.bspf * bpb.nft) % bpb.spc;
+ extra_res += bpb.spc - alignment;
+ }
+ attempts++;
+ } while(opt_A && alignment != 0 && attempts < 2);
+ if (alignment != 0)
+ warnx("warning: Alignment failed.");
+
cls = (bpb.bsec - x1) / bpb.spc;
x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (fat / BPN) - RESFTE;
if (cls > x)
@@ -1024,6 +1061,7 @@ static void usage(void)
"usage: newfs_msdos [ -options ] special [disktype]\n"
"where the options are:\n"
"\t-@ create file system at specified offset\n"
+ "\t-A Attempt to cluster align root directory\n"
"\t-B get bootstrap from file\n"
"\t-C create image file with specified size\n"
"\t-F FAT type (12, 16, or 32)\n"