diff options
author | bencollins <tailor@grayson> | 2001-06-06 18:51:19 -0400 |
---|---|---|
committer | Ben Collins <bcollins@ubuntu.com> | 2006-06-01 13:17:54 -0400 |
commit | 1ce2730cf223c047647567cb46b0a1caca05d8e6 (patch) | |
tree | c0ff5749cc9ccec6c2a568c1de3f3ae5437237d8 | |
parent | bb7bf352633c20f2b08092b3dee222ffa62a073e (diff) | |
download | silo-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-- | ChangeLog | 9 | ||||
-rw-r--r-- | second/Makefile | 2 | ||||
-rw-r--r-- | second/file.c | 10 | ||||
-rw-r--r-- | second/fs/isofs.c | 8 | ||||
-rw-r--r-- | second/fs/romfs.c | 336 | ||||
-rw-r--r-- | second/fs/ufs.c | 457 |
6 files changed, 816 insertions, 6 deletions
@@ -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, +}; |