Page MenuHomeFreeBSD

D14799.id40603.diff
No OneTemporary

D14799.id40603.diff

Index: release/amd64/mkisoimages.sh
===================================================================
--- release/amd64/mkisoimages.sh
+++ release/amd64/mkisoimages.sh
@@ -58,3 +58,8 @@
makefs -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$@"
rm -f "$1/etc/fstab"
rm -f efiboot.img
+
+# Drop our hybrid boot magic into the 32K of blank space at the front of the image.
+mkimg -s mbr -b $4/boot/mbr -p freebsd:-"mkimg -s bsd -b $4/boot/isoboot -p-" -o hybrid.img
+dd if=hybrid.img of=$NAME conv=notrunc
+rm -f hybrid.img
Index: stand/common/disk.c
===================================================================
--- stand/common/disk.c
+++ stand/common/disk.c
@@ -270,6 +270,9 @@
dev->d_offset = part.start;
od->entrysize = part.end - part.start + 1;
}
+ } else if (ptable_gettype(od->table) == PTABLE_ISO9660) {
+ dev->d_offset = 0;
+ od->entrysize = mediasize;
} else if (slice >= 0) {
/* Try to get information about partition */
if (slice == 0)
Index: stand/common/part.h
===================================================================
--- stand/common/part.h
+++ stand/common/part.h
@@ -36,7 +36,8 @@
PTABLE_BSD,
PTABLE_MBR,
PTABLE_GPT,
- PTABLE_VTOC8
+ PTABLE_VTOC8,
+ PTABLE_ISO9660
};
enum partition_type {
@@ -52,6 +53,7 @@
PART_LINUX,
PART_LINUX_SWAP,
PART_DOS,
+ PART_ISO9660
};
struct ptable_entry {
Index: stand/common/part.c
===================================================================
--- stand/common/part.c
+++ stand/common/part.c
@@ -37,6 +37,8 @@
#include <sys/queue.h>
#include <sys/vtoc.h>
+#include <fs/cd9660/iso.h>
+
#include <crc32.h>
#include <part.h>
#include <uuid.h>
@@ -97,6 +99,7 @@
{ PART_LINUX, "Linux" },
{ PART_LINUX_SWAP, "Linux swap" },
{ PART_DOS, "DOS/Windows" },
+ { PART_ISO9660, "ISO9660" },
};
const char *
@@ -603,6 +606,45 @@
}
#endif /* LOADER_VTOC8_SUPPORT */
+#define cdb2devb(bno) ((bno) * ISO_DEFAULT_BLOCK_SIZE / table->sectorsize)
+
+static struct ptable *
+ptable_iso9660read(struct ptable *table, void *dev, diskread_t dread)
+{
+ uint8_t *buf;
+ struct iso_primary_descriptor *vd;
+ struct pentry *entry;
+
+ buf = malloc(table->sectorsize);
+ if (buf == NULL)
+ return (table);
+
+ if (dread(dev, buf, 1, cdb2devb(16)) != 0) {
+ DEBUG("read failed");
+ ptable_close(table);
+ table = NULL;
+ goto out;
+ }
+ vd = (struct iso_primary_descriptor *)buf;
+ if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0)
+ goto out;
+
+ entry = malloc(sizeof(*entry));
+ if (entry == NULL)
+ goto out;
+ entry->part.start = 0;
+ entry->part.end = table->sectors;
+ entry->part.type = PART_ISO9660;
+ entry->part.index = 0;
+ STAILQ_INSERT_TAIL(&table->entries, entry, entry);
+
+ table->type = PTABLE_ISO9660;
+
+out:
+ free(buf);
+ return (table);
+}
+
struct ptable *
ptable_open(void *dev, uint64_t sectors, uint16_t sectorsize,
diskread_t *dread)
@@ -634,6 +676,11 @@
table->type = PTABLE_NONE;
STAILQ_INIT(&table->entries);
+ if (ptable_iso9660read(table, dev, dread) != NULL) {
+ if (table->type == PTABLE_ISO9660)
+ goto out;
+ }
+
#ifdef LOADER_VTOC8_SUPPORT
if (be16dec(buf + offsetof(struct vtoc8, magic)) == VTOC_MAGIC) {
if (ptable_vtoc8read(table, dev, dread) == NULL) {
Index: stand/i386/boot2/Makefile
===================================================================
--- stand/i386/boot2/Makefile
+++ stand/i386/boot2/Makefile
@@ -2,7 +2,7 @@
.include <bsd.init.mk>
-FILES= boot boot1 boot2
+FILES= boot boot1 boot2 isoboot isoboot2
NM?= nm
@@ -45,13 +45,18 @@
CFLAGS.clang+= -Oz ${CLANG_OPT_SMALL}
+CFLAGS.isoboot2.c+= -I${BOOTSRC}/i386/common
+
LD_FLAGS+=${LD_FLAGS_BIN}
-CLEANFILES+= boot
+CLEANFILES+= boot isoboot
boot: boot1 boot2
cat boot1 boot2 > boot
+isoboot: boot1 isoboot2
+ cat boot1 isoboot2 > isoboot
+
CLEANFILES+= boot1 boot1.out boot1.o
boot1: boot1.out
@@ -62,6 +67,8 @@
CLEANFILES+= boot2 boot2.ld boot2.ldr boot2.bin boot2.out boot2.o \
boot2.h sio.o
+CLEANFILES+= isoboot2 isoboot2.ld isoboot2.ldr isoboot2.bin isoboot2.out \
+ isoboot2.o
BOOT2SIZE= 7680
@@ -83,8 +90,6 @@
boot2.out: ${BTXCRT} boot2.o sio.o
${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC}
-SRCS= boot2.c boot2.h
-
boot2.h: boot1.out
${NM} -t d ${.ALLSRC} | awk '/([0-9])+ T xread/ \
{ x = $$1 - ORG1; \
@@ -92,6 +97,26 @@
ORG1=`printf "%d" ${ORG1}` \
REL1=`printf "%d" ${REL1}` > ${.TARGET}
+isoboot2: isoboot2.ld
+ @set -- `ls -l ${.ALLSRC}`; x=$$((${BOOT2SIZE}-$$5)); \
+ echo "$$x bytes available"; test $$x -ge 0
+ ${DD} if=${.ALLSRC} of=${.TARGET} obs=${BOOT2SIZE} conv=osync
+
+isoboot2.ld: isoboot2.ldr isoboot2.bin ${BTXKERN}
+ btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l isoboot2.ldr \
+ -o ${.TARGET} -P 1 isoboot2.bin
+
+isoboot2.ldr:
+ ${DD} if=/dev/zero of=${.TARGET} bs=512 count=1
+
+isoboot2.bin: isoboot2.out
+ ${OBJCOPY} -S -O binary isoboot2.out ${.TARGET}
+
+isoboot2.out: ${BTXCRT} isoboot2.o sio.o
+ ${LD} ${LD_FLAGS} -Ttext ${ORG2} -o ${.TARGET} ${.ALLSRC}
+
+SRCS= boot2.c isoboot2.c boot2.h
+
.include <bsd.prog.mk>
# XXX: clang integrated-as doesn't grok .codeNN directives yet
Index: stand/i386/boot2/isoboot2.c
===================================================================
--- /dev/null
+++ stand/i386/boot2/isoboot2.c
@@ -0,0 +1,901 @@
+/*-
+ * Copyright (c) 1998 Robert Nordier
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/disklabel.h>
+#include <sys/diskmbr.h>
+#include <sys/dirent.h>
+#include <sys/reboot.h>
+
+#include <machine/bootinfo.h>
+#include <machine/elf.h>
+
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include <a.out.h>
+
+#include <btxv86.h>
+
+#include <fs/cd9660/iso.h>
+#include <fs/cd9660/cd9660_rrip.h>
+
+#include "boot2.h"
+#include "lib.h"
+#include "paths.h"
+#include "rbx.h"
+
+#include "bootargs.h"
+
+/* Define to 0 to omit serial support */
+#ifndef SERIAL
+#define SERIAL 1
+#endif
+
+#define IO_KEYBOARD 1
+#define IO_SERIAL 2
+
+#if SERIAL
+#define DO_KBD (ioctrl & IO_KEYBOARD)
+#define DO_SIO (ioctrl & IO_SERIAL)
+#else
+#define DO_KBD (1)
+#define DO_SIO (0)
+#endif
+
+#define SECOND 18 /* Circa that many ticks in a second. */
+
+#define ARGS 0x900
+#define NOPT 14
+#define NDEV 3
+#define MEM_BASE 0x12
+#define MEM_EXT 0x15
+
+#define DRV_HARD 0x80
+#define DRV_MASK 0x7f
+
+#define TYPE_AD 0
+#define TYPE_DA 1
+#define TYPE_MAXHARD TYPE_DA
+#define TYPE_FD 2
+
+extern uint32_t _end;
+
+static const char optstr[NOPT] = "DhaCcdgmnpqrsv"; /* Also 'P', 'S' */
+static const unsigned char flags[NOPT] = {
+ RBX_DUAL,
+ RBX_SERIAL,
+ RBX_ASKNAME,
+ RBX_CDROM,
+ RBX_CONFIG,
+ RBX_KDB,
+ RBX_GDB,
+ RBX_MUTE,
+ RBX_NOINTR,
+ RBX_PAUSE,
+ RBX_QUIET,
+ RBX_DFLTROOT,
+ RBX_SINGLE,
+ RBX_VERBOSE
+};
+
+static const char *const dev_nm[NDEV] = {"ad", "da", "fd"};
+static const unsigned char dev_maj[NDEV] = {30, 4, 2};
+
+static struct dsk {
+ unsigned drive;
+ unsigned type;
+ unsigned unit;
+ uint8_t slice;
+ uint8_t part;
+ unsigned start;
+ int init;
+} dsk;
+static char cmd[512], cmddup[512], knamebuf[1024];
+static const char *kname;
+uint32_t opts;
+static struct bootinfo bootinfo;
+static off_t fs_off = 0;
+static bool ls;
+#if SERIAL
+static int comspeed = SIOSPD;
+static uint8_t ioctrl = IO_KEYBOARD;
+#endif
+
+#define VBLKSHIFT 12
+#define VBLKSIZE (1 << VBLKSHIFT)
+#define VBLKMASK (VBLKSIZE - 1)
+
+struct dmadat {
+ char blkbuf[VBLKSIZE]; /* filesystem blocks */
+ char indbuf[VBLKSIZE]; /* indir blocks */
+};
+static struct dmadat *dmadat;
+
+int main(void);
+void exit(int);
+static void load(void);
+static int parse(void);
+static void printf(const char *,...);
+static void putchar(int);
+static int drvread(void *, unsigned, unsigned);
+static int keyhit(unsigned);
+static int xputc(int);
+static int xgetc(int);
+static inline int getc(int);
+
+static int lookup(const char *, struct iso_directory_record *);
+static ssize_t fsread(struct iso_directory_record *, void *, size_t);
+
+static void memcpy(void *, const void *, int);
+static void
+memcpy(void *dst, const void *src, int len)
+{
+ const char *s;
+ char *d;
+
+ s = src;
+ d = dst;
+
+ while (len--)
+ *d++ = *s++;
+}
+
+static inline int
+strcmp(const char *s1, const char *s2)
+{
+
+ for (; *s1 == *s2 && *s1; s1++, s2++);
+ return ((unsigned char)*s1 - (unsigned char)*s2);
+}
+
+static inline int
+bcmp(const uint8_t *s1, const uint8_t *s2, size_t nbytes)
+{
+
+ for (; nbytes > 1 && *s1 == *s2; s1++, s2++, nbytes--);
+ return (*s1 - *s2);
+}
+
+static inline int
+toupper(int c)
+{
+
+ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c;
+}
+
+static int
+xfsread(struct iso_directory_record *rec, void *buf, size_t nbyte)
+{
+
+ if ((size_t)fsread(rec, buf, nbyte) != nbyte) {
+ printf("Invalid %s\n", "format");
+ return (-1);
+ }
+ return (0);
+}
+
+static inline void
+getstr(void)
+{
+ char *s;
+ int c;
+
+ s = cmd;
+ for (;;) {
+ switch (c = xgetc(0)) {
+ case 0:
+ break;
+ case '\177':
+ case '\b':
+ if (s > cmd) {
+ s--;
+ printf("\b \b");
+ }
+ break;
+ case '\n':
+ case '\r':
+ *s = 0;
+ return;
+ default:
+ if (s - cmd < sizeof(cmd) - 1)
+ *s++ = c;
+ putchar(c);
+ }
+ }
+}
+
+static inline void
+putc(int c)
+{
+
+ v86.addr = 0x10;
+ v86.eax = 0xe00 | (c & 0xff);
+ v86.ebx = 0x7;
+ v86int();
+}
+
+int
+main(void)
+{
+ uint8_t autoboot;
+ size_t nbyte;
+ struct iso_directory_record rec;
+
+ dmadat = (void *)(roundup2(__base + (int32_t)&_end, 0x10000) - __base);
+ v86.ctl = V86_FLAGS;
+ v86.efl = PSL_RESERVED_DEFAULT | PSL_I;
+ dsk.drive = *(uint8_t *)PTOV(ARGS);
+ dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD;
+ dsk.unit = dsk.drive & DRV_MASK;
+ dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1;
+ bootinfo.bi_version = BOOTINFO_VERSION;
+ bootinfo.bi_size = sizeof(bootinfo);
+
+ /* Process configuration file */
+
+ autoboot = 1;
+
+ if (lookup(PATH_CONFIG, &rec) == 0 ||
+ lookup(PATH_DOTCONFIG, &rec) == 0) {
+ nbyte = fsread(&rec, cmd, sizeof(cmd) - 1);
+ cmd[nbyte] = '\0';
+ }
+
+ if (*cmd) {
+ memcpy(cmddup, cmd, sizeof(cmd));
+ if (parse())
+ autoboot = 0;
+ if (!OPT_CHECK(RBX_QUIET))
+ printf("%s: %s", PATH_CONFIG, cmddup);
+ /* Do not process this command twice */
+ *cmd = 0;
+ }
+
+ /*
+ * Try to exec stage 3 boot loader. If interrupted by a keypress,
+ * or in case of failure, try to load a kernel directly instead.
+ */
+
+ if (!kname) {
+ kname = PATH_LOADER;
+ if (autoboot && !keyhit(3*SECOND)) {
+ load();
+ kname = PATH_KERNEL;
+ }
+ }
+
+ /* Present the user with the boot2 prompt. */
+
+ for (;;) {
+ if (!autoboot || !OPT_CHECK(RBX_QUIET))
+ printf("\nFreeBSD/x86 boot\n"
+ "Default: %u:%s(%u,%c)%s\n"
+ "boot: ",
+ dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit,
+ 'a' + dsk.part, kname);
+ if (DO_SIO)
+ sio_flush();
+ if (!autoboot || keyhit(3*SECOND))
+ getstr();
+ else if (!autoboot || !OPT_CHECK(RBX_QUIET))
+ putchar('\n');
+ autoboot = 0;
+ if (parse())
+ putchar('\a');
+ else
+ load();
+ }
+}
+
+/* XXX - Needed for btxld to link the boot2 binary; do not remove. */
+void
+exit(int x)
+{
+
+}
+
+static void
+load(void)
+{
+ union {
+ struct exec ex;
+ Elf32_Ehdr eh;
+ } hdr;
+ static Elf32_Phdr ep[2];
+ static Elf32_Shdr es[2];
+ caddr_t p;
+ uint32_t addr;
+ int k;
+ uint8_t i, j;
+ struct iso_directory_record rec;
+
+ if (lookup(kname, &rec)) {
+ if (!ls)
+ printf("No %s\n", kname);
+ return;
+ }
+ if (xfsread(&rec, &hdr, sizeof(hdr)))
+ return;
+
+ if (N_GETMAGIC(hdr.ex) == ZMAGIC) {
+ addr = hdr.ex.a_entry & 0xffffff;
+ p = PTOV(addr);
+ fs_off = PAGE_SIZE;
+ if (xfsread(&rec, p, hdr.ex.a_text))
+ return;
+ p += roundup2(hdr.ex.a_text, PAGE_SIZE);
+ if (xfsread(&rec, p, hdr.ex.a_data))
+ return;
+ } else if (IS_ELF(hdr.eh)) {
+ fs_off = hdr.eh.e_phoff;
+ for (j = k = 0; k < hdr.eh.e_phnum && j < 2; k++) {
+ if (xfsread(&rec, ep + j, sizeof(ep[0])))
+ return;
+ if (ep[j].p_type == PT_LOAD)
+ j++;
+ }
+ for (i = 0; i < 2; i++) {
+ p = PTOV(ep[i].p_paddr & 0xffffff);
+ fs_off = ep[i].p_offset;
+ if (xfsread(&rec, p, ep[i].p_filesz))
+ return;
+ }
+ p += roundup2(ep[1].p_memsz, PAGE_SIZE);
+ bootinfo.bi_symtab = VTOP(p);
+ if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) {
+ fs_off = hdr.eh.e_shoff + sizeof(es[0]) *
+ (hdr.eh.e_shstrndx + 1);
+ if (xfsread(&rec, &es, sizeof(es)))
+ return;
+ for (i = 0; i < 2; i++) {
+ *(Elf32_Word *)p = es[i].sh_size;
+ p += sizeof(es[i].sh_size);
+ fs_off = es[i].sh_offset;
+ if (xfsread(&rec, p, es[i].sh_size))
+ return;
+ p += es[i].sh_size;
+ }
+ }
+ addr = hdr.eh.e_entry & 0xffffff;
+ bootinfo.bi_esymtab = VTOP(p);
+ } else {
+ printf("Invalid %s\n", "format");
+ return;
+ }
+
+ bootinfo.bi_kernelname = VTOP(kname);
+ bootinfo.bi_bios_dev = dsk.drive;
+ __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
+ MAKEBOOTDEV(dev_maj[dsk.type], dsk.slice, dsk.unit, dsk.part),
+ 0, 0, 0, VTOP(&bootinfo));
+}
+
+static int
+parse()
+{
+ char *arg, *ep, *p;
+ const char *cp;
+ int c, i, j;
+ size_t k;
+
+ arg = cmd;
+
+ while ((c = *arg++)) {
+ if (c == ' ' || c == '\t' || c == '\n')
+ continue;
+ for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++);
+ ep = p;
+ if (*p)
+ *p++ = 0;
+ if (c == '-') {
+ while ((c = *arg++)) {
+ if (c == 'P') {
+ if (*(uint8_t *)PTOV(0x496) & 0x10) {
+ cp = "yes";
+ } else {
+ opts |= OPT_SET(RBX_DUAL) |
+ OPT_SET(RBX_SERIAL);
+ cp = "no";
+ }
+ printf("Keyboard: %s\n", cp);
+ continue;
+#if SERIAL
+ } else if (c == 'S') {
+ j = 0;
+ while ((u_int)(i = *arg++ - '0') <= 9)
+ j = j * 10 + i;
+ if (j > 0 && i == -'0') {
+ comspeed = j;
+ break;
+ }
+ /*
+ * Fall through to error below
+ * ('S' not in optstr[]).
+ */
+#endif
+ }
+ for (i = 0; c != optstr[i]; i++)
+ if (i == NOPT - 1)
+ return (-1);
+ opts ^= OPT_SET(flags[i]);
+ }
+#if SERIAL
+ ioctrl = OPT_CHECK(RBX_DUAL) ? (IO_SERIAL|IO_KEYBOARD) :
+ OPT_CHECK(RBX_SERIAL) ? IO_SERIAL : IO_KEYBOARD;
+ if (DO_SIO) {
+ if (sio_init(115200 / comspeed) != 0)
+ ioctrl &= ~IO_SERIAL;
+ }
+#endif
+ } else {
+ k = ep - arg;
+ if (k > 0) {
+ if (k >= sizeof(knamebuf))
+ return (-1);
+ memcpy(knamebuf, arg, k + 1);
+ kname = knamebuf;
+ }
+ }
+ arg = p;
+ }
+ return (0);
+}
+
+static void
+printf(const char *fmt,...)
+{
+ va_list ap;
+ static char buf[10];
+ char *s;
+ unsigned u;
+ int c;
+
+ va_start(ap, fmt);
+ while ((c = *fmt++)) {
+ if (c == '%') {
+ c = *fmt++;
+ switch (c) {
+ case 'c':
+ putchar(va_arg(ap, int));
+ continue;
+ case 's':
+ for (s = va_arg(ap, char *); *s; s++)
+ putchar(*s);
+ continue;
+ case 'u':
+ u = va_arg(ap, unsigned);
+ s = buf;
+ do
+ *s++ = '0' + u % 10U;
+ while (u /= 10U);
+ while (--s >= buf)
+ putchar(*s);
+ continue;
+ }
+ }
+ putchar(c);
+ }
+ va_end(ap);
+ return;
+}
+
+static void
+putchar(int c)
+{
+
+ if (c == '\n')
+ xputc('\r');
+ xputc(c);
+}
+
+static int
+drvread(void *buf, unsigned lba, unsigned nblk)
+{
+ static unsigned c = 0x2d5c7c2f;
+
+ if (!OPT_CHECK(RBX_QUIET)) {
+ xputc(c = c << 8 | c >> 24);
+ xputc('\b');
+ }
+ v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS;
+ v86.addr = XREADORG; /* call to xread in boot1 */
+ v86.es = VTOPSEG(buf);
+ v86.eax = lba;
+ v86.ebx = VTOPOFF(buf);
+ v86.ecx = lba >> 16;
+ v86.edx = nblk << 8 | dsk.drive;
+ v86int();
+ v86.ctl = V86_FLAGS;
+ if (V86_CY(v86.efl)) {
+ printf("error %u lba %u\n", v86.eax >> 8 & 0xff, lba);
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+keyhit(unsigned ticks)
+{
+ uint32_t t0, t1;
+
+ if (OPT_CHECK(RBX_NOINTR))
+ return (0);
+ t0 = 0;
+ for (;;) {
+ if (xgetc(1))
+ return (1);
+ t1 = *(uint32_t *)PTOV(0x46c);
+ if (!t0)
+ t0 = t1;
+ if ((uint32_t)(t1 - t0) >= ticks)
+ return (0);
+ }
+}
+
+static int
+xputc(int c)
+{
+
+ if (DO_KBD)
+ putc(c);
+ if (DO_SIO)
+ sio_putc(c);
+ return (c);
+}
+
+static int
+getc(int fn)
+{
+
+ v86.addr = 0x16;
+ v86.eax = fn << 8;
+ v86int();
+ return (fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl));
+}
+
+static int
+xgetc(int fn)
+{
+
+ if (OPT_CHECK(RBX_NOINTR))
+ return (0);
+ for (;;) {
+ if (DO_KBD && getc(1))
+ return (fn ? 1 : getc(0));
+ if (DO_SIO && sio_ischar())
+ return (fn ? 1 : sio_getc());
+ if (fn)
+ return (0);
+ }
+}
+
+#define SUSP_CONTINUATION "CE"
+#define SUSP_PRESENT "SP"
+#define SUSP_STOP "ST"
+#define SUSP_EXTREF "ER"
+#define RRIP_NAME "NM"
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char signature [ISODCL ( 5, 6)];
+ u_char len_skp [ISODCL ( 7, 7)]; /* 711 */
+} ISO_SUSP_PRESENT;
+
+static int
+read_iso_block(void *buffer, daddr_t blkno)
+{
+
+ return (drvread(buffer, blkno * 4, 4));
+}
+
+static ISO_SUSP_HEADER *
+susp_lookup_record(const char *identifier, struct iso_directory_record *dp,
+ int lenskip)
+{
+ static char susp_buffer[ISO_DEFAULT_BLOCK_SIZE];
+ ISO_SUSP_HEADER *sh;
+ ISO_RRIP_CONT *shc;
+ char *p, *end;
+ int error;
+
+ p = dp->name + isonum_711(dp->name_len) + lenskip;
+ /* Names of even length have a padding byte after the name. */
+ if ((isonum_711(dp->name_len) & 1) == 0)
+ p++;
+ end = (char *)dp + isonum_711(dp->length);
+ while (p + 3 < end) {
+ sh = (ISO_SUSP_HEADER *)p;
+ if (bcmp(sh->type, identifier, 2) == 0)
+ return (sh);
+ if (bcmp(sh->type, SUSP_STOP, 2) == 0)
+ return (NULL);
+ if (bcmp(sh->type, SUSP_CONTINUATION, 2) == 0) {
+ shc = (ISO_RRIP_CONT *)sh;
+ error = read_iso_block(susp_buffer,
+ isonum_733(shc->location));
+
+ /* Bail if it fails. */
+ if (error != 0)
+ return (NULL);
+ p = susp_buffer + isonum_733(shc->offset);
+ end = p + isonum_733(shc->length);
+ } else {
+ /* Ignore this record and skip to the next. */
+ p += isonum_711(sh->length);
+
+ /* Avoid infinite loops with corrupted file systems */
+ if (isonum_711(sh->length) == 0)
+ return (NULL);
+ }
+ }
+ return (NULL);
+}
+
+static const char *
+rrip_lookup_name(struct iso_directory_record *dp, int lenskip, size_t *len)
+{
+ ISO_RRIP_ALTNAME *p;
+
+ if (len == NULL)
+ return (NULL);
+
+ p = (ISO_RRIP_ALTNAME *)susp_lookup_record(RRIP_NAME, dp, lenskip);
+ if (p == NULL)
+ return (NULL);
+ switch (*p->flags) {
+ case ISO_SUSP_CFLAG_CURRENT:
+ *len = 1;
+ return (".");
+ case ISO_SUSP_CFLAG_PARENT:
+ *len = 2;
+ return ("..");
+ case 0:
+ *len = isonum_711(p->h.length) - 5;
+ return ((char *)p + 5);
+ default:
+ /*
+ * We don't handle hostnames or continued names as they are
+ * too hard, so just bail and use the default name.
+ */
+ return (NULL);
+ }
+}
+
+static int
+rrip_check(struct iso_directory_record *dp, int *lenskip)
+{
+ ISO_SUSP_PRESENT *sp;
+ ISO_RRIP_EXTREF *er;
+ char *p;
+
+ /* First, see if we can find a SP field. */
+ p = dp->name + isonum_711(dp->name_len);
+ if (p > (char *)dp + isonum_711(dp->length)) {
+ return (0);
+ }
+ sp = (ISO_SUSP_PRESENT *)p;
+ if (bcmp(sp->h.type, SUSP_PRESENT, 2) != 0) {
+ return (0);
+ }
+ if (isonum_711(sp->h.length) != sizeof(ISO_SUSP_PRESENT)) {
+ return (0);
+ }
+ if (sp->signature[0] != 0xbe || sp->signature[1] != 0xef) {
+ return (0);
+ }
+ *lenskip = isonum_711(sp->len_skp);
+
+ /*
+ * Now look for an ER field. If RRIP is present, then there must
+ * be at least one of these. It would be more pedantic to walk
+ * through the list of fields looking for a Rock Ridge ER field.
+ */
+ er = (ISO_RRIP_EXTREF *)susp_lookup_record(SUSP_EXTREF, dp, 0);
+ if (er == NULL) {
+ return (0);
+ }
+ return (1);
+}
+
+static int
+dirmatch(const char *path, struct iso_directory_record *dp, int use_rrip,
+ int lenskip)
+{
+ size_t len;
+ const char *cp = NULL, *name = NULL;
+ int i, icase;
+
+ if (use_rrip)
+ cp = rrip_lookup_name(dp, lenskip, &len);
+ else
+ cp = NULL;
+ if (cp == NULL) {
+ len = isonum_711(dp->name_len);
+ cp = dp->name;
+ icase = 1;
+ } else
+ icase = 0;
+ name = cp;
+ for (i = len; --i >= 0; path++, cp++) {
+ if (!*path || *path == '/')
+ break;
+ if (*path == *cp)
+ continue;
+ if (!icase && toupper(*path) == *cp)
+ continue;
+ return 0;
+ }
+ if (*path && *path != '/') {
+ return 0;
+ }
+ /*
+ * Allow stripping of trailing dots and the version number.
+ * Note that this will find the first instead of the last version
+ * of a file.
+ */
+ if (i >= 0 && (*cp == ';' || *cp == '.')) {
+ /* This is to prevent matching of numeric extensions */
+ if (*cp == '.' && cp[1] != ';') {
+ return 0;
+ }
+ while (--i >= 0)
+ if (*++cp != ';' && (*cp < '0' || *cp > '9')) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+lookup(const char *path, struct iso_directory_record *orec)
+{
+ static char blkbuf[ISO_DEFAULT_BLOCK_SIZE];
+ struct iso_primary_descriptor *vd;
+ struct iso_directory_record rec;
+ struct iso_directory_record *dp = NULL;
+ size_t dsize, off;
+ daddr_t bno, boff;
+ int rc, first, use_rrip, lenskip;
+
+ for (bno = 16;; bno++) {
+ rc = read_iso_block(blkbuf, bno);
+ vd = (struct iso_primary_descriptor *)blkbuf;
+
+ if (bcmp(vd->id, ISO_STANDARD_ID, sizeof vd->id) != 0)
+ return (-1);
+ if (isonum_711(vd->type) == ISO_VD_END)
+ return (-1);
+ if (isonum_711(vd->type) == ISO_VD_PRIMARY)
+ break;
+ }
+
+ rec = *(struct iso_directory_record *) vd->root_directory_record;
+ if (*path == '/') path++; /* eat leading '/' */
+
+ first = 1;
+ use_rrip = 0;
+ while (*path) {
+ bno = isonum_733(rec.extent) + isonum_711(rec.ext_attr_length);
+ dsize = isonum_733(rec.size);
+ off = 0;
+ boff = 0;
+
+ while (off < dsize) {
+ if ((off % ISO_DEFAULT_BLOCK_SIZE) == 0) {
+ rc = read_iso_block(blkbuf, bno + boff);
+ if (rc) {
+ return (-1);
+ }
+ boff++;
+ dp = (struct iso_directory_record *) blkbuf;
+ }
+ if (isonum_711(dp->length) == 0) {
+ /* skip to next block, if any */
+ off = boff * ISO_DEFAULT_BLOCK_SIZE;
+ continue;
+ }
+
+ /* See if RRIP is in use. */
+ if (first)
+ use_rrip = rrip_check(dp, &lenskip);
+
+ if (dirmatch(path, dp, use_rrip,
+ first ? 0 : lenskip)) {
+ first = 0;
+ break;
+ } else
+ first = 0;
+
+ dp = (struct iso_directory_record *)
+ ((char *) dp + isonum_711(dp->length));
+ /* If the new block has zero length, it is padding. */
+ if (isonum_711(dp->length) == 0) {
+ /* Skip to next block, if any. */
+ off = boff * ISO_DEFAULT_BLOCK_SIZE;
+ continue;
+ }
+ off += isonum_711(dp->length);
+ }
+ if (off >= dsize) {
+ return (-1);
+ }
+
+ rec = *dp;
+ while (*path && *path != '/') /* look for next component */
+ path++;
+ if (*path) path++; /* skip '/' */
+ }
+
+ if ((isonum_711(rec.flags) & 2) != 0) {
+ return (-1);
+ }
+
+ *orec = rec;
+
+ return (0);
+}
+
+static ssize_t
+fsread(struct iso_directory_record *rec, void *buf, size_t nbytes)
+{
+ static char blkbuf[ISO_DEFAULT_BLOCK_SIZE];
+ static daddr_t curstart = 0, curblk = 0;
+ daddr_t blk, blk_off;
+ off_t byte_off;
+ size_t size, remaining, n;
+ char *s;
+
+ blk = isonum_733(rec->extent) + isonum_711(rec->ext_attr_length);
+ size = isonum_733(rec->size);
+
+ if (blk != curstart) {
+ curstart = blk;
+ fs_off = 0;
+ }
+
+ size -= fs_off;
+ if (size < nbytes) {
+ nbytes = size;
+ }
+ remaining = nbytes;
+ s = buf;
+
+ while (remaining > 0) {
+ blk_off = fs_off >> ISO_DEFAULT_BLOCK_SHIFT;
+ byte_off = fs_off & (ISO_DEFAULT_BLOCK_SIZE - 1);
+
+ if (curblk != curstart + blk_off) {
+ curblk = curstart + blk_off;
+ read_iso_block(blkbuf, curblk);
+ }
+
+ if (remaining < ISO_DEFAULT_BLOCK_SIZE - byte_off) {
+ n = remaining;
+ } else {
+ n = ISO_DEFAULT_BLOCK_SIZE - byte_off;
+ }
+ memcpy(s, blkbuf + byte_off, n);
+ remaining -= n;
+ s += n;
+
+ fs_off += n;
+ }
+
+ return (nbytes);
+}
Index: sys/fs/cd9660/iso.h
===================================================================
--- sys/fs/cd9660/iso.h
+++ sys/fs/cd9660/iso.h
@@ -95,7 +95,8 @@
char application_data [ISODCL (884, 1395)];
char unused5 [ISODCL (1396, 2048)];
};
-#define ISO_DEFAULT_BLOCK_SIZE 2048
+#define ISO_DEFAULT_BLOCK_SHIFT 11
+#define ISO_DEFAULT_BLOCK_SIZE (1 << ISO_DEFAULT_BLOCK_SHIFT)
/*
* Used by Microsoft Joliet extension to ISO9660. Almost the same

File Metadata

Mime Type
text/plain
Expires
Sat, Aug 29, 11:45 PM (7 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37492889
Default Alt Text
D14799.id40603.diff (24 KB)

Event Timeline