summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2003-01-29 05:49:06 +0000
committerH. Peter Anvin <hpa@zytor.com>2003-01-29 05:49:06 +0000
commit55e615b964d5a74168af9275bb94fb619766d980 (patch)
tree6f0e634592cd66b24ab4e0fa2d33973b11246c40
parent401c6d8d9b8a410754a7ff7e18b317c6609e4111 (diff)
downloadmkfatfs-55e615b964d5a74168af9275bb94fb619766d980.tar.gz
mkfatfs-55e615b964d5a74168af9275bb94fb619766d980.tar.xz
mkfatfs-55e615b964d5a74168af9275bb94fb619766d980.zip
Now actually creates a FAT filesystem; can also incorporate SYSLINUX
directly.
-rw-r--r--Makefile17
-rw-r--r--date.c34
-rw-r--r--dirtree.c4
-rw-r--r--fat.h8
-rw-r--r--fatdata.h6
-rw-r--r--genfat.c77
-rw-r--r--gensuper.c80
-rw-r--r--getgeo.c6
-rw-r--r--main.c18
-rw-r--r--main.h9
-rw-r--r--syslinux.c64
-rw-r--r--ulint.h4
-rw-r--r--writedir.c49
-rw-r--r--writefile.c2
-rw-r--r--xstdio.c1
-rw-r--r--xstdio.h2
16 files changed, 298 insertions, 83 deletions
diff --git a/Makefile b/Makefile
index 0d70922..a33bf8d 100644
--- a/Makefile
+++ b/Makefile
@@ -16,14 +16,21 @@
#
CC = gcc
-CFLAGS = -g -O -Wall -D_FILE_OFFSET_BITS=64
+CFLAGS = -g -O -Wall -D_FILE_OFFSET_BITS=64 $(SYSLXFLAGS)
LDFLAGS = -g
LIBS =
OBJS = alloc.o dirtree.o main.o xmalloc.o xstdio.o genfat.o \
- clustparm.o writedir.o writefile.o writechain.o writefs.o
+ clustparm.o writedir.o writefile.o writechain.o writefs.o \
+ gensuper.o date.o syslinux.o
SRCS = alloc.c dirtree.c main.c xmalloc.c xstdio.c genfat.c \
- clustparm.c writedir.c writefile.c writechain.c writefs.c
+ clustparm.c writedir.c writefile.c writechain.c writefs.c \
+ gensuper.c date.c syslinux.c
+
+# Enable this to compile with SYSLINUX support
+SYSLXDIR = ../syslinux
+SYSLXLIB = $(SYSLXDIR)/libsyslinux.a
+SYSLXFLAGS = -I$(SYSLXDIR) -DWITH_SYSLINUX
.SUFFIXES: .c .o .asm .bin .lst
@@ -32,8 +39,8 @@ all: genfatimage getgeo
.c.o:
$(CC) $(CFLAGS) -c $<
-genfatimage: $(OBJS)
- $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+genfatimage: $(OBJS) $(SYSLXLIB)
+ $(CC) $(LDFLAGS) -o $@ $(OBJS) $(SYSLXLIB) $(LIBS)
getgeo: getgeo.c
$(CC) $(CFLAGS) $(LDFLAGS) -DSTANDALONE -o $@ $< $(LIBS)
diff --git a/date.c b/date.c
new file mode 100644
index 0000000..3d9d348
--- /dev/null
+++ b/date.c
@@ -0,0 +1,34 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Bostom MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include "date.h"
+
+unsigned int
+msdos_date(time_t unixdate)
+{
+ struct tm *tm = localtime(&unixdate);
+ unsigned int dosdate = 0;
+
+ if ( !tm || tm->tm_year < 80 )
+ return 0; /* Bogus... */
+
+ dosdate = (tm->tm_sec & 0x3f) >> 1;
+ dosdate |= (tm->tm_min & 0x3f) << 5;
+ dosdate |= (tm->tm_hour & 0x1f) << 9;
+ dosdate |= (tm->tm_mday & 0x1f) << 16;
+ dosdate |= ((tm->tm_mon+1) & 0xf) << 21;
+ dosdate |= ((tm->tm_year-80) & 0x7f) << 25;
+
+ return dosdate;
+}
+
diff --git a/dirtree.c b/dirtree.c
index e3f8dd3..1c69bd8 100644
--- a/dirtree.c
+++ b/dirtree.c
@@ -73,8 +73,8 @@ dos_mangle_name(const char *name, char *buf)
xc = '_';
}
- if ( (unsigned char)xc == 0xe5 ) {
- xc = 0xe5;
+ if ( (unsigned char)xc == 0xe5 && cp == buf ) {
+ xc = 0x05;
}
if ( cp < endp )
diff --git a/fat.h b/fat.h
index dda2ac2..5fd91af 100644
--- a/fat.h
+++ b/fat.h
@@ -42,6 +42,7 @@ struct fat_bootsect {
le8_t bsReserved1; /* Reserved */
le8_t bsBootSignature; /* 0x29 */
le32_t bsVolumeID; /* Volume serial number */
+ char bsVolumeLabel[11]; /* Volume name */
char bsFileSysType[8]; /* File system type */
le8_t bsCode[448]; /* Boot sector code */
@@ -58,7 +59,12 @@ struct fat_dirent
{
le8_t name[11]; /* Mangled filename */
le8_t attribute; /* File type/attribute */
- le8_t _something1[14];
+ le8_t caseflags; /* VFAT: case for basis and extension */
+ le8_t ctime_ms; /* ms of creation time */
+ le32_t ctime; /* Creation time */
+ le16_t atime; /* Date portion (high 16 bits) of atime */
+ le16_t hiclust; /* FAT32: high 16 bits of cluster */
+ le32_t mtime; /* Modification time */
le16_t firstclust; /* First cluster pointer */
le32_t size; /* File size (bytes) */
};
diff --git a/fatdata.h b/fatdata.h
index 9048c66..b14ccc3 100644
--- a/fatdata.h
+++ b/fatdata.h
@@ -32,6 +32,12 @@ struct fatfsparm {
int nfats; /* Number of FATs */
int diskuse; /* FAT+data sectors */
int fattype; /* 12, 16 or 32 */
+ int mediabyte; /* Magic media byte */
+ int h, s; /* Tracks/cylinder, sectors/track (geometry) */
+ unsigned int offset; /* Partition offset */
+ unsigned int driveno; /* Drive number (wtf?) */
+ unsigned int volumeid; /* Volume serial number */
+ char volumelabel[12]; /* Volume name */
void *resv; /* Reserved sectors data (boot sector etc) */
void *fat; /* FAT map */
};
diff --git a/genfat.c b/genfat.c
index b2277d1..49df81e 100644
--- a/genfat.c
+++ b/genfat.c
@@ -24,11 +24,14 @@
#include "xmalloc.h"
#include "ulint.h"
-static inline void
-setfat12ent(unsigned char *fat, unsigned int entry, unsigned int val)
+static void
+setfat12ent(void *fatp, unsigned int entry, unsigned int val)
{
+ unsigned char *fat = fatp;
int fptr = entry + (entry >> 1);
+ val &= 0xFFF;
+
if ( entry & 1 ) {
fat[fptr] = (fat[fptr] & 0x0F) | ((val << 4) & 0xF0);
fat[fptr+1] = (val >> 4) & 0xFF;
@@ -39,74 +42,52 @@ setfat12ent(unsigned char *fat, unsigned int entry, unsigned int val)
}
static void
-genfat12(struct direntry *chain, struct fatfsparm *parm)
+setfat16ent(void *fatp, unsigned int entry, unsigned int val)
{
- unsigned int fat_size;
- unsigned char *fat;
- int i, n;
-
- fat_size = parm->fatsects << parm->sectorshift;
- parm->fat = fat = xzalloc(fat_size);
-
- /* FIX: set FAT entries 0 and 1 */
-
- while ( chain ) {
- n = chain->clusters;
- assert(n > 0);
-
- for ( i = chain->cluster ; n > 1 ; i++, n-- ) {
- setfat12ent(fat, i, i+1);
- }
- setfat12ent(fat, i, 0xFFF); /* Last file cluster */
+ le16_t *fat = fatp;
- chain = chain->nextbyclust;
- }
-}
+ val &= 0xFFFF;
-static inline void
-setfat16ent(le16_t *fat, unsigned int entry, unsigned int val)
-{
write16(&fat[entry], val);
}
-static void
-genfat16(struct direntry *chain, struct fatfsparm *parm)
+void
+genfat(struct direntry *chain, struct fatfsparm *parm)
{
unsigned int fat_size;
- le16_t *fat;
+ void *fat;
int i, n;
+ void (*setfatent)(void *, unsigned int, unsigned int);
+
+ switch ( parm->fattype ) {
+ case 12:
+ setfatent = setfat12ent;
+ break;
+ case 16:
+ setfatent = setfat16ent;
+ break;
+ default:
+ assert(0); /* Unknown FAT type */
+ break;
+ }
fat_size = parm->fatsects << parm->sectorshift;
parm->fat = fat = xzalloc(fat_size);
- /* FIX: set FAT entries 0 and 1 */
+ /* FAT entry 0 - media type; FAT entry 1 - reserved/empty */
+ setfatent(fat, 0, ~0xFFU | parm->mediabyte); /* FAT entry 0 */
+ setfatent(fat, 1, ~0U); /* FAT entry 1 */
while ( chain ) {
n = chain->clusters;
assert(n > 0);
for ( i = chain->cluster ; n > 1 ; i++, n-- ) {
- setfat16ent(fat, i, i+1);
+ setfatent(fat, i, i+1);
}
- setfat16ent(fat, i, 0xFFFF); /* Last file cluster */
+ setfatent(fat, i, ~0U); /* Last file cluster */
chain = chain->nextbyclust;
}
}
-void
-genfat(struct direntry *allocchain, struct fatfsparm *parm)
-{
- switch ( parm->fattype ) {
- case 12:
- genfat12(allocchain, parm);
- break;
- case 16:
- genfat16(allocchain, parm);
- break;
- default:
- assert(0); /* Unknown FAT type */
- break;
- }
-}
-
diff --git a/gensuper.c b/gensuper.c
new file mode 100644
index 0000000..414bafa
--- /dev/null
+++ b/gensuper.c
@@ -0,0 +1,80 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2002 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Bostom MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * gensuper.c
+ *
+ * Create superblock in on-disk format
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include "fat.h"
+#include "fatdata.h"
+#include "ulint.h"
+
+void gensuper(struct fatfsparm *fsparm)
+{
+ struct fat_bootsect *bs;
+ char fattypestr[9];
+ char volumelabel[12];
+
+ bs = (struct fat_bootsect *)fsparm->resv;
+ assert(bs);
+
+ memset(bs, 0xee, 1 << fsparm->sectorshift);
+
+ write8(&bs->bsJump[0], 0xe9);
+ write16((le16_t *)(bs->bsJump+1),
+ offsetof(struct fat_bootsect, bsCode)-
+ offsetof(struct fat_bootsect, bsJump)-3);
+
+ memcpy(bs->bsOemName, "mkfatfs ", 8);
+
+ write16(&bs->bsBytesPerSec, 1 << fsparm->sectorshift);
+
+ write8(&bs->bsSecPerClust, 1 << (fsparm->clustshift-fsparm->sectorshift));
+
+ write16(&bs->bsResSectors, fsparm->resvsects);
+ write8(&bs->bsFATs, fsparm->nfats);
+ write16(&bs->bsRootDirEnts,
+ fsparm->rootdirsects << (fsparm->sectorshift - 5));
+ if ( fsparm->sectors >= 0xffff ) {
+ write16(&bs->bsSectors, 0xffff);
+ write32(&bs->bsHugeSectors, fsparm->sectors);
+ } else {
+ write16(&bs->bsSectors, fsparm->sectors);
+ write32(&bs->bsHugeSectors, 0);
+ }
+
+ write8(&bs->bsMedia, fsparm->mediabyte);
+
+ write16(&bs->bsFATsecs, fsparm->fatsects);
+ write16(&bs->bsSecPerTrack, fsparm->s);
+ write16(&bs->bsHeads, fsparm->h);
+ write32(&bs->bsHiddenSecs, fsparm->offset);
+ write8(&bs->bsDriveNumber, fsparm->driveno);
+ write8(&bs->bsBootSignature, BS_BOOTSIGNATURE);
+ write32(&bs->bsVolumeID, fsparm->volumeid);
+
+ snprintf(fattypestr, 9, "FAT%-5d", fsparm->fattype);
+ memcpy(bs->bsFileSysType, fattypestr, 8);
+
+ snprintf(volumelabel, 12, "%-11s", fsparm->volumelabel);
+ memcpy(bs->bsVolumeLabel, volumelabel, 11);
+
+ write16(&bs->bsSignature, BS_SIGNATURE);
+}
diff --git a/getgeo.c b/getgeo.c
index e0b3e6d..63c0d20 100644
--- a/getgeo.c
+++ b/getgeo.c
@@ -17,6 +17,7 @@
* Obtain output image length and/or geometry
*/
+#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
@@ -91,6 +92,11 @@ int main(int argc, char *argv[])
program = argv[0];
+ if ( fd < 0 ) {
+ perror(argv[1]);
+ exit(1);
+ }
+
memset(&geo, 0, sizeof geo);
get_geometry(fd, &geo);
diff --git a/main.c b/main.c
index 767c5fb..821a55c 100644
--- a/main.c
+++ b/main.c
@@ -1,7 +1,7 @@
#ident "$Id$"
/* ----------------------------------------------------------------------- *
*
- * Copyright 2001 H. Peter Anvin - All Rights Reserved
+ * Copyright 2001-2003 H. Peter Anvin - All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "dirtree.h"
#include "xmalloc.h"
#include "main.h"
@@ -39,16 +40,29 @@ int main(int argc, char *argv[])
fsparm.resvsects = 1; /* Should be 10 for FAT32 */
fsparm.sectors = 80000;
fsparm.rootdirsects = 224/(512/32);
- fsparm.sectorshift = 9;
+ fsparm.sectorshift = 9; /* 512 bytes/sector */
fsparm.nfats = 2;
+ fsparm.h = 8;
+ fsparm.s = 10;
+ fsparm.mediabyte = 0xf8; /* Default media byte */
getclustsize(&fsparm, 9);
fsparm.resv = xzalloc(fsparm.resvsects << fsparm.sectorshift);
tree = make_dir_tree(argv[1], &rootdirsize, NULL);
+
+#ifdef WITH_SYSLINUX
+ syslinux_add_ldlinux(&tree);
+#endif
+
alloc_space(tree, &cluster, fsparm.clustshift, &allocchain);
genfat(allocchain, &fsparm);
+ gensuper(&fsparm);
+
+#ifdef WITH_SYSLINUX
+ syslinux_add_bootsect(&fsparm);
+#endif
writefs(stdout, tree, allocchain, &fsparm);
diff --git a/main.h b/main.h
index ee8db4e..f658d93 100644
--- a/main.h
+++ b/main.h
@@ -31,6 +31,9 @@ void
genfat(struct direntry *allocchain, struct fatfsparm *fsparm);
void
+gensuper(struct fatfsparm *fsparm);
+
+void
getclustsize(struct fatfsparm *parm,
unsigned int minclustshift);
@@ -48,3 +51,9 @@ void
writeallocchain(FILE *f, struct direntry *dirp,
int *firstcluster, int clustshift);
+#ifdef WITH_SYSLINUX
+void
+syslinux_add_ldlinux(struct direntry **tree);
+void
+syslinux_add_bootsect(struct fatfsparm *fs);
+#endif
diff --git a/syslinux.c b/syslinux.c
new file mode 100644
index 0000000..1c3ffb1
--- /dev/null
+++ b/syslinux.c
@@ -0,0 +1,64 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Bostom MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux.c
+ *
+ * SYSLINUX install code (using libsyslinux) for mkfatfs
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "syslinux.h"
+
+#include "xmalloc.h"
+#include "dirtree.h"
+#include "fatdata.h"
+#include "main.h"
+
+#ifdef WITH_SYSLINUX
+
+/* Add LDLINUX.SYS to a directory tree structure */
+void
+syslinux_add_ldlinux(struct direntry **tree)
+{
+ struct direntry *de = xmalloc(sizeof(struct direntry));
+
+ memset(de, 0, sizeof *de);
+
+ de->name = "ldlinux.sys";
+ de->path = NULL; /* Internal data */
+ memcpy(de->mangled_name, "LDLINUX SYS", 12);
+ de->st.st_mode = S_IFREG|0555;
+ de->st.st_size = syslinux_ldlinux_len;
+ de->st.st_ctime = de->st.st_mtime = de->st.st_atime +
+ syslinux_ldlinux_mtime;
+ de->data = syslinux_ldlinux;
+ de->attribute = 0x01; /* Readonly */
+ de->parent = (*tree)->parent;
+ de->next = *tree;
+
+ *tree = de;
+}
+
+/* Modify the boot sector to have SYSLINUX boot code */
+/* Must be run *after* gensuper() */
+void
+syslinux_add_bootsect(struct fatfsparm *fs)
+{
+ /* The boot sector is the first thing in the reserved sectors */
+ syslinux_make_bootsect(fs->resv);
+}
+
+#endif
diff --git a/ulint.h b/ulint.h
index 3990642..74379d5 100644
--- a/ulint.h
+++ b/ulint.h
@@ -40,9 +40,9 @@ write8(le8_t *_p, unsigned char _v)
*_p = _v;
}
-#ifdef __i386__
+#if defined(__i386__) || defined(__x86_64__)
-/* Optimized version for i386, which can handle these directly */
+/* Littleendian architectures which support unaligned memory accesses */
static inline unsigned short
read16(le16_t *_p)
diff --git a/writedir.c b/writedir.c
index 333c033..c195145 100644
--- a/writedir.c
+++ b/writedir.c
@@ -18,11 +18,33 @@
*/
#include <sysexits.h>
+#include <string.h>
+#include <stdlib.h>
#include "dirtree.h"
#include "fat.h"
+#include "date.h"
#include "xstdio.h"
#include "main.h"
+static void
+makedirent(struct fat_dirent *dent, struct direntry *p)
+{
+ unsigned int size;
+
+ memset(dent, 0, 32);
+ memcpy(dent->name, p->mangled_name, 11);
+ write16(&dent->firstclust, p->cluster);
+ write16(&dent->hiclust, p->cluster >> 16);
+ if ( S_ISDIR(p->st.st_mode) ) {
+ size = (p->dirsize + 2) << 5;
+ } else {
+ size = p->st.st_size;
+ }
+ write32(&dent->size, size);
+ write32(&dent->mtime, msdos_date(p->st.st_mtime));
+ write8(&dent->attribute, p->attribute);
+}
+
/* Write out a subdirectory to disk */
void
writesubdir(FILE *f, struct direntry *dirp, int clustshift)
@@ -57,16 +79,7 @@ writesubdir(FILE *f, struct direntry *dirp, int clustshift)
dirsize += 32;
for ( p = dirp->dir ; p ; p = p->next ) {
- memset(&dent, 0, 32);
- memcpy(&dent.name, p->mangled_name, 11);
- write16(&dent.firstclust, p->cluster);
- if ( S_ISDIR(p->st.st_mode) ) {
- size = (p->dirsize + 2) << 5;
- } else {
- size = p->st.st_size;
- }
- write32(&dent.size, size);
- write8(&dent.attribute, p->attribute);
+ makedirent(&dent, p);
xfwrite(&dent, 32, f);
dirsize += 32;
}
@@ -84,14 +97,13 @@ writerootdir(FILE *f, struct direntry *dirp, struct fatfsparm *parm)
{
struct direntry *p;
struct fat_dirent dent;
- unsigned int size;
int rootdirents = parm->rootdirsects << (parm->sectorshift - 5);
fprintf(stderr, "Writing root directory (%u), offset = %lx\n",
parm->rootdirsects, ftell(f));
- /* No . or .. in the root directory. Disk label or ldlinux.sys
- should be added to the directory tree explicitly. */
+ /* No . or .. in the root directory. A volume label should
+ be added explicitly, since the order might matter. */
for ( p = dirp ; p ; p = p->next ) {
if ( rootdirents <= 0 ) {
@@ -100,16 +112,7 @@ writerootdir(FILE *f, struct direntry *dirp, struct fatfsparm *parm)
exit(EX_DATAERR);
}
- memset(&dent, 0, sizeof dent);
- memcpy(&dent.name, p->mangled_name, 11);
- write16(&dent.firstclust, p->cluster);
- if ( S_ISDIR(p->st.st_mode) ) {
- size = (p->dirsize + 2) << 5;
- } else {
- size = p->st.st_size;
- }
- write32(&dent.size, size);
- write8(&dent.attribute, p->attribute);
+ makedirent(&dent, p);
xfwrite(&dent, 32, f);
rootdirents--;
}
diff --git a/writefile.c b/writefile.c
index a861e16..c06e219 100644
--- a/writefile.c
+++ b/writefile.c
@@ -18,6 +18,8 @@
*/
#include <sysexits.h>
+#include <unistd.h>
+#include <stdlib.h>
#include "xstdio.h"
#include "dirtree.h"
#include "main.h"
diff --git a/xstdio.c b/xstdio.c
index c07c4e6..93a7e82 100644
--- a/xstdio.c
+++ b/xstdio.c
@@ -18,6 +18,7 @@
*/
#include <errno.h>
+#include <stdlib.h>
#include <sysexits.h>
#include "xstdio.h"
#include "minmax.h"
diff --git a/xstdio.h b/xstdio.h
index c9e2adf..9e16e74 100644
--- a/xstdio.h
+++ b/xstdio.h
@@ -21,6 +21,8 @@
#define XSTDIO_H
#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
size_t
xfwrite(const void *, size_t, FILE *);