Add Reiserfs support * Patch by Hinko Kocevar, 20 Mar 2004 - Add auto-release for SMSC LAN91c111 driver - Add save/restore of PTR and PNR regs as suggested in datasheetmaster
parent
6fb6af6dc9
commit
518e2e1ae3
@ -0,0 +1,277 @@ |
||||
/*
|
||||
* (C) Copyright 2003 - 2004 |
||||
* Sysgo Real-Time Solutions, AG <www.elinos.com> |
||||
* Pavel Bartusek <pba@sysgo.com> |
||||
* |
||||
* See file CREDITS for list of people who contributed to this |
||||
* project. |
||||
* |
||||
* 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., 59 Temple Place, Suite 330, Boston, |
||||
* MA 02111-1307 USA |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* Reiserfs support |
||||
*/ |
||||
#include <common.h> |
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_REISER) |
||||
#include <config.h> |
||||
#include <command.h> |
||||
#include <image.h> |
||||
#include <linux/ctype.h> |
||||
#include <asm/byteorder.h> |
||||
#include <reiserfs.h> |
||||
|
||||
#ifndef CONFIG_DOS_PARTITION |
||||
#error DOS partition support must be selected |
||||
#endif |
||||
|
||||
/* #define REISER_DEBUG */ |
||||
|
||||
#ifdef REISER_DEBUG |
||||
#define PRINTF(fmt,args...) printf (fmt ,##args) |
||||
#else |
||||
#define PRINTF(fmt,args...) |
||||
#endif |
||||
|
||||
static block_dev_desc_t *get_dev (char* ifname, int dev) |
||||
{ |
||||
#if (CONFIG_COMMANDS & CFG_CMD_IDE) |
||||
if (strncmp(ifname,"ide",3)==0) { |
||||
extern block_dev_desc_t * ide_get_dev(int dev); |
||||
return((dev >= CFG_IDE_MAXDEVICE) ? NULL : ide_get_dev(dev)); |
||||
} |
||||
#endif |
||||
#if (CONFIG_COMMANDS & CFG_CMD_SCSI) |
||||
if (strncmp(ifname,"scsi",4)==0) { |
||||
extern block_dev_desc_t * scsi_get_dev(int dev); |
||||
return((dev >= CFG_SCSI_MAXDEVICE) ? NULL : scsi_get_dev(dev)); |
||||
} |
||||
#endif |
||||
#if ((CONFIG_COMMANDS & CFG_CMD_USB) && defined(CONFIG_USB_STORAGE)) |
||||
if (strncmp(ifname,"usb",3)==0) { |
||||
extern block_dev_desc_t * usb_stor_get_dev(int dev); |
||||
return((dev >= USB_MAX_STOR_DEV) ? NULL : usb_stor_get_dev(dev)); |
||||
} |
||||
#endif |
||||
#if defined(CONFIG_MMC) |
||||
if (strncmp(ifname,"mmc",3)==0) { |
||||
extern block_dev_desc_t * mmc_get_dev(int dev); |
||||
return((dev >= 1) ? NULL : mmc_get_dev(dev)); |
||||
} |
||||
#endif |
||||
#if defined(CONFIG_SYSTEMACE) |
||||
if (strcmp(ifname,"ace")==0) { |
||||
extern block_dev_desc_t * systemace_get_dev(int dev); |
||||
return((dev >= 1) ? NULL : systemace_get_dev(dev)); |
||||
} |
||||
#endif |
||||
return NULL; |
||||
} |
||||
|
||||
int do_reiserls (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) |
||||
{ |
||||
char *filename = "/"; |
||||
int dev=0; |
||||
int part=1; |
||||
char *ep; |
||||
block_dev_desc_t *dev_desc=NULL; |
||||
int part_length; |
||||
|
||||
if (argc < 3) { |
||||
printf ("Usage:\n%s\n", cmdtp->usage); |
||||
return 1; |
||||
} |
||||
dev = (int)simple_strtoul (argv[2], &ep, 16); |
||||
dev_desc=get_dev(argv[1],dev); |
||||
|
||||
if (dev_desc == NULL) { |
||||
printf ("\n** Block device %s %d not supported\n", argv[1], dev); |
||||
return 1; |
||||
} |
||||
|
||||
if (*ep) { |
||||
if (*ep != ':') { |
||||
puts ("\n** Invalid boot device, use `dev[:part]' **\n"); |
||||
return 1; |
||||
} |
||||
part = (int)simple_strtoul(++ep, NULL, 16); |
||||
} |
||||
|
||||
if (argc == 4) { |
||||
filename = argv[3]; |
||||
} |
||||
|
||||
PRINTF("Using device %s %d:%d, directory: %s\n", argv[1], dev, part, filename); |
||||
|
||||
if ((part_length = reiserfs_set_blk_dev(dev_desc, part)) == 0) { |
||||
printf ("** Bad partition - %s %d:%d **\n", argv[1], dev, part); |
||||
return 1; |
||||
} |
||||
|
||||
if (!reiserfs_mount(part_length)) { |
||||
printf ("** Bad Reisefs partition or disk - %s %d:%d **\n", argv[1], dev, part); |
||||
return 1; |
||||
} |
||||
|
||||
if (reiserfs_ls (filename)) { |
||||
printf ("** Error reiserfs_ls() **\n"); |
||||
return 1; |
||||
}; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
reiserls, 4, 1, do_reiserls, |
||||
"reiserls- list files in a directory (default /)\n", |
||||
"<interface> <dev[:part]> [directory]\n" |
||||
" - list files from 'dev' on 'interface' in a 'directory'\n" |
||||
); |
||||
|
||||
/******************************************************************************
|
||||
* Reiserfs boot command intepreter. Derived from diskboot |
||||
*/ |
||||
int do_reiserload (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) |
||||
{ |
||||
char *filename = NULL; |
||||
char *ep; |
||||
int dev, part = 0; |
||||
ulong addr = 0, part_length, filelen; |
||||
disk_partition_t info; |
||||
block_dev_desc_t *dev_desc = NULL; |
||||
char buf [12]; |
||||
unsigned long count; |
||||
char *addr_str; |
||||
|
||||
switch (argc) { |
||||
case 3: |
||||
addr_str = getenv("loadaddr"); |
||||
if (addr_str != NULL) { |
||||
addr = simple_strtoul (addr_str, NULL, 16); |
||||
} else { |
||||
addr = CFG_LOAD_ADDR; |
||||
} |
||||
filename = getenv ("bootfile"); |
||||
count = 0; |
||||
break; |
||||
case 4: |
||||
addr = simple_strtoul (argv[3], NULL, 16); |
||||
filename = getenv ("bootfile"); |
||||
count = 0; |
||||
break; |
||||
case 5: |
||||
addr = simple_strtoul (argv[3], NULL, 16); |
||||
filename = argv[4]; |
||||
count = 0; |
||||
break; |
||||
case 6: |
||||
addr = simple_strtoul (argv[3], NULL, 16); |
||||
filename = argv[4]; |
||||
count = simple_strtoul (argv[5], NULL, 16); |
||||
break; |
||||
|
||||
default: |
||||
printf ("Usage:\n%s\n", cmdtp->usage); |
||||
return 1; |
||||
} |
||||
|
||||
if (!filename) { |
||||
puts ("\n** No boot file defined **\n"); |
||||
return 1; |
||||
} |
||||
|
||||
dev = (int)simple_strtoul (argv[2], &ep, 16); |
||||
dev_desc=get_dev(argv[1],dev); |
||||
if (dev_desc==NULL) { |
||||
printf ("\n** Block device %s %d not supported\n", argv[1], dev); |
||||
return 1; |
||||
} |
||||
if (*ep) { |
||||
if (*ep != ':') { |
||||
puts ("\n** Invalid boot device, use `dev[:part]' **\n"); |
||||
return 1; |
||||
} |
||||
part = (int)simple_strtoul(++ep, NULL, 16); |
||||
} |
||||
|
||||
PRINTF("Using device %s%d, partition %d\n", argv[1], dev, part); |
||||
|
||||
if (part != 0) { |
||||
if (get_partition_info (&dev_desc[dev], part, &info)) { |
||||
printf ("** Bad partition %d **\n", part); |
||||
return 1; |
||||
} |
||||
|
||||
if (strncmp(info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) { |
||||
printf ("\n** Invalid partition type \"%.32s\"" |
||||
" (expect \"" BOOT_PART_TYPE "\")\n", |
||||
info.type); |
||||
return 1; |
||||
} |
||||
PRINTF ("\nLoading from block device %s device %d, partition %d: " |
||||
"Name: %.32s Type: %.32s File:%s\n", |
||||
argv[1], dev, part, info.name, info.type, filename); |
||||
} else { |
||||
PRINTF ("\nLoading from block device %s device %d, File:%s\n", |
||||
argv[1], dev, filename); |
||||
} |
||||
|
||||
|
||||
if ((part_length = reiserfs_set_blk_dev(dev_desc, part)) == 0) { |
||||
printf ("** Bad partition - %s %d:%d **\n", argv[1], dev, part); |
||||
return 1; |
||||
} |
||||
|
||||
if (!reiserfs_mount(part_length)) { |
||||
printf ("** Bad Reisefs partition or disk - %s %d:%d **\n", argv[1], dev, part); |
||||
return 1; |
||||
} |
||||
|
||||
filelen = reiserfs_open(filename); |
||||
if (filelen < 0) { |
||||
printf("** File not found %s\n", filename); |
||||
return 1; |
||||
} |
||||
if ((count < filelen) && (count != 0)) { |
||||
filelen = count; |
||||
} |
||||
|
||||
if (reiserfs_read((char *)addr, filelen) != filelen) { |
||||
printf("\n** Unable to read \"%s\" from %s %d:%d **\n", filename, argv[1], dev, part); |
||||
return 1; |
||||
} |
||||
|
||||
/* Loading ok, update default load address */ |
||||
load_addr = addr; |
||||
|
||||
printf ("\n%ld bytes read\n", filelen); |
||||
sprintf(buf, "%lX", filelen); |
||||
setenv("filesize", buf); |
||||
|
||||
return filelen; |
||||
} |
||||
|
||||
U_BOOT_CMD( |
||||
reiserload, 6, 0, do_reiserload, |
||||
"reiserload- load binary file from a Reiser filesystem\n", |
||||
"<interface> <dev[:part]> [addr] [filename] [bytes]\n" |
||||
" - load binary file 'filename' from 'dev' on 'interface'\n" |
||||
" to address 'addr' from dos filesystem\n" |
||||
); |
||||
|
||||
#endif /* CONFIG_COMMANDS & CFG_CMD_REISER */ |
@ -0,0 +1,48 @@ |
||||
#
|
||||
# (C) Copyright 2003
|
||||
# Pavel Bartusek, Sysgo Real-Time Solutions AG, pba@sysgo.de
|
||||
#
|
||||
#
|
||||
# See file CREDITS for list of people who contributed to this
|
||||
# project.
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston,
|
||||
# MA 02111-1307 USA
|
||||
#
|
||||
|
||||
include $(TOPDIR)/config.mk |
||||
|
||||
LIB = libreiserfs.a
|
||||
|
||||
AOBJS =
|
||||
COBJS = reiserfs.o dev.o mode_string.o
|
||||
OBJS = $(AOBJS) $(COBJS)
|
||||
|
||||
#CPPFLAGS +=
|
||||
|
||||
all: $(LIB) $(AOBJS) |
||||
|
||||
$(LIB): .depend $(OBJS) |
||||
$(AR) crv $@ $(OBJS)
|
||||
|
||||
|
||||
#########################################################################
|
||||
|
||||
.depend: Makefile $(AOBJS:.o=.S) $(COBJS:.o=.c) |
||||
$(CC) -M $(CFLAGS) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@
|
||||
|
||||
sinclude .depend |
||||
|
||||
#########################################################################
|
@ -0,0 +1,123 @@ |
||||
/*
|
||||
* (C) Copyright 2003 - 2004 |
||||
* Sysgo AG, <www.elinos.com>, Pavel Bartusek <pba@sysgo.com> |
||||
* |
||||
* 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 <common.h> |
||||
#if (CONFIG_COMMANDS & CFG_CMD_REISER) |
||||
|
||||
#include <config.h> |
||||
#include <reiserfs.h> |
||||
|
||||
#include "reiserfs_private.h" |
||||
|
||||
static block_dev_desc_t *reiserfs_block_dev_desc; |
||||
static disk_partition_t part_info; |
||||
|
||||
|
||||
int reiserfs_set_blk_dev(block_dev_desc_t *rbdd, int part) |
||||
{ |
||||
reiserfs_block_dev_desc = rbdd; |
||||
|
||||
if (part == 0) { |
||||
/* disk doesn't use partition table */ |
||||
part_info.start = 0; |
||||
part_info.size = rbdd->lba; |
||||
part_info.blksz = rbdd->blksz; |
||||
} else { |
||||
if (get_partition_info (reiserfs_block_dev_desc, part, &part_info)) { |
||||
return 0; |
||||
} |
||||
} |
||||
return (part_info.size); |
||||
} |
||||
|
||||
|
||||
int reiserfs_devread (int sector, int byte_offset, int byte_len, char *buf) |
||||
{ |
||||
char sec_buf[SECTOR_SIZE]; |
||||
unsigned block_len; |
||||
/*
|
||||
unsigned len = byte_len; |
||||
u8 *start = buf; |
||||
*/ |
||||
/*
|
||||
* Check partition boundaries |
||||
*/ |
||||
if (sector < 0 |
||||
|| ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS)) |
||||
>= part_info.size)) { |
||||
// errnum = ERR_OUTSIDE_PART;
|
||||
printf (" ** reiserfs_devread() read outside partition\n"); |
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* Get the read to the beginning of a partition. |
||||
*/ |
||||
sector += byte_offset >> SECTOR_BITS; |
||||
byte_offset &= SECTOR_SIZE - 1; |
||||
|
||||
#if defined(DEBUG) |
||||
printf (" <%d, %d, %d> ", sector, byte_offset, byte_len); |
||||
#endif |
||||
|
||||
|
||||
if (reiserfs_block_dev_desc == NULL) |
||||
return 0; |
||||
|
||||
|
||||
if (byte_offset != 0) { |
||||
/* read first part which isn't aligned with start of sector */ |
||||
if (reiserfs_block_dev_desc->block_read(reiserfs_block_dev_desc->dev, |
||||
part_info.start+sector, 1, (unsigned long *)sec_buf) != 1) { |
||||
printf (" ** reiserfs_devread() read error\n"); |
||||
return 0; |
||||
} |
||||
memcpy(buf, sec_buf+byte_offset, min(SECTOR_SIZE-byte_offset, byte_len)); |
||||
buf+=min(SECTOR_SIZE-byte_offset, byte_len); |
||||
byte_len-=min(SECTOR_SIZE-byte_offset, byte_len); |
||||
sector++; |
||||
} |
||||
|
||||
/* read sector aligned part */ |
||||
block_len = byte_len & ~(SECTOR_SIZE-1); |
||||
if (reiserfs_block_dev_desc->block_read(reiserfs_block_dev_desc->dev, |
||||
part_info.start+sector, block_len/SECTOR_SIZE, (unsigned long *)buf) != |
||||
block_len/SECTOR_SIZE) { |
||||
printf (" ** reiserfs_devread() read error - block\n"); |
||||
return 0; |
||||
} |
||||
buf+=block_len; |
||||
byte_len-=block_len; |
||||
sector+= block_len/SECTOR_SIZE; |
||||
|
||||
if ( byte_len != 0 ) { |
||||
/* read rest of data which are not in whole sector */ |
||||
if (reiserfs_block_dev_desc->block_read(reiserfs_block_dev_desc->dev, |
||||
part_info.start+sector, 1, (unsigned long *)sec_buf) != 1) { |
||||
printf (" ** reiserfs_devread() read error - last part\n"); |
||||
return 0; |
||||
} |
||||
memcpy(buf, sec_buf, byte_len); |
||||
} |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
#endif /* CFG_CMD_REISERFS */ |
@ -0,0 +1,143 @@ |
||||
/* vi: set sw=4 ts=4: */ |
||||
/*
|
||||
* mode_string implementation for busybox |
||||
* |
||||
* Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> |
||||
* |
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
* |
||||
*/ |
||||
|
||||
/* Aug 13, 2003
|
||||
* Fix a bug reported by junkio@cox.net involving the mode_chars index. |
||||
*/ |
||||
|
||||
|
||||
#include <common.h> |
||||
#if (CONFIG_COMMANDS & CFG_CMD_REISER) |
||||
#include <linux/stat.h> |
||||
|
||||
#if ( S_ISUID != 04000 ) || ( S_ISGID != 02000 ) || ( S_ISVTX != 01000 ) \ |
||||
|| ( S_IRUSR != 00400 ) || ( S_IWUSR != 00200 ) || ( S_IXUSR != 00100 ) \
|
||||
|| ( S_IRGRP != 00040 ) || ( S_IWGRP != 00020 ) || ( S_IXGRP != 00010 ) \
|
||||
|| ( S_IROTH != 00004 ) || ( S_IWOTH != 00002 ) || ( S_IXOTH != 00001 ) |
||||
#error permission bitflag value assumption(s) violated! |
||||
#endif |
||||
|
||||
#if ( S_IFSOCK!= 0140000 ) || ( S_IFLNK != 0120000 ) \ |
||||
|| ( S_IFREG != 0100000 ) || ( S_IFBLK != 0060000 ) \
|
||||
|| ( S_IFDIR != 0040000 ) || ( S_IFCHR != 0020000 ) \
|
||||
|| ( S_IFIFO != 0010000 ) |
||||
#warning mode type bitflag value assumption(s) violated! falling back to larger version |
||||
|
||||
#if (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX) == 07777 |
||||
#undef mode_t |
||||
#define mode_t unsigned short |
||||
#endif |
||||
|
||||
static const mode_t mode_flags[] = { |
||||
S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID, |
||||
S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID, |
||||
S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX |
||||
}; |
||||
|
||||
/* The static const char arrays below are duplicated for the two cases
|
||||
* because moving them ahead of the mode_flags declaration cause a text |
||||
* size increase with the gcc version I'm using. */ |
||||
|
||||
/* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C',
|
||||
* and 'B' types don't appear to be available on linux. So I removed them. */ |
||||
static const char type_chars[16] = "?pc?d?b?-?l?s???"; |
||||
/* 0123456789abcdef */ |
||||
static const char mode_chars[7] = "rwxSTst"; |
||||
|
||||
const char *bb_mode_string(int mode) |
||||
{ |
||||
static char buf[12]; |
||||
char *p = buf; |
||||
|
||||
int i, j, k; |
||||
|
||||
*p = type_chars[ (mode >> 12) & 0xf ]; |
||||
i = 0; |
||||
do { |
||||
j = k = 0; |
||||
do { |
||||
*++p = '-'; |
||||
if (mode & mode_flags[i+j]) { |
||||
*p = mode_chars[j]; |
||||
k = j; |
||||
} |
||||
} while (++j < 3); |
||||
if (mode & mode_flags[i+j]) { |
||||
*p = mode_chars[3 + (k & 2) + ((i&8) >> 3)]; |
||||
} |
||||
i += 4; |
||||
} while (i < 12); |
||||
|
||||
/* Note: We don't bother with nul termination because bss initialization
|
||||
* should have taken care of that for us. If the user scribbled in buf |
||||
* memory, they deserve whatever happens. But we'll at least assert. */ |
||||
if (buf[10] != 0) return NULL; |
||||
|
||||
return buf; |
||||
} |
||||
|
||||
#else |
||||
|
||||
/* The previous version used "0pcCd?bB-?l?s???". However, the '0', 'C',
|
||||
* and 'B' types don't appear to be available on linux. So I removed them. */ |
||||
//static const char type_chars[16] = "?pc?d?b?-?l?s???";
|
||||
static const char type_chars[16] = "?pc?d?b?-?l?s???"; |
||||
/* 0123456789abcdef */ |
||||
static const char mode_chars[7] = "rwxSTst"; |
||||
|
||||
const char *bb_mode_string(int mode) |
||||
{ |
||||
static char buf[12]; |
||||
char *p = buf; |
||||
|
||||
int i, j, k, m; |
||||
|
||||
*p = type_chars[ (mode >> 12) & 0xf ]; |
||||
i = 0; |
||||
m = 0400; |
||||
do { |
||||
j = k = 0; |
||||
do { |
||||
*++p = '-'; |
||||
if (mode & m) { |
||||
*p = mode_chars[j]; |
||||
k = j; |
||||
} |
||||
m >>= 1; |
||||
} while (++j < 3); |
||||
++i; |
||||
if (mode & (010000 >> i)) { |
||||
*p = mode_chars[3 + (k & 2) + (i == 3)]; |
||||
} |
||||
} while (i < 3); |
||||
|
||||
/* Note: We don't bother with nul termination because bss initialization
|
||||
* should have taken care of that for us. If the user scribbled in buf |
||||
* memory, they deserve whatever happens. But we'll at least assert. */ |
||||
if (buf[10] != 0) return NULL; |
||||
|
||||
return buf; |
||||
} |
||||
|
||||
#endif |
||||
|
||||
#endif /* CFG_CMD_REISER */ |
@ -0,0 +1,986 @@ |
||||
/*
|
||||
* Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README |
||||
* |
||||
* GRUB -- GRand Unified Bootloader |
||||
* Copyright (C) 2000, 2001 Free Software Foundation, Inc. |
||||
* |
||||
* (C) Copyright 2003 - 2004 |
||||
* Sysgo AG, <www.elinos.com>, Pavel Bartusek <pba@sysgo.com> |
||||
* |
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
/* An implementation for the ReiserFS filesystem ported from GRUB.
|
||||
* Some parts of this code (mainly the structures and defines) are |
||||
* from the original reiser fs code, as found in the linux kernel. |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#if (CONFIG_COMMANDS & CFG_CMD_REISER) |
||||
|
||||
#include <malloc.h> |
||||
#include <linux/ctype.h> |
||||
#include <linux/time.h> |
||||
#include <asm/byteorder.h> |
||||
#include <reiserfs.h> |
||||
|
||||
#include "reiserfs_private.h" |
||||
|
||||
#undef REISERDEBUG |
||||
|
||||
/* Some parts of this code (mainly the structures and defines) are
|
||||
* from the original reiser fs code, as found in the linux kernel. |
||||
*/ |
||||
|
||||
static char fsys_buf[FSYS_BUFLEN]; |
||||
static reiserfs_error_t errnum = ERR_NONE; |
||||
static int print_possibilities; |
||||
static unsigned int filepos, filemax; |
||||
|
||||
static int |
||||
substring (const char *s1, const char *s2) |
||||
{ |
||||
while (*s1 == *s2) |
||||
{ |
||||
/* The strings match exactly. */ |
||||
if (! *(s1++)) |
||||
return 0; |
||||
s2 ++; |
||||
} |
||||
|
||||
/* S1 is a substring of S2. */ |
||||
if (*s1 == 0) |
||||
return -1; |
||||
|
||||
/* S1 isn't a substring. */ |
||||
return 1; |
||||
} |
||||
|
||||
static void sd_print_item (struct item_head * ih, char * item) |
||||
{ |
||||
char filetime[30]; |
||||
time_t ttime; |
||||
|
||||
if (stat_data_v1 (ih)) { |
||||
struct stat_data_v1 * sd = (struct stat_data_v1 *)item; |
||||
ttime = sd_v1_mtime(sd); |
||||
ctime_r(&ttime, filetime); |
||||
printf ("%-10s %4hd %6d %6d %9d %24.24s", |
||||
bb_mode_string(sd_v1_mode(sd)), sd_v1_nlink(sd),sd_v1_uid(sd), sd_v1_gid(sd), |
||||
sd_v1_size(sd), filetime); |
||||
} else { |
||||
struct stat_data * sd = (struct stat_data *)item; |
||||
ttime = sd_v2_mtime(sd); |
||||
ctime_r(&ttime, filetime); |
||||
printf ("%-10s %4d %6d %6d %9d %24.24s", |
||||
bb_mode_string(sd_v2_mode(sd)), sd_v2_nlink(sd),sd_v2_uid(sd),sd_v2_gid(sd), |
||||
(__u32) sd_v2_size(sd), filetime); |
||||
} |
||||
} |
||||
|
||||
static int |
||||
journal_read (int block, int len, char *buffer) |
||||
{ |
||||
return reiserfs_devread ((INFO->journal_block + block) << INFO->blocksize_shift, |
||||
0, len, buffer); |
||||
} |
||||
|
||||
/* Read a block from ReiserFS file system, taking the journal into
|
||||
* account. If the block nr is in the journal, the block from the |
||||
* journal taken. |
||||
*/ |
||||
static int |
||||
block_read (unsigned int blockNr, int start, int len, char *buffer) |
||||
{ |
||||
int transactions = INFO->journal_transactions; |
||||
int desc_block = INFO->journal_first_desc; |
||||
int journal_mask = INFO->journal_block_count - 1; |
||||
int translatedNr = blockNr; |
||||
__u32 *journal_table = JOURNAL_START; |
||||
while (transactions-- > 0) |
||||
{ |
||||
int i = 0; |
||||
int j_len; |
||||
if (__le32_to_cpu(*journal_table) != 0xffffffff) |
||||
{ |
||||
/* Search for the blockNr in cached journal */ |
||||
j_len = __le32_to_cpu(*journal_table++); |
||||
while (i++ < j_len) |
||||
{ |
||||
if (__le32_to_cpu(*journal_table++) == blockNr) |
||||
{ |
||||
journal_table += j_len - i; |
||||
goto found; |
||||
} |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
/* This is the end of cached journal marker. The remaining
|
||||
* transactions are still on disk. |
||||
*/ |
||||
struct reiserfs_journal_desc desc; |
||||
struct reiserfs_journal_commit commit; |
||||
|
||||
if (! journal_read (desc_block, sizeof (desc), (char *) &desc)) |
||||
return 0; |
||||
|
||||
j_len = __le32_to_cpu(desc.j_len); |
||||
while (i < j_len && i < JOURNAL_TRANS_HALF) |
||||
if (__le32_to_cpu(desc.j_realblock[i++]) == blockNr) |
||||
goto found; |
||||
|
||||
if (j_len >= JOURNAL_TRANS_HALF) |
||||
{ |
||||
int commit_block = (desc_block + 1 + j_len) & journal_mask; |
||||
if (! journal_read (commit_block, |
||||
sizeof (commit), (char *) &commit)) |
||||
return 0; |
||||
while (i < j_len) |
||||
if (__le32_to_cpu(commit.j_realblock[i++ - JOURNAL_TRANS_HALF]) == blockNr) |
||||
goto found; |
||||
} |
||||
} |
||||
goto not_found; |
||||
|
||||
found: |
||||
translatedNr = INFO->journal_block + ((desc_block + i) & journal_mask); |
||||
#ifdef REISERDEBUG |
||||
printf ("block_read: block %d is mapped to journal block %d.\n", |
||||
blockNr, translatedNr - INFO->journal_block); |
||||
#endif |
||||
/* We must continue the search, as this block may be overwritten
|
||||
* in later transactions. |
||||
*/ |
||||
not_found: |
||||
desc_block = (desc_block + 2 + j_len) & journal_mask; |
||||
} |
||||
return reiserfs_devread (translatedNr << INFO->blocksize_shift, start, len, buffer); |
||||
} |
||||
|
||||
/* Init the journal data structure. We try to cache as much as
|
||||
* possible in the JOURNAL_START-JOURNAL_END space, but if it is full |
||||
* we can still read the rest from the disk on demand. |
||||
* |
||||
* The first number of valid transactions and the descriptor block of the |
||||
* first valid transaction are held in INFO. The transactions are all |
||||
* adjacent, but we must take care of the journal wrap around. |
||||
*/ |
||||
static int |
||||
journal_init (void) |
||||
{ |
||||
unsigned int block_count = INFO->journal_block_count; |
||||
unsigned int desc_block; |
||||
unsigned int commit_block; |
||||
unsigned int next_trans_id; |
||||
struct reiserfs_journal_header header; |
||||
struct reiserfs_journal_desc desc; |
||||
struct reiserfs_journal_commit commit; |
||||
__u32 *journal_table = JOURNAL_START; |
||||
|
||||
journal_read (block_count, sizeof (header), (char *) &header); |
||||
desc_block = __le32_to_cpu(header.j_first_unflushed_offset); |
||||
if (desc_block >= block_count) |
||||
return 0; |
||||
|
||||
INFO->journal_first_desc = desc_block; |
||||
next_trans_id = __le32_to_cpu(header.j_last_flush_trans_id) + 1; |
||||
|
||||
#ifdef REISERDEBUG |
||||
printf ("journal_init: last flushed %d\n", |
||||
__le32_to_cpu(header.j_last_flush_trans_id)); |
||||
#endif |
||||
|
||||
while (1) |
||||
{ |
||||
journal_read (desc_block, sizeof (desc), (char *) &desc); |
||||
if (substring (JOURNAL_DESC_MAGIC, desc.j_magic) > 0 |
||||
|| __le32_to_cpu(desc.j_trans_id) != next_trans_id |
||||
|| __le32_to_cpu(desc.j_mount_id) != __le32_to_cpu(header.j_mount_id)) |
||||
/* no more valid transactions */ |
||||
break; |
||||
|
||||
commit_block = (desc_block + __le32_to_cpu(desc.j_len) + 1) & (block_count - 1); |
||||
journal_read (commit_block, sizeof (commit), (char *) &commit); |
||||
if (__le32_to_cpu(desc.j_trans_id) != commit.j_trans_id |
||||
|| __le32_to_cpu(desc.j_len) != __le32_to_cpu(commit.j_len)) |
||||
/* no more valid transactions */ |
||||
break; |
||||
|
||||
#ifdef REISERDEBUG |
||||
printf ("Found valid transaction %d/%d at %d.\n", |
||||
__le32_to_cpu(desc.j_trans_id), __le32_to_cpu(desc.j_mount_id), desc_block); |
||||
#endif |
||||
|
||||
next_trans_id++; |
||||
if (journal_table < JOURNAL_END) |
||||
{ |
||||
if ((journal_table + 1 + __le32_to_cpu(desc.j_len)) >= JOURNAL_END) |
||||
{ |
||||
/* The table is almost full; mark the end of the cached
|
||||
* journal.*/ |
||||
*journal_table = __cpu_to_le32(0xffffffff); |
||||
journal_table = JOURNAL_END; |
||||
} |
||||
else |
||||
{ |
||||
unsigned int i; |
||||
/* Cache the length and the realblock numbers in the table.
|
||||
* The block number of descriptor can easily be computed. |
||||
* and need not to be stored here. |
||||
*/ |
||||
|
||||
/* both are in the little endian format */ |
||||
*journal_table++ = desc.j_len; |
||||
for (i = 0; i < __le32_to_cpu(desc.j_len) && i < JOURNAL_TRANS_HALF; i++) |
||||
{ |
||||
/* both are in the little endian format */ |
||||
*journal_table++ = desc.j_realblock[i]; |
||||
#ifdef REISERDEBUG |
||||
printf ("block %d is in journal %d.\n", |
||||
__le32_to_cpu(desc.j_realblock[i]), desc_block); |
||||
#endif |
||||
} |
||||
for ( ; i < __le32_to_cpu(desc.j_len); i++) |
||||
{ |
||||
/* both are in the little endian format */ |
||||
*journal_table++ = commit.j_realblock[i-JOURNAL_TRANS_HALF]; |
||||
#ifdef REISERDEBUG |
||||
printf ("block %d is in journal %d.\n", |
||||
__le32_to_cpu(commit.j_realblock[i-JOURNAL_TRANS_HALF]), |
||||
desc_block); |
||||
#endif |
||||
} |
||||
} |
||||
} |
||||
desc_block = (commit_block + 1) & (block_count - 1); |
||||
} |
||||
#ifdef REISERDEBUG |
||||
printf ("Transaction %d/%d at %d isn't valid.\n", |
||||
__le32_to_cpu(desc.j_trans_id), __le32_to_cpu(desc.j_mount_id), desc_block); |
||||
#endif |
||||
|
||||
INFO->journal_transactions |
||||
= next_trans_id - __le32_to_cpu(header.j_last_flush_trans_id) - 1; |
||||
return errnum == 0; |
||||
} |
||||
|
||||
/* check filesystem types and read superblock into memory buffer */ |
||||
int |
||||
reiserfs_mount (unsigned part_length) |
||||
{ |
||||
struct reiserfs_super_block super; |
||||
int superblock = REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS; |
||||
|
||||
if (part_length < superblock + (sizeof (super) >> SECTOR_BITS) |
||||
|| ! reiserfs_devread (superblock, 0, sizeof (struct reiserfs_super_block), |
||||
(char *) &super) |
||||
|| (substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) > 0 |
||||
&& substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0 |
||||
&& substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0) |
||||
|| (/* check that this is not a copy inside the journal log */ |
||||
sb_journal_block(&super) * sb_blocksize(&super) |
||||
<= REISERFS_DISK_OFFSET_IN_BYTES)) |
||||
{ |
||||
/* Try old super block position */ |
||||
superblock = REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS; |
||||
if (part_length < superblock + (sizeof (super) >> SECTOR_BITS) |
||||
|| ! reiserfs_devread (superblock, 0, sizeof (struct reiserfs_super_block), |
||||
(char *) &super)) |
||||
return 0; |
||||
|
||||
if (substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0 |
||||
&& substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0) |
||||
{ |
||||
/* pre journaling super block ? */ |
||||
if (substring (REISERFS_SUPER_MAGIC_STRING, |
||||
(char*) ((int) &super + 20)) > 0) |
||||
return 0; |
||||
|
||||
set_sb_blocksize(&super, REISERFS_OLD_BLOCKSIZE); |
||||
set_sb_journal_block(&super, 0); |
||||
set_sb_version(&super, 0); |
||||
} |
||||
} |
||||
|
||||
/* check the version number. */ |
||||
if (sb_version(&super) > REISERFS_MAX_SUPPORTED_VERSION) |
||||
return 0; |
||||
|
||||
INFO->version = sb_version(&super); |
||||
INFO->blocksize = sb_blocksize(&super); |
||||
INFO->fullblocksize_shift = log2 (sb_blocksize(&super)); |
||||
INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS; |
||||
INFO->cached_slots = |
||||
(FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1; |
||||
|
||||
#ifdef REISERDEBUG |
||||
printf ("reiserfs_mount: version=%d, blocksize=%d\n", |
||||
INFO->version, INFO->blocksize); |
||||
#endif /* REISERDEBUG */ |
||||
|
||||
/* Clear node cache. */ |
||||
memset (INFO->blocks, 0, sizeof (INFO->blocks)); |
||||
|
||||
if (sb_blocksize(&super) < FSYSREISER_MIN_BLOCKSIZE |
||||
|| sb_blocksize(&super) > FSYSREISER_MAX_BLOCKSIZE |
||||
|| (SECTOR_SIZE << INFO->blocksize_shift) != sb_blocksize(&super)) |
||||
return 0; |
||||
|
||||
/* Initialize journal code. If something fails we end with zero
|
||||
* journal_transactions, so we don't access the journal at all. |
||||
*/ |
||||
INFO->journal_transactions = 0; |
||||
if (sb_journal_block(&super) != 0 && super.s_journal_dev == 0) |
||||
{ |
||||
INFO->journal_block = sb_journal_block(&super); |
||||
INFO->journal_block_count = sb_journal_size(&super); |
||||
if (is_power_of_two (INFO->journal_block_count)) |
||||
journal_init (); |
||||
|
||||
/* Read in super block again, maybe it is in the journal */ |
||||
block_read (superblock >> INFO->blocksize_shift, |
||||
0, sizeof (struct reiserfs_super_block), (char *) &super); |
||||
} |
||||
|
||||
if (! block_read (sb_root_block(&super), 0, INFO->blocksize, (char*) ROOT)) |
||||
return 0; |
||||
|
||||
INFO->tree_depth = __le16_to_cpu(BLOCKHEAD (ROOT)->blk_level); |
||||
|
||||
#ifdef REISERDEBUG |
||||
printf ("root read_in: block=%d, depth=%d\n", |
||||
sb_root_block(&super), INFO->tree_depth); |
||||
#endif /* REISERDEBUG */ |
||||
|
||||
if (INFO->tree_depth >= MAX_HEIGHT) |
||||
return 0; |
||||
if (INFO->tree_depth == DISK_LEAF_NODE_LEVEL) |
||||
{ |
||||
/* There is only one node in the whole filesystem,
|
||||
* which is simultanously leaf and root */ |
||||
memcpy (LEAF, ROOT, INFO->blocksize); |
||||
} |
||||
return 1; |
||||
} |
||||
|
||||
/***************** TREE ACCESSING METHODS *****************************/ |
||||
|
||||
/* I assume you are familiar with the ReiserFS tree, if not go to
|
||||
* http://www.namesys.com/content_table.html
|
||||
* |
||||
* My tree node cache is organized as following |
||||
* 0 ROOT node |
||||
* 1 LEAF node (if the ROOT is also a LEAF it is copied here |
||||
* 2-n other nodes on current path from bottom to top. |
||||
* if there is not enough space in the cache, the top most are |
||||
* omitted. |
||||
* |
||||
* I have only two methods to find a key in the tree: |
||||
* search_stat(dir_id, objectid) searches for the stat entry (always |
||||
* the first entry) of an object. |
||||
* next_key() gets the next key in tree order. |
||||
* |
||||
* This means, that I can only sequential reads of files are |
||||
* efficient, but this really doesn't hurt for grub. |
||||
*/ |
||||
|
||||
/* Read in the node at the current path and depth into the node cache.
|
||||
* You must set INFO->blocks[depth] before. |
||||
*/ |
||||
static char * |
||||
read_tree_node (unsigned int blockNr, int depth) |
||||
{ |
||||
char* cache = CACHE(depth); |
||||
int num_cached = INFO->cached_slots; |
||||
if (depth < num_cached) |
||||
{ |
||||
/* This is the cached part of the path. Check if same block is
|
||||
* needed. |
||||
*/ |
||||
if (blockNr == INFO->blocks[depth]) |
||||
return cache; |
||||
} |
||||
else |
||||
cache = CACHE(num_cached); |
||||
|
||||
#ifdef REISERDEBUG |
||||
printf (" next read_in: block=%d (depth=%d)\n", |
||||
blockNr, depth); |
||||
#endif /* REISERDEBUG */ |
||||
if (! block_read (blockNr, 0, INFO->blocksize, cache)) |
||||
return 0; |
||||
/* Make sure it has the right node level */ |
||||
if (__le16_to_cpu(BLOCKHEAD (cache)->blk_level) != depth) |
||||
{ |
||||
errnum = ERR_FSYS_CORRUPT; |
||||
return 0; |
||||
} |
||||
|
||||
INFO->blocks[depth] = blockNr; |
||||
return cache; |
||||
} |
||||
|
||||
/* Get the next key, i.e. the key following the last retrieved key in
|
||||
* tree order. INFO->current_ih and |
||||
* INFO->current_info are adapted accordingly. */ |
||||
static int |
||||
next_key (void) |
||||
{ |
||||
int depth; |
||||
struct item_head *ih = INFO->current_ih + 1; |
||||
char *cache; |
||||
|
||||
#ifdef REISERDEBUG |
||||
printf ("next_key:\n old ih: key %d:%d:%d:%d version:%d\n", |
||||
__le32_to_cpu(INFO->current_ih->ih_key.k_dir_id), |
||||
__le32_to_cpu(INFO->current_ih->ih_key.k_objectid), |
||||
__le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_offset), |
||||
__le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_uniqueness), |
||||
__le16_to_cpu(INFO->current_ih->ih_version)); |
||||
#endif /* REISERDEBUG */ |
||||
|
||||
if (ih == &ITEMHEAD[__le16_to_cpu(BLOCKHEAD (LEAF)->blk_nr_item)]) |
||||
{ |
||||
depth = DISK_LEAF_NODE_LEVEL; |
||||
/* The last item, was the last in the leaf node.
|
||||
* Read in the next block |
||||
*/ |
||||
do |
||||
{ |
||||
if (depth == INFO->tree_depth) |
||||
{ |
||||
/* There are no more keys at all.
|
||||
* Return a dummy item with MAX_KEY */ |
||||
ih = (struct item_head *) &BLOCKHEAD (LEAF)->blk_right_delim_key; |
||||
goto found; |
||||
} |
||||
depth++; |
||||
#ifdef REISERDEBUG |
||||
printf (" depth=%d, i=%d\n", depth, INFO->next_key_nr[depth]); |
||||
#endif /* REISERDEBUG */ |
||||
} |
||||
while (INFO->next_key_nr[depth] == 0); |
||||
|
||||
if (depth == INFO->tree_depth) |
||||
cache = ROOT; |
||||
else if (depth <= INFO->cached_slots) |
||||
cache = CACHE (depth); |
||||
else |
||||
{ |
||||
cache = read_tree_node (INFO->blocks[depth], depth); |
||||
if (! cache) |
||||
return 0; |
||||
} |
||||
|
||||
do |
||||
{ |
||||
int nr_item = __le16_to_cpu(BLOCKHEAD (cache)->blk_nr_item); |
||||
int key_nr = INFO->next_key_nr[depth]++; |
||||
#ifdef REISERDEBUG |
||||
printf (" depth=%d, i=%d/%d\n", depth, key_nr, nr_item); |
||||
#endif /* REISERDEBUG */ |
||||
if (key_nr == nr_item) |
||||
/* This is the last item in this block, set the next_key_nr to 0 */ |
||||
INFO->next_key_nr[depth] = 0; |
||||
|
||||
cache = read_tree_node (dc_block_number(&(DC (cache)[key_nr])), --depth); |
||||
if (! cache) |
||||
return 0; |
||||
} |
||||
while (depth > DISK_LEAF_NODE_LEVEL); |
||||
|
||||
ih = ITEMHEAD; |
||||
} |
||||
found: |
||||
INFO->current_ih = ih; |
||||
INFO->current_item = &LEAF[__le16_to_cpu(ih->ih_item_location)]; |
||||
#ifdef REISERDEBUG |
||||
printf (" new ih: key %d:%d:%d:%d version:%d\n", |
||||
__le32_to_cpu(INFO->current_ih->ih_key.k_dir_id), |
||||
__le32_to_cpu(INFO->current_ih->ih_key.k_objectid), |
||||
__le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_offset), |
||||
__le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_uniqueness), |
||||
__le16_to_cpu(INFO->current_ih->ih_version)); |
||||
#endif /* REISERDEBUG */ |
||||
return 1; |
||||
} |
||||
|
||||
/* preconditions: reiserfs_mount already executed, therefore
|
||||
* INFO block is valid |
||||
* returns: 0 if error (errnum is set), |
||||
* nonzero iff we were able to find the key successfully. |
||||
* postconditions: on a nonzero return, the current_ih and |
||||
* current_item fields describe the key that equals the |
||||
* searched key. INFO->next_key contains the next key after |
||||
* the searched key. |
||||
* side effects: messes around with the cache. |
||||
*/ |
||||
static int |
||||
search_stat (__u32 dir_id, __u32 objectid) |
||||
{ |
||||
char *cache; |
||||
int depth; |
||||
int nr_item; |
||||
int i; |
||||
struct item_head *ih; |
||||
#ifdef REISERDEBUG |
||||
printf ("search_stat:\n key %d:%d:0:0\n", dir_id, objectid); |
||||
#endif /* REISERDEBUG */ |
||||
|
||||
depth = INFO->tree_depth; |
||||
cache = ROOT; |
||||
|
||||
while (depth > DISK_LEAF_NODE_LEVEL) |
||||
{ |
||||
struct key *key; |
||||
nr_item = __le16_to_cpu(BLOCKHEAD (cache)->blk_nr_item); |
||||
|
||||
key = KEY (cache); |
||||
|
||||
for (i = 0; i < nr_item; i++) |
||||
{ |
||||
if (__le32_to_cpu(key->k_dir_id) > dir_id |
||||
|| (__le32_to_cpu(key->k_dir_id) == dir_id |
||||
&& (__le32_to_cpu(key->k_objectid) > objectid |
||||
|| (__le32_to_cpu(key->k_objectid) == objectid |
||||
&& (__le32_to_cpu(key->u.v1.k_offset) |
||||
| __le32_to_cpu(key->u.v1.k_uniqueness)) > 0)))) |
||||
break; |
||||
key++; |
||||
} |
||||
|
||||
#ifdef REISERDEBUG |
||||
printf (" depth=%d, i=%d/%d\n", depth, i, nr_item); |
||||
#endif /* REISERDEBUG */ |
||||
INFO->next_key_nr[depth] = (i == nr_item) ? 0 : i+1; |
||||
cache = read_tree_node (dc_block_number(&(DC (cache)[i])), --depth); |
||||
if (! cache) |
||||
return 0; |
||||
} |
||||
|
||||
/* cache == LEAF */ |
||||
nr_item = __le16_to_cpu(BLOCKHEAD (LEAF)->blk_nr_item); |
||||
ih = ITEMHEAD; |
||||
for (i = 0; i < nr_item; i++) |
||||
{ |
||||
if (__le32_to_cpu(ih->ih_key.k_dir_id) == dir_id |
||||
&& __le32_to_cpu(ih->ih_key.k_objectid) == objectid |
||||
&& __le32_to_cpu(ih->ih_key.u.v1.k_offset) == 0 |
||||
&& __le32_to_cpu(ih->ih_key.u.v1.k_uniqueness) == 0) |
||||
{ |
||||
#ifdef REISERDEBUG |
||||
printf (" depth=%d, i=%d/%d\n", depth, i, nr_item); |
||||
#endif /* REISERDEBUG */ |
||||
INFO->current_ih = ih; |
||||
INFO->current_item = &LEAF[__le16_to_cpu(ih->ih_item_location)]; |
||||
return 1; |
||||
} |
||||
ih++; |
||||
} |
||||
errnum = ERR_FSYS_CORRUPT; |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
reiserfs_read (char *buf, unsigned len) |
||||
{ |
||||
unsigned int blocksize; |
||||
unsigned int offset; |
||||
unsigned int to_read; |
||||
char *prev_buf = buf; |
||||
|
||||
#ifdef REISERDEBUG |
||||
printf ("reiserfs_read: filepos=%d len=%d, offset=%Lx\n", |
||||
filepos, len, (__u64) IH_KEY_OFFSET (INFO->current_ih) - 1); |
||||
#endif /* REISERDEBUG */ |
||||
|
||||
if (__le32_to_cpu(INFO->current_ih->ih_key.k_objectid) != INFO->fileinfo.k_objectid |
||||
|| IH_KEY_OFFSET (INFO->current_ih) > filepos + 1) |
||||
{ |
||||
search_stat (INFO->fileinfo.k_dir_id, INFO->fileinfo.k_objectid); |
||||
goto get_next_key; |
||||
} |
||||
|
||||
while (! errnum) |
||||
{ |
||||
if (__le32_to_cpu(INFO->current_ih->ih_key.k_objectid) != INFO->fileinfo.k_objectid) { |
||||
break; |
||||
} |
||||
|
||||
offset = filepos - IH_KEY_OFFSET (INFO->current_ih) + 1; |
||||
blocksize = __le16_to_cpu(INFO->current_ih->ih_item_len); |
||||
|
||||
#ifdef REISERDEBUG |
||||
printf (" loop: filepos=%d len=%d, offset=%d blocksize=%d\n", |
||||
filepos, len, offset, blocksize); |
||||
#endif /* REISERDEBUG */ |
||||
|
||||
if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_DIRECT) |
||||
&& offset < blocksize) |
||||
{ |
||||
#ifdef REISERDEBUG |
||||
printf ("direct_read: offset=%d, blocksize=%d\n", |
||||
offset, blocksize); |
||||
#endif /* REISERDEBUG */ |
||||
to_read = blocksize - offset; |
||||
if (to_read > len) |
||||
to_read = len; |
||||
|
||||
memcpy (buf, INFO->current_item + offset, to_read); |
||||
goto update_buf_len; |
||||
} |
||||
else if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_INDIRECT)) |
||||
{ |
||||
blocksize = (blocksize >> 2) << INFO->fullblocksize_shift; |
||||
#ifdef REISERDEBUG |
||||
printf ("indirect_read: offset=%d, blocksize=%d\n", |
||||
offset, blocksize); |
||||
#endif /* REISERDEBUG */ |
||||
|
||||
while (offset < blocksize) |
||||
{ |
||||
__u32 blocknr = __le32_to_cpu(((__u32 *) INFO->current_item) |
||||
[offset >> INFO->fullblocksize_shift]); |
||||
int blk_offset = offset & (INFO->blocksize-1); |
||||
to_read = INFO->blocksize - blk_offset; |
||||
if (to_read > len) |
||||
to_read = len; |
||||
|
||||
/* Journal is only for meta data. Data blocks can be read
|
||||
* directly without using block_read |
||||
*/ |
||||
reiserfs_devread (blocknr << INFO->blocksize_shift, |
||||
blk_offset, to_read, buf); |
||||
update_buf_len: |
||||
len -= to_read; |
||||
buf += to_read; |
||||
offset += to_read; |
||||
filepos += to_read; |
||||
if (len == 0) |
||||
goto done; |
||||
} |
||||
} |
||||
get_next_key: |
||||
next_key (); |
||||
} |
||||
done: |
||||
return errnum ? 0 : buf - prev_buf; |
||||
} |
||||
|
||||
|
||||
/* preconditions: reiserfs_mount already executed, therefore
|
||||
* INFO block is valid |
||||
* returns: 0 if error, nonzero iff we were able to find the file successfully |
||||
* postconditions: on a nonzero return, INFO->fileinfo contains the info |
||||
* of the file we were trying to look up, filepos is 0 and filemax is |
||||
* the size of the file. |
||||
*/ |
||||
static int |
||||
reiserfs_dir (char *dirname) |
||||
{ |
||||
struct reiserfs_de_head *de_head; |
||||
char *rest, ch; |
||||
__u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0; |
||||
#ifndef STAGE1_5 |
||||
int do_possibilities = 0; |
||||
#endif /* ! STAGE1_5 */ |
||||
char linkbuf[PATH_MAX]; /* buffer for following symbolic links */ |
||||
int link_count = 0; |
||||
int mode; |
||||
|
||||
dir_id = REISERFS_ROOT_PARENT_OBJECTID; |
||||
objectid = REISERFS_ROOT_OBJECTID; |
||||
|
||||
while (1) |
||||
{ |
||||
#ifdef REISERDEBUG |
||||
printf ("dirname=%s\n", dirname); |
||||
#endif /* REISERDEBUG */ |
||||
|
||||
/* Search for the stat info first. */ |
||||
if (! search_stat (dir_id, objectid)) |
||||
return 0; |
||||
|
||||
#ifdef REISERDEBUG |
||||
printf ("sd_mode=%x sd_size=%d\n", |
||||
stat_data_v1(INFO->current_ih) ? sd_v1_mode((struct stat_data_v1 *) INFO->current_item) : |
||||
sd_v2_mode((struct stat_data *) (INFO->current_item)), |
||||
stat_data_v1(INFO->current_ih) ? sd_v1_size((struct stat_data_v1 *) INFO->current_item) : |
||||
sd_v2_size((struct stat_data *) INFO->current_item) |
||||
); |
||||
|
||||
#endif /* REISERDEBUG */ |
||||
mode = stat_data_v1(INFO->current_ih) ? |
||||
sd_v1_mode((struct stat_data_v1 *) INFO->current_item) : |
||||
sd_v2_mode((struct stat_data *) INFO->current_item); |
||||
|
||||
/* If we've got a symbolic link, then chase it. */ |
||||
if (S_ISLNK (mode)) |
||||
{ |
||||
unsigned int len; |
||||
if (++link_count > MAX_LINK_COUNT) |
||||
{ |
||||
errnum = ERR_SYMLINK_LOOP; |
||||
return 0; |
||||
} |
||||
|
||||
/* Get the symlink size. */ |
||||
filemax = stat_data_v1(INFO->current_ih) ? |
||||
sd_v1_size((struct stat_data_v1 *) INFO->current_item) : |
||||
sd_v2_size((struct stat_data *) INFO->current_item); |
||||
|
||||
/* Find out how long our remaining name is. */ |
||||
len = 0; |
||||
while (dirname[len] && !isspace (dirname[len])) |
||||
len++; |
||||
|
||||
if (filemax + len > sizeof (linkbuf) - 1) |
||||
{ |
||||
errnum = ERR_FILELENGTH; |
||||
return 0; |
||||
} |
||||
|
||||
/* Copy the remaining name to the end of the symlink data.
|
||||
Note that DIRNAME and LINKBUF may overlap! */ |
||||
memmove (linkbuf + filemax, dirname, len+1); |
||||
|
||||
INFO->fileinfo.k_dir_id = dir_id; |
||||
INFO->fileinfo.k_objectid = objectid; |
||||
filepos = 0; |
||||
if (! next_key () |
||||
|| reiserfs_read (linkbuf, filemax) != filemax) |
||||
{ |
||||
if (! errnum) |
||||
errnum = ERR_FSYS_CORRUPT; |
||||
return 0; |
||||
} |
||||
|
||||
#ifdef REISERDEBUG |
||||
printf ("symlink=%s\n", linkbuf); |
||||
#endif /* REISERDEBUG */ |
||||
|
||||
dirname = linkbuf; |
||||
if (*dirname == '/') |
||||
{ |
||||
/* It's an absolute link, so look it up in root. */ |
||||
dir_id = REISERFS_ROOT_PARENT_OBJECTID; |
||||
objectid = REISERFS_ROOT_OBJECTID; |
||||
} |
||||
else |
||||
{ |
||||
/* Relative, so look it up in our parent directory. */ |
||||
dir_id = parent_dir_id; |
||||
objectid = parent_objectid; |
||||
} |
||||
|
||||
/* Now lookup the new name. */ |
||||
continue; |
||||
} |
||||
|
||||
/* if we have a real file (and we're not just printing possibilities),
|
||||
then this is where we want to exit */ |
||||
|
||||
if (! *dirname || isspace (*dirname)) |
||||
{ |
||||
if (! S_ISREG (mode)) |
||||
{ |
||||
errnum = ERR_BAD_FILETYPE; |
||||
return 0; |
||||
} |
||||
|
||||
filepos = 0; |
||||
filemax = stat_data_v1(INFO->current_ih) ? |
||||
sd_v1_size((struct stat_data_v1 *) INFO->current_item) : |
||||
sd_v2_size((struct stat_data *) INFO->current_item); |
||||
#if 0 |
||||
/* If this is a new stat data and size is > 4GB set filemax to
|
||||
* maximum |
||||
*/ |
||||
if (__le16_to_cpu(INFO->current_ih->ih_version) == ITEM_VERSION_2 |
||||
&& sd_size_hi((struct stat_data *) INFO->current_item) > 0) |
||||
filemax = 0xffffffff; |
||||
#endif |
||||
INFO->fileinfo.k_dir_id = dir_id; |
||||
INFO->fileinfo.k_objectid = objectid; |
||||
return next_key (); |
||||
} |
||||
|
||||
/* continue with the file/directory name interpretation */ |
||||
while (*dirname == '/') |
||||
dirname++; |
||||
if (! S_ISDIR (mode)) |
||||
{ |
||||
errnum = ERR_BAD_FILETYPE; |
||||
return 0; |
||||
} |
||||
for (rest = dirname; (ch = *rest) && ! isspace (ch) && ch != '/'; rest++); |
||||
*rest = 0; |
||||
|
||||
# ifndef STAGE1_5 |
||||
if (print_possibilities && ch != '/') |
||||
do_possibilities = 1; |
||||
# endif /* ! STAGE1_5 */ |
||||
|
||||
while (1) |
||||
{ |
||||
char *name_end; |
||||
int num_entries; |
||||
|
||||
if (! next_key ()) |
||||
return 0; |
||||
#ifdef REISERDEBUG |
||||
printf ("ih: key %d:%d:%d:%d version:%d\n", |
||||
__le32_to_cpu(INFO->current_ih->ih_key.k_dir_id), |
||||
__le32_to_cpu(INFO->current_ih->ih_key.k_objectid), |
||||
__le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_offset), |
||||
__le32_to_cpu(INFO->current_ih->ih_key.u.v1.k_uniqueness), |
||||
__le16_to_cpu(INFO->current_ih->ih_version)); |
||||
#endif /* REISERDEBUG */ |
||||
|
||||
if (__le32_to_cpu(INFO->current_ih->ih_key.k_objectid) != objectid) |
||||
break; |
||||
|
||||
name_end = INFO->current_item + __le16_to_cpu(INFO->current_ih->ih_item_len); |
||||
de_head = (struct reiserfs_de_head *) INFO->current_item; |
||||
num_entries = __le16_to_cpu(INFO->current_ih->u.ih_entry_count); |
||||
while (num_entries > 0) |
||||
{ |
||||
char *filename = INFO->current_item + deh_location(de_head); |
||||
char tmp = *name_end; |
||||
if ((deh_state(de_head) & DEH_Visible)) |
||||
{ |
||||
int cmp; |
||||
/* Directory names in ReiserFS are not null
|
||||
* terminated. We write a temporary 0 behind it. |
||||
* NOTE: that this may overwrite the first block in |
||||
* the tree cache. That doesn't hurt as long as we |
||||
* don't call next_key () in between. |
||||
*/ |
||||
*name_end = 0; |
||||
cmp = substring (dirname, filename); |
||||
*name_end = tmp; |
||||
# ifndef STAGE1_5 |
||||
if (do_possibilities) |
||||
{ |
||||
if (cmp <= 0) |
||||
{ |
||||
char fn[PATH_MAX]; |
||||
struct fsys_reiser_info info_save; |
||||
|
||||
if (print_possibilities > 0) |
||||
print_possibilities = -print_possibilities; |
||||
*name_end = 0; |
||||
strcpy(fn, filename); |
||||
*name_end = tmp; |
||||
|
||||
/* If NAME is "." or "..", do not count it. */ |
||||
if (strcmp (fn, ".") != 0 && strcmp (fn, "..") != 0) { |
||||
memcpy(&info_save, INFO, sizeof(struct fsys_reiser_info)); |
||||
search_stat (deh_dir_id(de_head), deh_objectid(de_head)); |
||||
sd_print_item(INFO->current_ih, INFO->current_item); |
||||
printf(" %s\n", fn); |
||||
search_stat (dir_id, objectid); |
||||
memcpy(INFO, &info_save, sizeof(struct fsys_reiser_info)); |
||||
} |
||||
} |
||||
} |
||||
else |
||||
# endif /* ! STAGE1_5 */ |
||||
if (cmp == 0) |
||||
goto found; |
||||
} |
||||
/* The beginning of this name marks the end of the next name.
|
||||
*/ |
||||
name_end = filename; |
||||
de_head++; |
||||
num_entries--; |
||||
} |
||||
} |
||||
|
||||
# ifndef STAGE1_5 |
||||
if (print_possibilities < 0) |
||||
return 1; |
||||
# endif /* ! STAGE1_5 */ |
||||
|
||||
errnum = ERR_FILE_NOT_FOUND; |
||||
*rest = ch; |
||||
return 0; |
||||
|
||||
found: |
||||
*rest = ch; |
||||
dirname = rest; |
||||
|
||||
parent_dir_id = dir_id; |
||||
parent_objectid = objectid; |
||||
dir_id = deh_dir_id(de_head); |
||||
objectid = deh_objectid(de_head); |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* U-Boot interface functions |
||||
*/ |
||||
|
||||
/*
|
||||
* List given directory |
||||
* |
||||
* RETURN: 0 - OK, else grub_error_t errnum |
||||
*/ |
||||
int |
||||
reiserfs_ls (char *dirname) |
||||
{ |
||||
char *dir_slash; |
||||
int res; |
||||
|
||||
errnum = 0; |
||||
dir_slash = malloc(strlen(dirname) + 1); |
||||
if (dir_slash == NULL) { |
||||
return ERR_NUMBER_OVERFLOW; |
||||
} |
||||
strcpy(dir_slash, dirname); |
||||
/* add "/" to the directory name */ |
||||
strcat(dir_slash, "/"); |
||||
|
||||
print_possibilities = 1; |
||||
res = reiserfs_dir (dir_slash); |
||||
free(dir_slash); |
||||
if (!res || errnum) { |
||||
return errnum; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/*
|
||||
* Open file for reading |
||||
* |
||||
* RETURN: >0 - OK, size of opened file |
||||
* <0 - ERROR -grub_error_t errnum |
||||
*/ |
||||
int |
||||
reiserfs_open (char *filename) |
||||
{ |
||||
/* open the file */ |
||||
errnum = 0; |
||||
print_possibilities = 0; |
||||
if (!reiserfs_dir (filename) || errnum) { |
||||
return -errnum; |
||||
} |
||||
return filemax; |
||||
} |
||||
|
||||
#endif /* CFG_CMD_REISER */ |
@ -0,0 +1,521 @@ |
||||
/*
|
||||
* Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README |
||||
* |
||||
* GRUB -- GRand Unified Bootloader |
||||
* Copyright (C) 2000, 2001 Free Software Foundation, Inc. |
||||
* |
||||
* (C) Copyright 2003 - 2004 |
||||
* Sysgo AG, <www.elinos.com>, Pavel Bartusek <pba@sysgo.com> |
||||
* |
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
/* An implementation for the ReiserFS filesystem ported from GRUB.
|
||||
* Some parts of this code (mainly the structures and defines) are |
||||
* from the original reiser fs code, as found in the linux kernel. |
||||
*/ |
||||
|
||||
#ifndef __BYTE_ORDER |
||||
#if defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) |
||||
#define __BYTE_ORDER __LITTLE_ENDIAN |
||||
#elif defined(__BIG_ENDIAN) && !defined(__LITTLE_ENDIAN) |
||||
#define __BYTE_ORDER __BIG_ENDIAN |
||||
#else |
||||
#error "unable to define __BYTE_ORDER" |
||||
#endif |
||||
#endif /* not __BYTE_ORDER */ |
||||
|
||||
#define FSYS_BUFLEN 0x8000 |
||||
#define FSYS_BUF fsys_buf |
||||
|
||||
/* This is the new super block of a journaling reiserfs system */ |
||||
struct reiserfs_super_block |
||||
{ |
||||
__u32 s_block_count; /* blocks count */ |
||||
__u32 s_free_blocks; /* free blocks count */ |
||||
__u32 s_root_block; /* root block number */ |
||||
__u32 s_journal_block; /* journal block number */ |
||||
__u32 s_journal_dev; /* journal device number */ |
||||
__u32 s_journal_size; /* size of the journal on FS creation. used to make sure they don't overflow it */ |
||||
__u32 s_journal_trans_max; /* max number of blocks in a transaction. */ |
||||
__u32 s_journal_magic; /* random value made on fs creation */ |
||||
__u32 s_journal_max_batch; /* max number of blocks to batch into a trans */ |
||||
__u32 s_journal_max_commit_age; /* in seconds, how old can an async commit be */ |
||||
__u32 s_journal_max_trans_age; /* in seconds, how old can a transaction be */ |
||||
__u16 s_blocksize; /* block size */ |
||||
__u16 s_oid_maxsize; /* max size of object id array */ |
||||
__u16 s_oid_cursize; /* current size of object id array */ |
||||
__u16 s_state; /* valid or error */ |
||||
char s_magic[16]; /* reiserfs magic string indicates that file system is reiserfs */ |
||||
__u16 s_tree_height; /* height of disk tree */ |
||||
__u16 s_bmap_nr; /* amount of bitmap blocks needed to address each block of file system */ |
||||
__u16 s_version; |
||||
char s_unused[128]; /* zero filled by mkreiserfs */ |
||||
}; |
||||
|
||||
|
||||
#define sb_root_block(sbp) (__le32_to_cpu((sbp)->s_root_block)) |
||||
#define sb_journal_block(sbp) (__le32_to_cpu((sbp)->s_journal_block)) |
||||
#define set_sb_journal_block(sbp,v) ((sbp)->s_journal_block = __cpu_to_le32(v)) |
||||
#define sb_journal_size(sbp) (__le32_to_cpu((sbp)->s_journal_size)) |
||||
#define sb_blocksize(sbp) (__le16_to_cpu((sbp)->s_blocksize)) |
||||
#define set_sb_blocksize(sbp,v) ((sbp)->s_blocksize = __cpu_to_le16(v)) |
||||
#define sb_version(sbp) (__le16_to_cpu((sbp)->s_version)) |
||||
#define set_sb_version(sbp,v) ((sbp)->s_version = __cpu_to_le16(v)) |
||||
|
||||
|
||||
#define REISERFS_MAX_SUPPORTED_VERSION 2 |
||||
#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" |
||||
#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" |
||||
#define REISER3FS_SUPER_MAGIC_STRING "ReIsEr3Fs" |
||||
|
||||
#define MAX_HEIGHT 7 |
||||
|
||||
/* must be correct to keep the desc and commit structs at 4k */ |
||||
#define JOURNAL_TRANS_HALF 1018 |
||||
|
||||
/* first block written in a commit. */ |
||||
struct reiserfs_journal_desc { |
||||
__u32 j_trans_id; /* id of commit */ |
||||
__u32 j_len; /* length of commit. len +1 is the commit block */ |
||||
__u32 j_mount_id; /* mount id of this trans*/ |
||||
__u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the first blocks */ |
||||
char j_magic[12]; |
||||
}; |
||||
|
||||
/* last block written in a commit */ |
||||
struct reiserfs_journal_commit { |
||||
__u32 j_trans_id; /* must match j_trans_id from the desc block */ |
||||
__u32 j_len; /* ditto */ |
||||
__u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the last blocks */ |
||||
char j_digest[16]; /* md5 sum of all the blocks involved, including desc and commit. not used, kill it */ |
||||
}; |
||||
|
||||
/* this header block gets written whenever a transaction is considered
|
||||
fully flushed, and is more recent than the last fully flushed |
||||
transaction. |
||||
fully flushed means all the log blocks and all the real blocks are |
||||
on disk, and this transaction does not need to be replayed. |
||||
*/ |
||||
struct reiserfs_journal_header { |
||||
/* id of last fully flushed transaction */ |
||||
__u32 j_last_flush_trans_id; |
||||
/* offset in the log of where to start replay after a crash */ |
||||
__u32 j_first_unflushed_offset; |
||||
/* mount id to detect very old transactions */ |
||||
__u32 j_mount_id; |
||||
}; |
||||
|
||||
/* magic string to find desc blocks in the journal */ |
||||
#define JOURNAL_DESC_MAGIC "ReIsErLB" |
||||
|
||||
|
||||
/*
|
||||
* directories use this key as well as old files |
||||
*/ |
||||
struct offset_v1 |
||||
{ |
||||
/*
|
||||
* for regular files this is the offset to the first byte of the |
||||
* body, contained in the object-item, as measured from the start of |
||||
* the entire body of the object. |
||||
* |
||||
* for directory entries, k_offset consists of hash derived from |
||||
* hashing the name and using few bits (23 or more) of the resulting |
||||
* hash, and generation number that allows distinguishing names with |
||||
* hash collisions. If number of collisions overflows generation |
||||
* number, we return EEXIST. High order bit is 0 always |
||||
*/ |
||||
__u32 k_offset; |
||||
__u32 k_uniqueness; |
||||
}; |
||||
|
||||
struct offset_v2 { |
||||
/*
|
||||
* for regular files this is the offset to the first byte of the |
||||
* body, contained in the object-item, as measured from the start of |
||||
* the entire body of the object. |
||||
* |
||||
* for directory entries, k_offset consists of hash derived from |
||||
* hashing the name and using few bits (23 or more) of the resulting |
||||
* hash, and generation number that allows distinguishing names with |
||||
* hash collisions. If number of collisions overflows generation |
||||
* number, we return EEXIST. High order bit is 0 always |
||||
*/ |
||||
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD) |
||||
/* little endian version */ |
||||
__u64 k_offset:60; |
||||
__u64 k_type: 4; |
||||
#elif defined(__BIG_ENDIAN_BITFIELD) |
||||
/* big endian version */ |
||||
__u64 k_type: 4; |
||||
__u64 k_offset:60; |
||||
#else |
||||
#error "__LITTLE_ENDIAN_BITFIELD or __BIG_ENDIAN_BITFIELD must be defined" |
||||
#endif |
||||
} __attribute__ ((__packed__)); |
||||
|
||||
#define TYPE_MAXTYPE 3 |
||||
#define TYPE_ANY 15 |
||||
|
||||
#if (__BYTE_ORDER == __BIG_ENDIAN) |
||||
typedef union { |
||||
struct offset_v2 offset_v2; |
||||
__u64 linear; |
||||
} __attribute__ ((__packed__)) offset_v2_esafe_overlay; |
||||
|
||||
static inline __u16 offset_v2_k_type( const struct offset_v2 *v2 ) |
||||
{ |
||||
offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2; |
||||
tmp.linear = __le64_to_cpu( tmp.linear ); |
||||
return (tmp.offset_v2.k_type <= TYPE_MAXTYPE)?tmp.offset_v2.k_type:TYPE_ANY; |
||||
} |
||||
|
||||
static inline loff_t offset_v2_k_offset( const struct offset_v2 *v2 ) |
||||
{ |
||||
offset_v2_esafe_overlay tmp = *(const offset_v2_esafe_overlay *)v2; |
||||
tmp.linear = __le64_to_cpu( tmp.linear ); |
||||
return tmp.offset_v2.k_offset; |
||||
} |
||||
#elif (__BYTE_ORDER == __LITTLE_ENDIAN) |
||||
# define offset_v2_k_type(v2) ((v2)->k_type) |
||||
# define offset_v2_k_offset(v2) ((v2)->k_offset) |
||||
#else |
||||
#error "__BYTE_ORDER must be __LITTLE_ENDIAN or __BIG_ENDIAN" |
||||
#endif |
||||
|
||||
struct key |
||||
{ |
||||
/* packing locality: by default parent directory object id */ |
||||
__u32 k_dir_id; |
||||
/* object identifier */ |
||||
__u32 k_objectid; |
||||
/* the offset and node type (old and new form) */ |
||||
union |
||||
{ |
||||
struct offset_v1 v1; |
||||
struct offset_v2 v2; |
||||
} |
||||
u; |
||||
}; |
||||
|
||||
#define KEY_SIZE (sizeof (struct key)) |
||||
|
||||
/* Header of a disk block. More precisely, header of a formatted leaf
|
||||
or internal node, and not the header of an unformatted node. */ |
||||
struct block_head |
||||
{ |
||||
__u16 blk_level; /* Level of a block in the tree. */ |
||||
__u16 blk_nr_item; /* Number of keys/items in a block. */ |
||||
__u16 blk_free_space; /* Block free space in bytes. */ |
||||
struct key blk_right_delim_key; /* Right delimiting key for this block (supported for leaf level nodes
|
||||
only) */ |
||||
}; |
||||
#define BLKH_SIZE (sizeof (struct block_head)) |
||||
#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */ |
||||
|
||||
struct item_head |
||||
{ |
||||
/* Everything in the tree is found by searching for it based on
|
||||
* its key.*/ |
||||
struct key ih_key; |
||||
union { |
||||
/* The free space in the last unformatted node of an
|
||||
indirect item if this is an indirect item. This |
||||
equals 0xFFFF iff this is a direct item or stat data |
||||
item. Note that the key, not this field, is used to |
||||
determine the item type, and thus which field this |
||||
union contains. */ |
||||
__u16 ih_free_space; |
||||
/* Iff this is a directory item, this field equals the
|
||||
number of directory entries in the directory item. */ |
||||
__u16 ih_entry_count; |
||||
} __attribute__ ((__packed__)) u; |
||||
__u16 ih_item_len; /* total size of the item body */ |
||||
__u16 ih_item_location; /* an offset to the item body
|
||||
* within the block */ |
||||
__u16 ih_version; /* 0 for all old items, 2 for new
|
||||
ones. Highest bit is set by fsck |
||||
temporary, cleaned after all |
||||
done */ |
||||
} __attribute__ ((__packed__)); |
||||
|
||||
/* size of item header */ |
||||
#define IH_SIZE (sizeof (struct item_head)) |
||||
|
||||
#define ITEM_VERSION_1 0 |
||||
#define ITEM_VERSION_2 1 |
||||
|
||||
#define ih_version(ih) (__le16_to_cpu((ih)->ih_version)) |
||||
|
||||
#define IH_KEY_OFFSET(ih) (ih_version(ih) == ITEM_VERSION_1 \ |
||||
? __le32_to_cpu((ih)->ih_key.u.v1.k_offset) \
|
||||
: offset_v2_k_offset(&((ih)->ih_key.u.v2))) |
||||
|
||||
#define IH_KEY_ISTYPE(ih, type) (ih_version(ih) == ITEM_VERSION_1 \ |
||||
? __le32_to_cpu((ih)->ih_key.u.v1.k_uniqueness) == V1_##type \
|
||||
: offset_v2_k_type(&((ih)->ih_key.u.v2)) == V2_##type) |
||||
|
||||
/***************************************************************************/ |
||||
/* DISK CHILD */ |
||||
/***************************************************************************/ |
||||
/* Disk child pointer: The pointer from an internal node of the tree
|
||||
to a node that is on disk. */ |
||||
struct disk_child { |
||||
__u32 dc_block_number; /* Disk child's block number. */ |
||||
__u16 dc_size; /* Disk child's used space. */ |
||||
__u16 dc_reserved; |
||||
}; |
||||
|
||||
#define DC_SIZE (sizeof(struct disk_child)) |
||||
#define dc_block_number(dc_p) (__le32_to_cpu((dc_p)->dc_block_number)) |
||||
|
||||
|
||||
//
|
||||
// old stat data is 32 bytes long. We are going to distinguish new one by
|
||||
// different size
|
||||
//
|
||||
struct stat_data_v1 |
||||
{ |
||||
__u16 sd_mode; /* file type, permissions */ |
||||
__u16 sd_nlink; /* number of hard links */ |
||||
__u16 sd_uid; /* owner */ |
||||
__u16 sd_gid; /* group */ |
||||
__u32 sd_size; /* file size */ |
||||
__u32 sd_atime; /* time of last access */ |
||||
__u32 sd_mtime; /* time file was last modified */ |
||||
__u32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ |
||||
union { |
||||
__u32 sd_rdev; |
||||
__u32 sd_blocks; /* number of blocks file uses */ |
||||
} __attribute__ ((__packed__)) u; |
||||
__u32 sd_first_direct_byte; /* first byte of file which is stored
|
||||
in a direct item: except that if it |
||||
equals 1 it is a symlink and if it |
||||
equals ~(__u32)0 there is no |
||||
direct item. The existence of this |
||||
field really grates on me. Let's |
||||
replace it with a macro based on |
||||
sd_size and our tail suppression |
||||
policy. Someday. -Hans */ |
||||
} __attribute__ ((__packed__)); |
||||
|
||||
#define stat_data_v1(ih) (ih_version(ih) == ITEM_VERSION_1) |
||||
//#define sd_v1_mode(sdp) (__le16_to_cpu((sdp)->sd_mode))
|
||||
#define sd_v1_mode(sdp) ((sdp)->sd_mode) |
||||
#define sd_v1_nlink(sdp) (__le16_to_cpu((sdp)->sd_nlink)) |
||||
#define sd_v1_uid(sdp) (__le16_to_cpu((sdp)->sd_uid)) |
||||
#define sd_v1_gid(sdp) (__le16_to_cpu((sdp)->sd_gid)) |
||||
#define sd_v1_size(sdp) (__le32_to_cpu((sdp)->sd_size)) |
||||
#define sd_v1_mtime(sdp) (__le32_to_cpu((sdp)->sd_mtime)) |
||||
|
||||
/* Stat Data on disk (reiserfs version of UFS disk inode minus the
|
||||
address blocks) */ |
||||
struct stat_data { |
||||
__u16 sd_mode; /* file type, permissions */ |
||||
__u16 sd_attrs; /* persistent inode flags */ |
||||
__u32 sd_nlink; /* number of hard links */ |
||||
__u64 sd_size; /* file size */ |
||||
__u32 sd_uid; /* owner */ |
||||
__u32 sd_gid; /* group */ |
||||
__u32 sd_atime; /* time of last access */ |
||||
__u32 sd_mtime; /* time file was last modified */ |
||||
__u32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ |
||||
__u32 sd_blocks; |
||||
union { |
||||
__u32 sd_rdev; |
||||
__u32 sd_generation; |
||||
//__u32 sd_first_direct_byte;
|
||||
/* first byte of file which is stored in a
|
||||
direct item: except that if it equals 1 |
||||
it is a symlink and if it equals |
||||
~(__u32)0 there is no direct item. The |
||||
existence of this field really grates |
||||
on me. Let's replace it with a macro |
||||
based on sd_size and our tail |
||||
suppression policy? */ |
||||
} __attribute__ ((__packed__)) u; |
||||
} __attribute__ ((__packed__)); |
||||
|
||||
#define stat_data_v2(ih) (ih_version(ih) == ITEM_VERSION_2) |
||||
#define sd_v2_mode(sdp) (__le16_to_cpu((sdp)->sd_mode)) |
||||
#define sd_v2_nlink(sdp) (__le32_to_cpu((sdp)->sd_nlink)) |
||||
#define sd_v2_size(sdp) (__le64_to_cpu((sdp)->sd_size)) |
||||
#define sd_v2_uid(sdp) (__le32_to_cpu((sdp)->sd_uid)) |
||||
#define sd_v2_gid(sdp) (__le32_to_cpu((sdp)->sd_gid)) |
||||
#define sd_v2_mtime(sdp) (__le32_to_cpu((sdp)->sd_mtime)) |
||||
|
||||
#define sd_mode(sdp) (__le16_to_cpu((sdp)->sd_mode)) |
||||
#define sd_size(sdp) (__le32_to_cpu((sdp)->sd_size)) |
||||
#define sd_size_hi(sdp) (__le32_to_cpu((sdp)->sd_size_hi)) |
||||
|
||||
struct reiserfs_de_head |
||||
{ |
||||
__u32 deh_offset; /* third component of the directory entry key */ |
||||
__u32 deh_dir_id; /* objectid of the parent directory of the
|
||||
object, that is referenced by directory entry */ |
||||
__u32 deh_objectid;/* objectid of the object, that is referenced by
|
||||
directory entry */ |
||||
__u16 deh_location;/* offset of name in the whole item */ |
||||
__u16 deh_state; /* whether 1) entry contains stat data (for
|
||||
future), and 2) whether entry is hidden |
||||
(unlinked) */ |
||||
}; |
||||
|
||||
#define DEH_SIZE (sizeof (struct reiserfs_de_head)) |
||||
#define deh_offset(p_deh) (__le32_to_cpu((p_deh)->deh_offset)) |
||||
#define deh_dir_id(p_deh) (__le32_to_cpu((p_deh)->deh_dir_id)) |
||||
#define deh_objectid(p_deh) (__le32_to_cpu((p_deh)->deh_objectid)) |
||||
#define deh_location(p_deh) (__le16_to_cpu((p_deh)->deh_location)) |
||||
#define deh_state(p_deh) (__le16_to_cpu((p_deh)->deh_state)) |
||||
|
||||
|
||||
#define DEH_Statdata (1 << 0) /* not used now */ |
||||
#define DEH_Visible (1 << 2) |
||||
|
||||
#define SD_OFFSET 0 |
||||
#define SD_UNIQUENESS 0 |
||||
#define DOT_OFFSET 1 |
||||
#define DOT_DOT_OFFSET 2 |
||||
#define DIRENTRY_UNIQUENESS 500 |
||||
|
||||
#define V1_TYPE_STAT_DATA 0x0 |
||||
#define V1_TYPE_DIRECT 0xffffffff |
||||
#define V1_TYPE_INDIRECT 0xfffffffe |
||||
#define V1_TYPE_DIRECTORY_MAX 0xfffffffd |
||||
#define V2_TYPE_STAT_DATA 0 |
||||
#define V2_TYPE_INDIRECT 1 |
||||
#define V2_TYPE_DIRECT 2 |
||||
#define V2_TYPE_DIRENTRY 3 |
||||
|
||||
#define REISERFS_ROOT_OBJECTID 2 |
||||
#define REISERFS_ROOT_PARENT_OBJECTID 1 |
||||
#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) |
||||
/* the spot for the super in versions 3.5 - 3.5.11 (inclusive) */ |
||||
#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024) |
||||
#define REISERFS_OLD_BLOCKSIZE 4096 |
||||
|
||||
#define S_ISREG(mode) (((mode) & 0170000) == 0100000) |
||||
#define S_ISDIR(mode) (((mode) & 0170000) == 0040000) |
||||
#define S_ISLNK(mode) (((mode) & 0170000) == 0120000) |
||||
|
||||
#define PATH_MAX 1024 /* include/linux/limits.h */ |
||||
#define MAX_LINK_COUNT 5 /* number of symbolic links to follow */ |
||||
|
||||
/* The size of the node cache */ |
||||
#define FSYSREISER_CACHE_SIZE 24*1024 |
||||
#define FSYSREISER_MIN_BLOCKSIZE SECTOR_SIZE |
||||
#define FSYSREISER_MAX_BLOCKSIZE FSYSREISER_CACHE_SIZE / 3 |
||||
|
||||
/* Info about currently opened file */ |
||||
struct fsys_reiser_fileinfo |
||||
{ |
||||
__u32 k_dir_id; |
||||
__u32 k_objectid; |
||||
}; |
||||
|
||||
/* In memory info about the currently mounted filesystem */ |
||||
struct fsys_reiser_info |
||||
{ |
||||
/* The last read item head */ |
||||
struct item_head *current_ih; |
||||
/* The last read item */ |
||||
char *current_item; |
||||
/* The information for the currently opened file */ |
||||
struct fsys_reiser_fileinfo fileinfo; |
||||
/* The start of the journal */ |
||||
__u32 journal_block; |
||||
/* The size of the journal */ |
||||
__u32 journal_block_count; |
||||
/* The first valid descriptor block in journal
|
||||
(relative to journal_block) */ |
||||
__u32 journal_first_desc; |
||||
|
||||
/* The ReiserFS version. */ |
||||
__u16 version; |
||||
/* The current depth of the reiser tree. */ |
||||
__u16 tree_depth; |
||||
/* SECTOR_SIZE << blocksize_shift == blocksize. */ |
||||
__u8 blocksize_shift; |
||||
/* 1 << full_blocksize_shift == blocksize. */ |
||||
__u8 fullblocksize_shift; |
||||
/* The reiserfs block size (must be a power of 2) */ |
||||
__u16 blocksize; |
||||
/* The number of cached tree nodes */ |
||||
__u16 cached_slots; |
||||
/* The number of valid transactions in journal */ |
||||
__u16 journal_transactions; |
||||
|
||||
unsigned int blocks[MAX_HEIGHT]; |
||||
unsigned int next_key_nr[MAX_HEIGHT]; |
||||
}; |
||||
|
||||
/* The cached s+tree blocks in FSYS_BUF, see below
|
||||
* for a more detailed description. |
||||
*/ |
||||
#define ROOT ((char *) ((int) FSYS_BUF)) |
||||
#define CACHE(i) (ROOT + ((i) << INFO->fullblocksize_shift)) |
||||
#define LEAF CACHE (DISK_LEAF_NODE_LEVEL) |
||||
|
||||
#define BLOCKHEAD(cache) ((struct block_head *) cache) |
||||
#define ITEMHEAD ((struct item_head *) ((int) LEAF + BLKH_SIZE)) |
||||
#define KEY(cache) ((struct key *) ((int) cache + BLKH_SIZE)) |
||||
#define DC(cache) ((struct disk_child *) \ |
||||
((int) cache + BLKH_SIZE + KEY_SIZE * nr_item)) |
||||
/* The fsys_reiser_info block.
|
||||
*/ |
||||
#define INFO \ |
||||
((struct fsys_reiser_info *) ((int) FSYS_BUF + FSYSREISER_CACHE_SIZE)) |
||||
/*
|
||||
* The journal cache. For each transaction it contains the number of |
||||
* blocks followed by the real block numbers of this transaction. |
||||
* |
||||
* If the block numbers of some transaction won't fit in this space, |
||||
* this list is stopped with a 0xffffffff marker and the remaining |
||||
* uncommitted transactions aren't cached. |
||||
*/ |
||||
#define JOURNAL_START ((__u32 *) (INFO + 1)) |
||||
#define JOURNAL_END ((__u32 *) (FSYS_BUF + FSYS_BUFLEN)) |
||||
|
||||
|
||||
static __inline__ unsigned long |
||||
log2 (unsigned long word) |
||||
{ |
||||
#ifdef __I386__ |
||||
__asm__ ("bsfl %1,%0" |
||||
: "=r" (word) |
||||
: "r" (word)); |
||||
return word; |
||||
#else |
||||
int i; |
||||
|
||||
for(i=0; i<(8*sizeof(word)); i++) |
||||
if ((1<<i) & word) |
||||
return i; |
||||
|
||||
return 0; |
||||
#endif |
||||
} |
||||
|
||||
static __inline__ int |
||||
is_power_of_two (unsigned long word) |
||||
{ |
||||
return (word & -word) == word; |
||||
} |
||||
|
||||
extern const char *bb_mode_string(int mode); |
||||
extern int reiserfs_devread (int sector, int byte_offset, int byte_len, char *buf); |
@ -0,0 +1,83 @@ |
||||
/*
|
||||
* Copyright 2000-2002 by Hans Reiser, licensing governed by reiserfs/README |
||||
* |
||||
* GRUB -- GRand Unified Bootloader |
||||
* Copyright (C) 2000, 2001 Free Software Foundation, Inc. |
||||
* |
||||
* (C) Copyright 2003 Sysgo Real-Time Solutions, AG <www.elinos.com> |
||||
* Pavel Bartusek <pba@sysgo.de> |
||||
* |
||||
* 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. |
||||
*/ |
||||
|
||||
/* An implementation for the ReiserFS filesystem ported from GRUB.
|
||||
* Some parts of this code (mainly the structures and defines) are |
||||
* from the original reiser fs code, as found in the linux kernel. |
||||
*/ |
||||
|
||||
|
||||
#define SECTOR_SIZE 0x200 |
||||
#define SECTOR_BITS 9 |
||||
|
||||
/* Error codes */ |
||||
typedef enum |
||||
{ |
||||
ERR_NONE = 0, |
||||
ERR_BAD_FILENAME, |
||||
ERR_BAD_FILETYPE, |
||||
ERR_BAD_GZIP_DATA, |
||||
ERR_BAD_GZIP_HEADER, |
||||
ERR_BAD_PART_TABLE, |
||||
ERR_BAD_VERSION, |
||||
ERR_BELOW_1MB, |
||||
ERR_BOOT_COMMAND, |
||||
ERR_BOOT_FAILURE, |
||||
ERR_BOOT_FEATURES, |
||||
ERR_DEV_FORMAT, |
||||
ERR_DEV_VALUES, |
||||
ERR_EXEC_FORMAT, |
||||
ERR_FILELENGTH, |
||||
ERR_FILE_NOT_FOUND, |
||||
ERR_FSYS_CORRUPT, |
||||
ERR_FSYS_MOUNT, |
||||
ERR_GEOM, |
||||
ERR_NEED_LX_KERNEL, |
||||
ERR_NEED_MB_KERNEL, |
||||
ERR_NO_DISK, |
||||
ERR_NO_PART, |
||||
ERR_NUMBER_PARSING, |
||||
ERR_OUTSIDE_PART, |
||||
ERR_READ, |
||||
ERR_SYMLINK_LOOP, |
||||
ERR_UNRECOGNIZED, |
||||
ERR_WONT_FIT, |
||||
ERR_WRITE, |
||||
ERR_BAD_ARGUMENT, |
||||
ERR_UNALIGNED, |
||||
ERR_PRIVILEGED, |
||||
ERR_DEV_NEED_INIT, |
||||
ERR_NO_DISK_SPACE, |
||||
ERR_NUMBER_OVERFLOW, |
||||
|
||||
MAX_ERR_NUM |
||||
} reiserfs_error_t; |
||||
|
||||
|
||||
extern int reiserfs_set_blk_dev(block_dev_desc_t *rbdd, int part); |
||||
extern int reiserfs_ls (char *dirname); |
||||
extern int reiserfs_open (char *filename); |
||||
extern int reiserfs_read (char *buf, unsigned len); |
||||
extern int reiserfs_mount (unsigned part_length); |
||||
|
Loading…
Reference in new issue