aboutsummaryrefslogtreecommitdiffstats
path: root/libfat
diff options
context:
space:
mode:
authorhpa <hpa>2004-12-15 10:14:39 +0000
committerhpa <hpa>2004-12-15 10:14:39 +0000
commit7be70022dd3ae138998fc7185351b9b49ad9a9b2 (patch)
tree2599a8ede407eec131228fb607a52e22145ba1f9 /libfat
parent4912df96419eff85394da1160bcb19a4dd2c1c59 (diff)
downloadsyslinux-elf-7be70022dd3ae138998fc7185351b9b49ad9a9b2.tar.gz
syslinux-elf-7be70022dd3ae138998fc7185351b9b49ad9a9b2.tar.xz
syslinux-elf-7be70022dd3ae138998fc7185351b9b49ad9a9b2.zip
Prepping for new 2.20 version: rewrite main syslinux program to support
FAT32 and EDD, and a new cleaner installer infrastructure.
Diffstat (limited to 'libfat')
-rw-r--r--libfat/cache.c70
-rw-r--r--libfat/fat.h112
-rw-r--r--libfat/fatchain.c136
-rw-r--r--libfat/libfat.h81
-rw-r--r--libfat/libfatint.h56
-rw-r--r--libfat/open.c118
-rw-r--r--libfat/searchdir.c61
-rw-r--r--libfat/ulint.h115
8 files changed, 749 insertions, 0 deletions
diff --git a/libfat/cache.c b/libfat/cache.c
new file mode 100644
index 00000000..cc6c57fe
--- /dev/null
+++ b/libfat/cache.c
@@ -0,0 +1,70 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 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,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * cache.c
+ *
+ * Simple sector cache
+ */
+
+#include <stdlib.h>
+#include "libfatint.h"
+
+void * libfat_get_sector(struct libfat_filesystem *fs, libfat_sector_t n)
+{
+ struct libfat_sector *ls;
+
+ for ( ls = fs->sectors ; ls ; ls = ls->next ) {
+ if ( ls->n == n )
+ return ls->data; /* Found in cache */
+ }
+
+ /* Not found in cache */
+ ls = malloc(sizeof(struct libfat_sector));
+ if ( !ls ) {
+ libfat_flush(fs);
+ ls = malloc(sizeof(struct libfat_sector));
+
+ if ( !ls )
+ return NULL; /* Can't allocate memory */
+ }
+
+ if ( fs->read(fs->readptr, ls->data, LIBFAT_SECTOR_SIZE, n)
+ != LIBFAT_SECTOR_SIZE ) {
+ free(ls);
+ return NULL; /* I/O error */
+ }
+
+ ls->n = n;
+ ls->next = fs->sectors;
+ fs->sectors = ls;
+
+ return ls->data;
+}
+
+void libfat_flush(struct libfat_filesystem *fs)
+{
+ struct libfat_sector *ls, *lsnext;
+
+ lsnext = fs->sectors;
+ fs->sectors = NULL;
+
+ for ( ls = lsnext ; ls ; ls = lsnext ) {
+ lsnext = ls->next;
+ free(ls);
+ }
+}
+
+
+
+
diff --git a/libfat/fat.h b/libfat/fat.h
new file mode 100644
index 00000000..921f9f4a
--- /dev/null
+++ b/libfat/fat.h
@@ -0,0 +1,112 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2004 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,
+ * Boston MA 02111-1307, 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] */
+ union {
+ /* FAT12/16 */
+ struct {
+ le8_t bsDriveNumber; /* Drive number */
+ 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 */
+ } fat16;
+
+ /* FAT32 */
+ struct {
+ le32_t bpb_fatsz32; /* Sectors/FAT */
+ le16_t bpb_extflags; /* Extended flags */
+ le16_t bpb_fsver; /* Filesystem version */
+ le32_t bpb_rootclus; /* Root directory cluster */
+ le16_t bpb_fsinfo; /* FSINFO sector number */
+ le16_t bpb_bkbootsec; /* Backup boot sector (superblock) */
+ char bpb_reserved[12];
+
+ /* Same shit, different offset! */
+ le8_t bsDriveNumber; /* Drive number */
+ 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[420]; /* Boot sector code */
+ } fat32;
+ } u;
+
+ 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 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 clusthi; /* FAT32: high 16 bits of cluster */
+ le32_t mtime; /* Modification time */
+ le16_t clustlo; /* First cluster pointer */
+ 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 /* FAT_H */
+
diff --git a/libfat/fatchain.c b/libfat/fatchain.c
new file mode 100644
index 00000000..6c640bed
--- /dev/null
+++ b/libfat/fatchain.c
@@ -0,0 +1,136 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 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,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * fatchain.c
+ *
+ * Follow a FAT chain
+ */
+
+#include "libfatint.h"
+#include "ulint.h"
+
+/*
+ * Convert a cluster number (or 0 for the root directory) to a
+ * sector number. Return -1 on failure.
+ */
+libfat_sector_t libfat_clustertosector(const struct libfat_filesystem *fs,
+ int32_t cluster)
+{
+ if ( cluster == 0 )
+ cluster = fs->rootcluster;
+
+ if ( cluster == 0 )
+ return fs->rootdir;
+ else if ( cluster < 2 || cluster >= fs->endcluster )
+ return -1;
+ else
+ return fs->data + ((libfat_sector_t)(cluster-2) << fs->clustshift);
+}
+
+/*
+ * Get the next sector of either the root directory or a FAT chain.
+ * Returns 0 on end of file and -1 on error.
+ */
+
+libfat_sector_t libfat_nextsector(struct libfat_filesystem *fs,
+ libfat_sector_t s)
+{
+ int32_t cluster, nextcluster;
+ uint32_t fatoffset;
+ libfat_sector_t fatsect;
+ uint8_t *fsdata;
+ uint32_t clustmask = fs->clustsize - 1;
+ libfat_sector_t rs;
+
+ if ( s < fs->data ) {
+ if ( s < fs->rootdir )
+ return -1;
+
+ /* Root directory */
+ s++;
+ return ( s < fs->data ) ? s : 0;
+ }
+
+ rs = s - fs->data;
+
+ if ( ~rs & clustmask )
+ return s+1; /* Next sector in cluster */
+
+ cluster = 2 + (rs >> fs->clustshift);
+
+ if ( cluster >= fs->endcluster )
+ return -1;
+
+ switch ( fs->fat_type ) {
+ case FAT12:
+ /* Get first byte */
+ fatoffset = cluster + (cluster >> 1);
+ fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT);
+ fsdata = libfat_get_sector(fs, fatsect);
+ if ( !fsdata )
+ return -1;
+ nextcluster = fsdata[fatoffset & LIBFAT_SECTOR_MASK];
+
+ /* Get second byte */
+ fatoffset++;
+ fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT);
+ fsdata = libfat_get_sector(fs, fatsect);
+ if ( !fsdata )
+ return -1;
+ nextcluster |= fsdata[fatoffset & LIBFAT_SECTOR_MASK] << 8;
+
+ /* Extract the FAT entry */
+ if ( cluster & 1 )
+ nextcluster >>= 4;
+ else
+ nextcluster &= 0x0FFF;
+
+ if ( nextcluster >= 0x0FF8 )
+ return 0;
+ break;
+
+ case FAT16:
+ fatoffset = cluster << 1;
+ fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT);
+ fsdata = libfat_get_sector(fs, fatsect);
+ if ( !fsdata )
+ return -1;
+ nextcluster = read16((le16_t *)&fsdata[fatoffset & LIBFAT_SECTOR_MASK]);
+
+ if ( nextcluster >= 0x0FFF8 )
+ return 0;
+ break;
+
+ case FAT28:
+ fatoffset = cluster << 2;
+ fatsect = fs->fat + (fatoffset >> LIBFAT_SECTOR_SHIFT);
+ fsdata = libfat_get_sector(fs, fatsect);
+ if ( !fsdata )
+ return -1;
+ nextcluster = read32((le32_t *)&fsdata[fatoffset & LIBFAT_SECTOR_MASK]);
+ nextcluster &= 0x0FFFFFFF;
+
+ if ( nextcluster >= 0x0FFFFFF8 )
+ return 0;
+ break;
+
+ default:
+ return -1; /* WTF? */
+ }
+
+ return libfat_clustertosector(fs, nextcluster);
+}
+
+
+
diff --git a/libfat/libfat.h b/libfat/libfat.h
new file mode 100644
index 00000000..b0682279
--- /dev/null
+++ b/libfat/libfat.h
@@ -0,0 +1,81 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 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,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * libfat.h
+ *
+ * Headers for the libfat library
+ */
+
+#ifndef LIBFAT_H
+#define LIBFAT_H
+
+#include <stddef.h>
+#include <inttypes.h>
+
+#define LIBFAT_SECTOR_SHIFT 9
+#define LIBFAT_SECTOR_SIZE 512
+#define LIBFAT_SECTOR_MASK 511
+
+typedef uint32_t libfat_sector_t;
+struct libfat_filesystem;
+
+/*
+ * Open the filesystem. The readfunc is the function to read
+ * sectors, in the format:
+ * int readfunc(void *readptr, void *buf, size_t secsize,
+ * libfat_sector_t secno)
+ *
+ * ... where readptr is a private argument.
+ *
+ * A return value of != secsize is treated as error.
+ */
+struct libfat_filesystem *
+libfat_open(int (*readfunc)(void *, void *, size_t, libfat_sector_t),
+ void *readptr);
+
+void libfat_close(struct libfat_filesystem *);
+
+/*
+ * Convert a cluster number (or 0 for the root directory) to a
+ * sector number. Return -1 on failure.
+ */
+libfat_sector_t libfat_clustertosector(const struct libfat_filesystem *fs,
+ int32_t cluster);
+
+/*
+ * Get the next sector of either the root directory or a FAT chain.
+ * Returns 0 on end of file and -1 on error.
+ */
+libfat_sector_t libfat_nextsector(struct libfat_filesystem *fs,
+ libfat_sector_t s);
+
+/*
+ * Flush all cached sectors for this filesystem.
+ */
+void libfat_flush(struct libfat_filesystem *fs);
+
+/*
+ * Get a pointer to a specific sector.
+ */
+void * libfat_get_sector(struct libfat_filesystem *fs, libfat_sector_t n);
+
+/*
+ * Search a FAT directory for a particular pre-mangled filename.
+ * Copies the directory entry into direntry and returns 0 if found.
+ */
+int32_t libfat_searchdir(struct libfat_filesystem *fs, int32_t dirclust,
+ const void *name, void *direntry);
+
+#endif /* LIBFAT_H */
+
diff --git a/libfat/libfatint.h b/libfat/libfatint.h
new file mode 100644
index 00000000..6da47f18
--- /dev/null
+++ b/libfat/libfatint.h
@@ -0,0 +1,56 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 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,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * libfatint.h
+ *
+ * Internals for the libfat filesystem
+ */
+
+#ifndef LIBFATINT_H
+#define LIBFATINT_H
+
+#include "libfat.h"
+#include "fat.h"
+
+struct libfat_sector {
+ libfat_sector_t n; /* Sector number */
+ struct libfat_sector *next; /* Next in list */
+ char data[LIBFAT_SECTOR_SIZE];
+};
+
+enum fat_type {
+ FAT12,
+ FAT16,
+ FAT28
+};
+
+struct libfat_filesystem {
+ int (*read)(void *, void *, size_t, libfat_sector_t);
+ void *readptr;
+
+ enum fat_type fat_type;
+ unsigned int clustsize;
+ int clustshift;
+ int32_t endcluster; /* Highest legal cluster number + 1 */
+ int32_t rootcluster; /* Root directory cluster */
+
+ libfat_sector_t fat; /* Start of FAT */
+ libfat_sector_t rootdir; /* Start of root directory */
+ libfat_sector_t data; /* Start of data area */
+ libfat_sector_t end; /* End of filesystem */
+
+ struct libfat_sector *sectors;
+};
+
+#endif /* LIBFATINT_H */
diff --git a/libfat/open.c b/libfat/open.c
new file mode 100644
index 00000000..835c336d
--- /dev/null
+++ b/libfat/open.c
@@ -0,0 +1,118 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 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,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * open.c
+ *
+ * Open a FAT filesystem and compute some initial values; return NULL
+ * on failure.
+ */
+
+#include <stdlib.h>
+#include "libfatint.h"
+#include "ulint.h"
+
+struct libfat_filesystem *
+libfat_open(int (*readfunc)(void *, void *, size_t, libfat_sector_t),
+ void *readptr)
+{
+ struct libfat_filesystem *fs = NULL;
+ struct fat_bootsect *bs;
+ int i;
+ uint32_t sectors, fatsize, minfatsize, rootdirsize;
+ uint32_t nclusters;
+
+ fs = malloc(sizeof(struct libfat_filesystem));
+ if ( !fs )
+ goto barf;
+
+ fs->sectors = NULL;
+ fs->read = readfunc;
+ fs->readptr = readptr;
+
+ bs = libfat_get_sector(fs, 0);
+ if ( !bs )
+ goto barf;
+
+ if ( read16(&bs->bsBytesPerSec) != LIBFAT_SECTOR_SIZE )
+ goto barf;
+
+ for ( i = 0 ; i <= 8 ; i++ ) {
+ if ( (uint8_t)(1 << i) == read8(&bs->bsSecPerClust) )
+ break;
+ }
+ if ( i > 8 )
+ goto barf;
+ fs->clustsize = 1 << i; /* Treat 0 as 2^8 = 64K */
+ fs->clustshift = i;
+
+ sectors = read16(&bs->bsSectors);
+ if ( !sectors )
+ sectors = read32(&bs->bsHugeSectors);
+
+ fs->end = sectors;
+
+ fs->fat = read16(&bs->bsResSectors);
+ fatsize = read16(&bs->bsFATsecs);
+ if ( !fatsize )
+ fatsize = read32(&bs->u.fat32.bpb_fatsz32);
+
+ fs->rootdir = fs->fat + fatsize * read8(&bs->bsFATs);
+
+ rootdirsize = ((read16(&bs->bsRootDirEnts) << 5) + LIBFAT_SECTOR_MASK)
+ >> LIBFAT_SECTOR_SHIFT;
+ fs->data = fs->rootdir + rootdirsize;
+
+ /* Sanity checking */
+ if ( fs->data >= fs->end )
+ goto barf;
+
+ /* Figure out how many clusters */
+ nclusters = (fs->end - fs->data) >> fs->clustshift;
+ fs->endcluster = nclusters + 2;
+
+ if ( nclusters <= 0xff4 ) {
+ fs->fat_type = FAT12;
+ minfatsize = fs->endcluster + (fs->endcluster >> 1);
+ } else if ( nclusters <= 0xfff4 ) {
+ fs->fat_type = FAT16;
+ minfatsize = fs->endcluster << 1;
+ } else if ( nclusters <= 0xffffff4 ) {
+ fs->fat_type = FAT28;
+ minfatsize = fs->endcluster << 2;
+ } else
+ goto barf; /* Impossibly many clusters */
+
+ minfatsize = (minfatsize + LIBFAT_SECTOR_SIZE-1) >> LIBFAT_SECTOR_SHIFT;
+
+ if ( minfatsize > fatsize )
+ goto barf; /* The FATs don't fit */
+
+ if ( fs->fat_type == FAT28 )
+ fs->rootcluster = read32(&bs->u.fat32.bpb_rootclus);
+ else
+ fs->rootcluster = 0;
+
+ return fs; /* All good */
+
+ barf:
+ if ( fs )
+ free(fs);
+ return NULL;
+}
+
+void libfat_close(struct libfat_filesystem *fs)
+{
+ libfat_flush(fs);
+ free(fs);
+}
diff --git a/libfat/searchdir.c b/libfat/searchdir.c
new file mode 100644
index 00000000..7c07165b
--- /dev/null
+++ b/libfat/searchdir.c
@@ -0,0 +1,61 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004 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,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * searchdir.c
+ *
+ * Search a FAT directory for a particular pre-mangled filename.
+ * Copies the directory entry into direntry and returns the starting cluster
+ * if found; returns -2 on not found, -1 on error, 0 on empty file.
+ */
+
+#include <string.h>
+#include "libfatint.h"
+
+int32_t libfat_searchdir(struct libfat_filesystem *fs, int32_t dirclust,
+ const void *name, void *direntry)
+{
+ struct fat_dirent *dep;
+ int nent;
+ libfat_sector_t s = libfat_clustertosector(fs, dirclust);
+
+ while ( 1 ) {
+ if ( s == 0 )
+ return -2; /* Not found */
+ else if ( s == (libfat_sector_t)-1 )
+ return -1; /* Error */
+
+ dep = libfat_get_sector(fs, s);
+ if ( !dep )
+ return -1; /* Read error */
+
+ for ( nent = LIBFAT_SECTOR_SIZE/sizeof(struct fat_dirent) ;
+ nent ; nent-- ) {
+ if ( !memcmp(dep->name, name, 11) ) {
+ if ( direntry )
+ memcpy(direntry, dep, sizeof (*dep));
+ if ( read32(&dep->size) == 0 )
+ return 0; /* An empty file has no clusters */
+ else
+ return read16(&dep->clustlo) + (read16(&dep->clusthi) << 16);
+ }
+
+ if ( dep->name[0] == 0 )
+ return -2; /* Hit high water mark */
+
+ dep++;
+ }
+
+ s = libfat_nextsector(fs, s);
+ }
+}
diff --git a/libfat/ulint.h b/libfat/ulint.h
new file mode 100644
index 00000000..0b200ea8
--- /dev/null
+++ b/libfat/ulint.h
@@ -0,0 +1,115 @@
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2004 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
+
+#include <inttypes.h>
+
+/* These are unaligned, littleendian integer types */
+
+typedef uint8_t le8_t; /* 8-bit byte */
+typedef uint8_t le16_t[2]; /* 16-bit word */
+typedef uint8_t 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;
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+
+/* Littleendian architectures which support unaligned memory accesses */
+
+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 */