summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbencollins <tailor@grayson>2001-06-06 18:51:19 -0400
committerBen Collins <bcollins@ubuntu.com>2006-06-01 13:17:54 -0400
commit1ce2730cf223c047647567cb46b0a1caca05d8e6 (patch)
treec0ff5749cc9ccec6c2a568c1de3f3ae5437237d8
parentbb7bf352633c20f2b08092b3dee222ffa62a073e (diff)
downloadsilo-1ce2730cf223c047647567cb46b0a1caca05d8e6.tar.gz
[silo @ 29]
* second/Makefile: Add fs/ufs.o and fs/romfs.o to libfs.a. * second/file.c: Add ufs and romfs file ops. * second/fs/romfs.c: Romfs support for SILO. * second/fs/ufs.c: UFS support for SILO. * second/fs/isofs.c: Oops, forget to set/unset have_inode.#
-rw-r--r--ChangeLog9
-rw-r--r--second/Makefile2
-rw-r--r--second/file.c10
-rw-r--r--second/fs/isofs.c8
-rw-r--r--second/fs/romfs.c336
-rw-r--r--second/fs/ufs.c457
6 files changed, 816 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index de18cd4..8b23eed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+Wed Jun 6 14:48:30 EDT 2001 Ben Collins <bcollins@debian.org>
+
+ * second/Makefile: Add fs/ufs.o and fs/romfs.o to libfs.a.
+ * second/file.c: Add ufs and romfs file ops.
+ * second/fs/romfs.c: Romfs support for SILO.
+ * second/fs/ufs.c: UFS support for SILO.
+
+ * second/fs/isofs.c: Oops, forget to set/unset have_inode.
+
Wed Jun 6 13:02:34 EDT 2001 Ben Collins <bcollins@debian.org>
* common/Makefile: Clean up the "clean" target.
diff --git a/second/Makefile b/second/Makefile
index abe624b..8a0934d 100644
--- a/second/Makefile
+++ b/second/Makefile
@@ -45,7 +45,7 @@ OBJS5 = cmdline.o disk.o file.o misc.o cfg.o strtol.o ranges.o timer.o \
OBJS = $(OBJS1) $(OBJS2) $(OBJS3) bmark.o $(OBJS4) $(OBJS5)
OBJSNET = $(OBJS1) $(OBJS2N) $(OBJS3) bmark.o $(OBJS4N) $(OBJS5)
-FS_OBJS = fs/iom.o fs/ext2.o fs/isofs.o
+FS_OBJS = fs/iom.o fs/ext2.o fs/isofs.o fs/romfs.o fs/ufs.o
ifeq (Linux,$(shell uname))
ifeq (sparc,$(subst sparc64,sparc,$(shell uname -m)))
diff --git a/second/file.c b/second/file.c
index 534c14f..3a11d5a 100644
--- a/second/file.c
+++ b/second/file.c
@@ -48,9 +48,17 @@ static char *match;
/* Externally provided filesystem operations */
extern struct fs_ops ext2_fs_ops;
extern struct fs_ops iso_fs_ops;
+extern struct fs_ops rom_fs_ops;
+extern struct fs_ops ufs_fs_ops;
/* Array of our supported ops */
-static struct fs_ops *silo_fs_ops[] = { &ext2_fs_ops, &iso_fs_ops, NULL };
+static struct fs_ops *silo_fs_ops[] = {
+ &ext2_fs_ops,
+ &iso_fs_ops,
+ &rom_fs_ops,
+ &ufs_fs_ops,
+ NULL,
+};
static struct fs_ops *cur_ops;
diff --git a/second/fs/isofs.c b/second/fs/isofs.c
index 080cbe6..addf9ed 100644
--- a/second/fs/isofs.c
+++ b/second/fs/isofs.c
@@ -91,7 +91,7 @@ static struct iso_primary_descriptor *isofs_read_super(isofs_filsys fs)
return iso;
}
-int open_isofs (char *device)
+static int open_isofs (char *device)
{
fs = (isofs_filsys) malloc (sizeof (struct struct_ext2_filsys));
if (!fs)
@@ -403,7 +403,7 @@ static int open_namei(isofs_filsys fs, const char *pathname,
struct fs_ops iso_fs_ops;
-int isofs_namei (const char *filename)
+static int isofs_namei (const char *filename)
{
int ret;
link_count = 0;
@@ -414,13 +414,13 @@ int isofs_namei (const char *filename)
return ret;
}
-void isofs_close(isofs_filsys fs)
+static void isofs_close(isofs_filsys fs)
{
free (fs->io);
free (fs);
}
-int isofs_block_iterate(isofs_filsys fs,
+static int isofs_block_iterate(isofs_filsys fs,
int (*func)(isofs_filsys, blk_t *, int, void *),
void *private)
{
diff --git a/second/fs/romfs.c b/second/fs/romfs.c
new file mode 100644
index 0000000..4b3a459
--- /dev/null
+++ b/second/fs/romfs.c
@@ -0,0 +1,336 @@
+/* ROMFS filesystem handling
+
+ Copyright (C) 1998 Jakub Jelinek <jj@ultra.linux.cz>
+ Copyright (C) 1997 Janos Farkas <chexum@shadow.banki.hu>
+
+ 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. */
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <silo.h>
+#include <file.h>
+#include <stringops.h>
+#include <linux/romfs_fs.h>
+
+/* Reuse and abuse */
+typedef ext2_filsys romfs_filsys;
+
+static ino_t inode = 0;
+
+#define SUPROMFS (struct romfs_super_block *)(fs->io->private_data)
+
+static __s32
+romfs_checksum(void *data, int size)
+{
+ __s32 sum, *ptr;
+ sum = 0; ptr = data;
+ size>>=2;
+ while (size>0) {
+ sum += *ptr++;
+ size--;
+ }
+ return sum;
+}
+
+static struct romfs_super_block *romfs_read_super(romfs_filsys fs)
+{
+ struct romfs_super_block *rsb;
+
+ rsb = (struct romfs_super_block *) malloc (2048+512);
+ if (!rsb) return 0;
+ if (io_channel_read_blk (fs->io, 0, 1, (char *)rsb))
+ return 0;
+ if (strncmp((char *)rsb, "-rom1fs-", 8) || rsb->size < ROMFH_SIZE)
+ return 0;
+ if (romfs_checksum(rsb, 512)) {
+ printf("Bad ROMFS initial checksum\n");
+ return 0;
+ }
+ rsb->checksum = strlen(rsb->name);
+ if (rsb->checksum > ROMFS_MAXFN) rsb->checksum = ROMFS_MAXFN;
+ rsb->checksum += (ROMFH_SIZE + 1 + ROMFH_PAD);
+ rsb->checksum &= ROMFH_MASK;
+ rsb->word0 = -1;
+ rsb->word1 = -1;
+ rsb->name[0] = 0;
+ return rsb;
+}
+
+static int romfs_copyfrom(romfs_filsys fs, void *dest, unsigned long offset, unsigned long count)
+{
+ int off;
+ struct romfs_super_block *rsb = SUPROMFS;
+
+ for (;;) {
+ if (rsb->word0 != (__u32)-1 && offset >= rsb->word0 && offset < rsb->word0 + 1024) {
+ int cnt = 1024 - (offset & 1023);
+ if (count < cnt)
+ cnt = count;
+ memcpy(dest, (char *)rsb + 512 + (offset & 1023), cnt);
+ if (count == cnt) return 0;
+ dest = (char *)dest + cnt;
+ offset += cnt;
+ count -= cnt;
+ }
+ if (rsb->word1 != (__u32)-1 && offset >= rsb->word1 && offset < rsb->word1 + 1024) {
+ int cnt = 1024 - (offset & 1023);
+ if (count < cnt)
+ cnt = count;
+ memcpy(dest, (char *)rsb + 1536 + (offset & 1023), cnt);
+ if (count == cnt) return 0;
+ dest = (char *)dest + cnt;
+ count -= cnt;
+ }
+ off = offset & ~1023;
+ if (io_channel_read_blk (fs->io, off / 512, 2, (char *)rsb + (rsb->name[0] ? 1536 : 512))) {
+ if (rsb->name[0])
+ rsb->word1 = -1;
+ else
+ rsb->word0 = -1;
+ return -1;
+ }
+ if (rsb->name[0])
+ rsb->word1 = off;
+ else
+ rsb->word0 = off;
+ rsb->name[0] ^= 1;
+ }
+}
+
+static int romfs_read_inode (romfs_filsys fs, ino_t inode, struct romfs_inode *ui)
+{
+ struct romfs_inode romfsip;
+ struct romfs_super_block *rsb = SUPROMFS;
+
+ if (inode < rsb->checksum || inode >= rsb->size)
+ return -1;
+
+ if (romfs_copyfrom (fs, &romfsip, inode, 16))
+ return -1;
+ *ui = romfsip;
+ return 0;
+}
+
+static int romfs_lookup (romfs_filsys fs, ino_t dir, struct romfs_inode *dirui,
+ const char *name, int len, ino_t *result)
+{
+ char buffer [8192];
+ struct romfs_inode ui;
+
+ dir = dirui->spec & ROMFH_MASK;
+ while (dir) {
+ if (romfs_read_inode (fs, dir, &ui))
+ return -1;
+ if (romfs_copyfrom (fs, buffer, dir + 16, ROMFS_MAXFN))
+ return -1;
+ if ((!len && buffer[0] == '.' && !buffer[1]) ||
+ (strlen(buffer) == len && !memcmp(buffer, name, len))) {
+ if ((ui.next & ROMFH_TYPE) == ROMFH_HRD)
+ dir = ui.spec;
+ *result = dir;
+ return 0;
+ }
+ dir = ui.next & ROMFH_MASK;
+ }
+ return -1;
+}
+
+static int link_count = 0;
+
+static int open_namei(romfs_filsys, const char *, ino_t *, ino_t);
+
+static int romfs_follow_link(romfs_filsys fs, ino_t dir, ino_t inode,
+ struct romfs_inode *ui, ino_t *res_inode)
+{
+ int error;
+ char buffer[1024];
+
+ if ((ui->next & ROMFH_TYPE) != ROMFH_SYM) {
+ *res_inode = inode;
+ return 0;
+ }
+ if (link_count > 5) {
+ printf ("Symlink loop\n");
+ return -1; /* Loop */
+ }
+ if (romfs_copyfrom (fs, buffer, inode + 16, ROMFS_MAXFN))
+ return -1;
+ error = inode + 16 + ((strlen(buffer) + 16) & ~15);
+ if (romfs_copyfrom (fs, buffer, error, ROMFS_MAXFN))
+ return -1;
+ link_count++;
+ error = open_namei (fs, buffer, res_inode, dir);
+ link_count--;
+ return error;
+}
+
+static int dir_namei(romfs_filsys fs, const char *pathname, int *namelen,
+ const char **name, ino_t base, ino_t *res_inode)
+{
+ char c;
+ const char *thisname;
+ int len;
+ struct romfs_inode ub;
+ ino_t inode;
+
+ if ((c = *pathname) == '/') {
+ base = (ino_t)fs->private;
+ pathname++;
+ }
+ if (romfs_read_inode (fs, base, &ub)) return -1;
+ while (1) {
+ thisname = pathname;
+ for(len=0;(c = *(pathname++))&&(c != '/');len++);
+ if (!c) break;
+ if (romfs_lookup (fs, base, &ub, thisname, len, &inode)) return -1;
+ if (romfs_read_inode (fs, inode, &ub)) return -1;
+ if (romfs_follow_link (fs, base, inode, &ub, &base)) return -1;
+ if (base != inode && romfs_read_inode (fs, base, &ub)) return -1;
+ }
+ *name = thisname;
+ *namelen = len;
+ *res_inode = base;
+ return 0;
+}
+
+static int open_namei(romfs_filsys fs, const char *pathname,
+ ino_t *res_inode, ino_t base)
+{
+ const char *basename;
+ int namelen;
+ ino_t dir, inode;
+ struct romfs_inode ub;
+
+ if (dir_namei(fs, pathname, &namelen, &basename, base, &dir)) return -1;
+ if (!namelen) { /* special case: '/usr/' etc */
+ *res_inode=dir;
+ return 0;
+ }
+ if (romfs_read_inode (fs, dir, &ub)) return -1;
+ if (romfs_lookup (fs, dir, &ub, basename, namelen, &inode)) return -1;
+ if (romfs_read_inode (fs, inode, &ub)) return -1;
+ if (romfs_follow_link (fs, dir, inode, &ub, &inode)) return -1;
+ *res_inode = inode;
+ return 0;
+}
+
+struct fs_ops ufs_fs_ops;
+
+static int namei_follow_romfs (const char *filename)
+{
+ int ret;
+
+ fs->private = (void *)root;
+ link_count = 0;
+
+ ret = open_namei (fs, filename, &inode, root);
+ ufs_fs_ops.have_inode = (ret) ? 0 : 1;
+
+ return ret;
+}
+
+static void romfs_close(romfs_filsys fs)
+{
+ free (fs->io);
+ free (fs);
+}
+
+static int romfs_block_iterate(romfs_filsys fs, ino_t inode,
+ int (*func)(romfs_filsys, blk_t *, int, void *),
+ void *private)
+{
+ struct romfs_inode ub;
+ int i;
+ blk_t nr;
+ int size;
+ char buffer[ROMFS_MAXFN];
+
+ if (romfs_read_inode (fs, inode, &ub)) return -1;
+ if (romfs_copyfrom (fs, buffer, inode + 16, ROMFS_MAXFN)) return -1;
+ nr = inode + 16 + ((strlen(buffer) + 16) & ~15);
+ if (nr & 511) {
+ printf("romfs: File not aligned on a 512B boundary\n");
+ return -1;
+ }
+ size = (ub.size + 511) / 512;
+ nr /= 512;
+ for (i = 0; i < size; i++, nr++) {
+ switch ((*func) (fs, &nr, i, private)) {
+ case BLOCK_ABORT:
+ case BLOCK_ERROR:
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int open_romfs (char *device)
+{
+ fs = (romfs_filsys) malloc (sizeof (struct struct_ext2_filsys));
+ if (!fs)
+ return 0;
+
+ if (((struct struct_io_manager *)(silo_io_manager))->open (device, 0, &fs->io))
+ return 0;
+
+ io_channel_set_blksize (fs->io, 512);
+
+ fs->io->private_data = romfs_read_super(fs);
+ if (!fs->io->private_data)
+ return 0;
+
+ root = ((struct romfs_super_block *)(fs->io->private_data))->checksum;
+
+ return 1;
+}
+
+static int dump_romfs (char *filename)
+{
+ if (romfs_block_iterate (fs, inode, dump_block, 0)) {
+ printf ("Error while loading of %s", filename);
+ return 0;
+ }
+ return dump_finish ();
+}
+
+static int ino_size_romfs (void)
+{
+ struct romfs_inode ri;
+
+ if (romfs_read_inode (fs, inode, &ri))
+ return 0;
+ if ((ri.next & ROMFH_TYPE) != ROMFH_REG) {
+ printf("romfs: get length on non-reg file?\n");
+ return 0;
+ }
+ return ri.size;
+}
+
+static void print_error_romfs (int error_val) {
+ printf("Unknown romfs error");
+}
+
+struct fs_ops rom_fs_ops = {
+ name: "Linux ROMFS",
+ open: open_romfs,
+ ls: NULL/*ls_romfs*/,
+ dump: dump_romfs,
+ close: romfs_close,
+ ino_size: ino_size_romfs,
+ print_error: print_error_romfs,
+ namei_follow: namei_follow_romfs,
+ have_inode: 0,
+};
diff --git a/second/fs/ufs.c b/second/fs/ufs.c
new file mode 100644
index 0000000..be0cfec
--- /dev/null
+++ b/second/fs/ufs.c
@@ -0,0 +1,457 @@
+/* UFS filesystem handling
+
+ Copyright (C) 1996 Adrian Rodriguez
+ 1996 Jakub Jelinek
+
+ 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. */
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <silo.h>
+#include <file.h>
+
+#include <features.h>
+#ifdef __GLIBC__
+# define _LINUX_TIME_H
+#endif
+#include <linux/ufs_fs.h>
+
+/* Reuse and abuse */
+typedef ext2_filsys ufs_filsys;
+
+ino_t inode = 0;
+
+#ifdef UFS_CIGAM
+/* Apparently new header */
+
+#define ufsi_size(x) ((unsigned int)((x)->ui_size))
+#define ufsi_db(x) ((unsigned int *)((x)->ui_u2.ui_addr.ui_db))
+#define ufsi_ib(x) ((unsigned int *)((x)->ui_u2.ui_addr.ui_ib))
+#define ufsd_namlen(x) ((unsigned char)((x)->d_u.d_44.d_namlen))
+
+#ifdef UFS_MINFREE
+/* Apparently even newer header */
+#define ufs_superblock ufs_super_block
+#define ufs_direct ufs_dir_entry
+#endif
+
+#else
+
+#define ufsi_size(x) (((x)->ui_size.val[1]))
+#define ufsi_db(x) ((unsigned int *)((x)->ui_db))
+#define ufsi_ib(x) ((unsigned int *)((x)->ui_ib))
+#define ufsd_namlen(x) ((unsigned char)((x)->d_namlen))
+
+#endif
+
+#ifndef S_ISLNK
+#include <sys/stat.h>
+#endif
+
+#include <stringops.h>
+
+#define SUPUFS (struct ufs_superblock *)(fs->io->private_data)
+#define cgstart(cg) ((sb->fs_fpg * (cg)) + sb->fs_cgoffset * ((cg) & ~(sb->fs_cgmask)))
+#define cgimin(cg) (cgstart(cg) + sb->fs_iblkno)
+#define cgdmin(cg) (cgstart(cg) + sb->fs_dblkno)
+#define ino2cg(ino) ((ino) / sb->fs_ipg)
+
+static char *get_archstr(void)
+{
+ char *p = "sun4c";
+
+ switch (get_architecture()) {
+ case sun4: p = "sun4"; break;
+ case sun4c: p = "sun4c"; break;
+ case sun4m: p = "sun4m"; break;
+ case sun4d: p = "sun4d"; break;
+ case sun4e: p = "sun4e"; break;
+ case sun4u: p = "sun4u"; break;
+ case sun4p: p = "sun4p"; break;
+ default: break;
+ }
+ return p;
+}
+
+static struct ufs_superblock *ufs_read_super(ufs_filsys fs)
+{
+ struct ufs_superblock *usb;
+
+ usb = (struct ufs_superblock *) malloc (2048);
+ if (!usb) return 0;
+ if (io_channel_read_blk (fs->io, UFS_SBLOCK/1024, -2048, (char *)usb))
+ return 0;
+ if (usb->fs_magic != UFS_MAGIC) {
+ /* XXX - replace hard-coded constant with a byte-swap macro */
+ if (usb->fs_magic == 0x54190100) {
+ }
+ return 0;
+ }
+ if (usb->fs_bsize != UFS_BSIZE)
+ return 0;
+ if (usb->fs_fsize != UFS_FSIZE)
+ return 0;
+ io_channel_set_blksize (fs->io, usb->fs_fsize);
+ return usb;
+}
+
+static int ufs_read_inode (ufs_filsys fs, ino_t inode, struct ufs_inode *ui)
+{
+ struct ufs_inode *ufsip;
+ struct ufs_superblock *sb = SUPUFS;
+ char *buffer;
+
+ if (inode < 2 || inode > (sb->fs_ncg * sb->fs_ipg - 1))
+ return -1;
+
+ ufsip = (struct ufs_inode *) malloc (1024);
+ buffer = (char *) ufsip;
+ if (io_channel_read_blk (fs->io,
+ cgimin (ino2cg(inode)) + (inode % sb->fs_ipg) / (sb->fs_inopb / sb->fs_frag),
+ -1024, (char *)ufsip)) {
+ printf ("Couldn't read inode\n");
+ return -1;
+ }
+ ufsip += (inode%(sb->fs_inopb / sb->fs_frag));
+ *ui = *ufsip;
+ free (buffer);
+ return 0;
+}
+
+static int block_bmap (ufs_filsys fs, int block, int nr)
+{
+ struct ufs_superblock *sb = SUPUFS;
+ int tmp = nr >> (sb->fs_fshift - 2);
+ static int lastbuftmp = -1;
+ static __u32 *lastdata = 0;
+
+ nr &= ~(sb->fs_fmask) >> 2;
+ if (block + tmp != lastbuftmp) {
+ if (!lastdata) lastdata = (__u32 *) malloc (sb->fs_fsize);
+ lastbuftmp = block + tmp;
+ if (io_channel_read_blk (fs->io, block + tmp, -sb->fs_fsize, lastdata))
+ return 0;
+ }
+ return lastdata[nr];
+}
+
+static int ufs_bmap (ufs_filsys fs, ino_t inode, struct ufs_inode *ui, int block)
+{
+ struct ufs_superblock *sb = SUPUFS;
+ int i;
+ int addr_per_block = sb->fs_bsize >> 2;
+ int addr_per_block_bits = sb->fs_bshift - 2;
+ int lbn = block >> (sb->fs_bshift - sb->fs_fshift);
+ int boff = (block & ((sb->fs_fmask - sb->fs_bmask) >> sb->fs_fshift));
+
+ if (lbn < 0) return 0;
+ if (lbn >= UFS_NDADDR + addr_per_block +
+ (1 << (addr_per_block_bits * 2)) +
+ ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits))
+ return 0;
+ if (lbn < UFS_NDADDR)
+ return ufsi_db(ui)[lbn] + boff;
+ lbn -= UFS_NDADDR;
+ if (lbn < addr_per_block) {
+ i = ufsi_ib(ui)[0];
+ if (!i)
+ return 0;
+ return block_bmap (fs, i, lbn) + boff;
+ }
+ lbn -= addr_per_block;
+ if (lbn < (1 << (addr_per_block_bits * 2))) {
+ i = ufsi_ib(ui)[1];
+ if (!i) return 0;
+ i = block_bmap (fs, i, lbn >> addr_per_block_bits);
+ if (!i) return 0;
+ return block_bmap (fs, i, lbn & (addr_per_block-1)) + boff;
+ }
+ lbn -= (1 << (addr_per_block_bits * 2));
+ i = ufsi_ib(ui)[2];
+ if (!i) return 0;
+ i = block_bmap (fs, i, lbn >> (addr_per_block_bits * 2));
+ if (!i) return 0;
+ i = block_bmap (fs, i, (lbn >> addr_per_block_bits) & (addr_per_block - 1));
+ if (!i) return 0;
+ return block_bmap (fs, i, lbn & (addr_per_block-1)) + boff;
+}
+
+static int ufs_match (int len, const char *const name, struct ufs_direct * d)
+{
+ if (!d || len > UFS_MAXNAMLEN) return 0;
+ if (!len && (ufsd_namlen(d) == 1) && (d->d_name[0] == '.') && (d->d_name[1] == '\0'))
+ return 1;
+ if (len != ufsd_namlen(d)) return 0;
+ return !memcmp(name, d->d_name, len);
+}
+
+static int ufs_lookup (ufs_filsys fs, ino_t dir, struct ufs_inode *dirui,
+ const char *name, int len, ino_t *result)
+{
+ unsigned long int lfragno, fragno;
+ struct ufs_direct * d;
+ char buffer [8192];
+ struct ufs_superblock *sb = SUPUFS;
+
+ for (lfragno = 0; lfragno < (dirui->ui_blocks)>>1; lfragno++) {
+ fragno = ufs_bmap(fs, dir, dirui, lfragno);
+ if (!fragno) return -1;
+ if (io_channel_read_blk (fs->io, fragno, -sb->fs_fsize, buffer)) {
+ printf ("Couldn't read directory\n");
+ return -1;
+ }
+ d = (struct ufs_direct *)buffer;
+ while (((char *)d - buffer + d->d_reclen) <= sb->fs_fsize) {
+ if (!d->d_reclen || !ufsd_namlen(d)) break;
+ if (ufsd_namlen(d) == len && ufs_match(len, name, d)) {
+ *result = d->d_ino;
+ return 0;
+ }
+ d = (struct ufs_direct *)((char *)d + d->d_reclen);
+ }
+ }
+ return -1;
+}
+
+static int link_count = 0;
+
+static int open_namei(ufs_filsys, const char *, ino_t *, ino_t);
+
+static int ufs_follow_link(ufs_filsys fs, ino_t dir, ino_t inode,
+ struct ufs_inode *ui, ino_t *res_inode)
+{
+ unsigned long int block;
+ int error;
+ char *link;
+ char buffer[1024];
+
+ if (!S_ISLNK(ui->ui_mode)) {
+ *res_inode = inode;
+ return 0;
+ }
+ if (link_count > 5) {
+ printf ("Symlink loop\n");
+ return -1; /* Loop */
+ }
+ if (ui->ui_blocks) {
+ /* read the link from disk */
+ block = ufs_bmap(fs, inode, ui, 0);
+
+ if (io_channel_read_blk (fs->io, block, -1024, buffer)) {
+ printf ("Couldn't readlink\n");
+ return -1;
+ }
+ link = buffer;
+ } else {
+ /* fast symlink */
+ link = (char *)&(ufsi_db(ui)[0]);
+ }
+ link_count++;
+ error = open_namei (fs, link, res_inode, dir);
+ link_count--;
+ return error;
+}
+
+static int dir_namei(ufs_filsys fs, const char *pathname, int *namelen,
+ const char **name, ino_t base, ino_t *res_inode)
+{
+ char c;
+ const char *thisname;
+ int len;
+ struct ufs_inode ub;
+ ino_t inode;
+
+ if ((c = *pathname) == '/') {
+ base = (ino_t)fs->private;
+ pathname++;
+ }
+ if (ufs_read_inode (fs, base, &ub)) return -1;
+ while (1) {
+ thisname = pathname;
+ for(len=0;(c = *(pathname++))&&(c != '/');len++);
+ if (!c) break;
+ if (ufs_lookup (fs, base, &ub, thisname, len, &inode)) return -1;
+ if (ufs_read_inode (fs, inode, &ub)) return -1;
+ if (ufs_follow_link (fs, base, inode, &ub, &base)) return -1;
+ if (base != inode && ufs_read_inode (fs, base, &ub)) return -1;
+ }
+ *name = thisname;
+ *namelen = len;
+ *res_inode = base;
+ return 0;
+}
+
+static int open_namei(ufs_filsys fs, const char *pathname,
+ ino_t *res_inode, ino_t base)
+{
+ const char *basename;
+ int namelen;
+ ino_t dir, inode;
+ struct ufs_inode ub;
+
+ if (dir_namei(fs, pathname, &namelen, &basename, base, &dir)) return -1;
+ if (!namelen) { /* special case: '/usr/' etc */
+ *res_inode=dir;
+ return 0;
+ }
+ if (ufs_read_inode (fs, dir, &ub)) return -1;
+ if (ufs_lookup (fs, dir, &ub, basename, namelen, &inode)) return -1;
+ if (ufs_read_inode (fs, inode, &ub)) return -1;
+ if (ufs_follow_link (fs, dir, inode, &ub, &inode)) return -1;
+ *res_inode = inode;
+ return 0;
+}
+
+static int ufs_namei (ufs_filsys fs, ino_t root, ino_t cwd, const char *filename, ino_t *inode)
+{
+ fs->private = (void *)root;
+ link_count = 0;
+ return open_namei (fs, filename, inode, cwd);
+}
+
+static void ufs_close(ufs_filsys fs)
+{
+ free (fs->io);
+ free (fs);
+}
+
+static int ufs_block_iterate(ufs_filsys fs, ino_t inode,
+ int (*func)(ufs_filsys, blk_t *, int, void *),
+ void *private)
+{
+ struct ufs_inode ub;
+ int i;
+ blk_t nr;
+ int frags;
+ struct ufs_superblock *sb = SUPUFS;
+
+ if (ufs_read_inode (fs, inode, &ub)) return -1;
+ frags = (ufsi_size(&ub) + sb->fs_fsize - 1) / sb->fs_fsize;
+ for (i = 0; i < frags; i++) {
+ nr = ufs_bmap (fs, inode, &ub, i);
+ if (!nr) return -1;
+ switch ((*func) (fs, &nr, i, private)) {
+ case BLOCK_ABORT:
+ case BLOCK_ERROR:
+ return -1;
+ }
+ }
+ return 0;
+}
+
+struct fs_ops ufs_fs_ops;
+
+static int namei_follow_ufs (const char *filename) {
+ int syspkg = 0;
+ cwd = root;
+ ufs_fs_ops.have_inode = 0;
+
+ if (solaris) {
+ if (!ufs_namei (fs, root, root, "/platform", &cwd)) {
+ if (!ufs_namei (fs, root, cwd, get_syspackage(), &inode)) {
+ cwd = inode;
+ syspkg = 1;
+ } else {
+ if (!ufs_namei (fs, root, cwd, get_archstr(), &inode))
+ cwd = inode;
+ }
+ }
+ if (cwd != root && *filename == '/') filename++;
+ }
+ if (ufs_namei (fs, root, cwd, filename, &inode)) {
+ if (syspkg) {
+ syspkg = 0;
+ ufs_namei (fs, root, root, "/platform", &cwd);
+ if (!ufs_namei (fs, root, cwd, get_archstr(), &inode)) {
+ cwd = inode;
+ if (!ufs_namei (fs, root, cwd, filename, &inode))
+ syspkg = 1;
+ }
+ }
+ if (!syspkg)
+ return 1;
+ }
+ if (solaris) {
+ ino_t sinode;
+
+ if (ufs_namei (fs, root, cwd, "ufsboot", &sinode)) {
+ printf ("\nCannot find Solaris kernel bootloader `ufsboot'. Will try to load it,\n"
+ "but it may fail\n");
+ solaris = 0;
+ } else
+ inode = sinode;
+ }
+ ufs_fs_ops.have_inode = 0;
+ return 0;
+}
+
+static int open_ufs (char *device)
+{
+ fs = (ufs_filsys) malloc (sizeof (struct struct_ext2_filsys));
+ if (!fs)
+ return 0;
+
+ if (((struct struct_io_manager *)(silo_io_manager))->open (device, 0, &fs->io))
+ return 0;
+
+ io_channel_set_blksize (fs->io, 1024);
+
+ if (!(fs->io->private_data = ufs_read_super(fs)))
+ return 0;
+
+ root = UFS_ROOTINO;
+ solaris = 1;
+
+ return 1;
+}
+
+static int dump_ufs (char *filename)
+{
+ if (ufs_block_iterate (fs, inode, dump_block, 0)) {
+ printf ("Error while loading of %s", filename);
+ return 0;
+ }
+ return dump_finish ();
+}
+
+static int ino_size_ufs (void)
+{
+ struct ufs_inode ui;
+
+ if (ufs_read_inode (fs, inode, &ui))
+ return 0;
+
+ /* Hope nobody is so stupid to load 4GB+
+ * kernel into core :)))) */
+ return ufsi_size(&ui);
+}
+
+static void print_error_ufs (int error_val) {
+ printf("Unknown ufs error");
+}
+
+struct fs_ops iso_fs_ops = {
+ name: "SunOS UFS",
+ open: open_ufs,
+ ls: NULL/*ls_ufs*/,
+ dump: dump_ufs,
+ close: ufs_close,
+ ino_size: ino_size_ufs,
+ print_error: print_error_ufs,
+ namei_follow: namei_follow_ufs,
+ have_inode: 0,
+};