summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2003-03-06 04:50:52 +0000
committerH. Peter Anvin <hpa@zytor.com>2003-03-06 04:50:52 +0000
commitd170a4fdba3fe7577db4097c5a87f06ddd4f2f53 (patch)
tree9f3f4ec5e01ba576eb90b0806d37c7310fe746d8
parent55e615b964d5a74168af9275bb94fb619766d980 (diff)
downloadmkfatfs-d170a4fdba3fe7577db4097c5a87f06ddd4f2f53.tar.gz
mkfatfs-d170a4fdba3fe7577db4097c5a87f06ddd4f2f53.tar.xz
mkfatfs-d170a4fdba3fe7577db4097c5a87f06ddd4f2f53.zip
Yet another snapshot...
-rw-r--r--Makefile4
-rw-r--r--collision.c83
-rw-r--r--date.c2
-rw-r--r--date.h25
-rw-r--r--dirtree.c15
-rw-r--r--fat.h13
-rw-r--r--geo.h35
-rw-r--r--getgeo.c110
-rw-r--r--vfat.c87
9 files changed, 327 insertions, 47 deletions
diff --git a/Makefile b/Makefile
index a33bf8d..329066b 100644
--- a/Makefile
+++ b/Makefile
@@ -22,10 +22,10 @@ LIBS =
OBJS = alloc.o dirtree.o main.o xmalloc.o xstdio.o genfat.o \
clustparm.o writedir.o writefile.o writechain.o writefs.o \
- gensuper.o date.o syslinux.o
+ gensuper.o date.o syslinux.o getgeo.o
SRCS = alloc.c dirtree.c main.c xmalloc.c xstdio.c genfat.c \
clustparm.c writedir.c writefile.c writechain.c writefs.c \
- gensuper.c date.c syslinux.c
+ gensuper.c date.c syslinux.c getgeo.c
# Enable this to compile with SYSLINUX support
SYSLXDIR = ../syslinux
diff --git a/collision.c b/collision.c
new file mode 100644
index 0000000..3b01355
--- /dev/null
+++ b/collision.c
@@ -0,0 +1,83 @@
+#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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * collision.h
+ *
+ * Handle DOS-name collisions
+ */
+
+#include <inttypes.h>
+#include "xmalloc.h"
+
+static uint32_t
+genhash(const char *str)
+{
+ uint32_t v;
+
+ while ( *str ) {
+ v = ((v << 5) | (v >> 27)) + *str;
+ str++;
+ }
+
+ return v;
+}
+
+#define HASH_BUCKETS 251
+
+struct collision_link {
+ uint32_t hash;
+ const char *str;
+ struct collision_link *next;
+};
+
+struct collision_hash {
+ struct collision_link *bucket[HASH_BUCKETS];
+};
+
+struct collision_hash *
+hash_alloc(void)
+{
+ return xzalloc(sizeof(struct collision_hash));
+}
+
+int
+hash_find(const struct collision_hash *hash, const char *str)
+{
+ uint32_t h = genhash(str);
+ const struct collision_link *l = hash->bucket[h % HASH_BUCKETS];
+
+ while ( l ) {
+ if ( l->hash == h && !strcmp(l->str, str) )
+ return 1;
+ l = l->next;
+ }
+
+ return 0;
+}
+
+void
+hash_insert(struct collision_hash *hash, const char *str)
+{
+ uint32_t h = genhash(str);
+ struct collision_link **ll = &hash->bucket[h % HASH_BUCKETS];
+ char *mystr = xstrdup(str);
+ struct collision_link *l = xmalloc(sizeof(struct collision_link));
+
+ l->next = *ll;
+ l->str = mystr;
+ l->hash = h;
+ *ll = l;
+}
+
+
diff --git a/date.c b/date.c
index 3d9d348..2d51db3 100644
--- a/date.c
+++ b/date.c
@@ -26,7 +26,7 @@ msdos_date(time_t unixdate)
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_mon+1) & 0x0f) << 21;
dosdate |= ((tm->tm_year-80) & 0x7f) << 25;
return dosdate;
diff --git a/date.h b/date.h
new file mode 100644
index 0000000..4cf5d41
--- /dev/null
+++ b/date.h
@@ -0,0 +1,25 @@
+#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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * date.h
+ */
+
+#ifndef DATE_H
+#define DATE_H
+
+#include <time.h>
+
+unsigned int msdos_date(time_t);
+
+#endif /* DATE_H */
diff --git a/dirtree.c b/dirtree.c
index 1c69bd8..b8c28f0 100644
--- a/dirtree.c
+++ b/dirtree.c
@@ -17,6 +17,7 @@
* Scan the input directory and create the appropriate structure
*/
+#include <inttypes.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
@@ -32,7 +33,7 @@
extern const char *program;
static int
-dos_mangle_name(const char *name, char *buf)
+dos_mangle_name(const char *name, char *buf, uint32_t numtail)
{
const char *dosforbidden =
"\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
@@ -41,6 +42,7 @@ dos_mangle_name(const char *name, char *buf)
const char *dot;
char *cp, *endp;
char xc;
+ const char numtail_str[9];
dot = strrchr(name, '.'); /* Find last dot */
if ( dot == name )
@@ -74,13 +76,20 @@ dos_mangle_name(const char *name, char *buf)
}
if ( (unsigned char)xc == 0xe5 && cp == buf ) {
- xc = 0x05;
+ xc = 0x05; /* Only applies to the first character... */
}
if ( cp < endp )
*cp++ = xc;
}
+ if ( numtail ) {
+ int nc = sprintf(numtail_str, "~%X", numtail);
+ cp = buf+8-nc;
+ while ( cp > buf && cp[-1] == ' ' ) cp--;
+ memcpy(cp, numtail_str, nc);
+ }
+
return 0;
}
@@ -154,7 +163,7 @@ make_dir_tree(const char *root, int *dirsizeptr, struct direntry *parent)
thisent->next = NULL;
/* Generate mangled DOS filename (eventually) */
- dos_mangle_name(thisent->name, thisent->mangled_name);
+ dos_mangle_name(thisent->name, thisent->mangled_name, 0);
/* Add to linked list */
*link = thisent;
diff --git a/fat.h b/fat.h
index 5fd91af..5a1db1a 100644
--- a/fat.h
+++ b/fat.h
@@ -69,4 +69,17 @@ struct fat_dirent
le32_t size; /* File size (bytes) */
};
+/* A VFAT filesystem continuation entry */
+struct fat_vfat_slot
+{
+ le8_t id; /* Sequence number for slot */
+ le16_t name0[5]; /* 5 characters */
+ le8_t attribute; /* Attribute byte */
+ le8_t reserved; /* Reserved, MBZ */
+ le8_t alias_csum; /* Short name checksum */
+ le16_t name5[6]; /* 6 characters */
+ le16_t firstclust; /* MBZ */
+ le16_t name11[2]; /* 2 characters */
+};
+
#endif
diff --git a/geo.h b/geo.h
new file mode 100644
index 0000000..070504e
--- /dev/null
+++ b/geo.h
@@ -0,0 +1,35 @@
+#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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * geo.h
+ *
+ * Geometry query interface
+ */
+
+#ifndef GEO_H
+#define GEO_H
+
+#include <inttypes.h>
+
+struct image_geometry {
+ unsigned long c, h, s;
+ uint64_t size, offset;
+ int secshift;
+};
+
+int
+get_geometry(int fd, struct image_geometry *geo);
+
+#endif /* GEO_H */
+
diff --git a/getgeo.c b/getgeo.c
index 63c0d20..1de9463 100644
--- a/getgeo.c
+++ b/getgeo.c
@@ -17,6 +17,8 @@
* Obtain output image length and/or geometry
*/
+#include <inttypes.h>
+#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
@@ -25,60 +27,89 @@
#include <sys/ioctl.h>
#include <linux/hdreg.h>
#include <linux/fs.h>
+#include <linux/fd.h>
#include <stdio.h>
-
-struct image_geometry {
- unsigned long c, h, s;
- unsigned long long size, offset;
- int secshift;
-};
+#include "geo.h"
extern const char *program;
-void
+int
get_geometry(int fd, struct image_geometry *geo)
{
struct hd_geometry hdgeo;
+ struct floppy_struct fdgeo;
struct stat st;
- long blksize;
+ uint64_t blksize64;
+ unsigned long blksize;
unsigned int secsize;
-
- if ( fstat(fd, &st) ) {
- perror(program);
- exit(1);
- }
+ const struct image_geometry *sg;
+ const struct image_geometry standard_geometries[] = {
+ { 40, 1, 8, 160<<10, 0, 9 },
+ { 40, 1, 9, 180<<10, 0, 9 },
+ { 40, 2, 8, 320<<10, 0, 9 },
+ { 40, 2, 9, 360<<10, 0, 9 },
+ { 80, 2, 9, 720<<10, 0, 9 },
+ { 80, 2, 15, 1200<<10, 0, 9 },
+ { 80, 2, 18, 1440<<10, 0, 9 },
+ { 80, 2, 36, 2880<<10, 0, 9 },
+ { 0, 0, 0, 0, 0, 0 }
+ };
+
+ if ( fstat(fd, &st) )
+ return -1;
+
+ memset(geo, 0, sizeof(*geo));
if ( S_ISBLK(st.st_mode) ) {
- if ( !ioctl(fd, HDIO_GETGEO, &hdgeo) ) {
- /* Got the geometry */
- if ( !geo->c )
- geo->c = hdgeo.cylinders;
- if ( !geo->h )
- geo->h = hdgeo.heads;
- if ( !geo->s )
- geo->s = hdgeo.sectors;
- if ( !geo->offset )
- geo->offset = hdgeo.start;
- }
- if ( !ioctl(fd, BLKGETSIZE, &blksize) ) {
- if ( !geo->size )
- geo->size = blksize;
- }
+#if 1 /*def BLKGETSIZE64*/
+ if ( !ioctl(fd, BLKGETSIZE64, &blksize64) ) {
+ geo->size = blksize64;
+ } else
+#endif
+ if ( !ioctl(fd, BLKGETSIZE, &blksize) ) {
+ geo->size = (uint64_t)blksize << 9;
+ }
if ( !ioctl(fd, BLKSSZGET, &secsize) ) {
- if ( !geo->secshift ) {
- geo->secshift = 0;
- while ( secsize > 1 ) {
- geo->secshift++;
- secsize >>= 1;
- }
+ while ( secsize > 1 ) {
+ geo->secshift++;
+ secsize >>= 1;
}
}
+
+ if ( !ioctl(fd, HDIO_GETGEO, &hdgeo) ) {
+ /* Got the geometry */
+ geo->c = hdgeo.cylinders; /* Don't use... may be truncated */
+ geo->h = hdgeo.heads;
+ geo->s = hdgeo.sectors;
+ geo->offset = (uint64_t)hdgeo.start << geo->secshift;
+ } else if ( !ioctl(fd, FDGETPRM, &fdgeo) ) {
+ geo->c = fdgeo.track; /* IS THIS CORRECT?!? */
+ geo->h = fdgeo.head;
+ geo->s = fdgeo.sect;
+ }
} else if ( S_ISREG(st.st_mode) ) {
- if ( !geo->size )
+ /* Plain file; set the size and hunt for a standard geometry, otherwise
+ just make something up */
geo->size = st.st_size;
+
+ for ( sg = standard_geometries ; sg->size ; sg++ ) {
+ if ( sg->size == geo->size ) {
+ *geo = *sg;
+ return 0;
+ }
+ }
+
+ /* DO SOMETHING! */
+ } else if ( S_ISDIR(st.st_mode) ) {
+ errno = EISDIR;
+ return -1;
} else {
/* Char device, pipe or something... geometry needs to be explicit */
+ errno = ESPIPE;
+ return -1;
}
+
+ return 0;
}
#ifdef STANDALONE
@@ -92,20 +123,17 @@ int main(int argc, char *argv[])
program = argv[0];
- if ( fd < 0 ) {
+ if ( fd < 0 || get_geometry(fd, &geo) ) {
perror(argv[1]);
exit(1);
}
- memset(&geo, 0, sizeof geo);
- get_geometry(fd, &geo);
-
printf("c = %lu, h = %lu, s = %lu\n",
geo.c, geo.h, geo.s);
- printf("size = %llu\n", geo.size);
+ printf("size = %llu\n", geo.size);
printf("secshift = %d\n", geo.secshift);
- printf("offset = %llu\n", geo.offset);
+ printf("offset = %llu\n", geo.offset);
return 0;
}
diff --git a/vfat.c b/vfat.c
new file mode 100644
index 0000000..801156b
--- /dev/null
+++ b/vfat.c
@@ -0,0 +1,87 @@
+#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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * vfat.h
+ *
+ * Construct VFAT long filename descriptors
+ */
+
+#include <iconv.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdio.h>
+#include "fat.h"
+#include "minmax.h"
+
+#define VFAT_MAX_LEN 64
+#define VFAT_MAX_SLOTS ((VFAT_MAX_LEN+12)/13)
+
+extern const char *program;
+
+static iconv_t iconv_utf16;
+
+void vfat_setup(void)
+{
+ iconv_utf16 = iconv_open("UTF-16LE", "");
+ if ( iconv_utf16 == (iconv_t)-1 ) {
+ fprintf("%s: failed to iconv_open UTF-16LE: %s\n",
+ program, strerror(errno));
+ exit(1);
+ }
+}
+
+int vfat_make_long_name(struct fat_vfat_slot *slots,
+ const char *str,
+ uint8_t csum)
+{
+ uint16_t buffer[VFAT_MAX_LEN];
+ uint16_t *xb;
+ char *inb, *outb;
+ int inbl, outbl, xl, nx;
+ int seq = 1;
+
+ inb = str;
+ inbl = strlen(inb);
+ outb = (char *)buffer;
+ outbl = VFAT_MAX_LEN << 1;
+
+ iconv(iconv_utf16, NULL, NULL, NULL, NULL); /* Reset input state */
+ iconv(iconv_utf16, &inb, &inbl, &outb, &outbl);
+
+ xl = VFAT_MAX_LEN - (outbl >> 1);
+ xb = buffer;
+
+ while ( xl ) {
+ memset(slots, 0, sizeof(*slots));
+ slots->id = seq++;
+ slots->attribute = 0xef; /* FIX */
+ slots->alias_csum = csum;
+
+ nx = min(xl,5);
+ memcpy(slots->name0, xb, nx<<1);
+ xl -= nx;
+
+ nx = min(xl,6);
+ memcpy(slots->name5, xb, nx<<1);
+ xl -= nx;
+
+ nx = min(xl,2);
+ memcpy(slots->name11, xb, nx<<1);
+ xl -= nx;
+
+ slots++;
+ }
+
+ return seq-1;
+}