summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2002-04-23 20:38:10 +0000
committerH. Peter Anvin <hpa@zytor.com>2002-04-23 20:38:10 +0000
commitf96ed279d909b218db296022a4d7bbdd964cbd0a (patch)
tree16366430ac18300a97d300586ce285e9e2584a41
downloadmkfatfs-f96ed279d909b218db296022a4d7bbdd964cbd0a.tar.gz
mkfatfs-f96ed279d909b218db296022a4d7bbdd964cbd0a.tar.xz
mkfatfs-f96ed279d909b218db296022a4d7bbdd964cbd0a.zip
Initial checkin into version control system
-rw-r--r--Makefile45
-rw-r--r--alloc.c120
-rw-r--r--clustparm.c114
-rw-r--r--dirtree.c172
-rw-r--r--dirtree.h44
-rw-r--r--fat.h66
-rw-r--r--fatdata.h39
-rw-r--r--genfat.c133
-rw-r--r--getgeo.c107
-rw-r--r--main.c51
-rw-r--r--main.h46
-rw-r--r--minmax.h53
-rw-r--r--ulint.h113
-rw-r--r--writechain.c49
-rw-r--r--writedir.c115
-rw-r--r--writefile.c87
-rw-r--r--writefs.c47
-rw-r--r--xmalloc.c47
-rw-r--r--xmalloc.h27
-rw-r--r--xstdio.c57
-rw-r--r--xstdio.h35
21 files changed, 1567 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5dd0726
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,45 @@
+#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., 675 Mass Ave, Cambridge MA 02139,
+## USA; either version 2 of the License, or (at your option) any later
+## version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+#
+# Makefile for genfatimage
+#
+
+CC = gcc
+CFLAGS = -g -O -Wall -D_FILE_OFFSET_BITS=64
+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
+SRCS = alloc.c dirtree.c main.c xmalloc.c xstdio.c genfat.c \
+ clustparm.c writedir.c writefile.c writechain.c writefs.c
+
+.SUFFIXES: .c .o .asm .bin .lst
+
+all: genfatimage getgeo
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+genfatimage: $(OBJS)
+ $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+
+getgeo: getgeo.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -DSTANDALONE -o $@ $< $(LIBS)
+
+clean:
+ rm -f *.o genfatimage
+
+spotless: clean
+ rm -f *~ \#* core
diff --git a/alloc.c b/alloc.c
new file mode 100644
index 0000000..6a3389d
--- /dev/null
+++ b/alloc.c
@@ -0,0 +1,120 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * alloc.c
+ *
+ * Allocate clusters to all entries in a directory tree
+ *
+ * First, allocate all directories; then allocate the files
+ * -- all in depth-first order by directory
+ */
+
+#include <fcntl.h>
+#include "fatdata.h"
+#include "dirtree.h"
+
+/* Allocate space for directories */
+
+static void
+alloc_directories(struct direntry *tree, int *first_cluster,
+ int clustshift,
+ struct direntry ***nextptrptr)
+{
+ struct direntry *p;
+ unsigned int size, nclust, clustsize;
+ int next_cluster = *first_cluster;
+ struct direntry **nextptr = *nextptrptr;
+
+ clustsize = 1U << clustshift;
+
+ for ( p = tree ; p ; p = p->next ) {
+ if ( S_ISDIR(p->st.st_mode) ) {
+ /* First allocate space for this same directory */
+
+ /* 2 entries for . and .. needed */
+ size = (p->dirsize + 2) << 5;
+
+ nclust = (size + clustsize - 1) >> clustshift;
+ p->clusters = nclust;
+ p->cluster = next_cluster;
+ next_cluster += nclust;
+
+ *nextptr = p;
+ nextptr = &p->nextbyclust;
+
+ /* Then allocate space for any subdirectories */
+ alloc_directories(p->dir, &next_cluster, clustshift, &nextptr);
+ }
+ }
+
+ *first_cluster = next_cluster;
+ *nextptrptr = nextptr;
+}
+
+
+/* Allocate space for files */
+
+static void
+alloc_files(struct direntry *tree, int *first_cluster, int clustshift,
+ struct direntry ***nextptrptr)
+{
+ struct direntry *p;
+ unsigned int size, nclust, clustsize;
+ int next_cluster = *first_cluster;
+ struct direntry **nextptr = *nextptrptr;
+
+ clustsize = 1U << clustshift;
+
+ /* First allocate space for the files in this directory */
+
+ for ( p = tree ; p ; p = p->next ) {
+ if ( !S_ISDIR(p->st.st_mode) ) {
+ size = p->st.st_size;
+
+ if ( size > 0 ) {
+ nclust = (size + clustsize - 1) >> clustshift;
+ p->clusters = nclust;
+ p->cluster = next_cluster;
+ next_cluster += nclust;
+
+ *nextptr = p;
+ nextptr = &p->nextbyclust;
+ } else {
+ /* Empty files have no cluster pointer */
+ p->cluster = p->clusters = 0;
+ }
+ }
+ }
+
+ /* Then allocate space for the files in subdirectories */
+
+ for ( p = tree ; p ; p = p->next ) {
+ if ( S_ISDIR(p->st.st_mode) ) {
+ alloc_files(p->dir, &next_cluster, clustshift, &nextptr);
+ }
+ }
+
+ *first_cluster = next_cluster;
+ *nextptrptr = nextptr;
+}
+
+/* Complete allocation algorithm */
+
+void
+alloc_space(struct direntry *tree, int *first_cluster, int clustshift,
+ struct direntry **nextptr)
+{
+ alloc_directories(tree, first_cluster, clustshift, &nextptr);
+ alloc_files(tree, first_cluster, clustshift, &nextptr);
+}
diff --git a/clustparm.c b/clustparm.c
new file mode 100644
index 0000000..075df7d
--- /dev/null
+++ b/clustparm.c
@@ -0,0 +1,114 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * clustparm.c
+ *
+ * Compute the appropriate cluster (given as a shift) for a specific
+ * filesystem.
+ */
+
+#include <string.h>
+#include "main.h"
+#include "minmax.h"
+
+/*
+ * The following entries in the parm structure should be
+ * filled in ahead of time:
+ * - sectorshift
+ * - sectors
+ * - rootdirdects
+ * - nfats
+ * minclustshift is the *minimum* cluster size shift count to use
+ */
+#define FAT12_MAX_CLUST (0x0FFF-10)
+#define FAT16_MAX_CLUST (0xFFFF-10)
+
+void
+getclustsize(struct fatfsparm *parm,
+ unsigned int minclustshift)
+{
+ unsigned int sectorsize = 1U << parm->sectorshift;
+ int clustshift;
+ int fatsects, maxfatsects, maxfatsize;
+ unsigned long nclust, nclust_fat, nclust_space;
+ unsigned long diskuse = 0;
+ unsigned long sectors;
+ int nfats = parm->nfats;
+ int sectorshift = parm->sectorshift;
+
+ sectors = parm->sectors - parm->resvsects - parm->rootdirsects;
+
+ /* "Thou shalt not use more than 32K per cluster" */
+ for ( clustshift = minclustshift ;
+ clustshift < 16 ; clustshift++ ) {
+ /* Select FAT12 vs FAT16 by assuming FAT16 and falling back
+ to FAT12 if the number of clusters is 4086 or less. */
+
+ /* Maximum possible FAT size */
+ maxfatsize = (min2((sectors >> (clustshift-sectorshift)),
+ FAT16_MAX_CLUST)+2) << 1;
+ maxfatsects = (maxfatsize + sectorsize - 1) >> sectorshift;
+
+ for ( fatsects = 1 ; fatsects <= maxfatsects ; fatsects++ ) {
+ /* Max clusters by FAT limitation */
+ nclust_fat = ((fatsects << sectorshift) >> 1) - 2;
+ /* Max clusters by available space */
+ nclust_space = (sectors-fatsects*nfats) >> (clustshift-sectorshift);
+
+ nclust = min3(nclust_fat, nclust_space, FAT16_MAX_CLUST);
+
+ diskuse = fatsects*nfats + (nclust << (clustshift-sectorshift));
+
+ if ( diskuse > parm->diskuse ) {
+ parm->diskuse = diskuse;
+ parm->clusters = nclust;
+ parm->fatsects = fatsects;
+ parm->clustshift = clustshift;
+ parm->fattype = 16;
+ }
+ }
+
+ /* Is our best solution so far a FAT12 solution? */
+ if ( parm->clusters <= FAT12_MAX_CLUST ) {
+ /* Redo computation for FAT12 */
+
+ /* Maximum possible FAT size */
+ maxfatsize = min2(sectors >> (clustshift-sectorshift), FAT12_MAX_CLUST)+2;
+ maxfatsize = maxfatsize + (maxfatsize << 1);
+ maxfatsize = (maxfatsize + 1) & ~1;
+ maxfatsects = (maxfatsize + sectorsize - 1) >> sectorshift;
+
+ for ( fatsects = 1 ; fatsects <= maxfatsects ; fatsects++ ) {
+ /* Max clusters by FAT limitation */
+ nclust_fat = ((fatsects << sectorshift) << 1)/3 - 2;
+ /* Max clusters by available space */
+ nclust_space = (sectors-fatsects*nfats) >> (clustshift-sectorshift);
+
+ nclust = min3(nclust_fat, nclust_space, FAT12_MAX_CLUST);
+
+ diskuse = fatsects*nfats + (nclust << (clustshift-sectorshift));
+
+ if ( diskuse > parm->diskuse ) {
+ parm->diskuse = diskuse;
+ parm->clusters = nclust;
+ parm->fatsects = fatsects;
+ parm->clustshift = clustshift;
+ parm->fattype = 12;
+ }
+ }
+ }
+ }
+ parm->slopsectors = sectors - parm->diskuse;
+}
+
diff --git a/dirtree.c b/dirtree.c
new file mode 100644
index 0000000..e3f8dd3
--- /dev/null
+++ b/dirtree.c
@@ -0,0 +1,172 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * dirtree.c
+ *
+ * Scan the input directory and create the appropriate structure
+ */
+
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include "dirtree.h"
+#include "xmalloc.h"
+
+extern const char *program;
+
+static int
+dos_mangle_name(const char *name, char *buf)
+{
+ const char *dosforbidden =
+ "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
+ "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+ " \"\'\\/[]|<>,*$+";
+ const char *dot;
+ char *cp, *endp;
+ char xc;
+
+ dot = strrchr(name, '.'); /* Find last dot */
+ if ( dot == name )
+ dot = NULL; /* Leading dot? */
+
+ cp = buf; endp = buf+11;
+ memset(buf, ' ', 11);
+ *endp = '\0';
+
+ for ( ; *name ; name++ ) {
+ xc = *name;
+ if ( xc == '.' ) {
+ if ( name == dot ) {
+ /* Last dot */
+ cp = buf+8;
+ cp[0] = ' ';
+ cp[1] = ' ';
+ cp[2] = ' ';
+ continue;
+ } else {
+ xc = '_';
+ }
+ }
+
+ if ( islower(xc) ) {
+ xc = toupper(xc);
+ }
+
+ if ( strchr(dosforbidden, xc) ) {
+ xc = '_';
+ }
+
+ if ( (unsigned char)xc == 0xe5 ) {
+ xc = 0xe5;
+ }
+
+ if ( cp < endp )
+ *cp++ = xc;
+ }
+
+ return 0;
+}
+
+
+struct direntry *
+make_dir_tree(const char *root, int *dirsizeptr, struct direntry *parent)
+{
+ DIR *dirp;
+ struct dirent *de;
+ struct direntry *thisent;
+ struct direntry *tree = NULL;
+ struct direntry **link = &tree;
+ int rootlen = strlen(root);
+ int namelen;
+ int dirsize;
+
+ dirsize = 0;
+
+ dirp = opendir(root);
+ if ( !dirp )
+ return NULL;
+
+ while ( (de = readdir(dirp)) != NULL ) {
+ if ( !strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") )
+ continue; /* Ignore . and .. */
+
+ thisent = xmalloc(sizeof(struct direntry));
+ memset(thisent, 0, sizeof(struct direntry));
+
+ thisent->name = xstrdup(de->d_name);
+ namelen = strlen(thisent->name);
+
+ thisent->path = xmalloc(rootlen+namelen+3);
+ memcpy(thisent->path, root, rootlen);
+ thisent->path[rootlen] = '/';
+ memcpy(thisent->path+rootlen+1, thisent->name, namelen+1);
+
+ thisent->parent = parent;
+
+ if ( stat(thisent->path, &thisent->st) ) {
+ fprintf(stderr, "%s: Cannot stat file: %s\n", program,
+ thisent->path);
+ free(thisent->name);
+ free(thisent->path);
+ free(thisent);
+ continue;
+ }
+
+ if ( S_ISDIR(thisent->st.st_mode) ) {
+ /* Recursion: see recursion */
+ thisent->dir = make_dir_tree(thisent->path, &thisent->dirsize, thisent);
+ thisent->attribute = 0x10; /* Directory */
+ } else if ( !S_ISREG(thisent->st.st_mode) ) {
+ /* Some kind of special file (not symbolic link, we used stat,
+ not lstat.) This isn't representable, so just ignore it. */
+ fprintf(stderr, "%s: Ignoring special file: %s\n", program,
+ thisent->path);
+ free(thisent->name);
+ free(thisent->path);
+ free(thisent);
+ continue;
+ } else {
+ thisent->dir = NULL;
+ thisent->attribute = 0x00; /* File */
+ }
+
+ if ( !(thisent->st.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) ) {
+ thisent->attribute |= 0x01; /* Readonly */
+ }
+
+ thisent->next = NULL;
+
+ /* Generate mangled DOS filename (eventually) */
+ dos_mangle_name(thisent->name, thisent->mangled_name);
+
+ /* Add to linked list */
+ *link = thisent;
+ link = &thisent->next;
+ dirsize++;
+ }
+
+ closedir(dirp);
+
+ if (dirsizeptr)
+ *dirsizeptr = dirsize;
+
+ return tree;
+}
+
diff --git a/dirtree.h b/dirtree.h
new file mode 100644
index 0000000..23b0dc3
--- /dev/null
+++ b/dirtree.h
@@ -0,0 +1,44 @@
+/* $Id$ */
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * dirtree.h
+ *
+ * Directory tree data structure
+ */
+
+#ifndef DIRTREE_H
+#define DIRTREE_H
+
+#include <sys/stat.h>
+
+struct direntry {
+ char *name; /* Filename */
+ char *path; /* Full path */
+ char mangled_name[12]; /* Mangled */
+ struct stat st; /* stat info */
+ struct direntry *dir; /* Directory contents (directory only) */
+ unsigned int dirsize; /* Cardinality of directory */
+ struct direntry *parent; /* Parent directory */
+ struct direntry *next; /* Linked list */
+ void *data; /* If path is null, in-core data here */
+ unsigned int attribute; /* DOS attribute byte */
+ unsigned int clusters; /* Number of clusters allocated */
+ unsigned int cluster; /* Assigned cluster (once we get there) */
+ struct direntry *nextbyclust; /* Next pointer in on-disk order */
+};
+
+struct direntry *
+make_dir_tree(const char *, int *, struct direntry *parent);
+
+#endif
diff --git a/fat.h b/fat.h
new file mode 100644
index 0000000..dda2ac2
--- /dev/null
+++ b/fat.h
@@ -0,0 +1,66 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * fat.h
+ *
+ * Basic data structures for a FAT filesystem
+ */
+
+#ifndef FAT_H
+#define FAT_H
+
+#include "ulint.h"
+
+/* The poor excuse FAT has for a superblock -- in the boot sector */
+struct fat_bootsect {
+ le8_t bsJump[3]; /* Jump to code */
+ char bsOemName[8]; /* Formatting program */
+ le16_t bsBytesPerSec; /* Bytes/sector */
+ le8_t bsSecPerClust; /* Sectors/cluster */
+ le16_t bsResSectors; /* Reserved sectors */
+ le8_t bsFATs; /* Number of FATs */
+ le16_t bsRootDirEnts; /* Number of entries/root directory */
+ le16_t bsSectors; /* Number of sectors [1] */
+ le8_t bsMedia; /* Magic media type byte */
+ le16_t bsFATsecs; /* Sectors/FAT */
+ le16_t bsSecPerTrack; /* Sectors/track */
+ le16_t bsHeads; /* Number of heads */
+ le32_t bsHiddenSecs; /* Number of hidden sectors */
+ le32_t bsHugeSectors; /* Number of sectors [2] */
+ le8_t bsDriveNumber; /* Drive number */
+ le8_t bsReserved1; /* Reserved */
+ le8_t bsBootSignature; /* 0x29 */
+ le32_t bsVolumeID; /* Volume serial number */
+ char bsFileSysType[8]; /* File system type */
+
+ le8_t bsCode[448]; /* Boot sector code */
+
+ le16_t bsSignature; /* 0xAA55 */
+};
+
+#define BS_BOOTSIGNATURE 0x29
+#define BS_SIGNATURE 0xAA55
+
+/* A FAT filesystem directory entry */
+
+struct fat_dirent
+{
+ le8_t name[11]; /* Mangled filename */
+ le8_t attribute; /* File type/attribute */
+ le8_t _something1[14];
+ le16_t firstclust; /* First cluster pointer */
+ le32_t size; /* File size (bytes) */
+};
+
+#endif
diff --git a/fatdata.h b/fatdata.h
new file mode 100644
index 0000000..b6bf511
--- /dev/null
+++ b/fatdata.h
@@ -0,0 +1,39 @@
+#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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * fatdata.h
+ *
+ * Internal representation of the FAT filesysem
+ */
+
+#ifndef FATDATA_H
+#define FATDATA_H
+
+struct fatfsparm {
+ int clustshift; /* log2(bytes/cluster) */
+ int clusters; /* Number of clusters */
+ int sectorshift; /* log2(bytes/sector) */
+ int sectors; /* Total sectors */
+ int fatsects; /* Sectors for each FAT */
+ int resvsects; /* Reserved sectors (boot, ...) */
+ int rootdirsects; /* Sectors for the root directory */
+ int slopsectors; /* Nonclustered sectors at the end */
+ int nfats; /* Number of FATs */
+ int diskuse; /* FAT+data sectors */
+ int fattype; /* 12, 16 or 32 */
+ void *fat; /* FAT map */
+};
+
+#endif
+
diff --git a/genfat.c b/genfat.c
new file mode 100644
index 0000000..5607d10
--- /dev/null
+++ b/genfat.c
@@ -0,0 +1,133 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * genfat.c
+ *
+ * Generate the FAT
+ */
+
+#include <assert.h>
+#include "main.h"
+#include "fatdata.h"
+#include "dirtree.h"
+#include "xmalloc.h"
+#include "ulint.h"
+
+static inline void
+setfat12ent(unsigned char *fat, unsigned int entry, unsigned int val)
+{
+ int fptr = entry + (entry >> 1);
+
+ if ( entry & 1 ) {
+ fat[fptr] = (fat[fptr] & 0x0F) | ((val << 4) & 0xF0);
+ fat[fptr+1] = (val >> 4) & 0xFF;
+ } else {
+ fat[fptr] = val & 0xFF;
+ fat[fptr+1] = (fat[fptr+1] & 0xF0) | ((val >> 8) & 0x0F);
+ }
+}
+
+static void *
+genfat12(struct direntry *chain, int clusters, int secshift)
+{
+ unsigned char *fat;
+ unsigned int fat_size, rest;
+ unsigned int secsize = 1U << secshift;
+ int i, n;
+
+ if ( clusters & 1 )
+ clusters++; /* Avoid odd-sized FATs */
+
+ fat_size = clusters + (clusters >> 1);
+ rest = fat_size & (secsize - 1);
+ if ( rest ) {
+ /* Round up to the nearest sector */
+ fat_size = fat_size - rest + secsize;
+ }
+
+ fat = xmalloc(fat_size);
+ memset(fat, 0, 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 */
+
+ chain = chain->nextbyclust;
+ }
+
+ return fat;
+}
+
+static inline void
+setfat16ent(le16_t *fat, unsigned int entry, unsigned int val)
+{
+ write16(&fat[entry], val);
+}
+
+static void *
+genfat16(struct direntry *chain, int clusters, int secshift)
+{
+ le16_t *fat;
+ unsigned int fat_size, rest;
+ unsigned int secsize = 1U << secshift;
+ int i, n;
+
+ fat_size = clusters << 1;
+ rest = fat_size & (secsize - 1);
+ if ( rest ) {
+ /* Round up to the nearest sector */
+ fat_size = fat_size - rest + secsize;
+ }
+
+ fat = xmalloc(fat_size);
+ memset(fat, 0, 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-- ) {
+ setfat16ent(fat, i, i+1);
+ }
+ setfat16ent(fat, i, 0xFFFF); /* Last file cluster */
+
+ chain = chain->nextbyclust;
+ }
+
+ return fat;
+}
+
+void *
+genfat(struct direntry *allocchain, struct fatfsparm *parm)
+{
+ switch ( parm->fattype ) {
+ case 12:
+ return genfat12(allocchain, parm->clusters, parm->sectorshift);
+ case 16:
+ return genfat16(allocchain, parm->clusters, parm->sectorshift);
+ default:
+ assert(0); /* Unknown FAT type */
+ return NULL;
+ }
+}
+
diff --git a/getgeo.c b/getgeo.c
new file mode 100644
index 0000000..e0b3e6d
--- /dev/null
+++ b/getgeo.c
@@ -0,0 +1,107 @@
+#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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * getgeo.c
+ *
+ * Obtain output image length and/or geometry
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/hdreg.h>
+#include <linux/fs.h>
+#include <stdio.h>
+
+struct image_geometry {
+ unsigned long c, h, s;
+ unsigned long long size, offset;
+ int secshift;
+};
+
+extern const char *program;
+
+void
+get_geometry(int fd, struct image_geometry *geo)
+{
+ struct hd_geometry hdgeo;
+ struct stat st;
+ long blksize;
+ unsigned int secsize;
+
+ if ( fstat(fd, &st) ) {
+ perror(program);
+ exit(1);
+ }
+
+ 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 ( !ioctl(fd, BLKSSZGET, &secsize) ) {
+ if ( !geo->secshift ) {
+ geo->secshift = 0;
+ while ( secsize > 1 ) {
+ geo->secshift++;
+ secsize >>= 1;
+ }
+ }
+ }
+ } else if ( S_ISREG(st.st_mode) ) {
+ if ( !geo->size )
+ geo->size = st.st_size;
+ } else {
+ /* Char device, pipe or something... geometry needs to be explicit */
+ }
+}
+
+#ifdef STANDALONE
+
+const char *program;
+
+int main(int argc, char *argv[])
+{
+ int fd = open(argv[1], O_RDONLY);
+ struct image_geometry geo;
+
+ program = argv[0];
+
+ 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("secshift = %d\n", geo.secshift);
+ printf("offset = %llu\n", geo.offset);
+
+ return 0;
+}
+
+#endif
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..77db2b5
--- /dev/null
+++ b/main.c
@@ -0,0 +1,51 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * main.c
+ *
+ * Command-line parsing; main()
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "dirtree.h"
+#include "main.h"
+
+const char *program;
+
+int main(int argc, char *argv[])
+{
+ struct direntry *tree;
+ struct direntry *allocchain;
+ int cluster = 2; /* 2 is the first cluster */
+ int rootdirsize;
+ struct fatfsparm fsparm;
+ void *fat;
+
+ program = argv[0];
+
+ memset(&fsparm, 0, sizeof fsparm);
+ fsparm.sectors = 200000;
+ fsparm.rootdirsects = 224/(512/32);
+ fsparm.sectorshift = 9;
+ fsparm.nfats = 2;
+
+ getclustsize(&fsparm, 9);
+
+ tree = make_dir_tree(argv[1], &rootdirsize, NULL);
+ alloc_space(tree, &cluster, fsparm.clustshift, &allocchain);
+ fat = genfat(allocchain, &fsparm);
+
+ return 0;
+}
diff --git a/main.h b/main.h
new file mode 100644
index 0000000..2710f45
--- /dev/null
+++ b/main.h
@@ -0,0 +1,46 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * main.h
+ *
+ * Header file for module entrypoints
+ */
+
+#include <stdio.h>
+#include "fatdata.h"
+
+struct direntry;
+
+extern const char *program; /* Program name (for errors) */
+
+void
+alloc_space(struct direntry *, int *, int, struct direntry **);
+
+void *
+genfat(struct direntry *allocchain, struct fatfsparm *fsparm);
+
+void
+getclustsize(struct fatfsparm *parm,
+ unsigned int minclustshift);
+
+void
+writerootdir(FILE *, struct direntry *, int);
+void
+writesubdir(FILE *, struct direntry *, int);
+void
+writefile(FILE *, struct direntry *, int);
+void
+writeallocchain(FILE *f, struct direntry *dirp,
+ int *firstcluster, int clustshift);
+
diff --git a/minmax.h b/minmax.h
new file mode 100644
index 0000000..a03fd2c
--- /dev/null
+++ b/minmax.h
@@ -0,0 +1,53 @@
+#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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef MINMAX_H
+#define MINMAX_H
+
+static inline
+unsigned int min2(unsigned int a, unsigned int b)
+{
+ return (a < b) ? a : b;
+}
+
+static inline
+unsigned int min3(unsigned int a, unsigned int b, unsigned int c)
+{
+ return min2(min2(a,b),c);
+}
+
+static inline
+unsigned int min4(unsigned int a, unsigned int b, unsigned int c, unsigned int d)
+{
+ return min2(min2(a,b),min2(c,d));
+}
+
+static inline
+unsigned int max2(unsigned int a, unsigned int b)
+{
+ return (a > b) ? a : b;
+}
+
+static inline
+unsigned int max3(unsigned int a, unsigned int b, unsigned int c)
+{
+ return max2(max2(a,b),c);
+}
+
+static inline
+unsigned int max4(unsigned int a, unsigned int b, unsigned int c, unsigned int d)
+{
+ return max2(max2(a,b),max2(c,d));
+}
+
+#endif
diff --git a/ulint.h b/ulint.h
new file mode 100644
index 0000000..3990642
--- /dev/null
+++ b/ulint.h
@@ -0,0 +1,113 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * ulint.h
+ *
+ * Basic operations on unaligned, littleendian integers
+ */
+
+#ifndef ULINT_H
+#define ULINT_H
+
+/* These are unaligned, littleendian integer types */
+
+typedef unsigned char le8_t; /* 8-bit byte */
+typedef unsigned char le16_t[2]; /* 16-bit word */
+typedef unsigned char le32_t[4]; /* 32-bit dword */
+
+/* Read/write these quantities */
+
+static inline unsigned char
+read8(le8_t *_p)
+{
+ return *_p;
+}
+
+static inline void
+write8(le8_t *_p, unsigned char _v)
+{
+ *_p = _v;
+}
+
+#ifdef __i386__
+
+/* Optimized version for i386, which can handle these directly */
+
+static inline unsigned short
+read16(le16_t *_p)
+{
+ return *((unsigned short *)_p);
+}
+
+static inline void
+write16(le16_t *_p, unsigned short _v)
+{
+ *((unsigned short *)_p) = _v;
+}
+
+static inline unsigned int
+read32(le32_t *_p)
+{
+ return *((unsigned int *)_p);
+}
+
+static inline void
+write32(le32_t *_p, unsigned int _v)
+{
+ *((unsigned int *)_p) = _v;
+}
+
+#else
+
+/* Generic, mostly portable versions */
+
+static inline unsigned short
+read16(le16_t *_p)
+{
+ unsigned short _v;
+
+ _v = p[0];
+ _v |= p[1] << 8;
+ return _v;
+}
+
+static inline void
+write16(le16_t *_p, unsigned short _v)
+{
+ _p[0] = _v & 0xFF;
+ _p[1] = (_v >> 8) & 0xFF;
+}
+
+static inline unsigned int
+read32(le32_t *_p)
+{
+ _v = _p[0];
+ _v |= _p[1] << 8;
+ _v |= _p[2] << 16;
+ _v |= _p[3] << 24;
+ return _v;
+}
+
+static inline void
+write32(le32_t *_p, unsigned int _v)
+{
+ _p[0] = _v & 0xFF;
+ _p[1] = (_v >> 8) & 0xFF;
+ _p[2] = (_v >> 16) & 0xFF;
+ _p[3] = (_v >> 24) & 0xFF;
+}
+
+#endif
+
+#endif /* ULINT_H */
diff --git a/writechain.c b/writechain.c
new file mode 100644
index 0000000..9591600
--- /dev/null
+++ b/writechain.c
@@ -0,0 +1,49 @@
+#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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * writetree.c
+ *
+ * Write out the entire directory tree
+ */
+
+#include <assert.h>
+#include <sysexits.h>
+#include "dirtree.h"
+#include "fat.h"
+#include "xstdio.h"
+#include "main.h"
+
+/*
+ * Write out the contents of an allocation chain.
+ */
+void
+writeallocchain(FILE *f, struct direntry *dirp,
+ int *firstcluster, int clustshift)
+{
+ /* Write out directories and files in on-disk order */
+ while ( dirp ) {
+ assert(*firstcluster == dirp->cluster);
+ if ( dirp->attribute & 0x10 ) {
+ /* Directory */
+ writesubdir(f, dirp, clustshift);
+ } else {
+ /* File */
+ writefile(f, dirp, clustshift);
+ }
+
+ *firstcluster += dirp->clusters;
+ dirp = dirp->nextbyclust;
+ }
+}
+
diff --git a/writedir.c b/writedir.c
new file mode 100644
index 0000000..50265b7
--- /dev/null
+++ b/writedir.c
@@ -0,0 +1,115 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * writedir.c
+ *
+ * Write out a FAT directory
+ */
+
+#include <sysexits.h>
+#include "dirtree.h"
+#include "fat.h"
+#include "xstdio.h"
+#include "main.h"
+
+/* Write out a subdirectory to disk */
+void
+writesubdir(FILE *f, struct direntry *dirp, int clustshift)
+{
+ struct direntry *p;
+ struct fat_dirent dent;
+ unsigned int size;
+ unsigned int clustsize = 1U << clustshift;
+
+ /* Write . */
+ memset(&dent, 0, 32);
+ memcpy(dent.name, ". ", 11);
+ write8(&dent.attribute, 0x10); /* Directory */
+ write16(&dent.firstclust, dirp->cluster);
+ size = (dirp->dirsize + 2) << 5;
+ write32(&dent.size, size);
+ xfwrite(&dent, 32, 1, f);
+
+ /* Write .. */
+ memset(&dent, 0, 32);
+ memcpy(&dent.name, ".. ", 11);
+ write8(&dent.attribute, 0x10); /* Directory */
+ if ( dirp->parent ) {
+ /* If .. is the root directory, skip these */
+ write16(&dent.firstclust, dirp->parent->cluster);
+ size = (dirp->parent->dirsize + 2) << 5;
+ write32(&dent.size, size);
+ }
+ xfwrite(&dent, 32, 1, f);
+
+ 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);
+ xfwrite(&dent, 32, 1, f);
+ }
+
+ /* Pad out the last cluster */
+ size = (dirp->dirsize + 2) << 5;
+ size &= (clustsize - 1);
+ if ( size ) {
+ xfwritezero(clustsize-size, f);
+ }
+}
+
+
+/* Write out the root directory to disk */
+void
+writerootdir(FILE *f, struct direntry *dirp, int rootdirents)
+{
+ struct direntry *p;
+ struct fat_dirent dent;
+ unsigned int size;
+
+ /* No . or .. in the root directory. Disk label or ldlinux.sys
+ should be added to the directory tree explicitly. */
+
+ for ( p = dirp->dir ; p ; p = p->next ) {
+ if ( rootdirents <= 0 ) {
+ fprintf(stderr, "%s: Fatal error: root directory overflow\n",
+ program);
+ exit(EX_DATAERR);
+ }
+
+ 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);
+ xfwrite(&dent, 32, 1, f);
+ rootdirents--;
+ }
+
+ /* Pad out the root directory */
+ if ( rootdirents ) {
+ xfwritezero(rootdirents << 5, f);
+ }
+}
diff --git a/writefile.c b/writefile.c
new file mode 100644
index 0000000..efd5736
--- /dev/null
+++ b/writefile.c
@@ -0,0 +1,87 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * writefile.c
+ *
+ * Write out a file
+ */
+
+#include <sysexits.h>
+#include "xstdio.h"
+#include "dirtree.h"
+#include "main.h"
+
+#define BUFFER_SIZE 65536
+
+void
+writefile(FILE *f, struct direntry *dirp, int clustshift)
+{
+ FILE *src;
+ char buffer[BUFFER_SIZE];
+ unsigned int bytestowrite = dirp->clusters << clustshift;
+ int bytesread, writebytes;
+
+ if ( dirp->path ) {
+ /* External file */
+
+ if ( !(src = fopen(dirp->path, "rb")) ) {
+ fprintf(stderr, "%s: File disappeared during processing: %s\n",
+ program, dirp->path);
+ exit(EX_IOERR);
+ }
+
+ while ( bytestowrite &&
+ (bytesread = fread(buffer, 1, BUFFER_SIZE, src)) > 0 ) {
+ if ( bytesread > bytestowrite )
+ writebytes = bytestowrite;
+ else
+ writebytes = bytesread;
+
+ xfwrite(buffer, 1, writebytes, f);
+
+ bytestowrite -= writebytes;
+ }
+
+ if ( ferror(src) ) {
+ fprintf(stderr, "%s: Error received on reading file: %s\n",
+ program, dirp->path);
+ }
+
+ fclose(src);
+ } else {
+ /* File data in core */
+
+ if ( dirp->st.st_size > bytestowrite )
+ writebytes = bytestowrite;
+ else
+ writebytes = dirp->st.st_size;
+
+ xfwrite(dirp->data, 1, writebytes, f);
+
+ bytestowrite -= writebytes;
+ }
+
+ /* Fill the remaining cluster (hopefully only one) with zero */
+ memset(buffer, 0, BUFFER_SIZE);
+ while ( bytestowrite ) {
+ if ( BUFFER_SIZE > bytestowrite )
+ writebytes = bytestowrite;
+ else
+ writebytes = BUFFER_SIZE;
+
+ xfwrite(buffer, 1, writebytes, f);
+
+ bytestowrite -= writebytes;
+ }
+}
diff --git a/writefs.c b/writefs.c
new file mode 100644
index 0000000..00e5319
--- /dev/null
+++ b/writefs.c
@@ -0,0 +1,47 @@
+#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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * writefs.c
+ *
+ * Write out the whole enchilada
+ */
+
+#include <sysexits.h>
+#include "dirtree.h"
+#include "fat.h"
+#include "xstdio.h"
+#include "main.h"
+
+void
+writedirtree(FILE *f, struct direntry *rootp, struct direntry *allocchain,
+ struct fatfsparm *parm)
+{
+ int cluster = 2; /* 2 is the first cluster */
+
+ /* Write superblock */
+
+ /* Write FATs */
+
+ /* Write root directory */
+ writerootdir(f, rootp, rootdirents);
+
+ /* Write allocation chain */
+ writeallocchain(f, allocchain, &cluster, clustshift);
+
+ /* Pad image to proper size */
+ xfwritezero(f, ((parm->clusters-cluster-2) << parm->clustshift) +
+ (parm->slopsectors << parm->sectorshift));
+}
+
+
diff --git a/xmalloc.c b/xmalloc.c
new file mode 100644
index 0000000..46ff2dc
--- /dev/null
+++ b/xmalloc.c
@@ -0,0 +1,47 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include "xmalloc.h"
+
+extern const char *program;
+
+void *
+xmalloc(size_t size)
+{
+ void *p = malloc(size);
+
+ if ( !p ) {
+ perror(program);
+ exit(EX_OSERR);
+ }
+
+ return p;
+}
+
+char *
+xstrdup(const char *str)
+{
+ char *dup = strdup(str);
+
+ if ( !dup ) {
+ perror(program);
+ exit(EX_OSERR);
+ }
+
+ return dup;
+}
diff --git a/xmalloc.h b/xmalloc.h
new file mode 100644
index 0000000..770af18
--- /dev/null
+++ b/xmalloc.h
@@ -0,0 +1,27 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 Transmeta Corporation - All Rights Reserved
+ *
+ * This source module contains confidential and proprietary information
+ * of Transmeta Corporation. It is not to be disclosed or used except
+ * in accordance with applicable agreements. This copyright notice does
+ * not evidence any actual or intended publication of such source code.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * xmalloc.h
+ *
+ * Convenience functions
+ */
+
+#ifndef XMALLOC_H
+#define XMALLOC_H
+
+#include <stdlib.h> /* size_t */
+
+void *xmalloc(size_t);
+char *xstrdup(const char *);
+
+#endif
diff --git a/xstdio.c b/xstdio.c
new file mode 100644
index 0000000..50b468f
--- /dev/null
+++ b/xstdio.c
@@ -0,0 +1,57 @@
+/* $Id$ */
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * xstdio.c
+ *
+ * Error-trapping versions of some stdio routines
+ */
+
+#include <errno.h>
+#include <sysexits.h>
+#include "xstdio.h"
+#include "minmax.h"
+
+#define LOTSOFZERO 65536
+static const char lotsofzero[LOTSOFZERO];
+extern const char *program;
+
+size_t
+xfwrite(const void *p, size_t size, size_t nmemb, FILE *stream)
+{
+ if ( fwrite(p, size, nmemb, stream) != nmemb ) {
+ perror(program);
+ exit(EX_IOERR);
+ }
+
+ return nmemb;
+}
+
+size_t
+xfwritezero(size_t size, FILE *stream)
+{
+ size_t left = size;
+ while ( left ) {
+ left -= xfwrite(lotsofzero, 1, min2(left,LOTSOFZERO), stream);
+ }
+ return size;
+}
+
+void
+xfseek(FILE *stream, off_t offset, int whence)
+{
+ if ( fseek(stream, offset, whence) != 0 ) {
+ perror(program);
+ exit(EX_IOERR);
+ }
+}
diff --git a/xstdio.h b/xstdio.h
new file mode 100644
index 0000000..82debf3
--- /dev/null
+++ b/xstdio.h
@@ -0,0 +1,35 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001 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., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * xstdio.h
+ *
+ * Error-trapping versions of some stdio routines
+ */
+
+#ifndef XSTDIO_H
+#define XSTDIO_H
+
+#include <stdio.h>
+
+size_t
+xfwrite(const void *, size_t, size_t, FILE *);
+
+size_t
+xfwritezero(size_t, FILE *);
+
+void
+xfseek(FILE *, off_t, int);
+
+#endif
+