diff -rcN filo-0.4.2.orig/defconfig filo-0.4.2/defconfig *** filo-0.4.2.orig/defconfig 2003-10-30 23:18:46.000000000 -0800 --- filo-0.4.2/defconfig 2006-06-27 16:33:37.000000000 -0700 *************** *** 3,12 **** # It confuses some versions of make. # Image filename for automatic boot and optional command line parameter ! AUTOBOOT_FILE = "hda1:/vmlinuz root=/dev/hda1 console=tty0 console=ttyS0,115200" # Time in second before booting AUTOBOOT_FILE ! AUTOBOOT_DELAY = 2 # Driver for hard disk, CompactFlash, and CD-ROM on IDE bus IDE_DISK = 1 --- 3,13 ---- # It confuses some versions of make. # Image filename for automatic boot and optional command line parameter ! # AUTOBOOT_FILE = "hdc1:/boot/vmlinuz-2.4.18-3 root=/dev/hdc1 console=tty0 console=ttyS0,115200" ! AUTOBOOT_FILE = "hdc2,a:/platform/i86pc/multiboot -L -B module=/platform/i86pc/boot_archive,console=ttya,ttya-mode='115200,8,n,1,-'" # Time in second before booting AUTOBOOT_FILE ! AUTOBOOT_DELAY = 30 # Driver for hard disk, CompactFlash, and CD-ROM on IDE bus IDE_DISK = 1 *************** *** 26,34 **** --- 27,39 ---- FSYS_JFS = 1 FSYS_MINIX = 1 FSYS_REISERFS = 1 + FSYS_UFS = 1 FSYS_XFS = 1 FSYS_ISO9660 = 1 + # Support gzip modules + COMPRESSION = 1 + # Support for boot disk image in bootable CD-ROM (El Torito) ELTORITO = 1 diff -rcN filo-0.4.2.orig/fs/blockdev.c filo-0.4.2/fs/blockdev.c *** filo-0.4.2.orig/fs/blockdev.c 2003-10-29 00:19:48.000000000 -0800 --- filo-0.4.2/fs/blockdev.c 2006-06-27 12:15:53.000000000 -0700 *************** *** 2,7 **** --- 2,9 ---- #include #include + #include "filesys.h" /* for pc slice */ + #define DEBUG_THIS DEBUG_BLOCKDEV #include *************** *** 28,34 **** } /* IBM-PC/MS-DOS style partitioning scheme */ ! static int open_pc_partition(int part, unsigned long *start_p, unsigned long *length_p) { /* Layout of PC partition table */ --- 30,36 ---- } /* IBM-PC/MS-DOS style partitioning scheme */ ! static int open_pc_partition(int part, int subpart, unsigned long *start_p, unsigned long *length_p) { /* Layout of PC partition table */ *************** *** 66,71 **** --- 68,87 ---- } *start_p = get_le32(p->start_sect); *length_p = get_le32(p->nr_sects); + if (subpart == 0) + return 1; + + /* Solaris sub-partition */ + if (!IS_PC_SLICE_TYPE_SOLARIS(p->type) || subpart > 8) + return 0; + /* Solaris VTOC is in sector of parition */ + if (!devread(1, 0, sizeof buf, buf)) + return 0; + if (!SOL_LABEL_CHECK_MAG(buf) || !SOL_PART_EXISTS(buf, subpart -1)) + return 0; + + *start_p += SOL_PART_START(buf, subpart - 1); + *length_p = SOL_PART_LENGTH(buf, subpart - 1); return 1; } else { /* Extended partition */ *************** *** 159,164 **** --- 175,186 ---- if (*name == ',') *length = strtoull_with_suffix(name+1, (char **)&name, 0); debug("offset=%#Lx length=%#Lx\n", *offset, *length); + } else if (*name == ',') { + int subpart; + name++; + subpart = *name - 'a' + 1; + *part |= (subpart << 16); + name++; } if (*name != '\0') { *************** *** 171,177 **** int devopen(const char *name, int *reopen) { ! int type, drive, part; uint64_t offset, length; uint32_t disk_size = 0; --- 193,199 ---- int devopen(const char *name, int *reopen) { ! int type, drive, part, subpart; uint64_t offset, length; uint32_t disk_size = 0; *************** *** 225,235 **** part_start = 0; part_length = disk_size; using_devsize = 1; if (part != 0) { /* partition is specified */ int ret; ! ret = open_pc_partition(part - 1, &part_start, &part_length); if (ret == PARTITION_UNKNOWN) { ret = open_eltorito_image(part - 1, &part_start, &part_length); if (ret == PARTITION_UNKNOWN) { --- 247,259 ---- part_start = 0; part_length = disk_size; using_devsize = 1; + subpart = (part >> 16); + part &= 0xffff; if (part != 0) { /* partition is specified */ int ret; ! ret = open_pc_partition(part - 1, subpart, &part_start, &part_length); if (ret == PARTITION_UNKNOWN) { ret = open_eltorito_image(part - 1, &part_start, &part_length); if (ret == PARTITION_UNKNOWN) { *************** *** 242,249 **** return 0; } ! debug("Partition %d start %lu length %lu\n", part, ! part_start, part_length); } if (offset) { --- 266,277 ---- return 0; } ! if (subpart) ! debug("Partition %d,%c start %lu length %lu\n", part, ! 'a' + subpart - 1, part_start, part_length); ! else ! debug("Partition %d start %lu length %lu\n", part, ! part_start, part_length); } if (offset) { *************** *** 274,279 **** --- 302,308 ---- /* Read a sector from opened device with simple/stupid buffer cache */ static void *read_sector(unsigned long sector) { + static int count = 0; unsigned int hash; void *buf; *************** *** 292,297 **** --- 321,329 ---- switch (dev_type) { #ifdef IDE_DISK case DISK_IDE: + count++; + if (count % 2000 == 0) + printf("."); if (ide_read(dev_drive, sector, buf) != 0) goto readerr; break; diff -rcN filo-0.4.2.orig/fs/filesys.h filo-0.4.2/fs/filesys.h *** filo-0.4.2.orig/fs/filesys.h 2003-10-15 04:19:38.000000000 -0700 --- filo-0.4.2/fs/filesys.h 2006-06-23 12:37:44.000000000 -0700 *************** *** 102,107 **** --- 102,108 ---- ERR_DEV_NEED_INIT, ERR_NO_DISK_SPACE, ERR_NUMBER_OVERFLOW, + ERR_BAD_GZIP_CRC, MAX_ERR_NUM } grub_error_t; *************** *** 158,163 **** --- 159,170 ---- int jfs_embed (int *start_sector, int needed_sectors); #endif + #ifdef FSYS_UFS + int ufs_mount (void); + int ufs_read (char *buf, int len); + int ufs_dir (char *dirname); + #endif + #ifdef FSYS_XFS int xfs_mount (void); int xfs_read (char *buf, int len); *************** *** 185,193 **** --- 192,203 ---- #define PC_SLICE_TYPE_EZD 0x55 #define PC_SLICE_TYPE_MINIX 0x80 #define PC_SLICE_TYPE_LINUX_MINIX 0x81 + #define PC_SLICE_TYPE_SOLARIS 0x82 /* also Linux swap! */ #define PC_SLICE_TYPE_EXT2FS 0x83 #define PC_SLICE_TYPE_LINUX_EXTENDED 0x85 #define PC_SLICE_TYPE_VSTAFS 0x9e + #define PC_SLICE_TYPE_SOLARIS_BOOT 0xbe /* Solaris boot (fat) */ + #define PC_SLICE_TYPE_SOLARIS2 0xbf /* new Solaris type */ #define PC_SLICE_TYPE_DELL_UTIL 0xde #define PC_SLICE_TYPE_LINUX_RAID 0xfd *************** *** 202,207 **** --- 212,218 ---- || _type == PC_SLICE_TYPE_FAT16_LBA \ || _type == PC_SLICE_TYPE_FAT32 \ || _type == PC_SLICE_TYPE_FAT32_LBA \ + || _type == PC_SLICE_TYPE_SOLARIS_BOOT \ || _type == PC_SLICE_TYPE_DELL_UTIL; }) #define IS_PC_SLICE_TYPE_MINIX(type) \ *************** *** 210,215 **** --- 221,229 ---- #define IS_PC_SLICE_TYPE_BSD_WITH_FS(type,fs) 0 + #define IS_PC_SLICE_TYPE_SOLARIS(type) \ + (((type) == PC_SLICE_TYPE_SOLARIS) || ((type) == PC_SLICE_TYPE_SOLARIS2)) + /* possible values for the *BSD-style partition type */ #define FS_UNUSED 0 /* unused */ #define FS_SWAP 1 /* swap */ *************** *** 229,231 **** --- 243,269 ---- #define FS_HFS 15 /* Macintosh HFS */ #define FS_FILECORE 16 /* Acorn Filecore Filing System */ #define FS_EXT2FS 17 /* Linux Extended 2 file system */ + + /* + * Solaris LABEL definitions. All definitions are relative to the + * current PC_SLICE. + */ + #define SOL_LABEL_LOC 1 + #define SOL_LABEL_SIZE 512 + #define SOL_LABEL_MAGIC 0xdabe + #define SOL_LABEL_MAGIC_OFFSET 0x1fc + #define SOL_LABEL_NPARTS 0x10 + + #define SOL_PART_OFFSET 0x48 + + #define SOL_LABEL_CHECK_MAG(l_ptr) \ + (*((unsigned short *) (((int) l_ptr) + SOL_LABEL_MAGIC_OFFSET)) \ + == ((unsigned short) SOL_LABEL_MAGIC )) + + #define SOL_PART_START(l_ptr, p) \ + (*((unsigned long *) (((int) l_ptr) + SOL_PART_OFFSET + (p) * 0xc + 4))) + + #define SOL_PART_LENGTH(l_ptr, p) \ + (*((unsigned long *) (((int) l_ptr) + SOL_PART_OFFSET + (p) * 0xc + 8))) + + #define SOL_PART_EXISTS(l_ptr, p) (SOL_PART_LENGTH(l_ptr, p) != 0) diff -rcN filo-0.4.2.orig/fs/fsys_ufs.c filo-0.4.2/fs/fsys_ufs.c *** filo-0.4.2.orig/fs/fsys_ufs.c 1969-12-31 16:00:00.000000000 -0800 --- filo-0.4.2/fs/fsys_ufs.c 2006-06-23 12:29:27.000000000 -0700 *************** *** 0 **** --- 1,271 ---- + /* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + /* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + /* From Solaris usr/src/stand/lib/fs/ufs/ufsops.c */ + + #ifdef FSYS_UFS + + #include "shared.h" + #include "filesys.h" + + #include "ufs.h" + + /* These are the pools of buffers, etc. */ + + #define SUPERBLOCK ((struct fs *)(FSYS_BUF + 0x2000)) + #define INODE ((struct icommon *)(FSYS_BUF + 0x1000)) + #define DIRENT (FSYS_BUF + 0x4000) + #define INDIRBLK1 ((grub_daddr32_t *)(FSYS_BUF + 0x4000)) /* 2+ indir blk */ + #define INDIRBLK0 ((grub_daddr32_t *)(FSYS_BUF+ 0x6000)) /* 1st indirect blk */ + + static int indirblk0, indirblk1; + + static int openi(grub_ino_t); + static grub_ino_t dlook(grub_ino_t, char *); + static grub_daddr32_t sbmap(grub_daddr32_t); + + /* read superblock and check fs magic */ + int + ufs_mount(void) + { + if (!devread(UFS_SBLOCK, 0, UFS_SBSIZE, (char *)SUPERBLOCK)) { + printf("ufs_mount: can't read superblock\n"); + return 0; + } + if (SUPERBLOCK->fs_magic != UFS_MAGIC) { + printf("ufs_mount: magic number mismatch %x:%x\n", + SUPERBLOCK->fs_magic, UFS_MAGIC); + return 0; + } + + return 1; + } + + + /* + * searching for a file, if successful, inode will be loaded in INODE + * The entry point should really be named ufs_open(char *pathname). + * For now, keep it consistent with the rest of fsys modules. + */ + int + ufs_dir(char *dirname) + { + grub_ino_t inode = ROOTINO; /* start from root */ + char *fname, ch; + + indirblk0 = indirblk1 = 0; + + /* skip leading slashes */ + while (*dirname == '/') + dirname++; + + while (inode && *dirname && !isspace(*dirname)) { + if (!openi(inode)) + return 0; + + /* parse for next path component */ + fname = dirname; + while (*dirname && !isspace(*dirname) && *dirname != '/') + dirname++; + ch = *dirname; + *dirname = 0; /* ensure null termination */ + + inode = dlook(inode, fname); + *dirname = ch; + while (*dirname == '/') + dirname++; + } + + /* return 1 only if inode exists and is a regular file */ + if (! openi(inode)) + return (0); + filepos = 0; + filemax = INODE->ic_sizelo; + return (inode && ((INODE->ic_smode & IFMT) == IFREG)); + } + + /* + * This is the high-level read function. + */ + int + ufs_read(char *buf, int len) + { + int off, size, ret = 0, ok; + grub_daddr32_t lblk, dblk; + + while (len) { + off = blkoff(SUPERBLOCK, filepos); + lblk = lblkno(SUPERBLOCK, filepos); + size = SUPERBLOCK->fs_bsize; + size -= off; + if (size > len) + size = len; + + if ((dblk = sbmap(lblk)) <= 0) { + /* we are in a file hole, just zero the buf */ + memset(buf, 0, size); + } else { + disk_read_func = disk_read_hook; + ok = devread(fsbtodb(SUPERBLOCK, dblk), off, size, buf); + disk_read_func = 0; + if (!ok) + return 0; + } + buf += size; + len -= size; + filepos += size; + ret += size; + } + + return (ret); + } + + int + ufs_embed (int *start_sector, int needed_sectors) + { + if (needed_sectors > 14) + return 0; + + *start_sector = 2; + return 1; + } + + /* read inode and place content in INODE */ + static int + openi(grub_ino_t inode) + { + grub_daddr32_t dblk; + int off; + + /* get block and byte offset into the block */ + dblk = fsbtodb(SUPERBLOCK, itod(SUPERBLOCK, inode)); + off = itoo(SUPERBLOCK, inode) * sizeof (struct icommon); + + return (devread(dblk, off, sizeof (struct icommon), (char *)INODE)); + } + + /* + * Performs fileblock mapping. Convert file block no. to disk block no. + * Returns 0 when block doesn't exist and <0 when block isn't initialized + * (i.e belongs to a hole in the file). + */ + grub_daddr32_t + sbmap(grub_daddr32_t bn) + { + int level, bound, i, index; + grub_daddr32_t nb, blkno; + grub_daddr32_t *db = INODE->ic_db; + + /* blocks 0..UFS_NDADDR are direct blocks */ + if (bn < UFS_NDADDR) { + return db[bn]; + } + + /* determine how many levels of indirection. */ + level = 0; + bn -= UFS_NDADDR; + bound = UFS_NINDIR(SUPERBLOCK); + while (bn >= bound) { + level++; + bn -= bound; + bound *= UFS_NINDIR(SUPERBLOCK); + } + if (level >= UFS_NIADDR) /* bn too big */ + return ((grub_daddr32_t)0); + + /* fetch the first indirect block */ + nb = INODE->ic_ib[level]; + if (nb == 0) { + return ((grub_daddr32_t)0); + } + if (indirblk0 != nb) { + indirblk0 = 0; + blkno = fsbtodb(SUPERBLOCK, nb); + if (!devread(blkno, 0, SUPERBLOCK->fs_bsize, + (char *)INDIRBLK0)) + return (0); + indirblk0 = nb; + } + bound /= UFS_NINDIR(SUPERBLOCK); + index = (bn / bound) % UFS_NINDIR(SUPERBLOCK); + nb = INDIRBLK0[index]; + + /* fetch through the indirect blocks */ + for (i = 1; i <= level; i++) { + if (indirblk1 != nb) { + blkno = fsbtodb(SUPERBLOCK, nb); + if (!devread(blkno, 0, SUPERBLOCK->fs_bsize, + (char *)INDIRBLK1)) + return (0); + indirblk1 = nb; + } + bound /= UFS_NINDIR(SUPERBLOCK); + index = (bn / bound) % UFS_NINDIR(SUPERBLOCK); + nb = INDIRBLK1[index]; + if (nb == 0) + return ((grub_daddr32_t)0); + } + + return (nb); + } + + /* search directory content for name, return inode number */ + static grub_ino_t + dlook(grub_ino_t dir_ino, char *name) + { + int loc, off; + grub_daddr32_t lbn, dbn, dblk; + struct direct *dp; + + if ((INODE->ic_smode & IFMT) != IFDIR) + return 0; + + loc = 0; + while (loc < INODE->ic_sizelo) { + /* offset into block */ + off = blkoff(SUPERBLOCK, loc); + if (off == 0) { /* need to read in a new block */ + + /* get logical block number */ + lbn = lblkno(SUPERBLOCK, loc); + /* resolve indrect blocks */ + dbn = sbmap(lbn); + if (dbn == 0) + return (0); + + dblk = fsbtodb(SUPERBLOCK, dbn); + if (!devread(dblk, 0, SUPERBLOCK->fs_bsize, + (char *)DIRENT)) { + return 0; + } + } + + dp = (struct direct *)(DIRENT + off); + if (dp->d_ino && substring(name, dp->d_name) == 0) + return (dp->d_ino); + loc += dp->d_reclen; + } + return (0); + } + + #endif /* FSYS_UFS */ diff -rcN filo-0.4.2.orig/fs/gunzip.c filo-0.4.2/fs/gunzip.c *** filo-0.4.2.orig/fs/gunzip.c 1969-12-31 16:00:00.000000000 -0800 --- filo-0.4.2/fs/gunzip.c 2006-06-23 14:28:16.000000000 -0700 *************** *** 0 **** --- 1,1324 ---- + /* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + /* + * Most of this file was originally the source file "inflate.c", written + * by Mark Adler. It has been very heavily modified. In particular, the + * original would run through the whole file at once, and this version can + * by Mark Adler. It has been very heavily modified. In particular, the + * original would run through the whole file at once, and this version can + * be stopped and restarted on any boundary during the decompression process. + * + * The license and header comments that file are included here. + */ + + /* inflate.c -- Not copyrighted 1992 by Mark Adler + version c10p1, 10 January 1993 */ + + /* You can do whatever you like with this source file, though I would + prefer that if you modify it and redistribute it that you include + comments to that effect with your name and the date. Thank you. + */ + + /* + Inflate deflated (PKZIP's method 8 compressed) data. The compression + method searches for as much of the current string of bytes (up to a + length of 258) in the previous 32K bytes. If it doesn't find any + matches (of at least length 3), it codes the next byte. Otherwise, it + codes the length of the matched string and its distance backwards from + the current position. There is a single Huffman code that codes both + single bytes (called "literals") and match lengths. A second Huffman + the current position. There is a single Huffman code that codes both + single bytes (called "literals") and match lengths. A second Huffman + code codes the distance information, which follows a length code. Each + length or distance code actually represents a base value and a number + of "extra" (sometimes zero) bits to get to add to the base value. At + the end of each deflated block is a special end-of-block (EOB) literal/ + length code. The decoding process is basically: get a literal/length + code; if EOB then done; if a literal, emit the decoded byte; if a + length then get the distance and emit the referred-to bytes from the + sliding window of previously emitted data. + + There are (currently) three kinds of inflate blocks: stored, fixed, and + dynamic. The compressor deals with some chunk of data at a time, and + decides which method to use on a chunk-by-chunk basis. A chunk might + typically be 32K or 64K. If the chunk is uncompressible, then the + "stored" method is used. In this case, the bytes are simply stored as + is, eight bits per byte, with none of the above coding. The bytes are + preceded by a count, since there is no longer an EOB code. + + If the data is compressible, then either the fixed or dynamic methods + are used. In the dynamic method, the compressed data is preceded by + an encoding of the literal/length and distance Huffman codes that are + to be used to decode this block. The representation is itself Huffman + an encoding of the literal/length and distance Huffman codes that are + to be used to decode this block. The representation is itself Huffman + coded, and so is preceded by a description of that code. These code + descriptions take up a little space, and so for small blocks, there is + a predefined set of codes, called the fixed codes. The fixed method is + used if the block codes up smaller that way (usually for quite small + chunks), otherwise the dynamic method is used. In the latter case, the + codes are customized to the probabilities in the current block, and so + can code it much better than the pre-determined fixed codes. + + The Huffman codes themselves are decoded using a mutli-level table + lookup, in order to maximize the speed of decoding plus the speed of + building the decoding tables. See the comments below that precede the + lbits and dbits tuning parameters. + */ + + + /* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarly, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + #ifdef COMPRESSION + + #include "lib.h" + #include "filesys.h" + + #define MAXINT 0x7fffffff + + static void *gzip_alloc(int); + static void gzip_free_all(); + + typedef unsigned char uch; + typedef unsigned short ush; + typedef unsigned long ulg; + + /* internal variables only */ + static int gzip_filepos; + static int gzip_filemax; + static int gzip_data_offset; + static int saved_filepos; + static unsigned long gzip_crc; + static unsigned long crc; + + /* internal extra variables for use of inflate code */ + static int block_type; + static int block_len; + static int last_block; + static int code_state; + + /* Function prototypes */ + static void initialize_tables (void); + static unsigned long updcrc(unsigned char *, int); + + + /* Helper function for memory allocation */ + struct alloc_list { + struct alloc_list *next; + char buf[1]; + } *alloc_head; + + static void * + gzip_alloc(int len) + { + struct alloc_list *tmp; + + tmp = malloc(len + sizeof (void *)); + if (tmp == NULL) + return (NULL); + + tmp->next = alloc_head; + alloc_head = tmp; + return ((void *)tmp->buf); + } + + static void + gzip_free_all(void) + { + struct alloc_list *next, *tmp = alloc_head; + + while (tmp) { + next = tmp->next; + free(tmp); + tmp = next; + } + alloc_head = NULL; + } + + /* internal function for eating variable-length header fields */ + static int + bad_field (int len) + { + unsigned char ch = 1; + int not_retval = 1; + + do + { + if (len >= 0) + { + if (!(len--)) + break; + } + else + { + if (!ch) + break; + } + } + while ((not_retval = file_read (&ch, 1)) == 1); + + return (!not_retval); + } + + + /* Little-Endian defines for the 2-byte magic number for gzip files */ + #define GZIP_HDR_LE 0x8B1F + #define OLD_GZIP_HDR_LE 0x9E1F + + /* Compression methods (see algorithm.doc) */ + #define STORED 0 + #define COMPRESSED 1 + #define PACKED 2 + #define LZHED 3 + /* methods 4 to 7 reserved */ + #define DEFLATED 8 + #define MAX_METHODS 9 + + /* gzip flag byte */ + #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ + #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ + #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ + #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ + #define COMMENT 0x10 /* bit 4 set: file comment present */ + #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ + #define RESERVED 0xC0 /* bit 6,7: reserved */ + + #define UNSUPP_FLAGS (CONTINUATION|ENCRYPTED|RESERVED) + + /* inflate block codes */ + #define INFLATE_STORED 0 + #define INFLATE_FIXED 1 + #define INFLATE_DYNAMIC 2 + + /* + * Window Size + * + * This must be a power of two, and at least 32K for zip's deflate method + */ + + #define WSIZE 0x8000 + + + int + gunzip_test_header (void) + { + unsigned char buf[10]; + + /* + * This checks if the file is gzipped. If a problem occurs here + * (other than a real error with the disk) then we don't think it + * is a compressed file, and simply mark it as such. + */ + if (file_read (buf, 10) != 10 + || ((*((unsigned short *) buf) != GZIP_HDR_LE) + && (*((unsigned short *) buf) != OLD_GZIP_HDR_LE))) + { + filepos = 0; + return 0; + } + + /* + * This does consistency checking on the header data. If a + * problem occurs from here on, then we have corrupt or otherwise + * bad data, and the error should be reported to the user. + */ + if (buf[2] != DEFLATED + || (buf[3] & UNSUPP_FLAGS) + || ((buf[3] & EXTRA_FIELD) + && (file_read (buf, 2) != 2 + || bad_field (*((unsigned short *) buf)))) + || ((buf[3] & ORIG_NAME) && bad_field (-1)) + || ((buf[3] & COMMENT) && bad_field (-1))) + { + if (! errnum) + errnum = ERR_BAD_GZIP_HEADER; + + filepos = 0; + return 0; + } + + gzip_data_offset = filepos; + + /* We could read the last 8 bytes of the file to get the uncompressed + * size. Doing so under tftp would cause the file to be downloaded + * twice, which can be problem with large files. So we set it to + * MAXINT and correct it later when we get to the end of the file + * in get_byte(). + */ + gzip_filemax = MAXINT; + + initialize_tables (); + + filepos = 0; + + crc = (ulg)0xffffffffUL; + + return 1; + } + + + /* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). + Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 + means that v is a literal, 16 < e < 32 means that v is a pointer to + the next table, which codes e - 16 bits, and lastly e == 99 indicates + an unused code. If a code with e == 99 is looked up, this implies an + error in the data. */ + struct huft + { + uch e; /* number of extra bits or operation */ + uch b; /* number of bits in this code or subcode */ + union + { + ush n; /* literal, length base, or distance base */ + struct huft *t; /* pointer to next level of table */ + } + v; + }; + + + /* The inflate algorithm uses a sliding 32K byte window on the uncompressed + stream to find repeated byte strings. This is implemented here as a + circular buffer. The index is updated simply by incrementing and then + and'ing with 0x7fff (32K-1). */ + /* It is left to other modules to supply the 32K area. It is assumed + to be usable as if it were declared "uch slide[32768];" or as just + "uch *slide;" and then malloc'ed in the latter case. The definition + must be in unzip.h, included above. */ + + + /* sliding window in uncompressed data */ + static uch slide[WSIZE]; + + /* current position in slide */ + static unsigned wp; + + + /* Tables for deflate from PKZIP's appnote.txt. */ + static unsigned bitorder[] = + { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + static ush cplens[] = + { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ + static ush cplext[] = + { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ + static ush cpdist[] = + { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; + static ush cpdext[] = + { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + + /* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + + static int lbits = 9; /* bits in base literal/length lookup table */ + static int dbits = 6; /* bits in base distance lookup table */ + + + /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ + #define BMAX 16 /* maximum bit length of any code (16 for explode) */ + #define N_MAX 288 /* maximum number of codes in any set */ + + + static unsigned hufts; /* track memory usage */ + + + /* Macros for inflate() bit peeking and grabbing. + The usage is: + + NEEDBITS(j) + x = b & mask_bits[j]; + DUMPBITS(j) + + where NEEDBITS makes sure that b has at least j bits in it, and + DUMPBITS removes the bits from b. The macros use the variable k + for the number of bits in b. Normally, b and k are register + variables for speed, and are initialized at the beginning of a + routine that uses these macros from a global bit buffer and count. + + If we assume that EOB will be the longest code, then we will never + ask for bits with NEEDBITS that are beyond the end of the stream. + So, NEEDBITS should not read any more bytes than are needed to + meet the request. Then no bytes need to be "returned" to the buffer + at the end of the last block. + + However, this assumption is not true for fixed blocks--the EOB code + is 7 bits, but the other literal/length codes can be 8 or 9 bits. + (The EOB code is shorter than other codes because fixed blocks are + generally short. So, while a block always has an EOB, many other + literal/length codes have a significantly lower probability of + showing up at all.) However, by making the first table have a + lookup of seven bits, the EOB code will be found in that first + lookup, and so will not require that too many bits be pulled from + the stream. + */ + + static ulg bb; /* bit buffer */ + static unsigned bk; /* bits in bit buffer */ + + static ush mask_bits[] = + { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff + }; + + #define NEEDBITS(n) do {while(k<(n)){b|=((ulg)get_byte())<>=(n);k-=(n);} while (0) + + #define INBUFSIZ 0x2000 + + static uch inbuf[INBUFSIZ]; + static int bufloc; + static uch endbuf[8]; + + static int + get_byte (void) + { + if (filepos == gzip_data_offset || bufloc == INBUFSIZ) + { + int pos; + int old_filepos = filepos; + bufloc = 0; + file_read (inbuf, INBUFSIZ); + /* If there are 8 bytes or less left, we have read in all the + * the file content. So get the last 8 bytes and get the crc + * and uncompressed size. This is important for the loop in + * gunzip_read() to terminate properly. + */ + if (filepos >= filemax - 8) { + uch *eb = endbuf; + for (pos = filemax - 8; pos < filepos; pos++) + *eb++ = inbuf[pos - old_filepos]; + if (filemax > filepos) + file_read(eb, filemax - filepos); + gzip_crc = *((unsigned long *) endbuf); + gzip_filemax = *((unsigned long *) (endbuf + 4)); + } + } + + return inbuf[bufloc++]; + } + + /* decompression global pointers */ + static struct huft *tl; /* literal/length code table */ + static struct huft *td; /* distance code table */ + static int bl; /* lookup bits for tl */ + static int bd; /* lookup bits for td */ + + + /* more function prototypes */ + static int huft_build (unsigned *, unsigned, unsigned, ush *, ush *, + struct huft **, int *); + static int inflate_codes_in_window (void); + + + /* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. */ + + static int + huft_build (unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ + unsigned n, /* number of codes (assumed <= N_MAX) */ + unsigned s, /* number of simple-valued codes (0..s-1) */ + ush * d, /* list of base values for non-simple codes */ + ush * e, /* list of extra bits for non-simple codes */ + struct huft **t, /* result: starting table */ + int *m) /* maximum lookup bits, returns actual */ + { + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX + 1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX + 1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + /* Generate counts for each bit length */ + memset ((char *) c, 0, sizeof (c)); + p = b; + i = n; + do + { + c[*p]++; /* assume all entries <= BMAX */ + p++; /* Can't combine with above line (Solaris bug) */ + } + while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (struct huft *) NULL; + *m = 0; + return 0; + } + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned) l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned) l > i) + l = i; + *m = l; + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; + xp = x + 2; + while (--i) + { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + /* Make a table of values in order of bit lengths */ + p = b; + i = 0; + do + { + if ((j = *p++) != 0) + v[x[j]++] = i; + } + while (++i < n); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (struct huft *) NULL; /* just to keep compilers happy */ + q = (struct huft *) NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + q = (struct huft *) gzip_alloc ((z + 1) * sizeof (struct huft)); + + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = (struct huft *) NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch) l; /* bits to dump before this table */ + r.e = (uch) (16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h - 1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (uch) (k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (ush) (*p); /* simple code is just the value */ + p++; /* one compiler does not like *p++ */ + } + else + { + r.e = (uch) e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } + } + } + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; + } + + + /* + * inflate (decompress) the codes in a deflated (compressed) block. + * Return an error code or zero if it all goes ok. + */ + + static unsigned inflate_n, inflate_d; + + static int + inflate_codes_in_window (void) + { + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + d = inflate_d; + n = inflate_n; + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + for (;;) /* do until end of block */ + { + if (!code_state) + { + NEEDBITS ((unsigned) bl); + if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) + do + { + if (e == 99) + { + errnum = ERR_BAD_GZIP_DATA; + return 0; + } + DUMPBITS (t->b); + e -= 16; + NEEDBITS (e); + } + while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + DUMPBITS (t->b); + + if (e == 16) /* then it's a literal */ + { + slide[w++] = (uch) t->v.n; + if (w == WSIZE) + break; + } + else + /* it's an EOB or a length */ + { + /* exit if end of block */ + if (e == 15) + { + block_len = 0; + break; + } + + /* get length of block to copy */ + NEEDBITS (e); + n = t->v.n + ((unsigned) b & mask_bits[e]); + DUMPBITS (e); + + /* decode distance of block to copy */ + NEEDBITS ((unsigned) bd); + if ((e = (t = td + ((unsigned) b & md))->e) > 16) + do + { + if (e == 99) + { + errnum = ERR_BAD_GZIP_DATA; + return 0; + } + DUMPBITS (t->b); + e -= 16; + NEEDBITS (e); + } + while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) + > 16); + DUMPBITS (t->b); + NEEDBITS (e); + d = w - t->v.n - ((unsigned) b & mask_bits[e]); + DUMPBITS (e); + code_state++; + } + } + + if (code_state) + { + /* do the copy */ + do + { + n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n + : e); + if (w - d >= e) + { + memmove (slide + w, slide + d, e); + w += e; + d += e; + } + else + /* purposefully use the overlap for extra copies here!! */ + { + while (e--) + slide[w++] = slide[d++]; + } + if (w == WSIZE) + break; + } + while (n); + + if (!n) + code_state--; + + /* did we break from the loop too soon? */ + if (w == WSIZE) + break; + } + } + + /* restore the globals from the locals */ + inflate_d = d; + inflate_n = n; + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + return !block_len; + } + + + /* get header for an inflated type 0 (stored) block. */ + + static void + init_stored_block (void) + { + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + + /* go to byte boundary */ + DUMPBITS (k & 7); + + /* get the length and its complement */ + NEEDBITS (16); + block_len = ((unsigned) b & 0xffff); + DUMPBITS (16); + NEEDBITS (16); + if (block_len != (unsigned) ((~b) & 0xffff)) + errnum = ERR_BAD_GZIP_DATA; + DUMPBITS (16); + + /* restore global variables */ + bb = b; + bk = k; + } + + + /* get header for an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ + + static void + init_fixed_block () + { + int i; /* temporary variable */ + unsigned l[288]; /* length list for huft_build */ + + /* set up literal table */ + for (i = 0; i < 144; i++) + l[i] = 8; + for (; i < 256; i++) + l[i] = 9; + for (; i < 280; i++) + l[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + bl = 7; + if ((i = huft_build (l, 288, 257, cplens, cplext, &tl, &bl)) != 0) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + + /* set up distance table */ + for (i = 0; i < 30; i++) /* make an incomplete code set */ + l[i] = 5; + bd = 5; + if ((i = huft_build (l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + + /* indicate we're now working on a block */ + code_state = 0; + block_len++; + } + + + /* get header for an inflated type 2 (dynamic Huffman codes) block. */ + + static void + init_dynamic_block (void) + { + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ + unsigned ll[286 + 30]; /* literal/length and distance code lengths */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b = bb; + k = bk; + + /* read in table lengths */ + NEEDBITS (5); + nl = 257 + ((unsigned) b & 0x1f); /* number of literal/length codes */ + DUMPBITS (5); + NEEDBITS (5); + nd = 1 + ((unsigned) b & 0x1f); /* number of distance codes */ + DUMPBITS (5); + NEEDBITS (4); + nb = 4 + ((unsigned) b & 0xf); /* number of bit length codes */ + DUMPBITS (4); + if (nl > 286 || nd > 30) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS (3); + ll[bitorder[j]] = (unsigned) b & 7; + DUMPBITS (3); + } + for (; j < 19; j++) + ll[bitorder[j]] = 0; + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build (ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned) i < n) + { + NEEDBITS ((unsigned) bl); + j = (td = tl + ((unsigned) b & m))->b; + DUMPBITS (j); + j = td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS (2); + j = 3 + ((unsigned) b & 3); + DUMPBITS (2); + if ((unsigned) i + j > n) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS (3); + j = 3 + ((unsigned) b & 7); + DUMPBITS (3); + if ((unsigned) i + j > n) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + while (j--) + ll[i++] = 0; + l = 0; + } + else + /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS (7); + j = 11 + ((unsigned) b & 0x7f); + DUMPBITS (7); + if ((unsigned) i + j > n) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + while (j--) + ll[i++] = 0; + l = 0; + } + } + + /* free decoding table for trees */ + gzip_free_all(); + + /* restore the global bit buffer */ + bb = b; + bk = k; + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build (ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) + { + #if 0 + if (i == 1) + printf ("gunzip: incomplete literal tree\n"); + #endif + + errnum = ERR_BAD_GZIP_DATA; + return; + } + bd = dbits; + if ((i = huft_build (ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) + { + #if 0 + if (i == 1) + printf ("gunzip: incomplete distance tree\n"); + #endif + + errnum = ERR_BAD_GZIP_DATA; + return; + } + + /* indicate we're now working on a block */ + code_state = 0; + block_len++; + } + + + static void + get_new_block (void) + { + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + hufts = 0; + + /* make local bit buffer */ + b = bb; + k = bk; + + /* read in last block bit */ + NEEDBITS (1); + last_block = (int) b & 1; + DUMPBITS (1); + + /* read in block type */ + NEEDBITS (2); + block_type = (unsigned) b & 3; + DUMPBITS (2); + + /* restore the global bit buffer */ + bb = b; + bk = k; + + if (block_type == INFLATE_STORED) + init_stored_block (); + if (block_type == INFLATE_FIXED) + init_fixed_block (); + if (block_type == INFLATE_DYNAMIC) + init_dynamic_block (); + } + + + static void + inflate_window (void) + { + + + /* initialize window */ + wp = 0; + + /* + * Main decompression loop. + */ + while (wp < WSIZE && !errnum) { + if (!block_len) { + if (last_block) + break; + + get_new_block (); + } + + if (block_type > INFLATE_DYNAMIC) + errnum = ERR_BAD_GZIP_DATA; + + if (errnum) + return; + + /* + * Expand stored block here. + */ + if (block_type == INFLATE_STORED) + { + int w = wp; + + /* + * This is basically a glorified pass-through + */ + + while (block_len && w < WSIZE && !errnum) + { + slide[w++] = get_byte (); + block_len--; + } + + wp = w; + + continue; + } + + /* + * Expand other kind of block. + */ + + if (inflate_codes_in_window ()) + gzip_free_all(); + } + + saved_filepos += WSIZE; + } + + + static void + initialize_tables (void) + { + gzip_filepos = 0; + gzip_filemax = MAXINT; + saved_filepos = 0; + filepos = gzip_data_offset; + + /* initialize window, bit buffer */ + bk = 0; + bb = 0; + + /* reset partial decompression code */ + last_block = 0; + block_len = 0; + } + + + int + gunzip_read (char *buf, int len) + { + int ret = 0; + ulg crc_value = 0xffffffffUL; + + initialize_tables (); + + /* + * This loop operates upon uncompressed data only. The only + * special thing it does is to make sure the decompression + * window is within the range of data it needs. + */ + while (len > 0 && !errnum) { + int size; + char *srcaddr; + + while (gzip_filepos >= saved_filepos && !errnum) + inflate_window (); + + if (errnum) + break; + + /* We could have started with an unknown gzip_filemax (MAXINT) + * which has been updated in get_byte(). If so, update len + * to avoid reading beyond the end. + */ + if (len > (gzip_filemax - gzip_filepos)) { + len = gzip_filemax - gzip_filepos; + if (len < 0) { + errnum = ERR_BAD_GZIP_DATA; + break; + } + } + + srcaddr = (char *) ((gzip_filepos & (WSIZE - 1)) + slide); + size = saved_filepos - gzip_filepos; + if (size > len) + size = len; + + memmove (buf, srcaddr, size); + + /* do CRC calculation here! */ + crc_value = updcrc((unsigned char *)buf, size); + + buf += size; + len -= size; + gzip_filepos += size; + ret += size; + } + + /* check for CRC error if reading entire file */ + if (!errnum && gzip_crc != crc_value) { + printf ("gunzip: crc value 0x%lx, expected 0x%lx\n", crc_value, gzip_crc); + errnum = ERR_BAD_GZIP_CRC; + } + + if (errnum) + ret = 0; + + return ret; + } + + /* The crc_23_tab and updcrc() are adapted from gzip 1.3.3 */ + + /* ======================================================================== + * Table of CRC-32's of all single-byte values (made by makecrc.c) + */ + static ulg crc_32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL + }; + + /* =========================================================================== + * Run a set of bytes through the crc shift register. If s is a NULL + * pointer, then initialize the crc shift register contents instead. + * Return the current crc in either case. + */ + static ulg updcrc(s, n) + uch *s; /* pointer to bytes to pump through */ + int n; /* number of bytes in s[] */ + { + register ulg c; /* temporary variable */ + + c = crc; + if (n) do { + c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8); + } while (--n); + crc = c; + return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ + } + + #endif /* COMPRESSION */ diff -rcN filo-0.4.2.orig/fs/Makefile filo-0.4.2/fs/Makefile *** filo-0.4.2.orig/fs/Makefile 2003-10-10 04:19:49.000000000 -0700 --- filo-0.4.2/fs/Makefile 2006-06-12 12:36:26.000000000 -0700 *************** *** 2,13 **** --- 2,15 ---- -include $(TOPDIR)/Config OBJS-1 := blockdev.o vfs.o + OBJS-$(COMPRESSION) += gunzip.o OBJS-$(ELTORITO) += eltorito.o OBJS-$(FSYS_EXT2FS) += fsys_ext2fs.o OBJS-$(FSYS_FAT) += fsys_fat.o OBJS-$(FSYS_JFS) += fsys_jfs.o OBJS-$(FSYS_MINIX) += fsys_minix.o OBJS-$(FSYS_REISERFS) += fsys_reiserfs.o + OBJS-$(FSYS_UFS) += fsys_ufs.o OBJS-$(FSYS_XFS) += fsys_xfs.o OBJS-$(FSYS_ISO9660) += fsys_iso9660.o diff -rcN filo-0.4.2.orig/fs/ufs.h filo-0.4.2/fs/ufs.h *** filo-0.4.2.orig/fs/ufs.h 1969-12-31 16:00:00.000000000 -0800 --- filo-0.4.2/fs/ufs.h 2006-06-09 10:58:19.000000000 -0700 *************** *** 0 **** --- 1,232 ---- + /* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + + #ifndef _GRUB_UFS_H + #define _GRUB_UFS_H_ + + #ifdef FSYS_UFS + + /* ufs specific constants */ + #define UFS_SBLOCK 16 + #define UFS_SBSIZE 8192 + #define UFS_MAGIC 0x011954 + #define ROOTINO 2 /* i number of all roots */ + #define UFS_NDADDR 12 /* direct blocks */ + #define UFS_NIADDR 3 /* indirect blocks */ + #define MAXMNTLEN 512 + #define MAXCSBUFS 32 + #define MAXNAMELEN 256 + + /* file types */ + #define IFMT 0xf000 + #define IFREG 0x8000 + #define IFDIR 0x4000 + + typedef unsigned char grub_uchar_t; + typedef unsigned short grub_ushort_t; + typedef unsigned short grub_o_mode_t; + typedef unsigned short grub_o_uid_t; + typedef unsigned short grub_o_gid_t; + typedef long grub_ino_t; + typedef long grub_int32_t; + typedef long grub_uid_t; + typedef long grub_gid_t; + typedef unsigned long grub_uint32_t; + typedef unsigned long grub_daddr32_t; + typedef unsigned long grub_time32_t; + typedef struct { int val[2]; } grub_quad_t; + + struct timeval32 { + grub_time32_t tv_sec; + grub_int32_t tv_usec; + }; + + /* + * Per cylinder group information; summarized in blocks allocated + * from first cylinder group data blocks. These blocks have to be + * read in from fs_csaddr (size fs_cssize) in addition to the + * super block. + * + * N.B. sizeof (struct csum) must be a power of two in order for + * the ``fs_cs'' macro to work (see below). + */ + struct csum { + grub_int32_t cs_ndir; /* number of directories */ + grub_int32_t cs_nbfree; /* number of free blocks */ + grub_int32_t cs_nifree; /* number of free inodes */ + grub_int32_t cs_nffree; /* number of free frags */ + }; + + /* Ufs super block */ + struct fs { + grub_uint32_t fs_link; /* linked list of file systems */ + grub_uint32_t fs_rolled; /* logging only: fs fully rolled */ + grub_daddr32_t fs_sblkno; /* addr of super-block in filesys */ + grub_daddr32_t fs_cblkno; /* offset of cyl-block in filesys */ + grub_daddr32_t fs_iblkno; /* offset of inode-blocks in filesys */ + grub_daddr32_t fs_dblkno; /* offset of first data after cg */ + grub_int32_t fs_cgoffset; /* cylinder group offset in cylinder */ + grub_int32_t fs_cgmask; /* used to calc mod fs_ntrak */ + grub_time32_t fs_time; /* last time written */ + grub_int32_t fs_size; /* number of blocks in fs */ + grub_int32_t fs_dsize; /* number of data blocks in fs */ + grub_int32_t fs_ncg; /* number of cylinder groups */ + grub_int32_t fs_bsize; /* size of basic blocks in fs */ + grub_int32_t fs_fsize; /* size of frag blocks in fs */ + grub_int32_t fs_frag; /* number of frags in a block in fs */ + /* these are configuration parameters */ + grub_int32_t fs_minfree; /* minimum percentage of free blocks */ + grub_int32_t fs_rotdelay; /* num of ms for optimal next block */ + grub_int32_t fs_rps; /* disk revolutions per second */ + /* these fields can be computed from the others */ + grub_int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */ + grub_int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */ + grub_int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */ + grub_int32_t fs_fshift; /* ``numfrags'' calc number of frags */ + /* these are configuration parameters */ + grub_int32_t fs_maxcontig; /* max number of contiguous blks */ + grub_int32_t fs_maxbpg; /* max number of blks per cyl group */ + /* these fields can be computed from the others */ + grub_int32_t fs_fragshift; /* block to frag shift */ + grub_int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ + grub_int32_t fs_sbsize; /* actual size of super block */ + grub_int32_t fs_csmask; /* csum block offset */ + grub_int32_t fs_csshift; /* csum block number */ + grub_int32_t fs_nindir; /* value of NINDIR */ + grub_int32_t fs_inopb; /* value of INOPB */ + grub_int32_t fs_nspf; /* value of NSPF */ + /* yet another configuration parameter */ + grub_int32_t fs_optim; /* optimization preference, see below */ + /* these fields are derived from the hardware */ + /* USL SVR4 compatibility */ + /* + * * USL SVR4 compatibility + * + * There was a significant divergence here between Solaris and + * SVR4 for x86. By swapping these two members in the superblock, + * we get read-only compatibility of SVR4 filesystems. Otherwise + * there would be no compatibility. This change was introduced + * during bootstrapping of Solaris on x86. By making this ifdef'ed + * on byte order, we provide ongoing compatibility across all + * platforms with the same byte order, the highest compatibility + * that can be achieved. + */ + grub_int32_t fs_state; /* file system state time stamp */ + grub_int32_t fs_si; /* summary info state - lufs only */ + grub_int32_t fs_trackskew; /* sector 0 skew, per track */ + /* unique id for this filesystem (currently unused and unmaintained) */ + /* In 4.3 Tahoe this space is used by fs_headswitch and fs_trkseek */ + /* Neither of those fields is used in the Tahoe code right now but */ + /* there could be problems if they are. */ + grub_int32_t fs_id[2]; /* file system id */ + /* sizes determined by number of cylinder groups and their sizes */ + grub_daddr32_t fs_csaddr; /* blk addr of cyl grp summary area */ + grub_int32_t fs_cssize; /* size of cyl grp summary area */ + grub_int32_t fs_cgsize; /* cylinder group size */ + /* these fields are derived from the hardware */ + grub_int32_t fs_ntrak; /* tracks per cylinder */ + grub_int32_t fs_nsect; /* sectors per track */ + grub_int32_t fs_spc; /* sectors per cylinder */ + /* this comes from the disk driver partitioning */ + grub_int32_t fs_ncyl; /* cylinders in file system */ + /* these fields can be computed from the others */ + grub_int32_t fs_cpg; /* cylinders per group */ + grub_int32_t fs_ipg; /* inodes per group */ + grub_int32_t fs_fpg; /* blocks per group * fs_frag */ + /* this data must be re-computed after crashes */ + struct csum fs_cstotal; /* cylinder summary information */ + /* these fields are cleared at mount time */ + char fs_fmod; /* super block modified flag */ + char fs_clean; /* file system state flag */ + char fs_ronly; /* mounted read-only flag */ + char fs_flags; /* largefiles flag, etc. */ + char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ + /* these fields retain the current block allocation info */ + grub_int32_t fs_cgrotor; /* last cg searched */ + /* + * The following used to be fs_csp[MAXCSBUFS]. It was not + * used anywhere except in old utilities. We removed this + * in 5.6 and expect fs_u.fs_csp to be used instead. + * We no longer limit fs_cssize based on MAXCSBUFS. + */ + union { /* fs_cs (csum) info */ + grub_uint32_t fs_csp_pad[MAXCSBUFS]; + struct csum *fs_csp; + } fs_u; + grub_int32_t fs_cpc; /* cyl per cycle in postbl */ + short fs_opostbl[16][8]; /* old rotation block list head */ + grub_int32_t fs_sparecon[51]; /* reserved for future constants */ + grub_int32_t fs_version; /* minor version of MTB ufs */ + grub_int32_t fs_logbno; /* block # of embedded log */ + grub_int32_t fs_reclaim; /* reclaim open, deleted files */ + grub_int32_t fs_sparecon2; /* reserved for future constant */ + /* USL SVR4 compatibility */ + grub_int32_t fs_npsect; /* # sectors/track including spares */ + grub_quad_t fs_qbmask; /* ~fs_bmask - for use with quad size */ + grub_quad_t fs_qfmask; /* ~fs_fmask - for use with quad size */ + grub_int32_t fs_postblformat; /* fmt of positional layout tables */ + grub_int32_t fs_nrpos; /* number of rotaional positions */ + grub_int32_t fs_postbloff; /* (short) rotation block list head */ + grub_int32_t fs_rotbloff; /* (grub_uchar_t) blocks for each */ + /* rotation */ + grub_int32_t fs_magic; /* magic number */ + grub_uchar_t fs_space[1]; /* list of blocks for each rotation */ + /* actually longer */ + }; + + struct icommon { + grub_o_mode_t ic_smode; /* 0: mode and type of file */ + short ic_nlink; /* 2: number of links to file */ + grub_o_uid_t ic_suid; /* 4: owner's user id */ + grub_o_gid_t ic_sgid; /* 6: owner's group id */ + grub_uint32_t ic_sizelo; /* 8: number of bytes in file */ + grub_uint32_t ic_sizehi; /* 12: number of bytes in file */ + struct timeval32 ic_atime; /* 16: time last accessed */ + struct timeval32 ic_mtime; /* 24: time last modified */ + struct timeval32 ic_ctime; /* 32: last time inode changed */ + grub_daddr32_t ic_db[UFS_NDADDR]; /* 40: disk block addresses */ + grub_daddr32_t ic_ib[UFS_NIADDR]; /* 88: indirect blocks */ + grub_int32_t ic_flags; /* 100: cflags */ + grub_int32_t ic_blocks; /* 104: 512 byte blocks actually held */ + grub_int32_t ic_gen; /* 108: generation number */ + grub_int32_t ic_shadow; /* 112: shadow inode */ + grub_uid_t ic_uid; /* 116: long EFT version of uid */ + grub_gid_t ic_gid; /* 120: long EFT version of gid */ + grub_uint32_t ic_oeftflag; /* 124: extended attr directory ino, */ + /* 0 = none */ + }; + + struct direct { + grub_ino_t d_ino; + grub_ushort_t d_reclen; + grub_ushort_t d_namelen; + char d_name[MAXNAMELEN + 1]; + }; + + /* inode macros */ + #define INOPB(fs) ((fs)->fs_inopb) + #define itoo(fs, x) ((x) % (grub_uint32_t)INOPB(fs)) + #define itog(fs, x) ((x) / (grub_uint32_t)(fs)->fs_ipg) + #define itod(fs, x) ((grub_daddr32_t)(cgimin(fs, itog(fs, x)) + \ + (blkstofrags((fs), \ + ((x) % (grub_uint32_t)(fs)->fs_ipg / (grub_uint32_t)INOPB(fs)))))) + + /* block conversion macros */ + #define UFS_NINDIR(fs) ((fs)->fs_nindir) /* # of indirects */ + #define blkoff(fs, loc) ((int)((loc & ~(fs)->fs_bmask))) + #define lblkno(fs, loc) ((grub_int32_t)((loc) >> (fs)->fs_bshift)) + /* frag to blk */ + #define fsbtodb(fs, b) (((grub_daddr32_t)(b)) << (fs)->fs_fsbtodb) + #define blkstofrags(fs, b) ((b) << (fs)->fs_fragshift) + + /* cynlinder group macros */ + #define cgbase(fs, c) ((grub_daddr32_t)((fs)->fs_fpg * (c))) + #define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode block */ + #define cgstart(fs, c) \ + (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask))) + + #endif /* FSYS_UFS */ + + #endif /* !_GRUB_UFS_H */ diff -rcN filo-0.4.2.orig/fs/vfs.c filo-0.4.2/fs/vfs.c *** filo-0.4.2.orig/fs/vfs.c 2003-10-15 04:19:38.000000000 -0700 --- filo-0.4.2/fs/vfs.c 2006-06-23 14:30:42.000000000 -0700 *************** *** 40,45 **** --- 40,48 ---- # ifdef FSYS_JFS {"jfs", jfs_mount, jfs_read, jfs_dir, 0, jfs_embed}, # endif + # ifdef FSYS_UFS + {"ufs", ufs_mount, ufs_read, ufs_dir, 0, 0}, + # endif # ifdef FSYS_XFS {"xfs", xfs_mount, xfs_read, xfs_dir, 0, 0}, # endif diff -rcN filo-0.4.2.orig/i386/context.c filo-0.4.2/i386/context.c *** filo-0.4.2.orig/i386/context.c 2003-10-02 05:51:45.000000000 -0700 --- filo-0.4.2/i386/context.c 2006-06-27 17:05:15.000000000 -0700 *************** *** 106,119 **** } /* Start ELF Boot image */ ! uint32_t start_elf(uint32_t entry_point, uint32_t param) { struct context *ctx; ctx = init_context(image_stack, sizeof image_stack, 1); ctx->eip = entry_point; ctx->param[0] = param; ! ctx->eax = 0xe1fb007; ctx->ebx = param; ctx = switch_to(ctx); --- 106,119 ---- } /* Start ELF Boot image */ ! uint32_t start_elf(uint32_t entry_point, uint32_t param, uint32_t magic) { struct context *ctx; ctx = init_context(image_stack, sizeof image_stack, 1); ctx->eip = entry_point; ctx->param[0] = param; ! ctx->eax = magic; ctx->ebx = param; ctx = switch_to(ctx); diff -rcN filo-0.4.2.orig/i386/Makefile filo-0.4.2/i386/Makefile *** filo-0.4.2.orig/i386/Makefile 2003-10-02 05:51:45.000000000 -0700 --- filo-0.4.2/i386/Makefile 2006-06-21 14:42:40.000000000 -0700 *************** *** 3,8 **** OBJS-1 := context.o switch.o segment.o timer.o sys_info.o OBJS-$(LINUX_LOADER) += linux_load.o ! OBJS-$(MULTIBOOT_IMAGE) += multiboot.o include $(TOPDIR)/makerules --- 3,8 ---- OBJS-1 := context.o switch.o segment.o timer.o sys_info.o OBJS-$(LINUX_LOADER) += linux_load.o ! OBJS-1 += multiboot.o include $(TOPDIR)/makerules diff -rcN filo-0.4.2.orig/i386/multiboot.c filo-0.4.2/i386/multiboot.c *** filo-0.4.2.orig/i386/multiboot.c 2003-08-08 06:18:29.000000000 -0700 --- filo-0.4.2/i386/multiboot.c 2006-06-27 14:21:50.000000000 -0700 *************** *** 3,8 **** --- 3,9 ---- #include #include #include + #include #define DEBUG_THIS DEBUG_MULTIBOOT #include *************** *** 11,26 **** #define MULTIBOOT_HEADER_MAGIC 0x1BADB002 #define MULTIBOOT_HEADER_FLAGS 0x00000003 struct mbheader { unsigned int magic, flags, checksum; ! }; ! const struct mbheader multiboot_header ! __attribute__((section (".hdr"))) = ! { ! MULTIBOOT_HEADER_MAGIC, ! MULTIBOOT_HEADER_FLAGS, ! -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) }; /* Multiboot information structure, provided by loader to us */ --- 12,28 ---- #define MULTIBOOT_HEADER_MAGIC 0x1BADB002 #define MULTIBOOT_HEADER_FLAGS 0x00000003 + #define MULTIBOOT_SEARCH 8192 + #define MULTIBOOT_FOUND(addr, len) \ + ((len) >= 12 \ + && *((int *) (addr)) == MULTIBOOT_HEADER_MAGIC \ + && ! (*((unsigned *) (addr)) + *((unsigned *) (addr + 4)) \ + + *((unsigned *) (addr + 8)))) struct mbheader { unsigned int magic, flags, checksum; ! unsigned int header_addr, load_addr; ! unsigned int load_end_addr, bss_end_addr, entry_addr; }; /* Multiboot information structure, provided by loader to us */ *************** *** 41,46 **** --- 43,49 ---- #define MULTIBOOT_AOUT_SYMS_VALID 0x10 #define MULTIBOOT_ELF_SYMS_VALID 0x20 #define MULTIBOOT_MMAP_VALID 0x40 + #define MULTIBOOT_LOADER_NAME_VALID 0x200 unsigned mem_lower; unsigned mem_upper; unsigned char boot_device[4]; *************** *** 53,58 **** --- 56,89 ---- unsigned syms_shndx; unsigned mmap_length; unsigned mmap_addr; + unsigned long drives_length; + unsigned long drives_addr; + unsigned long config_table; + unsigned long boot_loader_name; + unsigned long apm_table; + unsigned long vbe_control_info; + unsigned long vbe_mode_info; + unsigned short vbe_mode; + unsigned short vbe_interface_seg; + unsigned short vbe_interface_off; + unsigned short vbe_interface_len; + }; + + struct mod_list { + unsigned long mod_start; + unsigned long mod_end; + unsigned long cmdline; + unsigned long pad; + }; + + #ifdef MULTIBOOT_IMAGE + + const struct mbheader multiboot_header + __attribute__((section (".hdr"))) = + { + MULTIBOOT_HEADER_MAGIC, + MULTIBOOT_HEADER_FLAGS, + -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) }; void collect_multiboot_info(struct sys_info *info) *************** *** 126,128 **** --- 157,237 ---- info->n_memranges = mmap_count; return; } + #endif /* MULTIBOOT_IMAGE */ + + /* + * The entire multiboot_header must be contained + * within the first MULTIBOOT_SEARCH bytes of the kernel image. + */ + unsigned int multiboot_find_header() + { + int i, size; + char *buf; + + size = MULTIBOOT_SEARCH; + buf = malloc(size); + size = file_read(buf, size); + file_seek(0); /* reset file offset */ + for (i = 0; i < size; i += 4) { + if (MULTIBOOT_FOUND((int) (buf + i), size - i)) { + free(buf); + return (i); + } + } + free(buf); + return (0); + } + + /* fill in the program address range */ + void multiboot_fill_header(unsigned int mbh_addr, unsigned int low_addr, + unsigned int high_addr) + { + struct mbheader *mbh = (struct mbheader *)mbh_addr; + mbh->load_addr = low_addr; + mbh->bss_end_addr = high_addr; + } + + extern void *multiboot_build_info(struct sys_info *info, char *filename, + const char *cmdline, char *mod_name, char *mod_start, unsigned int mod_size) + { + int i, n_mmap; + struct multiboot_info *mbi; + struct mod_list *mod; + struct multiboot_mmap *mmap; + char *grub_cmdline; + + mbi = malloc(sizeof (*mbi)); + /* we only care about cmdline, mmap, and mod_addr */ + mbi->flags = ( MULTIBOOT_CMDLINE_VALID | MULTIBOOT_MODS_VALID | + MULTIBOOT_MMAP_VALID | MULTIBOOT_LOADER_NAME_VALID ); + + grub_cmdline = malloc(strlen (filename) + strlen(cmdline) + 2); + strncpy(grub_cmdline, filename, strlen(filename)); + grub_cmdline[strlen(filename)] = ' '; + strncpy(grub_cmdline + strlen(filename) + 1, cmdline, strlen(cmdline)); + mbi->command_line = virt_to_phys(grub_cmdline); + mbi->boot_loader_name = (int) "FILO"; + + /* add ramdisk module */ + mbi->mods_count = 1; + mod = malloc(sizeof (*mod)); + mbi->mods_addr = virt_to_phys((unsigned int) mod); + mod->cmdline = virt_to_phys(mod_name); + mod->mod_start = (unsigned int) mod_start; + mod->mod_end = (unsigned int) mod_start + mod_size - 1; + + /* add memory map */ + n_mmap = info->n_memranges; + mbi->mmap_length = n_mmap * sizeof (struct multiboot_mmap); + mmap = malloc(mbi->mmap_length); + mbi->mmap_addr = virt_to_phys((unsigned int) mmap); + for (i = 0; i < info->n_memranges; i++) { + mmap[i].entry_size = 20; /* 8 + 8 + 4 */ + mmap[i].base_lo = info->memrange[i].base & 0xffffffff; + mmap[i].base_hi = info->memrange[i].base >> 32; + mmap[i].size_lo = info->memrange[i].size & 0xffffffff; + mmap[i].size_hi = info->memrange[i].size >> 32; + mmap[i].type = 1; /* RAM */ + } + return (mbi); + } diff -rcN filo-0.4.2.orig/include/fs.h filo-0.4.2/include/fs.h *** filo-0.4.2.orig/include/fs.h 2003-10-14 06:30:40.000000000 -0700 --- filo-0.4.2/include/fs.h 2006-06-22 21:59:10.000000000 -0700 *************** *** 32,35 **** --- 32,40 ---- extern int using_devsize; + #ifndef NO_DECOMPRESSION + extern int gunzip_read(char *buf, int len); + extern int gunzip_test_header(void); + #endif + #endif /* FS_H */ diff -rcN filo-0.4.2.orig/include/lib.h filo-0.4.2/include/lib.h *** filo-0.4.2.orig/include/lib.h 2003-10-15 04:19:39.000000000 -0700 --- filo-0.4.2/include/lib.h 2006-06-21 12:54:56.000000000 -0700 *************** *** 43,48 **** --- 43,49 ---- size_t strnlen(const char *src, size_t max); size_t strlen(const char *src); int strcmp(const char *s1, const char *s2); + int strncmp(const char *s1, const char *s2, int n); int memcmp(const void *s1, const void *s2, size_t n); void *memcpy(void *dest, const void *src, size_t n); void *memset(void *s, int c, size_t n); diff -rcN filo-0.4.2.orig/main/elfload.c filo-0.4.2/main/elfload.c *** filo-0.4.2.orig/main/elfload.c 2003-10-15 04:19:39.000000000 -0700 --- filo-0.4.2/main/elfload.c 2006-06-27 17:34:49.000000000 -0700 *************** *** 15,24 **** #define DEBUG_THIS DEBUG_ELFBOOT #include ! extern unsigned int start_elf(unsigned long entry_point, unsigned long param); extern char _start, _end; static char *image_name, *image_version; static int check_mem_ranges(struct sys_info *info, Elf_phdr *phdr, int phnum) --- 15,37 ---- #define DEBUG_THIS DEBUG_ELFBOOT #include ! extern unsigned int start_elf(unsigned long entry_point, unsigned long param, ! unsigned long magic); extern char _start, _end; + /* multiboot support */ + extern unsigned int multiboot_find_header(void); + extern void multiboot_fill_header(unsigned int, unsigned int, unsigned int); + extern void *multiboot_build_info(struct sys_info *, const char *, const char *, + char *, char *, unsigned int); + static unsigned int multiboot_header_foff; /* header offset in file */ + static unsigned int multiboot_header_addr; /* header addr after loading */ + static unsigned int low_addr = ~0, max_addr = 0; + static char *ramdisk_start, *ramdisk_filename; + uint32_t ramdisk_size; + static char *image_name, *image_version; + static int load_module(const char *); static int check_mem_ranges(struct sys_info *info, Elf_phdr *phdr, int phnum) *************** *** 145,150 **** --- 158,174 ---- memset(phys_to_virt(phdr[i].p_paddr + checksum_offset - phdr[i].p_offset), 0, 2); } + if (phdr[i].p_paddr < low_addr) + low_addr = phdr[i].p_paddr; + if (phdr[i].p_paddr + phdr[i].p_memsz > max_addr) + max_addr = phdr[i].p_paddr + phdr[i].p_memsz; + if (multiboot_header_foff >= phdr[i].p_offset && + multiboot_header_foff < phdr[i].p_offset + phdr[i].p_filesz) { + multiboot_header_addr = phdr[i].p_paddr + + multiboot_header_foff - phdr[i].p_offset; + debug("multiboot header loaded at 0x%x\n", multiboot_header_addr); + } + debug("ok\n"); } *************** *** 281,295 **** unsigned long phdr_size; unsigned long checksum_offset; unsigned short checksum; ! Elf_Bhdr *boot_notes = NULL; int retval = -1; int image_retval; image_name = image_version = 0; if (!file_open(filename)) goto out; if (file_read(&ehdr, sizeof ehdr) != sizeof ehdr) { debug("Can't read ELF header\n"); retval = LOADER_NOT_SUPPORT; --- 305,326 ---- unsigned long phdr_size; unsigned long checksum_offset; unsigned short checksum; ! void *boot_notes = NULL; int retval = -1; int image_retval; + unsigned long magic; image_name = image_version = 0; if (!file_open(filename)) goto out; + multiboot_header_foff = multiboot_find_header(); + if (multiboot_header_foff) { + debug("found multiboot header at file offset 0x%x\n", + multiboot_header_foff); + } + if (file_read(&ehdr, sizeof ehdr) != sizeof ehdr) { debug("Can't read ELF header\n"); retval = LOADER_NOT_SUPPORT; *************** *** 338,356 **** goto out; } ! boot_notes = build_boot_notes(info, cmdline); debug("current time: %lu\n", currticks()); debug("entry point is %#x\n", ehdr.e_entry); printf("Jumping to entry point...\n"); ! image_retval = start_elf(ehdr.e_entry, virt_to_phys(boot_notes)); console_init(); printf("Image returned with return value %#x\n", image_retval); retval = 0; out: if (phdr) free(phdr); if (boot_notes) --- 369,400 ---- goto out; } ! if (!load_module(cmdline)) ! goto out; ! ! if (multiboot_header_addr) { ! boot_notes = multiboot_build_info(info, filename, cmdline, ! ramdisk_filename, ramdisk_start, ramdisk_size); ! multiboot_fill_header(multiboot_header_addr, low_addr, max_addr); ! magic = 0x2BADB002; /* multiboot magic */ ! } else { ! boot_notes = build_boot_notes(info, cmdline); ! magic = ELF_BHDR_MAGIC; ! } debug("current time: %lu\n", currticks()); debug("entry point is %#x\n", ehdr.e_entry); printf("Jumping to entry point...\n"); ! image_retval = start_elf(ehdr.e_entry, virt_to_phys(boot_notes), magic); console_init(); printf("Image returned with return value %#x\n", image_retval); retval = 0; out: + if (retval) + printf("Image loading failed\n"); if (phdr) free(phdr); if (boot_notes) *************** *** 361,363 **** --- 405,462 ---- free(image_version); return retval; } + + static int + load_module(const char *cmdline) + { + char *tmp, *modname = NULL; + + tmp = strchr((char *)cmdline, 'm'); + while (tmp) { + if (strncmp(tmp, "module=", strlen("module=")) == 0) { + modname = tmp + strlen("module="); + break; + } + tmp = strchr(tmp, 'm'); + } + + if (modname == NULL) { + printf("no module specified\n"); + return 1; + } + + tmp = strchr(modname, ','); + if (tmp) + *tmp = '\0'; + printf("Loading module: %s\n", modname); + ramdisk_filename = strdup(modname); + + /* now attempt to load the module */ + if (!file_open(modname)) { + printf("Can't open module: %s\n", modname); + if (tmp) + *tmp = ','; + return 0; + } + + ramdisk_start = (char *)((max_addr + 0xfff) & ~0xfff); + #ifdef COMPRESSION + if (gunzip_test_header()) + ramdisk_size = gunzip_read(phys_to_virt(ramdisk_start), 0x7fffffff); + else + #endif + ramdisk_size = file_read(phys_to_virt(ramdisk_start), file_size()); + if (ramdisk_size < file_size()) { + printf("Failed to load module: %s file size 0x%lx, loaded 0x%x\n", + modname, file_size(), ramdisk_size); + if (tmp) + *tmp = ','; + return 0; + } + + printf("loaded module %s at 0x%x, size 0x%x\n", + modname, (unsigned int)ramdisk_start, ramdisk_size); + if (tmp) + *tmp = ','; + return 1; + } diff -rcN filo-0.4.2.orig/main/lib.c filo-0.4.2/main/lib.c *** filo-0.4.2.orig/main/lib.c 2003-10-10 04:19:49.000000000 -0700 --- filo-0.4.2/main/lib.c 2006-03-09 17:46:47.000000000 -0800 *************** *** 18,23 **** --- 18,36 ---- return i; } + int strncmp(const char *s1, const char *s2, int n) + { + int i, r; + + i = 0; + while (i < n && (r = (*s1 - *s2)) == 0 && *s1) { + s1++; + s2++; + i++; + } + return r; + } + int strcmp(const char *s1, const char *s2) { int r;