mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
* Patch by Pavel Bartusek, 21 Mar 2004
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 datasheet
This commit is contained in:
parent
6fb6af6dc9
commit
518e2e1ae3
15 changed files with 2239 additions and 8 deletions
|
@ -2,6 +2,13 @@
|
|||
Changes for U-Boot 1.0.2:
|
||||
======================================================================
|
||||
|
||||
* Patch by Pavel Bartusek, 21 Mar 2004
|
||||
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 datasheet
|
||||
|
||||
* Patch by Stephen Williams, 19 March 2004
|
||||
Increase speed of sector reads from SystemACE,
|
||||
shorten poll timeout and remove a useless reset
|
||||
|
|
5
CREDITS
5
CREDITS
|
@ -38,6 +38,11 @@ N: Jerry van Baren
|
|||
E: <vanbaren@cideas.com>
|
||||
D: BedBug port to 603e core (MPC82xx). Code for enhanced memory test.
|
||||
|
||||
N: Pavel Bartusek
|
||||
E: <pba@sysgo.com>
|
||||
D: Reiserfs support
|
||||
W: http://www.elinos.com
|
||||
|
||||
N: Andre Beaudin
|
||||
E: <andre.beaudin@colubris.com>
|
||||
D: PCMCIA, Ethernet, TFTP
|
||||
|
|
3
Makefile
3
Makefile
|
@ -99,7 +99,8 @@ LIBS = lib_generic/libgeneric.a
|
|||
LIBS += board/$(BOARDDIR)/lib$(BOARD).a
|
||||
LIBS += cpu/$(CPU)/lib$(CPU).a
|
||||
LIBS += lib_$(ARCH)/lib$(ARCH).a
|
||||
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a
|
||||
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
|
||||
fs/reiserfs/libreiserfs.a
|
||||
LIBS += net/libnet.a
|
||||
LIBS += disk/libdisk.a
|
||||
LIBS += rtc/librtc.a
|
||||
|
|
|
@ -39,7 +39,7 @@ COBJS = main.o ACEX1K.o altera.o bedbug.o \
|
|||
cmd_mem.o cmd_mii.o cmd_misc.o cmd_mmc.o \
|
||||
cmd_nand.o cmd_net.o cmd_nvedit.o \
|
||||
cmd_pci.o cmd_pcmcia.o cmd_portio.o \
|
||||
cmd_reginfo.o cmd_scsi.o cmd_spi.o cmd_usb.o cmd_vfd.o \
|
||||
cmd_reginfo.o cmd_reiser.o cmd_scsi.o cmd_spi.o cmd_usb.o cmd_vfd.o \
|
||||
command.o console.o devices.o dlmalloc.o docecc.o \
|
||||
environment.o env_common.o \
|
||||
env_dataflash.o env_flash.o env_eeprom.o env_nvram.o env_nowhere.o exports.o \
|
||||
|
|
277
common/cmd_reiser.c
Normal file
277
common/cmd_reiser.c
Normal file
|
@ -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 */
|
|
@ -481,7 +481,13 @@ static int smc_send_packet (volatile void *packet, int packet_length)
|
|||
int try = 0;
|
||||
int time_out;
|
||||
byte status;
|
||||
byte saved_pnr;
|
||||
word saved_ptr;
|
||||
|
||||
/* save PTR and PNR registers before manipulation */
|
||||
SMC_SELECT_BANK (2);
|
||||
saved_pnr = SMC_inb( PN_REG );
|
||||
saved_ptr = SMC_inw( PTR_REG );
|
||||
|
||||
PRINTK3 ("%s:smc_hardware_send_packet\n", SMC_DEV_NAME);
|
||||
|
||||
|
@ -559,6 +565,10 @@ again:
|
|||
/* we have a packet address, so tell the card to use it */
|
||||
SMC_outb (packet_no, PN_REG);
|
||||
|
||||
/* do not write new ptr value if Write data fifo not empty */
|
||||
while ( saved_ptr & PTR_NOTEMPTY )
|
||||
printf ("Write data fifo not empty!\n");
|
||||
|
||||
/* point to the beginning of the packet */
|
||||
SMC_outw (PTR_AUTOINC, PTR_REG);
|
||||
|
||||
|
@ -607,12 +617,15 @@ again:
|
|||
SMC_outw (MC_ENQUEUE, MMU_CMD_REG);
|
||||
|
||||
/* poll for TX INT */
|
||||
if (poll4int (IM_TX_INT, SMC_TX_TIMEOUT)) {
|
||||
/* if (poll4int (IM_TX_INT, SMC_TX_TIMEOUT)) { */
|
||||
/* poll for TX_EMPTY INT - autorelease enabled */
|
||||
if (poll4int(IM_TX_EMPTY_INT, SMC_TX_TIMEOUT)) {
|
||||
/* sending failed */
|
||||
PRINTK2 ("%s: TX timeout, sending failed...\n", SMC_DEV_NAME);
|
||||
|
||||
/* release packet */
|
||||
SMC_outw (MC_FREEPKT, MMU_CMD_REG);
|
||||
/* no need to release, MMU does that now */
|
||||
/* SMC_outw (MC_FREEPKT, MMU_CMD_REG); */
|
||||
|
||||
/* wait for MMU getting ready (low) */
|
||||
while (SMC_inw (MMU_CMD_REG) & MC_BUSY) {
|
||||
|
@ -625,12 +638,14 @@ again:
|
|||
return 0;
|
||||
} else {
|
||||
/* ack. int */
|
||||
SMC_outb (IM_TX_INT, SMC91111_INT_REG);
|
||||
SMC_outb (IM_TX_EMPTY_INT, SMC91111_INT_REG);
|
||||
/* SMC_outb (IM_TX_INT, SMC91111_INT_REG); */
|
||||
PRINTK2 ("%s: Sent packet of length %d \n", SMC_DEV_NAME,
|
||||
length);
|
||||
|
||||
/* release packet */
|
||||
SMC_outw (MC_FREEPKT, MMU_CMD_REG);
|
||||
/* no need to release, MMU does that now */
|
||||
/* SMC_outw (MC_FREEPKT, MMU_CMD_REG); */
|
||||
|
||||
/* wait for MMU getting ready (low) */
|
||||
while (SMC_inw (MMU_CMD_REG) & MC_BUSY) {
|
||||
|
@ -642,6 +657,10 @@ again:
|
|||
|
||||
}
|
||||
|
||||
/* restore previously saved registers */
|
||||
SMC_outb( saved_pnr, PN_REG );
|
||||
SMC_outw( saved_ptr, PTR_REG );
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -730,8 +749,14 @@ static int smc_rcv()
|
|||
#ifdef USE_32_BIT
|
||||
dword stat_len;
|
||||
#endif
|
||||
byte saved_pnr;
|
||||
word saved_ptr;
|
||||
|
||||
SMC_SELECT_BANK(2);
|
||||
/* save PTR and PTR registers */
|
||||
saved_pnr = SMC_inb( PN_REG );
|
||||
saved_ptr = SMC_inw( PTR_REG );
|
||||
|
||||
packet_number = SMC_inw( RXFIFO_REG );
|
||||
|
||||
if ( packet_number & RXFIFO_REMPTY ) {
|
||||
|
@ -810,6 +835,10 @@ static int smc_rcv()
|
|||
while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY )
|
||||
udelay(1); /* Wait until not busy */
|
||||
|
||||
/* restore saved registers */
|
||||
SMC_outb( saved_pnr, PN_REG );
|
||||
SMC_outw( saved_ptr, PTR_REG );
|
||||
|
||||
if (!is_error) {
|
||||
/* Pass the packet up to the protocol layers. */
|
||||
NetReceive(NetRxPackets[0], packet_length);
|
||||
|
@ -1252,6 +1281,11 @@ static void smc_phy_configure ()
|
|||
/* Update our Auto-Neg Advertisement Register */
|
||||
smc_write_phy_register (PHY_AD_REG, my_ad_caps);
|
||||
|
||||
/* Read the register back. Without this, it appears that when */
|
||||
/* auto-negotiation is restarted, sometimes it isn't ready and */
|
||||
/* the link does not come up. */
|
||||
smc_read_phy_register(PHY_AD_REG);
|
||||
|
||||
PRINTK2 ("%s:phy caps=%x\n", SMC_DEV_NAME, my_phy_caps);
|
||||
PRINTK2 ("%s:phy advertised caps=%x\n", SMC_DEV_NAME, my_ad_caps);
|
||||
|
||||
|
|
|
@ -378,7 +378,7 @@ typedef unsigned long int dword;
|
|||
#define CTL_EEPROM_SELECT 0x0004 /* Controls EEPROM reload & store */
|
||||
#define CTL_RELOAD 0x0002 /* When set reads EEPROM into registers */
|
||||
#define CTL_STORE 0x0001 /* When set stores registers into EEPROM */
|
||||
#define CTL_DEFAULT (0x1210)
|
||||
#define CTL_DEFAULT (0x1A10) /* Autorelease enabled*/
|
||||
|
||||
/* MMU Command Register */
|
||||
/* BANK 2 */
|
||||
|
@ -423,6 +423,7 @@ typedef unsigned long int dword;
|
|||
#define PTR_RCV 0x8000 /* 1=Receive area, 0=Transmit area */
|
||||
#define PTR_AUTOINC 0x4000 /* Auto increment the pointer on each access */
|
||||
#define PTR_READ 0x2000 /* When 1 the operation is a read */
|
||||
#define PTR_NOTEMPTY 0x0800 /* When 1 _do not_ write fifo DATA REG */
|
||||
|
||||
|
||||
/* Data Register */
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#
|
||||
#
|
||||
|
||||
SUBDIRS := jffs2 cramfs fdos fat
|
||||
SUBDIRS := jffs2 cramfs fdos fat reiserfs
|
||||
|
||||
.depend all:
|
||||
@for dir in $(SUBDIRS) ; do \
|
||||
|
|
48
fs/reiserfs/Makefile
Normal file
48
fs/reiserfs/Makefile
Normal file
|
@ -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
|
||||
|
||||
#########################################################################
|
123
fs/reiserfs/dev.c
Normal file
123
fs/reiserfs/dev.c
Normal file
|
@ -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 */
|
143
fs/reiserfs/mode_string.c
Normal file
143
fs/reiserfs/mode_string.c
Normal file
|
@ -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 */
|
986
fs/reiserfs/reiserfs.c
Normal file
986
fs/reiserfs/reiserfs.c
Normal file
|
@ -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 */
|
521
fs/reiserfs/reiserfs_private.h
Normal file
521
fs/reiserfs/reiserfs_private.h
Normal file
|
@ -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);
|
|
@ -87,6 +87,7 @@
|
|||
#define CFG_CMD_IMLS 0x0020000000000000U /* List all found images */
|
||||
#define CFG_CMD_ITEST 0x0040000000000000U /* Integer (and string) test */
|
||||
#define CFG_CMD_NFS 0x0080000000000000U /* NFS support */
|
||||
#define CFG_CMD_REISER 0x0100000000000000U /* Reiserfs support */
|
||||
|
||||
#define CFG_CMD_ALL 0xFFFFFFFFFFFFFFFFU /* ALL commands */
|
||||
|
||||
|
@ -124,6 +125,7 @@
|
|||
CFG_CMD_PING | \
|
||||
CFG_CMD_PORTIO | \
|
||||
CFG_CMD_REGINFO | \
|
||||
CFG_CMD_REISER | \
|
||||
CFG_CMD_SAVES | \
|
||||
CFG_CMD_SCSI | \
|
||||
CFG_CMD_SDRAM | \
|
||||
|
|
83
include/reiserfs.h
Normal file
83
include/reiserfs.h
Normal file
|
@ -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 a new issue