remove uncompilable filesystems
This commit is contained in:
parent
a83669c197
commit
9a365ade16
|
@ -1,52 +0,0 @@
|
|||
#
|
||||
# (C) Copyright 2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# (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 = $(obj)libext2fs.a
|
||||
|
||||
AOBJS =
|
||||
COBJS = ext2fs.o dev.o
|
||||
|
||||
SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS))
|
||||
|
||||
#CPPFLAGS +=
|
||||
|
||||
all: $(LIB) $(AOBJS)
|
||||
|
||||
$(LIB): $(obj).depend $(OBJS)
|
||||
$(AR) $(ARFLAGS) $@ $(OBJS)
|
||||
|
||||
#########################################################################
|
||||
|
||||
# defines $(obj).depend target
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
126
fs/ext2/dev.c
126
fs/ext2/dev.c
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2004
|
||||
* esd gmbh <www.esd-electronics.com>
|
||||
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
|
||||
*
|
||||
* based on code of fs/reiserfs/dev.c by
|
||||
*
|
||||
* (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_EXT2)
|
||||
|
||||
#include <config.h>
|
||||
#include <ext2fs.h>
|
||||
|
||||
static block_dev_desc_t *ext2fs_block_dev_desc;
|
||||
static disk_partition_t part_info;
|
||||
|
||||
int ext2fs_set_blk_dev (block_dev_desc_t * rbdd, int part)
|
||||
{
|
||||
ext2fs_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
|
||||
(ext2fs_block_dev_desc, part, &part_info)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return (part_info.size);
|
||||
}
|
||||
|
||||
|
||||
int ext2fs_devread (int sector, int byte_offset, int byte_len, char *buf) {
|
||||
char sec_buf[SECTOR_SIZE];
|
||||
unsigned block_len;
|
||||
|
||||
/*
|
||||
* Check partition boundaries
|
||||
*/
|
||||
if ((sector < 0)
|
||||
|| ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS)) >=
|
||||
part_info.size)) {
|
||||
/* errnum = ERR_OUTSIDE_PART; */
|
||||
printf (" ** ext2fs_devread() read outside partition sector %d\n", sector);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the read to the beginning of a partition.
|
||||
*/
|
||||
sector += byte_offset >> SECTOR_BITS;
|
||||
byte_offset &= SECTOR_SIZE - 1;
|
||||
|
||||
debug (" <%d, %d, %d>\n", sector, byte_offset, byte_len);
|
||||
|
||||
if (ext2fs_block_dev_desc == NULL) {
|
||||
printf ("** Invalid Block Device Descriptor (NULL)\n");
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (byte_offset != 0) {
|
||||
/* read first part which isn't aligned with start of sector */
|
||||
if (ext2fs_block_dev_desc->
|
||||
block_read (ext2fs_block_dev_desc->dev,
|
||||
part_info.start + sector, 1,
|
||||
(unsigned long *) sec_buf) != 1) {
|
||||
printf (" ** ext2fs_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 (ext2fs_block_dev_desc->block_read (ext2fs_block_dev_desc->dev,
|
||||
part_info.start + sector,
|
||||
block_len / SECTOR_SIZE,
|
||||
(unsigned long *) buf) !=
|
||||
block_len / SECTOR_SIZE) {
|
||||
printf (" ** ext2fs_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 (ext2fs_block_dev_desc->
|
||||
block_read (ext2fs_block_dev_desc->dev,
|
||||
part_info.start + sector, 1,
|
||||
(unsigned long *) sec_buf) != 1) {
|
||||
printf (" ** ext2fs_devread() read error - last part\n");
|
||||
return (0);
|
||||
}
|
||||
memcpy (buf, sec_buf, byte_len);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
#endif /* CFG_CMD_EXT2FS */
|
878
fs/ext2/ext2fs.c
878
fs/ext2/ext2fs.c
|
@ -1,878 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2004
|
||||
* esd gmbh <www.esd-electronics.com>
|
||||
* Reinhard Arlt <reinhard.arlt@esd-electronics.com>
|
||||
*
|
||||
* based on code from grub2 fs/ext2.c and fs/fshelp.c by
|
||||
*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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_EXT2)
|
||||
#include <ext2fs.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
extern int ext2fs_devread (int sector, int byte_offset, int byte_len,
|
||||
char *buf);
|
||||
|
||||
/* Magic value used to identify an ext2 filesystem. */
|
||||
#define EXT2_MAGIC 0xEF53
|
||||
/* Amount of indirect blocks in an inode. */
|
||||
#define INDIRECT_BLOCKS 12
|
||||
/* Maximum lenght of a pathname. */
|
||||
#define EXT2_PATH_MAX 4096
|
||||
/* Maximum nesting of symlinks, used to prevent a loop. */
|
||||
#define EXT2_MAX_SYMLINKCNT 8
|
||||
|
||||
/* Filetype used in directory entry. */
|
||||
#define FILETYPE_UNKNOWN 0
|
||||
#define FILETYPE_REG 1
|
||||
#define FILETYPE_DIRECTORY 2
|
||||
#define FILETYPE_SYMLINK 7
|
||||
|
||||
/* Filetype information as used in inodes. */
|
||||
#define FILETYPE_INO_MASK 0170000
|
||||
#define FILETYPE_INO_REG 0100000
|
||||
#define FILETYPE_INO_DIRECTORY 0040000
|
||||
#define FILETYPE_INO_SYMLINK 0120000
|
||||
|
||||
/* Bits used as offset in sector */
|
||||
#define DISK_SECTOR_BITS 9
|
||||
|
||||
/* Log2 size of ext2 block in 512 blocks. */
|
||||
#define LOG2_EXT2_BLOCK_SIZE(data) (__le32_to_cpu (data->sblock.log2_block_size) + 1)
|
||||
|
||||
/* Log2 size of ext2 block in bytes. */
|
||||
#define LOG2_BLOCK_SIZE(data) (__le32_to_cpu (data->sblock.log2_block_size) + 10)
|
||||
|
||||
/* The size of an ext2 block in bytes. */
|
||||
#define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE(data))
|
||||
|
||||
/* The ext2 superblock. */
|
||||
struct ext2_sblock {
|
||||
uint32_t total_inodes;
|
||||
uint32_t total_blocks;
|
||||
uint32_t reserved_blocks;
|
||||
uint32_t free_blocks;
|
||||
uint32_t free_inodes;
|
||||
uint32_t first_data_block;
|
||||
uint32_t log2_block_size;
|
||||
uint32_t log2_fragment_size;
|
||||
uint32_t blocks_per_group;
|
||||
uint32_t fragments_per_group;
|
||||
uint32_t inodes_per_group;
|
||||
uint32_t mtime;
|
||||
uint32_t utime;
|
||||
uint16_t mnt_count;
|
||||
uint16_t max_mnt_count;
|
||||
uint16_t magic;
|
||||
uint16_t fs_state;
|
||||
uint16_t error_handling;
|
||||
uint16_t minor_revision_level;
|
||||
uint32_t lastcheck;
|
||||
uint32_t checkinterval;
|
||||
uint32_t creator_os;
|
||||
uint32_t revision_level;
|
||||
uint16_t uid_reserved;
|
||||
uint16_t gid_reserved;
|
||||
uint32_t first_inode;
|
||||
uint16_t inode_size;
|
||||
uint16_t block_group_number;
|
||||
uint32_t feature_compatibility;
|
||||
uint32_t feature_incompat;
|
||||
uint32_t feature_ro_compat;
|
||||
uint32_t unique_id[4];
|
||||
char volume_name[16];
|
||||
char last_mounted_on[64];
|
||||
uint32_t compression_info;
|
||||
};
|
||||
|
||||
/* The ext2 blockgroup. */
|
||||
struct ext2_block_group {
|
||||
uint32_t block_id;
|
||||
uint32_t inode_id;
|
||||
uint32_t inode_table_id;
|
||||
uint16_t free_blocks;
|
||||
uint16_t free_inodes;
|
||||
uint16_t pad;
|
||||
uint32_t reserved[3];
|
||||
};
|
||||
|
||||
/* The ext2 inode. */
|
||||
struct ext2_inode {
|
||||
uint16_t mode;
|
||||
uint16_t uid;
|
||||
uint32_t size;
|
||||
uint32_t atime;
|
||||
uint32_t ctime;
|
||||
uint32_t mtime;
|
||||
uint32_t dtime;
|
||||
uint16_t gid;
|
||||
uint16_t nlinks;
|
||||
uint32_t blockcnt; /* Blocks of 512 bytes!! */
|
||||
uint32_t flags;
|
||||
uint32_t osd1;
|
||||
union {
|
||||
struct datablocks {
|
||||
uint32_t dir_blocks[INDIRECT_BLOCKS];
|
||||
uint32_t indir_block;
|
||||
uint32_t double_indir_block;
|
||||
uint32_t tripple_indir_block;
|
||||
} blocks;
|
||||
char symlink[60];
|
||||
} b;
|
||||
uint32_t version;
|
||||
uint32_t acl;
|
||||
uint32_t dir_acl;
|
||||
uint32_t fragment_addr;
|
||||
uint32_t osd2[3];
|
||||
};
|
||||
|
||||
/* The header of an ext2 directory entry. */
|
||||
struct ext2_dirent {
|
||||
uint32_t inode;
|
||||
uint16_t direntlen;
|
||||
uint8_t namelen;
|
||||
uint8_t filetype;
|
||||
};
|
||||
|
||||
struct ext2fs_node {
|
||||
struct ext2_data *data;
|
||||
struct ext2_inode inode;
|
||||
int ino;
|
||||
int inode_read;
|
||||
};
|
||||
|
||||
/* Information about a "mounted" ext2 filesystem. */
|
||||
struct ext2_data {
|
||||
struct ext2_sblock sblock;
|
||||
struct ext2_inode *inode;
|
||||
struct ext2fs_node diropen;
|
||||
};
|
||||
|
||||
|
||||
typedef struct ext2fs_node *ext2fs_node_t;
|
||||
|
||||
struct ext2_data *ext2fs_root = NULL;
|
||||
ext2fs_node_t ext2fs_file = NULL;
|
||||
int symlinknest = 0;
|
||||
uint32_t *indir1_block = NULL;
|
||||
int indir1_size = 0;
|
||||
int indir1_blkno = -1;
|
||||
uint32_t *indir2_block = NULL;
|
||||
int indir2_size = 0;
|
||||
int indir2_blkno = -1;
|
||||
|
||||
|
||||
static int ext2fs_blockgroup
|
||||
(struct ext2_data *data, int group, struct ext2_block_group *blkgrp) {
|
||||
#ifdef DEBUG
|
||||
printf ("ext2fs read blockgroup\n");
|
||||
#endif
|
||||
return (ext2fs_devread
|
||||
(((__le32_to_cpu (data->sblock.first_data_block) +
|
||||
1) << LOG2_EXT2_BLOCK_SIZE (data)),
|
||||
group * sizeof (struct ext2_block_group),
|
||||
sizeof (struct ext2_block_group), (char *) blkgrp));
|
||||
}
|
||||
|
||||
|
||||
static int ext2fs_read_inode
|
||||
(struct ext2_data *data, int ino, struct ext2_inode *inode) {
|
||||
struct ext2_block_group blkgrp;
|
||||
struct ext2_sblock *sblock = &data->sblock;
|
||||
int inodes_per_block;
|
||||
int status;
|
||||
|
||||
unsigned int blkno;
|
||||
unsigned int blkoff;
|
||||
|
||||
/* It is easier to calculate if the first inode is 0. */
|
||||
ino--;
|
||||
#ifdef DEBUG
|
||||
printf ("ext2fs read inode %d\n", ino);
|
||||
#endif
|
||||
status = ext2fs_blockgroup (data,
|
||||
ino /
|
||||
__le32_to_cpu (sblock->inodes_per_group),
|
||||
&blkgrp);
|
||||
if (status == 0) {
|
||||
return (0);
|
||||
}
|
||||
inodes_per_block = EXT2_BLOCK_SIZE (data) / 128;
|
||||
blkno = (ino % __le32_to_cpu (sblock->inodes_per_group)) /
|
||||
inodes_per_block;
|
||||
blkoff = (ino % __le32_to_cpu (sblock->inodes_per_group)) %
|
||||
inodes_per_block;
|
||||
#ifdef DEBUG
|
||||
printf ("ext2fs read inode blkno %d blkoff %d\n", blkno, blkoff);
|
||||
#endif
|
||||
/* Read the inode. */
|
||||
status = ext2fs_devread (((__le32_to_cpu (blkgrp.inode_table_id) +
|
||||
blkno) << LOG2_EXT2_BLOCK_SIZE (data)),
|
||||
sizeof (struct ext2_inode) * blkoff,
|
||||
sizeof (struct ext2_inode), (char *) inode);
|
||||
if (status == 0) {
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
void ext2fs_free_node (ext2fs_node_t node, ext2fs_node_t currroot) {
|
||||
if ((node != &ext2fs_root->diropen) && (node != currroot)) {
|
||||
free (node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int ext2fs_read_block (ext2fs_node_t node, int fileblock) {
|
||||
struct ext2_data *data = node->data;
|
||||
struct ext2_inode *inode = &node->inode;
|
||||
int blknr;
|
||||
int blksz = EXT2_BLOCK_SIZE (data);
|
||||
int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
|
||||
int status;
|
||||
|
||||
/* Direct blocks. */
|
||||
if (fileblock < INDIRECT_BLOCKS) {
|
||||
blknr = __le32_to_cpu (inode->b.blocks.dir_blocks[fileblock]);
|
||||
}
|
||||
/* Indirect. */
|
||||
else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
|
||||
if (indir1_block == NULL) {
|
||||
indir1_block = (uint32_t *) malloc (blksz);
|
||||
if (indir1_block == NULL) {
|
||||
printf ("** ext2fs read block (indir 1) malloc failed. **\n");
|
||||
return (-1);
|
||||
}
|
||||
indir1_size = blksz;
|
||||
indir1_blkno = -1;
|
||||
}
|
||||
if (blksz != indir1_size) {
|
||||
free (indir1_block);
|
||||
indir1_block = NULL;
|
||||
indir1_size = 0;
|
||||
indir1_blkno = -1;
|
||||
indir1_block = (uint32_t *) malloc (blksz);
|
||||
if (indir1_block == NULL) {
|
||||
printf ("** ext2fs read block (indir 1) malloc failed. **\n");
|
||||
return (-1);
|
||||
}
|
||||
indir1_size = blksz;
|
||||
}
|
||||
if ((__le32_to_cpu (inode->b.blocks.indir_block) <<
|
||||
log2_blksz) != indir1_blkno) {
|
||||
status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.indir_block) << log2_blksz,
|
||||
0, blksz,
|
||||
(char *) indir1_block);
|
||||
if (status == 0) {
|
||||
printf ("** ext2fs read block (indir 1) failed. **\n");
|
||||
return (0);
|
||||
}
|
||||
indir1_blkno =
|
||||
__le32_to_cpu (inode->b.blocks.
|
||||
indir_block) << log2_blksz;
|
||||
}
|
||||
blknr = __le32_to_cpu (indir1_block
|
||||
[fileblock - INDIRECT_BLOCKS]);
|
||||
}
|
||||
/* Double indirect. */
|
||||
else if (fileblock <
|
||||
(INDIRECT_BLOCKS + (blksz / 4 * (blksz / 4 + 1)))) {
|
||||
unsigned int perblock = blksz / 4;
|
||||
unsigned int rblock = fileblock - (INDIRECT_BLOCKS
|
||||
+ blksz / 4);
|
||||
|
||||
if (indir1_block == NULL) {
|
||||
indir1_block = (uint32_t *) malloc (blksz);
|
||||
if (indir1_block == NULL) {
|
||||
printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
|
||||
return (-1);
|
||||
}
|
||||
indir1_size = blksz;
|
||||
indir1_blkno = -1;
|
||||
}
|
||||
if (blksz != indir1_size) {
|
||||
free (indir1_block);
|
||||
indir1_block = NULL;
|
||||
indir1_size = 0;
|
||||
indir1_blkno = -1;
|
||||
indir1_block = (uint32_t *) malloc (blksz);
|
||||
if (indir1_block == NULL) {
|
||||
printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
|
||||
return (-1);
|
||||
}
|
||||
indir1_size = blksz;
|
||||
}
|
||||
if ((__le32_to_cpu (inode->b.blocks.double_indir_block) <<
|
||||
log2_blksz) != indir1_blkno) {
|
||||
status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.double_indir_block) << log2_blksz,
|
||||
0, blksz,
|
||||
(char *) indir1_block);
|
||||
if (status == 0) {
|
||||
printf ("** ext2fs read block (indir 2 1) failed. **\n");
|
||||
return (-1);
|
||||
}
|
||||
indir1_blkno =
|
||||
__le32_to_cpu (inode->b.blocks.double_indir_block) << log2_blksz;
|
||||
}
|
||||
|
||||
if (indir2_block == NULL) {
|
||||
indir2_block = (uint32_t *) malloc (blksz);
|
||||
if (indir2_block == NULL) {
|
||||
printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
|
||||
return (-1);
|
||||
}
|
||||
indir2_size = blksz;
|
||||
indir2_blkno = -1;
|
||||
}
|
||||
if (blksz != indir2_size) {
|
||||
free (indir2_block);
|
||||
indir2_block = NULL;
|
||||
indir2_size = 0;
|
||||
indir2_blkno = -1;
|
||||
indir2_block = (uint32_t *) malloc (blksz);
|
||||
if (indir2_block == NULL) {
|
||||
printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
|
||||
return (-1);
|
||||
}
|
||||
indir2_size = blksz;
|
||||
}
|
||||
if ((__le32_to_cpu (indir1_block[rblock / perblock]) <<
|
||||
log2_blksz) != indir1_blkno) {
|
||||
status = ext2fs_devread (__le32_to_cpu(indir1_block[rblock / perblock]) << log2_blksz,
|
||||
0, blksz,
|
||||
(char *) indir2_block);
|
||||
if (status == 0) {
|
||||
printf ("** ext2fs read block (indir 2 2) failed. **\n");
|
||||
return (-1);
|
||||
}
|
||||
indir2_blkno =
|
||||
__le32_to_cpu (indir1_block[rblock / perblock]) << log2_blksz;
|
||||
}
|
||||
blknr = __le32_to_cpu (indir2_block[rblock % perblock]);
|
||||
}
|
||||
/* Tripple indirect. */
|
||||
else {
|
||||
printf ("** ext2fs doesn't support tripple indirect blocks. **\n");
|
||||
return (-1);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf ("ext2fs_read_block %08x\n", blknr);
|
||||
#endif
|
||||
return (blknr);
|
||||
}
|
||||
|
||||
|
||||
int ext2fs_read_file
|
||||
(ext2fs_node_t node, int pos, unsigned int len, char *buf) {
|
||||
int i;
|
||||
int blockcnt;
|
||||
int log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data);
|
||||
int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
|
||||
unsigned int filesize = __le32_to_cpu(node->inode.size);
|
||||
|
||||
/* Adjust len so it we can't read past the end of the file. */
|
||||
if (len > filesize) {
|
||||
len = filesize;
|
||||
}
|
||||
blockcnt = ((len + pos) + blocksize - 1) / blocksize;
|
||||
|
||||
for (i = pos / blocksize; i < blockcnt; i++) {
|
||||
int blknr;
|
||||
int blockoff = pos % blocksize;
|
||||
int blockend = blocksize;
|
||||
|
||||
int skipfirst = 0;
|
||||
|
||||
blknr = ext2fs_read_block (node, i);
|
||||
if (blknr < 0) {
|
||||
return (-1);
|
||||
}
|
||||
blknr = blknr << log2blocksize;
|
||||
|
||||
/* Last block. */
|
||||
if (i == blockcnt - 1) {
|
||||
blockend = (len + pos) % blocksize;
|
||||
|
||||
/* The last portion is exactly blocksize. */
|
||||
if (!blockend) {
|
||||
blockend = blocksize;
|
||||
}
|
||||
}
|
||||
|
||||
/* First block. */
|
||||
if (i == pos / blocksize) {
|
||||
skipfirst = blockoff;
|
||||
blockend -= skipfirst;
|
||||
}
|
||||
|
||||
/* If the block number is 0 this block is not stored on disk but
|
||||
is zero filled instead. */
|
||||
if (blknr) {
|
||||
int status;
|
||||
|
||||
status = ext2fs_devread (blknr, skipfirst, blockend, buf);
|
||||
if (status == 0) {
|
||||
return (-1);
|
||||
}
|
||||
} else {
|
||||
memset (buf, blocksize - skipfirst, 0);
|
||||
}
|
||||
buf += blocksize - skipfirst;
|
||||
}
|
||||
return (len);
|
||||
}
|
||||
|
||||
|
||||
static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fnode, int *ftype)
|
||||
{
|
||||
unsigned int fpos = 0;
|
||||
int status;
|
||||
struct ext2fs_node *diro = (struct ext2fs_node *) dir;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (name != NULL)
|
||||
printf ("Iterate dir %s\n", name);
|
||||
#endif /* of DEBUG */
|
||||
if (!diro->inode_read) {
|
||||
status = ext2fs_read_inode (diro->data, diro->ino,
|
||||
&diro->inode);
|
||||
if (status == 0) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
/* Search the file. */
|
||||
while (fpos < __le32_to_cpu (diro->inode.size)) {
|
||||
struct ext2_dirent dirent;
|
||||
|
||||
status = ext2fs_read_file (diro, fpos,
|
||||
sizeof (struct ext2_dirent),
|
||||
(char *) &dirent);
|
||||
if (status < 1) {
|
||||
return (0);
|
||||
}
|
||||
if (dirent.namelen != 0) {
|
||||
char filename[dirent.namelen + 1];
|
||||
ext2fs_node_t fdiro;
|
||||
int type = FILETYPE_UNKNOWN;
|
||||
|
||||
status = ext2fs_read_file (diro,
|
||||
fpos + sizeof (struct ext2_dirent),
|
||||
dirent.namelen, filename);
|
||||
if (status < 1) {
|
||||
return (0);
|
||||
}
|
||||
fdiro = malloc (sizeof (struct ext2fs_node));
|
||||
if (!fdiro) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
fdiro->data = diro->data;
|
||||
fdiro->ino = __le32_to_cpu (dirent.inode);
|
||||
|
||||
filename[dirent.namelen] = '\0';
|
||||
|
||||
if (dirent.filetype != FILETYPE_UNKNOWN) {
|
||||
fdiro->inode_read = 0;
|
||||
|
||||
if (dirent.filetype == FILETYPE_DIRECTORY) {
|
||||
type = FILETYPE_DIRECTORY;
|
||||
} else if (dirent.filetype ==
|
||||
FILETYPE_SYMLINK) {
|
||||
type = FILETYPE_SYMLINK;
|
||||
} else if (dirent.filetype == FILETYPE_REG) {
|
||||
type = FILETYPE_REG;
|
||||
}
|
||||
} else {
|
||||
/* The filetype can not be read from the dirent, get it from inode */
|
||||
|
||||
status = ext2fs_read_inode (diro->data,
|
||||
__le32_to_cpu(dirent.inode),
|
||||
&fdiro->inode);
|
||||
if (status == 0) {
|
||||
free (fdiro);
|
||||
return (0);
|
||||
}
|
||||
fdiro->inode_read = 1;
|
||||
|
||||
if ((__le16_to_cpu (fdiro->inode.mode) &
|
||||
FILETYPE_INO_MASK) ==
|
||||
FILETYPE_INO_DIRECTORY) {
|
||||
type = FILETYPE_DIRECTORY;
|
||||
} else if ((__le16_to_cpu (fdiro->inode.mode)
|
||||
& FILETYPE_INO_MASK) ==
|
||||
FILETYPE_INO_SYMLINK) {
|
||||
type = FILETYPE_SYMLINK;
|
||||
} else if ((__le16_to_cpu (fdiro->inode.mode)
|
||||
& FILETYPE_INO_MASK) ==
|
||||
FILETYPE_INO_REG) {
|
||||
type = FILETYPE_REG;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf ("iterate >%s<\n", filename);
|
||||
#endif /* of DEBUG */
|
||||
if ((name != NULL) && (fnode != NULL)
|
||||
&& (ftype != NULL)) {
|
||||
if (strcmp (filename, name) == 0) {
|
||||
*ftype = type;
|
||||
*fnode = fdiro;
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
if (fdiro->inode_read == 0) {
|
||||
status = ext2fs_read_inode (diro->data,
|
||||
__le32_to_cpu (dirent.inode),
|
||||
&fdiro->inode);
|
||||
if (status == 0) {
|
||||
free (fdiro);
|
||||
return (0);
|
||||
}
|
||||
fdiro->inode_read = 1;
|
||||
}
|
||||
switch (type) {
|
||||
case FILETYPE_DIRECTORY:
|
||||
printf ("<DIR> ");
|
||||
break;
|
||||
case FILETYPE_SYMLINK:
|
||||
printf ("<SYM> ");
|
||||
break;
|
||||
case FILETYPE_REG:
|
||||
printf (" ");
|
||||
break;
|
||||
default:
|
||||
printf ("< ? > ");
|
||||
break;
|
||||
}
|
||||
printf ("%10d %s\n",
|
||||
__le32_to_cpu (fdiro->inode.size),
|
||||
filename);
|
||||
}
|
||||
free (fdiro);
|
||||
}
|
||||
fpos += __le16_to_cpu (dirent.direntlen);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
static char *ext2fs_read_symlink (ext2fs_node_t node) {
|
||||
char *symlink;
|
||||
struct ext2fs_node *diro = node;
|
||||
int status;
|
||||
|
||||
if (!diro->inode_read) {
|
||||
status = ext2fs_read_inode (diro->data, diro->ino,
|
||||
&diro->inode);
|
||||
if (status == 0) {
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
symlink = malloc (__le32_to_cpu (diro->inode.size) + 1);
|
||||
if (!symlink) {
|
||||
return (0);
|
||||
}
|
||||
/* If the filesize of the symlink is bigger than
|
||||
60 the symlink is stored in a separate block,
|
||||
otherwise it is stored in the inode. */
|
||||
if (__le32_to_cpu (diro->inode.size) <= 60) {
|
||||
strncpy (symlink, diro->inode.b.symlink,
|
||||
__le32_to_cpu (diro->inode.size));
|
||||
} else {
|
||||
status = ext2fs_read_file (diro, 0,
|
||||
__le32_to_cpu (diro->inode.size),
|
||||
symlink);
|
||||
if (status == 0) {
|
||||
free (symlink);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
symlink[__le32_to_cpu (diro->inode.size)] = '\0';
|
||||
return (symlink);
|
||||
}
|
||||
|
||||
|
||||
int ext2fs_find_file1
|
||||
(const char *currpath,
|
||||
ext2fs_node_t currroot, ext2fs_node_t * currfound, int *foundtype) {
|
||||
char fpath[strlen (currpath) + 1];
|
||||
char *name = fpath;
|
||||
char *next;
|
||||
int status;
|
||||
int type = FILETYPE_DIRECTORY;
|
||||
ext2fs_node_t currnode = currroot;
|
||||
ext2fs_node_t oldnode = currroot;
|
||||
|
||||
strncpy (fpath, currpath, strlen (currpath) + 1);
|
||||
|
||||
/* Remove all leading slashes. */
|
||||
while (*name == '/') {
|
||||
name++;
|
||||
}
|
||||
if (!*name) {
|
||||
*currfound = currnode;
|
||||
return (1);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int found;
|
||||
|
||||
/* Extract the actual part from the pathname. */
|
||||
next = strchr (name, '/');
|
||||
if (next) {
|
||||
/* Remove all leading slashes. */
|
||||
while (*next == '/') {
|
||||
*(next++) = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point it is expected that the current node is a directory, check if this is true. */
|
||||
if (type != FILETYPE_DIRECTORY) {
|
||||
ext2fs_free_node (currnode, currroot);
|
||||
return (0);
|
||||
}
|
||||
|
||||
oldnode = currnode;
|
||||
|
||||
/* Iterate over the directory. */
|
||||
found = ext2fs_iterate_dir (currnode, name, &currnode, &type);
|
||||
if (found == 0) {
|
||||
return (0);
|
||||
}
|
||||
if (found == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read in the symlink and follow it. */
|
||||
if (type == FILETYPE_SYMLINK) {
|
||||
char *symlink;
|
||||
|
||||
/* Test if the symlink does not loop. */
|
||||
if (++symlinknest == 8) {
|
||||
ext2fs_free_node (currnode, currroot);
|
||||
ext2fs_free_node (oldnode, currroot);
|
||||
return (0);
|
||||
}
|
||||
|
||||
symlink = ext2fs_read_symlink (currnode);
|
||||
ext2fs_free_node (currnode, currroot);
|
||||
|
||||
if (!symlink) {
|
||||
ext2fs_free_node (oldnode, currroot);
|
||||
return (0);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf ("Got symlink >%s<\n", symlink);
|
||||
#endif /* of DEBUG */
|
||||
/* The symlink is an absolute path, go back to the root inode. */
|
||||
if (symlink[0] == '/') {
|
||||
ext2fs_free_node (oldnode, currroot);
|
||||
oldnode = &ext2fs_root->diropen;
|
||||
}
|
||||
|
||||
/* Lookup the node the symlink points to. */
|
||||
status = ext2fs_find_file1 (symlink, oldnode,
|
||||
&currnode, &type);
|
||||
|
||||
free (symlink);
|
||||
|
||||
if (status == 0) {
|
||||
ext2fs_free_node (oldnode, currroot);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
ext2fs_free_node (oldnode, currroot);
|
||||
|
||||
/* Found the node! */
|
||||
if (!next || *next == '\0') {
|
||||
*currfound = currnode;
|
||||
*foundtype = type;
|
||||
return (1);
|
||||
}
|
||||
name = next;
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
int ext2fs_find_file
|
||||
(const char *path,
|
||||
ext2fs_node_t rootnode, ext2fs_node_t * foundnode, int expecttype) {
|
||||
int status;
|
||||
int foundtype = FILETYPE_DIRECTORY;
|
||||
|
||||
|
||||
symlinknest = 0;
|
||||
if (!path) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
status = ext2fs_find_file1 (path, rootnode, foundnode, &foundtype);
|
||||
if (status == 0) {
|
||||
return (0);
|
||||
}
|
||||
/* Check if the node that was found was of the expected type. */
|
||||
if ((expecttype == FILETYPE_REG) && (foundtype != expecttype)) {
|
||||
return (0);
|
||||
} else if ((expecttype == FILETYPE_DIRECTORY)
|
||||
&& (foundtype != expecttype)) {
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
int ext2fs_ls (char *dirname) {
|
||||
ext2fs_node_t dirnode;
|
||||
int status;
|
||||
|
||||
if (ext2fs_root == NULL) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
status = ext2fs_find_file (dirname, &ext2fs_root->diropen, &dirnode,
|
||||
FILETYPE_DIRECTORY);
|
||||
if (status != 1) {
|
||||
printf ("** Can not find directory. **\n");
|
||||
return (1);
|
||||
}
|
||||
ext2fs_iterate_dir (dirnode, NULL, NULL, NULL);
|
||||
ext2fs_free_node (dirnode, &ext2fs_root->diropen);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int ext2fs_open (char *filename) {
|
||||
ext2fs_node_t fdiro = NULL;
|
||||
int status;
|
||||
int len;
|
||||
|
||||
if (ext2fs_root == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
ext2fs_file = NULL;
|
||||
status = ext2fs_find_file (filename, &ext2fs_root->diropen, &fdiro,
|
||||
FILETYPE_REG);
|
||||
if (status == 0) {
|
||||
goto fail;
|
||||
}
|
||||
if (!fdiro->inode_read) {
|
||||
status = ext2fs_read_inode (fdiro->data, fdiro->ino,
|
||||
&fdiro->inode);
|
||||
if (status == 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
len = __le32_to_cpu (fdiro->inode.size);
|
||||
ext2fs_file = fdiro;
|
||||
return (len);
|
||||
|
||||
fail:
|
||||
ext2fs_free_node (fdiro, &ext2fs_root->diropen);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
int ext2fs_close (void
|
||||
) {
|
||||
if ((ext2fs_file != NULL) && (ext2fs_root != NULL)) {
|
||||
ext2fs_free_node (ext2fs_file, &ext2fs_root->diropen);
|
||||
ext2fs_file = NULL;
|
||||
}
|
||||
if (ext2fs_root != NULL) {
|
||||
free (ext2fs_root);
|
||||
ext2fs_root = NULL;
|
||||
}
|
||||
if (indir1_block != NULL) {
|
||||
free (indir1_block);
|
||||
indir1_block = NULL;
|
||||
indir1_size = 0;
|
||||
indir1_blkno = -1;
|
||||
}
|
||||
if (indir2_block != NULL) {
|
||||
free (indir2_block);
|
||||
indir2_block = NULL;
|
||||
indir2_size = 0;
|
||||
indir2_blkno = -1;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
int ext2fs_read (char *buf, unsigned len) {
|
||||
int status;
|
||||
|
||||
if (ext2fs_root == NULL) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (ext2fs_file == NULL) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
status = ext2fs_read_file (ext2fs_file, 0, len, buf);
|
||||
return (status);
|
||||
}
|
||||
|
||||
|
||||
int ext2fs_mount (unsigned part_length) {
|
||||
struct ext2_data *data;
|
||||
int status;
|
||||
|
||||
data = malloc (sizeof (struct ext2_data));
|
||||
if (!data) {
|
||||
return (0);
|
||||
}
|
||||
/* Read the superblock. */
|
||||
status = ext2fs_devread (1 * 2, 0, sizeof (struct ext2_sblock),
|
||||
(char *) &data->sblock);
|
||||
if (status == 0) {
|
||||
goto fail;
|
||||
}
|
||||
/* Make sure this is an ext2 filesystem. */
|
||||
if (__le16_to_cpu (data->sblock.magic) != EXT2_MAGIC) {
|
||||
goto fail;
|
||||
}
|
||||
data->diropen.data = data;
|
||||
data->diropen.ino = 2;
|
||||
data->diropen.inode_read = 1;
|
||||
data->inode = &data->diropen.inode;
|
||||
|
||||
status = ext2fs_read_inode (data, 2, data->inode);
|
||||
if (status == 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ext2fs_root = data;
|
||||
|
||||
return (1);
|
||||
|
||||
fail:
|
||||
printf ("Failed to mount ext2 filesystem...\n");
|
||||
free (data);
|
||||
ext2fs_root = NULL;
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif /* CFG_CMD_EXT2FS */
|
|
@ -1,45 +0,0 @@
|
|||
#
|
||||
#
|
||||
# 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 = $(obj)libfat.a
|
||||
|
||||
AOBJS =
|
||||
COBJS = fat.o file.o
|
||||
|
||||
SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS))
|
||||
|
||||
all: $(LIB) $(AOBJS)
|
||||
|
||||
$(LIB): $(obj).depend $(OBJS)
|
||||
$(AR) $(ARFLAGS) $@ $(OBJS)
|
||||
|
||||
|
||||
#########################################################################
|
||||
|
||||
# defines $(obj).depend target
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
1012
fs/fat/fat.c
1012
fs/fat/fat.c
File diff suppressed because it is too large
Load Diff
208
fs/fat/file.c
208
fs/fat/file.c
|
@ -1,208 +0,0 @@
|
|||
/*
|
||||
* file.c
|
||||
*
|
||||
* Mini "VFS" by Marcus Sundberg
|
||||
*
|
||||
* 2002-07-28 - rjones@nexus-tech.net - ported to ppcboot v1.1.6
|
||||
* 2003-03-10 - kharris@nexus-tech.net - ported to uboot
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <config.h>
|
||||
#include <malloc.h>
|
||||
#include <fat.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_FAT)
|
||||
|
||||
/* Supported filesystems */
|
||||
static const struct filesystem filesystems[] = {
|
||||
{ file_fat_detectfs, file_fat_ls, file_fat_read, "FAT" },
|
||||
};
|
||||
#define NUM_FILESYS (sizeof(filesystems)/sizeof(struct filesystem))
|
||||
|
||||
/* The filesystem which was last detected */
|
||||
static int current_filesystem = FSTYPE_NONE;
|
||||
|
||||
/* The current working directory */
|
||||
#define CWD_LEN 511
|
||||
char file_cwd[CWD_LEN+1] = "/";
|
||||
|
||||
const char *
|
||||
file_getfsname(int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= NUM_FILESYS) return NULL;
|
||||
|
||||
return filesystems[idx].name;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pathcpy(char *dest, const char *src)
|
||||
{
|
||||
char *origdest = dest;
|
||||
|
||||
do {
|
||||
if (dest-file_cwd >= CWD_LEN) {
|
||||
*dest = '\0';
|
||||
return;
|
||||
}
|
||||
*(dest) = *(src);
|
||||
if (*src == '\0') {
|
||||
if (dest-- != origdest && ISDIRDELIM(*dest)) {
|
||||
*dest = '\0';
|
||||
}
|
||||
return;
|
||||
}
|
||||
++dest;
|
||||
if (ISDIRDELIM(*src)) {
|
||||
while (ISDIRDELIM(*src)) src++;
|
||||
} else {
|
||||
src++;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
file_cd(const char *path)
|
||||
{
|
||||
if (ISDIRDELIM(*path)) {
|
||||
while (ISDIRDELIM(*path)) path++;
|
||||
strncpy(file_cwd+1, path, CWD_LEN-1);
|
||||
} else {
|
||||
const char *origpath = path;
|
||||
char *tmpstr = file_cwd;
|
||||
int back = 0;
|
||||
|
||||
while (*tmpstr != '\0') tmpstr++;
|
||||
do {
|
||||
tmpstr--;
|
||||
} while (ISDIRDELIM(*tmpstr));
|
||||
|
||||
while (*path == '.') {
|
||||
path++;
|
||||
while (*path == '.') {
|
||||
path++;
|
||||
back++;
|
||||
}
|
||||
if (*path != '\0' && !ISDIRDELIM(*path)) {
|
||||
path = origpath;
|
||||
back = 0;
|
||||
break;
|
||||
}
|
||||
while (ISDIRDELIM(*path)) path++;
|
||||
origpath = path;
|
||||
}
|
||||
|
||||
while (back--) {
|
||||
/* Strip off path component */
|
||||
while (!ISDIRDELIM(*tmpstr)) {
|
||||
tmpstr--;
|
||||
}
|
||||
if (tmpstr == file_cwd) {
|
||||
/* Incremented again right after the loop. */
|
||||
tmpstr--;
|
||||
break;
|
||||
}
|
||||
/* Skip delimiters */
|
||||
while (ISDIRDELIM(*tmpstr)) tmpstr--;
|
||||
}
|
||||
tmpstr++;
|
||||
if (*path == '\0') {
|
||||
if (tmpstr == file_cwd) {
|
||||
*tmpstr = '/';
|
||||
tmpstr++;
|
||||
}
|
||||
*tmpstr = '\0';
|
||||
return 0;
|
||||
}
|
||||
*tmpstr = '/';
|
||||
pathcpy(tmpstr+1, path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
file_detectfs(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
current_filesystem = FSTYPE_NONE;
|
||||
|
||||
for (i = 0; i < NUM_FILESYS; i++) {
|
||||
if (filesystems[i].detect() == 0) {
|
||||
strcpy(file_cwd, "/");
|
||||
current_filesystem = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return current_filesystem;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
file_ls(const char *dir)
|
||||
{
|
||||
char fullpath[1024];
|
||||
const char *arg;
|
||||
|
||||
if (current_filesystem == FSTYPE_NONE) {
|
||||
printf("Can't list files without a filesystem!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ISDIRDELIM(*dir)) {
|
||||
arg = dir;
|
||||
} else {
|
||||
sprintf(fullpath, "%s/%s", file_cwd, dir);
|
||||
arg = fullpath;
|
||||
}
|
||||
return filesystems[current_filesystem].ls(arg);
|
||||
}
|
||||
|
||||
|
||||
long
|
||||
file_read(const char *filename, void *buffer, unsigned long maxsize)
|
||||
{
|
||||
char fullpath[1024];
|
||||
const char *arg;
|
||||
|
||||
if (current_filesystem == FSTYPE_NONE) {
|
||||
printf("Can't load file without a filesystem!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ISDIRDELIM(*filename)) {
|
||||
arg = filename;
|
||||
} else {
|
||||
sprintf(fullpath, "%s/%s", file_cwd, filename);
|
||||
arg = fullpath;
|
||||
}
|
||||
|
||||
return filesystems[current_filesystem].read(arg, buffer, maxsize);
|
||||
}
|
||||
|
||||
#endif /* #if (CONFIG_COMMANDS & CFG_CMD_FAT) */
|
|
@ -1,54 +0,0 @@
|
|||
#
|
||||
# (C) Copyright 2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# (C) Copyright 2002
|
||||
# Stäubli Faverges - <www.staubli.com>
|
||||
# Pierre AUBERT p.aubert@staubli.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
|
||||
#
|
||||
|
||||
include $(TOPDIR)/config.mk
|
||||
|
||||
LIB = $(obj)libfdos.a
|
||||
|
||||
AOBJS =
|
||||
COBJS = fat.o vfat.o dev.o fdos.o fs.o subdir.o
|
||||
|
||||
SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS))
|
||||
|
||||
#CPPFLAGS +=
|
||||
|
||||
all: $(LIB) $(AOBJS)
|
||||
|
||||
$(LIB): $(obj).depend $(OBJS)
|
||||
$(AR) $(ARFLAGS) $@ $(OBJS)
|
||||
|
||||
|
||||
#########################################################################
|
||||
|
||||
# defines $(obj).depend target
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
195
fs/fdos/dev.c
195
fs/fdos/dev.c
|
@ -1,195 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Stäubli Faverges - <www.staubli.com>
|
||||
* Pierre AUBERT p.aubert@staubli.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
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
|
||||
#include "dos.h"
|
||||
#include "fdos.h"
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
|
||||
|
||||
#define NB_HEADS 2
|
||||
#define NB_TRACKS 80
|
||||
#define NB_SECTORS 18
|
||||
|
||||
|
||||
static int lastwhere;
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* dev_open --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int dev_open (void)
|
||||
{
|
||||
lastwhere = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* dev_read -- len and where are sectors number
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int dev_read (void *buffer, int where, int len)
|
||||
{
|
||||
PRINTF ("dev_read (len = %d, where = %d)\n", len, where);
|
||||
|
||||
/* Si on ne desire pas lire a la position courante, il faut un seek */
|
||||
if (where != lastwhere) {
|
||||
if (!fdc_fdos_seek (where)) {
|
||||
PRINTF ("seek error in dev_read");
|
||||
lastwhere = -1;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fdc_fdos_read (buffer, len)) {
|
||||
PRINTF ("read error\n");
|
||||
lastwhere = -1;
|
||||
return (-1);
|
||||
}
|
||||
lastwhere = where + len;
|
||||
return (0);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* check_dev -- verify the diskette format
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int check_dev (BootSector_t *boot, Fs_t *fs)
|
||||
{
|
||||
unsigned int heads, sectors, tracks;
|
||||
int BootP, Infp0, InfpX, InfTm;
|
||||
int sect_per_track;
|
||||
|
||||
/* Display Boot header */
|
||||
PRINTF ("Jump to boot code 0x%02x 0x%02x 0x%02x\n",
|
||||
boot -> jump [0], boot -> jump [1], boot -> jump[2]);
|
||||
PRINTF ("OEM name & version '%*.*s'\n",
|
||||
BANNER_LG, BANNER_LG, boot -> banner );
|
||||
PRINTF ("Bytes per sector hopefully 512 %d\n",
|
||||
__le16_to_cpu (boot -> secsiz));
|
||||
PRINTF ("Cluster size in sectors %d\n",
|
||||
boot -> clsiz);
|
||||
PRINTF ("Number of reserved (boot) sectors %d\n",
|
||||
__le16_to_cpu (boot -> nrsvsect));
|
||||
PRINTF ("Number of FAT tables hopefully 2 %d\n",
|
||||
boot -> nfat);
|
||||
PRINTF ("Number of directory slots %d\n",
|
||||
__le16_to_cpu (boot -> dirents));
|
||||
PRINTF ("Total sectors on disk %d\n",
|
||||
__le16_to_cpu (boot -> psect));
|
||||
PRINTF ("Media descriptor=first byte of FAT %d\n",
|
||||
boot -> descr);
|
||||
PRINTF ("Sectors in FAT %d\n",
|
||||
__le16_to_cpu (boot -> fatlen));
|
||||
PRINTF ("Sectors/track %d\n",
|
||||
__le16_to_cpu (boot -> nsect));
|
||||
PRINTF ("Heads %d\n",
|
||||
__le16_to_cpu (boot -> nheads));
|
||||
PRINTF ("number of hidden sectors %d\n",
|
||||
__le32_to_cpu (boot -> nhs));
|
||||
PRINTF ("big total sectors %d\n",
|
||||
__le32_to_cpu (boot -> bigsect));
|
||||
PRINTF ("physical drive ? %d\n",
|
||||
boot -> physdrive);
|
||||
PRINTF ("reserved %d\n",
|
||||
boot -> reserved);
|
||||
PRINTF ("dos > 4.0 diskette %d\n",
|
||||
boot -> dos4);
|
||||
PRINTF ("serial number %d\n",
|
||||
__le32_to_cpu (boot -> serial));
|
||||
PRINTF ("disk label %*.*s\n",
|
||||
LABEL_LG, LABEL_LG, boot -> label);
|
||||
PRINTF ("FAT type %8.8s\n",
|
||||
boot -> fat_type);
|
||||
PRINTF ("reserved by 2M %d\n",
|
||||
boot -> res_2m);
|
||||
PRINTF ("2M checksum (not used) %d\n",
|
||||
boot -> CheckSum);
|
||||
PRINTF ("2MF format version %d\n",
|
||||
boot -> fmt_2mf);
|
||||
PRINTF ("1 if write track after format %d\n",
|
||||
boot -> wt);
|
||||
PRINTF ("data transfer rate on track 0 %d\n",
|
||||
boot -> rate_0);
|
||||
PRINTF ("data transfer rate on track<>0 %d\n",
|
||||
boot -> rate_any);
|
||||
PRINTF ("offset to boot program %d\n",
|
||||
__le16_to_cpu (boot -> BootP));
|
||||
PRINTF ("T1: information for track 0 %d\n",
|
||||
__le16_to_cpu (boot -> Infp0));
|
||||
PRINTF ("T2: information for track<>0 %d\n",
|
||||
__le16_to_cpu (boot -> InfpX));
|
||||
PRINTF ("T3: track sectors size table %d\n",
|
||||
__le16_to_cpu (boot -> InfTm));
|
||||
PRINTF ("Format date 0x%04x\n",
|
||||
__le16_to_cpu (boot -> DateF));
|
||||
PRINTF ("Format time 0x%04x\n",
|
||||
__le16_to_cpu (boot -> TimeF));
|
||||
|
||||
|
||||
/* information is extracted from boot sector */
|
||||
heads = __le16_to_cpu (boot -> nheads);
|
||||
sectors = __le16_to_cpu (boot -> nsect);
|
||||
fs -> tot_sectors = __le32_to_cpu (boot -> bigsect);
|
||||
if (__le16_to_cpu (boot -> psect) != 0) {
|
||||
fs -> tot_sectors = __le16_to_cpu (boot -> psect);
|
||||
}
|
||||
|
||||
sect_per_track = heads * sectors;
|
||||
tracks = (fs -> tot_sectors + sect_per_track - 1) / sect_per_track;
|
||||
|
||||
BootP = __le16_to_cpu (boot -> BootP);
|
||||
Infp0 = __le16_to_cpu (boot -> Infp0);
|
||||
InfpX = __le16_to_cpu (boot -> InfpX);
|
||||
InfTm = __le16_to_cpu (boot -> InfTm);
|
||||
|
||||
if (boot -> dos4 == EXTENDED_BOOT &&
|
||||
strncmp( boot->banner,"2M", 2 ) == 0 &&
|
||||
BootP < SZ_STD_SECTOR &&
|
||||
Infp0 < SZ_STD_SECTOR &&
|
||||
InfpX < SZ_STD_SECTOR &&
|
||||
InfTm < SZ_STD_SECTOR &&
|
||||
BootP >= InfTm + 2 &&
|
||||
InfTm >= InfpX &&
|
||||
InfpX >= Infp0 &&
|
||||
Infp0 >= 76 ) {
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (heads != NB_HEADS ||
|
||||
tracks != NB_TRACKS ||
|
||||
sectors != NB_SECTORS ||
|
||||
__le16_to_cpu (boot -> secsiz) != SZ_STD_SECTOR ||
|
||||
fs -> tot_sectors == 0 ||
|
||||
(fs -> tot_sectors % sectors) != 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
175
fs/fdos/dos.h
175
fs/fdos/dos.h
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Stäubli Faverges - <www.staubli.com>
|
||||
* Pierre AUBERT p.aubert@staubli.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
|
||||
*/
|
||||
|
||||
#ifndef _DOS_H_
|
||||
#define _DOS_H_
|
||||
|
||||
/* Definitions for Dos diskettes */
|
||||
|
||||
/* General definitions */
|
||||
#define SZ_STD_SECTOR 512 /* Standard sector size */
|
||||
#define MDIR_SIZE 32 /* Direntry size */
|
||||
#define FAT_BITS 12 /* Diskette use 12 bits fat */
|
||||
|
||||
#define MAX_PATH 128 /* Max size of the MSDOS PATH */
|
||||
#define MAX_DIR_SECS 64 /* Taille max d'un repertoire (en */
|
||||
/* secteurs) */
|
||||
/* Misc. definitions */
|
||||
#define DELMARK '\xe5'
|
||||
#define EXTENDED_BOOT (0x29)
|
||||
#define MEDIA_STD (0xf0)
|
||||
#define JUMP_0_1 (0xe9)
|
||||
#define JUMP_0_2 (0xeb)
|
||||
|
||||
/* Boot size is 256 bytes, but we need to read almost a sector, then
|
||||
assume bootsize is 512 */
|
||||
#define BOOTSIZE 512
|
||||
|
||||
/* Fat definitions for 12 bits fat */
|
||||
#define FAT12_MAX_NB 4086
|
||||
#define FAT12_LAST 0x0ff6
|
||||
#define FAT12_END 0x0fff
|
||||
|
||||
/* file attributes */
|
||||
#define ATTR_READONLY 0x01
|
||||
#define ATTR_HIDDEN 0x02
|
||||
#define ATTR_SYSTEM 0x04
|
||||
#define ATTR_VOLUME 0x08
|
||||
#define ATTR_DIRECTORY 0x10
|
||||
#define ATTR_ARCHIVE 0x20
|
||||
#define ATTR_VSE 0x0f
|
||||
|
||||
/* Name format */
|
||||
#define EXTCASE 0x10
|
||||
#define BASECASE 0x8
|
||||
|
||||
/* Definition of the boot sector */
|
||||
#define BANNER_LG 8
|
||||
#define LABEL_LG 11
|
||||
|
||||
typedef struct bootsector
|
||||
{
|
||||
unsigned char jump [3]; /* 0 Jump to boot code */
|
||||
char banner [BANNER_LG]; /* 3 OEM name & version */
|
||||
unsigned short secsiz; /* 11 Bytes per sector hopefully 512 */
|
||||
unsigned char clsiz; /* 13 Cluster size in sectors */
|
||||
unsigned short nrsvsect; /* 14 Number of reserved (boot) sectors */
|
||||
unsigned char nfat; /* 16 Number of FAT tables hopefully 2 */
|
||||
unsigned short dirents; /* 17 Number of directory slots */
|
||||
unsigned short psect; /* 19 Total sectors on disk */
|
||||
unsigned char descr; /* 21 Media descriptor=first byte of FAT */
|
||||
unsigned short fatlen; /* 22 Sectors in FAT */
|
||||
unsigned short nsect; /* 24 Sectors/track */
|
||||
unsigned short nheads; /* 26 Heads */
|
||||
unsigned int nhs; /* 28 number of hidden sectors */
|
||||
unsigned int bigsect; /* 32 big total sectors */
|
||||
unsigned char physdrive; /* 36 physical drive ? */
|
||||
unsigned char reserved; /* 37 reserved */
|
||||
unsigned char dos4; /* 38 dos > 4.0 diskette */
|
||||
unsigned int serial; /* 39 serial number */
|
||||
char label [LABEL_LG]; /* 43 disk label */
|
||||
char fat_type [8]; /* 54 FAT type */
|
||||
unsigned char res_2m; /* 62 reserved by 2M */
|
||||
unsigned char CheckSum; /* 63 2M checksum (not used) */
|
||||
unsigned char fmt_2mf; /* 64 2MF format version */
|
||||
unsigned char wt; /* 65 1 if write track after format */
|
||||
unsigned char rate_0; /* 66 data transfer rate on track 0 */
|
||||
unsigned char rate_any; /* 67 data transfer rate on track<>0 */
|
||||
unsigned short BootP; /* 68 offset to boot program */
|
||||
unsigned short Infp0; /* 70 T1: information for track 0 */
|
||||
unsigned short InfpX; /* 72 T2: information for track<>0 */
|
||||
unsigned short InfTm; /* 74 T3: track sectors size table */
|
||||
unsigned short DateF; /* 76 Format date */
|
||||
unsigned short TimeF; /* 78 Format time */
|
||||
unsigned char junk [BOOTSIZE - 80]; /* 80 remaining data */
|
||||
} __attribute__ ((packed)) BootSector_t;
|
||||
|
||||
/* Structure d'une entree de repertoire */
|
||||
typedef struct directory {
|
||||
char name [8]; /* file name */
|
||||
char ext [3]; /* file extension */
|
||||
unsigned char attr; /* attribute byte */
|
||||
unsigned char Case; /* case of short filename */
|
||||
unsigned char reserved [9]; /* ?? */
|
||||
unsigned char time [2]; /* time stamp */
|
||||
unsigned char date [2]; /* date stamp */
|
||||
unsigned short start; /* starting cluster number */
|
||||
unsigned int size; /* size of the file */
|
||||
} __attribute__ ((packed)) Directory_t;
|
||||
|
||||
|
||||
#define MAX_VFAT_SUBENTRIES 20
|
||||
#define VSE_NAMELEN 13
|
||||
|
||||
#define VSE1SIZE 5
|
||||
#define VSE2SIZE 6
|
||||
#define VSE3SIZE 2
|
||||
|
||||
#define VBUFSIZE ((MAX_VFAT_SUBENTRIES * VSE_NAMELEN) + 1)
|
||||
|
||||
#define MAX_VNAMELEN (255)
|
||||
|
||||
#define VSE_PRESENT 0x01
|
||||
#define VSE_LAST 0x40
|
||||
#define VSE_MASK 0x1f
|
||||
|
||||
/* Flag used by vfat_lookup */
|
||||
#define DO_OPEN 1
|
||||
#define ACCEPT_PLAIN 0x20
|
||||
#define ACCEPT_DIR 0x10
|
||||
#define ACCEPT_LABEL 0x08
|
||||
#define SINGLE 2
|
||||
#define MATCH_ANY 0x40
|
||||
|
||||
struct vfat_subentry {
|
||||
unsigned char id; /* VSE_LAST pour la fin, VSE_MASK */
|
||||
/* pour un VSE */
|
||||
char text1 [VSE1SIZE * 2]; /* Caracteres encodes sur 16 bits */
|
||||
unsigned char attribute; /* 0x0f pour les VFAT */
|
||||
unsigned char hash1; /* toujours 0 */
|
||||
unsigned char sum; /* Checksum du nom court */
|
||||
char text2 [VSE2SIZE * 2]; /* Caracteres encodes sur 16 bits */
|
||||
unsigned char sector_l; /* 0 pour les VFAT */
|
||||
unsigned char sector_u; /* 0 pour les VFAT */
|
||||
char text3 [VSE3SIZE * 2]; /* Caracteres encodes sur 16 bits */
|
||||
} __attribute__ ((packed)) ;
|
||||
|
||||
struct vfat_state {
|
||||
char name [VBUFSIZE];
|
||||
int status; /* is now a bit map of 32 bits */
|
||||
int subentries;
|
||||
unsigned char sum; /* no need to remember the sum for each */
|
||||
/* entry, it is the same anyways */
|
||||
} __attribute__ ((packed)) ;
|
||||
|
||||
/* Conversion macros */
|
||||
#define DOS_YEAR(dir) (((dir)->date[1] >> 1) + 1980)
|
||||
#define DOS_MONTH(dir) (((((dir)->date[1]&0x1) << 3) + ((dir)->date[0] >> 5)))
|
||||
#define DOS_DAY(dir) ((dir)->date[0] & 0x1f)
|
||||
#define DOS_HOUR(dir) ((dir)->time[1] >> 3)
|
||||
#define DOS_MINUTE(dir) (((((dir)->time[1]&0x7) << 3) + ((dir)->time[0] >> 5)))
|
||||
#define DOS_SEC(dir) (((dir)->time[0] & 0x1f) * 2)
|
||||
|
||||
|
||||
#endif
|
142
fs/fdos/fat.c
142
fs/fdos/fat.c
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Stäubli Faverges - <www.staubli.com>
|
||||
* Pierre AUBERT p.aubert@staubli.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
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
|
||||
|
||||
#include "dos.h"
|
||||
#include "fdos.h"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* fat_decode --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
unsigned int fat_decode (Fs_t *fs, unsigned int num)
|
||||
{
|
||||
unsigned int start = num * 3 / 2;
|
||||
unsigned char *address = fs -> fat_buf + start;
|
||||
|
||||
if (num < 2 || start + 1 > (fs -> fat_len * SZ_STD_SECTOR))
|
||||
return 1;
|
||||
|
||||
if (num & 1)
|
||||
return ((address [1] & 0xff) << 4) | ((address [0] & 0xf0 ) >> 4);
|
||||
else
|
||||
return ((address [1] & 0xf) << 8) | (address [0] & 0xff );
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* check_fat --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int check_fat (Fs_t *fs)
|
||||
{
|
||||
int i, f;
|
||||
|
||||
/* Cluster verification */
|
||||
for (i = 3 ; i < fs -> num_clus; i++){
|
||||
f = fat_decode (fs, i);
|
||||
if (f < FAT12_LAST && f > fs -> num_clus){
|
||||
/* Wrong cluster number detected */
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* read_one_fat --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int read_one_fat (BootSector_t *boot, Fs_t *fs, int nfat)
|
||||
{
|
||||
if (dev_read (fs -> fat_buf,
|
||||
(fs -> fat_start + nfat * fs -> fat_len),
|
||||
fs -> fat_len) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (fs -> fat_buf [0] || fs -> fat_buf [1] || fs -> fat_buf [2]) {
|
||||
if ((fs -> fat_buf [0] != boot -> descr &&
|
||||
(fs -> fat_buf [0] != 0xf9 || boot -> descr != MEDIA_STD)) ||
|
||||
fs -> fat_buf [0] < MEDIA_STD){
|
||||
/* Unknown Media */
|
||||
return (-1);
|
||||
}
|
||||
if (fs -> fat_buf [1] != 0xff || fs -> fat_buf [2] != 0xff){
|
||||
/* FAT doesn't start with good values */
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (fs -> num_clus >= FAT12_MAX_NB) {
|
||||
/* Too much clusters */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return check_fat (fs);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* read_fat --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int read_fat (BootSector_t *boot, Fs_t *fs)
|
||||
{
|
||||
unsigned int buflen;
|
||||
int i;
|
||||
|
||||
/* Allocate Fat Buffer */
|
||||
buflen = fs -> fat_len * SZ_STD_SECTOR;
|
||||
if (fs -> fat_buf) {
|
||||
free (fs -> fat_buf);
|
||||
}
|
||||
|
||||
if ((fs -> fat_buf = malloc (buflen)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Try to read each Fat */
|
||||
for (i = 0; i< fs -> nb_fat; i++){
|
||||
if (read_one_fat (boot, fs, i) == 0) {
|
||||
/* Fat is OK */
|
||||
fs -> num_fat = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == fs -> nb_fat){
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (fs -> fat_len > (((fs -> num_clus + 2) *
|
||||
(FAT_BITS / 4) -1 ) / 2 /
|
||||
SZ_STD_SECTOR + 1)) {
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
175
fs/fdos/fdos.c
175
fs/fdos/fdos.c
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Stäubli Faverges - <www.staubli.com>
|
||||
* Pierre AUBERT p.aubert@staubli.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
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
|
||||
#include <malloc.h>
|
||||
#include "dos.h"
|
||||
#include "fdos.h"
|
||||
|
||||
|
||||
const char *month [] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
|
||||
Fs_t fs;
|
||||
File_t file;
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* dos_open --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int dos_open(char *name)
|
||||
{
|
||||
int lg;
|
||||
int entry;
|
||||
char *fname;
|
||||
|
||||
/* We need to suppress the " char around the name */
|
||||
if (name [0] == '"') {
|
||||
name ++;
|
||||
}
|
||||
lg = strlen (name);
|
||||
if (name [lg - 1] == '"') {
|
||||
name [lg - 1] = '\0';
|
||||
}
|
||||
|
||||
/* Open file system */
|
||||
if (fs_init (&fs) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Init the file descriptor */
|
||||
file.name = name;
|
||||
file.fs = &fs;
|
||||
|
||||
/* find the subdirectory containing the file */
|
||||
if (open_subdir (&file) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
fname = basename (name);
|
||||
|
||||
/* if we try to open root directory */
|
||||
if (*fname == '\0') {
|
||||
file.file = file.subdir;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* find the file in the subdir */
|
||||
entry = 0;
|
||||
if (vfat_lookup (&file.subdir,
|
||||
file.fs,
|
||||
&file.file.dir,
|
||||
&entry,
|
||||
0,
|
||||
fname,
|
||||
ACCEPT_DIR | ACCEPT_PLAIN | SINGLE | DO_OPEN,
|
||||
0,
|
||||
&file.file) != 0) {
|
||||
/* File not found */
|
||||
printf ("File not found\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* dos_read --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int dos_read (ulong addr)
|
||||
{
|
||||
int read = 0, nb;
|
||||
|
||||
/* Try to boot a directory ? */
|
||||
if (file.file.dir.attr & (ATTR_DIRECTORY | ATTR_VOLUME)) {
|
||||
printf ("Unable to boot %s !!\n", file.name);
|
||||
return (-1);
|
||||
}
|
||||
while (read < file.file.FileSize) {
|
||||
PRINTF ("read_file (%ld)\n", (file.file.FileSize - read));
|
||||
nb = read_file (&fs,
|
||||
&file.file,
|
||||
(char *)addr + read,
|
||||
read,
|
||||
(file.file.FileSize - read));
|
||||
PRINTF ("read_file -> %d\n", nb);
|
||||
if (nb < 0) {
|
||||
printf ("read error\n");
|
||||
return (-1);
|
||||
}
|
||||
read += nb;
|
||||
}
|
||||
return (read);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* dos_dir --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int dos_dir (void)
|
||||
{
|
||||
int entry;
|
||||
Directory_t dir;
|
||||
char *name;
|
||||
|
||||
|
||||
if ((file.file.dir.attr & ATTR_DIRECTORY) == 0) {
|
||||
printf ("%s: not a directory !!\n", file.name);
|
||||
return (1);
|
||||
}
|
||||
entry = 0;
|
||||
if ((name = malloc (MAX_VNAMELEN + 1)) == NULL) {
|
||||
PRINTF ("Allcation error\n");
|
||||
return (1);
|
||||
}
|
||||
|
||||
while (vfat_lookup (&file.file,
|
||||
file.fs,
|
||||
&dir,
|
||||
&entry,
|
||||
0,
|
||||
NULL,
|
||||
ACCEPT_DIR | ACCEPT_PLAIN | MATCH_ANY,
|
||||
name,
|
||||
NULL) == 0) {
|
||||
/* Display file info */
|
||||
printf ("%3.3s %9d %s %02d %04d %02d:%02d:%02d %s\n",
|
||||
(dir.attr & ATTR_DIRECTORY) ? "dir" : " ",
|
||||
__le32_to_cpu (dir.size),
|
||||
month [DOS_MONTH (&dir) - 1],
|
||||
DOS_DAY (&dir),
|
||||
DOS_YEAR (&dir),
|
||||
DOS_HOUR (&dir),
|
||||
DOS_MINUTE (&dir),
|
||||
DOS_SEC (&dir),
|
||||
name);
|
||||
|
||||
}
|
||||
free (name);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
116
fs/fdos/fdos.h
116
fs/fdos/fdos.h
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Stäubli Faverges - <www.staubli.com>
|
||||
* Pierre AUBERT p.aubert@staubli.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
|
||||
*/
|
||||
|
||||
#ifndef _FDOS_H_
|
||||
#define _FDOS_H_
|
||||
|
||||
|
||||
#undef FDOS_DEBUG
|
||||
|
||||
#ifdef FDOS_DEBUG
|
||||
#define PRINTF(fmt,args...) printf (fmt ,##args)
|
||||
#else
|
||||
#define PRINTF(fmt,args...)
|
||||
#endif
|
||||
|
||||
/* Data structure describing media */
|
||||
typedef struct fs
|
||||
{
|
||||
unsigned long tot_sectors;
|
||||
|
||||
int cluster_size;
|
||||
int num_clus;
|
||||
|
||||
int fat_start;
|
||||
int fat_len;
|
||||
int nb_fat;
|
||||
int num_fat;
|
||||
|
||||
int dir_start;
|
||||
int dir_len;
|
||||
|
||||
unsigned char *fat_buf;
|
||||
|
||||
} Fs_t;
|
||||
|
||||
/* Data structure describing one file system slot */
|
||||
typedef struct slot {
|
||||
int (*map) (struct fs *fs,
|
||||
struct slot *file,
|
||||
int where,
|
||||
int *len);
|
||||
unsigned long FileSize;
|
||||
|
||||
unsigned short int FirstAbsCluNr;
|
||||
unsigned short int PreviousAbsCluNr;
|
||||
unsigned short int PreviousRelCluNr;
|
||||
|
||||
Directory_t dir;
|
||||
} Slot_t;
|
||||
|
||||
typedef struct file {
|
||||
char *name;
|
||||
int Case;
|
||||
Fs_t *fs;
|
||||
Slot_t subdir;
|
||||
Slot_t file;
|
||||
} File_t;
|
||||
|
||||
|
||||
/* dev.c */
|
||||
int dev_read (void *buffer, int where, int len);
|
||||
int dev_open (void);
|
||||
int check_dev (BootSector_t *boot, Fs_t *fs);
|
||||
|
||||
/* fat.c */
|
||||
unsigned int fat_decode (Fs_t *fs, unsigned int num);
|
||||
int read_fat (BootSector_t *boot, Fs_t *fs);
|
||||
|
||||
/* vfat.c */
|
||||
int vfat_lookup (Slot_t *dir,
|
||||
Fs_t *fs,
|
||||
Directory_t *dirent,
|
||||
int *entry,
|
||||
int *vfat_start,
|
||||
char *filename,
|
||||
int flags,
|
||||
char *outname,
|
||||
Slot_t *file);
|
||||
|
||||
/* subdir.c */
|
||||
char *basename (char *name);
|
||||
int open_subdir (File_t *desc);
|
||||
int open_file (Slot_t *file, Directory_t *dir);
|
||||
int read_file (Fs_t *fs,
|
||||
Slot_t *file,
|
||||
char *buf,
|
||||
int where,
|
||||
int len);
|
||||
void init_subdir (void);
|
||||
|
||||
/* fs.c */
|
||||
int fs_init (Fs_t *fs);
|
||||
|
||||
|
||||
#endif
|
118
fs/fdos/fs.c
118
fs/fdos/fs.c
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Stäubli Faverges - <www.staubli.com>
|
||||
* Pierre AUBERT p.aubert@staubli.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
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
|
||||
|
||||
#include "dos.h"
|
||||
#include "fdos.h"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* fill_fs -- Read info on file system
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int fill_fs (BootSector_t *boot, Fs_t *fs)
|
||||
{
|
||||
|
||||
fs -> fat_start = __le16_to_cpu (boot -> nrsvsect);
|
||||
fs -> fat_len = __le16_to_cpu (boot -> fatlen);
|
||||
fs -> nb_fat = boot -> nfat;
|
||||
|
||||
fs -> dir_start = fs -> fat_start + fs -> nb_fat * fs -> fat_len;
|
||||
fs -> dir_len = __le16_to_cpu (boot -> dirents) * MDIR_SIZE / SZ_STD_SECTOR;
|
||||
fs -> cluster_size = boot -> clsiz;
|
||||
fs -> num_clus = (fs -> tot_sectors - fs -> dir_start - fs -> dir_len) / fs -> cluster_size;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* fs_init --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int fs_init (Fs_t *fs)
|
||||
{
|
||||
BootSector_t *boot;
|
||||
|
||||
/* Initialize physical device */
|
||||
if (dev_open () < 0) {
|
||||
PRINTF ("Unable to initialize the fdc\n");
|
||||
return (-1);
|
||||
}
|
||||
init_subdir ();
|
||||
|
||||
/* Allocate space for read the boot sector */
|
||||
if ((boot = (BootSector_t *)malloc (sizeof (BootSector_t))) == NULL) {
|
||||
PRINTF ("Unable to allocate space for boot sector\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* read boot sector */
|
||||
if (dev_read (boot, 0, 1)){
|
||||
PRINTF ("Error during boot sector read\n");
|
||||
free (boot);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* we verify it'a a DOS diskette */
|
||||
if (boot -> jump [0] != JUMP_0_1 && boot -> jump [0] != JUMP_0_2) {
|
||||
PRINTF ("Not a DOS diskette\n");
|
||||
free (boot);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (boot -> descr < MEDIA_STD) {
|
||||
/* We handle only recent medias (type F0) */
|
||||
PRINTF ("unrecognized diskette type\n");
|
||||
free (boot);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (check_dev (boot, fs) < 0) {
|
||||
PRINTF ("Bad diskette\n");
|
||||
free (boot);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (fill_fs (boot, fs) < 0) {
|
||||
free (boot);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Read FAT */
|
||||
if (read_fat (boot, fs) < 0) {
|
||||
free (boot);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
free (boot);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
348
fs/fdos/subdir.c
348
fs/fdos/subdir.c
|
@ -1,348 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Stäubli Faverges - <www.staubli.com>
|
||||
* Pierre AUBERT p.aubert@staubli.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
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
|
||||
|
||||
#include "dos.h"
|
||||
#include "fdos.h"
|
||||
|
||||
static int cache_sect;
|
||||
static unsigned char cache [SZ_STD_SECTOR];
|
||||
|
||||
|
||||
#define min(x,y) ((x)<(y)?(x):(y))
|
||||
|
||||
static int descend (Slot_t *parent,
|
||||
Fs_t *fs,
|
||||
char *path);
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* init_subdir --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
void init_subdir (void)
|
||||
{
|
||||
cache_sect = -1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* basename --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
char *basename (char *name)
|
||||
{
|
||||
register char *cptr;
|
||||
|
||||
if (!name || !*name) {
|
||||
return ("");
|
||||
}
|
||||
|
||||
for (cptr= name; *cptr++; );
|
||||
while (--cptr >= name) {
|
||||
if (*cptr == '/') {
|
||||
return (cptr + 1);
|
||||
}
|
||||
}
|
||||
return(name);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* root_map --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int root_map (Fs_t *fs, Slot_t *file, int where, int *len)
|
||||
{
|
||||
*len = min (*len, fs -> dir_len * SZ_STD_SECTOR - where);
|
||||
if (*len < 0 ) {
|
||||
*len = 0;
|
||||
return (-1);
|
||||
}
|
||||
return fs -> dir_start * SZ_STD_SECTOR + where;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* normal_map --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int normal_map (Fs_t *fs, Slot_t *file, int where, int *len)
|
||||
{
|
||||
int offset;
|
||||
int NrClu;
|
||||
unsigned short RelCluNr;
|
||||
unsigned short CurCluNr;
|
||||
unsigned short NewCluNr;
|
||||
unsigned short AbsCluNr;
|
||||
int clus_size;
|
||||
|
||||
clus_size = fs -> cluster_size * SZ_STD_SECTOR;
|
||||
offset = where % clus_size;
|
||||
|
||||
*len = min (*len, file -> FileSize - where);
|
||||
|
||||
if (*len < 0 ) {
|
||||
*len = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (file -> FirstAbsCluNr < 2){
|
||||
*len = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
RelCluNr = where / clus_size;
|
||||
|
||||
if (RelCluNr >= file -> PreviousRelCluNr){
|
||||
CurCluNr = file -> PreviousRelCluNr;
|
||||
AbsCluNr = file -> PreviousAbsCluNr;
|
||||
} else {
|
||||
CurCluNr = 0;
|
||||
AbsCluNr = file -> FirstAbsCluNr;
|
||||
}
|
||||
|
||||
|
||||
NrClu = (offset + *len - 1) / clus_size;
|
||||
while (CurCluNr <= RelCluNr + NrClu) {
|
||||
if (CurCluNr == RelCluNr){
|
||||
/* we have reached the beginning of our zone. Save
|
||||
* coordinates */
|
||||
file -> PreviousRelCluNr = RelCluNr;
|
||||
file -> PreviousAbsCluNr = AbsCluNr;
|
||||
}
|
||||
NewCluNr = fat_decode (fs, AbsCluNr);
|
||||
if (NewCluNr == 1 || NewCluNr == 0) {
|
||||
PRINTF("Fat problem while decoding %d %x\n",
|
||||
AbsCluNr, NewCluNr);
|
||||
return (-1);
|
||||
}
|
||||
if (CurCluNr == RelCluNr + NrClu) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (CurCluNr < RelCluNr && NewCluNr == FAT12_END) {
|
||||
*len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
|
||||
break;
|
||||
CurCluNr++;
|
||||
AbsCluNr = NewCluNr;
|
||||
}
|
||||
|
||||
*len = min (*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
|
||||
|
||||
return (((file -> PreviousAbsCluNr - 2) * fs -> cluster_size +
|
||||
fs -> dir_start + fs -> dir_len) *
|
||||
SZ_STD_SECTOR + offset);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* open_subdir -- open the subdir containing the file
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int open_subdir (File_t *desc)
|
||||
{
|
||||
char *pathname;
|
||||
char *tmp, *s, *path;
|
||||
char terminator;
|
||||
|
||||
if ((pathname = (char *)malloc (MAX_PATH)) == NULL) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
strcpy (pathname, desc -> name);
|
||||
|
||||
/* Suppress file name */
|
||||
tmp = basename (pathname);
|
||||
*tmp = '\0';
|
||||
|
||||
/* root directory init */
|
||||
desc -> subdir.FirstAbsCluNr = 0;
|
||||
desc -> subdir.FileSize = -1;
|
||||
desc -> subdir.map = root_map;
|
||||
desc -> subdir.dir.attr = ATTR_DIRECTORY;
|
||||
|
||||
tmp = pathname;
|
||||
for (s = tmp; ; ++s) {
|
||||
if (*s == '/' || *s == '\0') {
|
||||
path = tmp;
|
||||
terminator = *s;
|
||||
*s = '\0';
|
||||
if (s != tmp && strcmp (path,".")) {
|
||||
if (descend (&desc -> subdir, desc -> fs, path) < 0) {
|
||||
free (pathname);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
if (terminator == 0) {
|
||||
break;
|
||||
}
|
||||
tmp = s + 1;
|
||||
}
|
||||
}
|
||||
free (pathname);
|
||||
return (0);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* descend --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int descend (Slot_t *parent,
|
||||
Fs_t *fs,
|
||||
char *path)
|
||||
{
|
||||
int entry;
|
||||
Slot_t SubDir;
|
||||
|
||||
if(path[0] == '\0' || strcmp (path, ".") == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
entry = 0;
|
||||
if (vfat_lookup (parent,
|
||||
fs,
|
||||
&(SubDir.dir),
|
||||
&entry,
|
||||
0,
|
||||
path,
|
||||
ACCEPT_DIR | SINGLE | DO_OPEN,
|
||||
0,
|
||||
&SubDir) == 0) {
|
||||
*parent = SubDir;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (strcmp(path, "..") == 0) {
|
||||
parent -> FileSize = -1;
|
||||
parent -> FirstAbsCluNr = 0;
|
||||
parent -> map = root_map;
|
||||
return (0);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* open_file --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int open_file (Slot_t *file, Directory_t *dir)
|
||||
{
|
||||
int first;
|
||||
unsigned long size;
|
||||
|
||||
first = __le16_to_cpu (dir -> start);
|
||||
|
||||
if(first == 0 &&
|
||||
(dir -> attr & ATTR_DIRECTORY) != 0) {
|
||||
file -> FirstAbsCluNr = 0;
|
||||
file -> FileSize = -1;
|
||||
file -> map = root_map;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if ((dir -> attr & ATTR_DIRECTORY) != 0) {
|
||||
size = (1UL << 31) - 1;
|
||||
}
|
||||
else {
|
||||
size = __le32_to_cpu (dir -> size);
|
||||
}
|
||||
|
||||
file -> map = normal_map;
|
||||
file -> FirstAbsCluNr = first;
|
||||
file -> PreviousRelCluNr = 0xffff;
|
||||
file -> FileSize = size;
|
||||
return (0);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* read_file --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int read_file (Fs_t *fs,
|
||||
Slot_t *file,
|
||||
char *buf,
|
||||
int where,
|
||||
int len)
|
||||
{
|
||||
int pos;
|
||||
int read, nb, sect, offset;
|
||||
|
||||
pos = file -> map (fs, file, where, &len);
|
||||
if (pos < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (len == 0) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Compute sector number */
|
||||
sect = pos / SZ_STD_SECTOR;
|
||||
offset = pos % SZ_STD_SECTOR;
|
||||
read = 0;
|
||||
|
||||
if (offset) {
|
||||
/* Read doesn't start at the sector beginning. We need to use our */
|
||||
/* cache */
|
||||
if (sect != cache_sect) {
|
||||
if (dev_read (cache, sect, 1) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
cache_sect = sect;
|
||||
}
|
||||
nb = min (len, SZ_STD_SECTOR - offset);
|
||||
|
||||
memcpy (buf, cache + offset, nb);
|
||||
read += nb;
|
||||
len -= nb;
|
||||
sect += 1;
|
||||
}
|
||||
|
||||
if (len > SZ_STD_SECTOR) {
|
||||
nb = (len - 1) / SZ_STD_SECTOR;
|
||||
if (dev_read (buf + read, sect, nb) < 0) {
|
||||
return ((read) ? read : -1);
|
||||
}
|
||||
/* update sector position */
|
||||
sect += nb;
|
||||
|
||||
/* Update byte position */
|
||||
nb *= SZ_STD_SECTOR;
|
||||
read += nb;
|
||||
len -= nb;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
if (sect != cache_sect) {
|
||||
if (dev_read (cache, sect, 1) < 0) {
|
||||
return ((read) ? read : -1);
|
||||
cache_sect = -1;
|
||||
}
|
||||
cache_sect = sect;
|
||||
}
|
||||
|
||||
memcpy (buf + read, cache, len);
|
||||
read += len;
|
||||
}
|
||||
return (read);
|
||||
}
|
||||
#endif
|
357
fs/fdos/vfat.c
357
fs/fdos/vfat.c
|
@ -1,357 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Stäubli Faverges - <www.staubli.com>
|
||||
* Pierre AUBERT p.aubert@staubli.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
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_FDOS)
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include "dos.h"
|
||||
#include "fdos.h"
|
||||
|
||||
static int dir_read (Fs_t *fs,
|
||||
Slot_t *dir,
|
||||
Directory_t *dirent,
|
||||
int num,
|
||||
struct vfat_state *v);
|
||||
|
||||
static int unicode_read (char *in, char *out, int num);
|
||||
static int match (const char *s, const char *p);
|
||||
static unsigned char sum_shortname (char *name);
|
||||
static int check_vfat (struct vfat_state *v, Directory_t *dir);
|
||||
static char *conv_name (char *name, char *ext, char Case, char *ans);
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* clear_vfat --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static void clear_vfat (struct vfat_state *v)
|
||||
{
|
||||
v -> subentries = 0;
|
||||
v -> status = 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* vfat_lookup --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
int vfat_lookup (Slot_t *dir,
|
||||
Fs_t *fs,
|
||||
Directory_t *dirent,
|
||||
int *entry,
|
||||
int *vfat_start,
|
||||
char *filename,
|
||||
int flags,
|
||||
char *outname,
|
||||
Slot_t *file)
|
||||
{
|
||||
int found;
|
||||
struct vfat_state vfat;
|
||||
char newfile [VSE_NAMELEN];
|
||||
int vfat_present = 0;
|
||||
|
||||
if (*entry == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
clear_vfat (&vfat);
|
||||
while (1) {
|
||||
if (dir_read (fs, dir, dirent, *entry, &vfat) < 0) {
|
||||
if (vfat_start) {
|
||||
*vfat_start = *entry;
|
||||
}
|
||||
break;
|
||||
}
|
||||
(*entry)++;
|
||||
|
||||
/* Empty slot */
|
||||
if (dirent -> name[0] == '\0'){
|
||||
if (vfat_start == 0) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dirent -> attr == ATTR_VSE) {
|
||||
/* VSE entry, continue */
|
||||
continue;
|
||||
}
|
||||
if ( (dirent -> name [0] == DELMARK) ||
|
||||
((dirent -> attr & ATTR_DIRECTORY) != 0 &&
|
||||
(flags & ACCEPT_DIR) == 0) ||
|
||||
((dirent -> attr & ATTR_VOLUME) != 0 &&
|
||||
(flags & ACCEPT_LABEL) == 0) ||
|
||||
(((dirent -> attr & (ATTR_DIRECTORY | ATTR_VOLUME)) == 0) &&
|
||||
(flags & ACCEPT_PLAIN) == 0)) {
|
||||
clear_vfat (&vfat);
|
||||
continue;
|
||||
}
|
||||
|
||||
vfat_present = check_vfat (&vfat, dirent);
|
||||
if (vfat_start) {
|
||||
*vfat_start = *entry - 1;
|
||||
if (vfat_present) {
|
||||
*vfat_start -= vfat.subentries;
|
||||
}
|
||||
}
|
||||
|
||||
if (dirent -> attr & ATTR_VOLUME) {
|
||||
strncpy (newfile, dirent -> name, 8);
|
||||
newfile [8] = '\0';
|
||||
strncat (newfile, dirent -> ext, 3);
|
||||
newfile [11] = '\0';
|
||||
}
|
||||
else {
|
||||
conv_name (dirent -> name, dirent -> ext, dirent -> Case, newfile);
|
||||
}
|
||||
|
||||
if (flags & MATCH_ANY) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((vfat_present && match (vfat.name, filename)) ||
|
||||
(match (newfile, filename))) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
clear_vfat (&vfat);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
if ((flags & DO_OPEN) && file) {
|
||||
if (open_file (file, dirent) < 0) {
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
if (outname) {
|
||||
if (vfat_present) {
|
||||
strcpy (outname, vfat.name);
|
||||
}
|
||||
else {
|
||||
strcpy (outname, newfile);
|
||||
}
|
||||
}
|
||||
return (0); /* File found */
|
||||
} else {
|
||||
*entry = -1;
|
||||
return -1; /* File not found */
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* dir_read -- Read one directory entry
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int dir_read (Fs_t *fs,
|
||||
Slot_t *dir,
|
||||
Directory_t *dirent,
|
||||
int num,
|
||||
struct vfat_state *v)
|
||||
{
|
||||
|
||||
/* read the directory entry */
|
||||
if (read_file (fs,
|
||||
dir,
|
||||
(char *)dirent,
|
||||
num * MDIR_SIZE,
|
||||
MDIR_SIZE) != MDIR_SIZE) {
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (v && (dirent -> attr == ATTR_VSE)) {
|
||||
struct vfat_subentry *vse;
|
||||
unsigned char id, last_flag;
|
||||
char *c;
|
||||
|
||||
vse = (struct vfat_subentry *) dirent;
|
||||
id = vse -> id & VSE_MASK;
|
||||
last_flag = (vse -> id & VSE_LAST);
|
||||
if (id > MAX_VFAT_SUBENTRIES) {
|
||||
/* Invalid VSE entry */
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
/* Decode VSE */
|
||||
if(v -> sum != vse -> sum) {
|
||||
clear_vfat (v);
|
||||
v -> sum = vse -> sum;
|
||||
}
|
||||
|
||||
|
||||
v -> status |= 1 << (id - 1);
|
||||
if (last_flag) {
|
||||
v -> subentries = id;
|
||||
}
|
||||
|
||||
c = &(v -> name [VSE_NAMELEN * (id - 1)]);
|
||||
c += unicode_read (vse->text1, c, VSE1SIZE);
|
||||
c += unicode_read (vse->text2, c, VSE2SIZE);
|
||||
c += unicode_read (vse->text3, c, VSE3SIZE);
|
||||
|
||||
if (last_flag) {
|
||||
*c = '\0'; /* Null terminate long name */
|
||||
}
|
||||
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* unicode_read --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int unicode_read (char *in, char *out, int num)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < num; ++j) {
|
||||
if (in [1])
|
||||
*out = '_';
|
||||
else
|
||||
*out = in [0];
|
||||
out ++;
|
||||
in += 2;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* match --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int match (const char *s, const char *p)
|
||||
{
|
||||
|
||||
for (; *p != '\0'; ) {
|
||||
if (toupper (*s) != toupper (*p)) {
|
||||
return (0);
|
||||
}
|
||||
p++;
|
||||
s++;
|
||||
}
|
||||
|
||||
if (*s != '\0') {
|
||||
return (0);
|
||||
}
|
||||
else {
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* sum_shortname --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static unsigned char sum_shortname (char *name)
|
||||
{
|
||||
unsigned char sum;
|
||||
int j;
|
||||
|
||||
for (j = sum = 0; j < 11; ++j) {
|
||||
sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) +
|
||||
(name [j] ? name [j] : ' ');
|
||||
}
|
||||
return (sum);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* check_vfat --
|
||||
* Return 1 if long name is valid, 0 else
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static int check_vfat (struct vfat_state *v, Directory_t *dir)
|
||||
{
|
||||
char name[12];
|
||||
|
||||
if (v -> subentries == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
strncpy (name, dir -> name, 8);
|
||||
strncpy (name + 8, dir -> ext, 3);
|
||||
name [11] = '\0';
|
||||
|
||||
if (v -> sum != sum_shortname (name)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( (v -> status & ((1 << v -> subentries) - 1)) !=
|
||||
(1 << v -> subentries) - 1) {
|
||||
return 0;
|
||||
}
|
||||
v->name [VSE_NAMELEN * v -> subentries] = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* conv_name --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static char *conv_name (char *name, char *ext, char Case, char *ans)
|
||||
{
|
||||
char tname [9], text [4];
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while (i < 8 && name [i] != ' ' && name [i] != '\0') {
|
||||
tname [i] = name [i];
|
||||
i++;
|
||||
}
|
||||
tname [i] = '\0';
|
||||
|
||||
if (Case & BASECASE) {
|
||||
for (i = 0; i < 8 && tname [i]; i++) {
|
||||
tname [i] = tolower (tname [i]);
|
||||
}
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < 3 && ext [i] != ' ' && ext [i] != '\0') {
|
||||
text [i] = ext [i];
|
||||
i++;
|
||||
}
|
||||
text [i] = '\0';
|
||||
|
||||
if (Case & EXTCASE){
|
||||
for (i = 0; i < 3 && text [i]; i++) {
|
||||
text [i] = tolower (text [i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (*text) {
|
||||
strcpy (ans, tname);
|
||||
strcat (ans, ".");
|
||||
strcat (ans, text);
|
||||
}
|
||||
else {
|
||||
strcpy(ans, tname);
|
||||
}
|
||||
return (ans);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,50 +0,0 @@
|
|||
#
|
||||
# (C) Copyright 2000-2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.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 = $(obj)libjffs2.a
|
||||
|
||||
AOBJS =
|
||||
COBJS = jffs2_1pass.o compr_rtime.o compr_rubin.o compr_zlib.o mini_inflate.o
|
||||
COBJS += compr_lzo.o compr_lzari.o
|
||||
|
||||
SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS))
|
||||
|
||||
#CPPFLAGS +=
|
||||
|
||||
all: $(LIB) $(AOBJS)
|
||||
|
||||
$(LIB): $(obj).depend $(OBJS)
|
||||
$(AR) $(ARFLAGS) $@ $(OBJS)
|
||||
|
||||
|
||||
#########################################################################
|
||||
|
||||
# defines $(obj).depend target
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
|
@ -1,262 +0,0 @@
|
|||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2004 Patrik Kluba,
|
||||
* University of Szeged, Hungary
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in the
|
||||
* jffs2 directory.
|
||||
*
|
||||
* $Id: compr_lzari.c,v 1.3 2004/06/23 16:34:39 havasi Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
Lempel-Ziv-Arithmetic coding compression module for jffs2
|
||||
Based on the LZARI source included in LDS (lossless datacompression sources)
|
||||
*/
|
||||
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
|
||||
|
||||
/*
|
||||
Original copyright follows:
|
||||
|
||||
**************************************************************
|
||||
LZARI.C -- A Data Compression Program
|
||||
(tab = 4 spaces)
|
||||
**************************************************************
|
||||
4/7/1989 Haruhiko Okumura
|
||||
Use, distribute, and modify this program freely.
|
||||
Please send me your improved versions.
|
||||
PC-VAN SCIENCE
|
||||
NIFTY-Serve PAF01022
|
||||
CompuServe 74050,1022
|
||||
**************************************************************
|
||||
|
||||
LZARI.C (c)1989 by Haruyasu Yoshizaki, Haruhiko Okumura, and Kenji Rikitake.
|
||||
All rights reserved. Permission granted for non-commercial use.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
2004-02-18 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
|
||||
Removed unused variables and fixed no return value
|
||||
|
||||
2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
|
||||
Initial release
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#if ((CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_LZO_LZARI))
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#include <jffs2/jffs2.h>
|
||||
|
||||
|
||||
#define N 4096 /* size of ring buffer */
|
||||
#define F 60 /* upper limit for match_length */
|
||||
#define THRESHOLD 2 /* encode string into position and length
|
||||
if match_length is greater than this */
|
||||
#define NIL N /* index for root of binary search trees */
|
||||
|
||||
static unsigned char
|
||||
text_buf[N + F - 1]; /* ring buffer of size N,
|
||||
with extra F-1 bytes to facilitate string comparison */
|
||||
|
||||
/********** Arithmetic Compression **********/
|
||||
|
||||
/* If you are not familiar with arithmetic compression, you should read
|
||||
I. E. Witten, R. M. Neal, and J. G. Cleary,
|
||||
Communications of the ACM, Vol. 30, pp. 520-540 (1987),
|
||||
from which much have been borrowed. */
|
||||
|
||||
#define M 15
|
||||
|
||||
/* Q1 (= 2 to the M) must be sufficiently large, but not so
|
||||
large as the unsigned long 4 * Q1 * (Q1 - 1) overflows. */
|
||||
|
||||
#define Q1 (1UL << M)
|
||||
#define Q2 (2 * Q1)
|
||||
#define Q3 (3 * Q1)
|
||||
#define Q4 (4 * Q1)
|
||||
#define MAX_CUM (Q1 - 1)
|
||||
|
||||
#define N_CHAR (256 - THRESHOLD + F)
|
||||
/* character code = 0, 1, ..., N_CHAR - 1 */
|
||||
|
||||
static unsigned long char_to_sym[N_CHAR], sym_to_char[N_CHAR + 1];
|
||||
static unsigned long
|
||||
sym_freq[N_CHAR + 1], /* frequency for symbols */
|
||||
sym_cum[N_CHAR + 1], /* cumulative freq for symbols */
|
||||
position_cum[N + 1]; /* cumulative freq for positions */
|
||||
|
||||
static void StartModel(void) /* Initialize model */
|
||||
{
|
||||
unsigned long ch, sym, i;
|
||||
|
||||
sym_cum[N_CHAR] = 0;
|
||||
for (sym = N_CHAR; sym >= 1; sym--) {
|
||||
ch = sym - 1;
|
||||
char_to_sym[ch] = sym; sym_to_char[sym] = ch;
|
||||
sym_freq[sym] = 1;
|
||||
sym_cum[sym - 1] = sym_cum[sym] + sym_freq[sym];
|
||||
}
|
||||
sym_freq[0] = 0; /* sentinel (!= sym_freq[1]) */
|
||||
position_cum[N] = 0;
|
||||
for (i = N; i >= 1; i--)
|
||||
position_cum[i - 1] = position_cum[i] + 10000 / (i + 200);
|
||||
/* empirical distribution function (quite tentative) */
|
||||
/* Please devise a better mechanism! */
|
||||
}
|
||||
|
||||
static void UpdateModel(unsigned long sym)
|
||||
{
|
||||
unsigned long c, ch_i, ch_sym;
|
||||
unsigned long i;
|
||||
if (sym_cum[0] >= MAX_CUM) {
|
||||
c = 0;
|
||||
for (i = N_CHAR; i > 0; i--) {
|
||||
sym_cum[i] = c;
|
||||
c += (sym_freq[i] = (sym_freq[i] + 1) >> 1);
|
||||
}
|
||||
sym_cum[0] = c;
|
||||
}
|
||||
for (i = sym; sym_freq[i] == sym_freq[i - 1]; i--) ;
|
||||
if (i < sym) {
|
||||
ch_i = sym_to_char[i]; ch_sym = sym_to_char[sym];
|
||||
sym_to_char[i] = ch_sym; sym_to_char[sym] = ch_i;
|
||||
char_to_sym[ch_i] = sym; char_to_sym[ch_sym] = i;
|
||||
}
|
||||
sym_freq[i]++;
|
||||
while (--i > 0) sym_cum[i]++;
|
||||
sym_cum[0]++;
|
||||
}
|
||||
|
||||
static unsigned long BinarySearchSym(unsigned long x)
|
||||
/* 1 if x >= sym_cum[1],
|
||||
N_CHAR if sym_cum[N_CHAR] > x,
|
||||
i such that sym_cum[i - 1] > x >= sym_cum[i] otherwise */
|
||||
{
|
||||
unsigned long i, j, k;
|
||||
|
||||
i = 1; j = N_CHAR;
|
||||
while (i < j) {
|
||||
k = (i + j) / 2;
|
||||
if (sym_cum[k] > x) i = k + 1; else j = k;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
unsigned long BinarySearchPos(unsigned long x)
|
||||
/* 0 if x >= position_cum[1],
|
||||
N - 1 if position_cum[N] > x,
|
||||
i such that position_cum[i] > x >= position_cum[i + 1] otherwise */
|
||||
{
|
||||
unsigned long i, j, k;
|
||||
|
||||
i = 1; j = N;
|
||||
while (i < j) {
|
||||
k = (i + j) / 2;
|
||||
if (position_cum[k] > x) i = k + 1; else j = k;
|
||||
}
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
static int Decode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long srclen,
|
||||
unsigned long dstlen) /* Just the reverse of Encode(). */
|
||||
{
|
||||
unsigned long i, r, j, k, c, range, sym;
|
||||
unsigned char *ip, *op;
|
||||
unsigned char *srcend = srcbuf + srclen;
|
||||
unsigned char *dstend = dstbuf + dstlen;
|
||||
unsigned char buffer = 0;
|
||||
unsigned char mask = 0;
|
||||
unsigned long low = 0;
|
||||
unsigned long high = Q4;
|
||||
unsigned long value = 0;
|
||||
|
||||
ip = srcbuf;
|
||||
op = dstbuf;
|
||||
for (i = 0; i < M + 2; i++) {
|
||||
value *= 2;
|
||||
if ((mask >>= 1) == 0) {
|
||||
buffer = (ip >= srcend) ? 0 : *(ip++);
|
||||
mask = 128;
|
||||
}
|
||||
value += ((buffer & mask) != 0);
|
||||
}
|
||||
|
||||
StartModel();
|
||||
for (i = 0; i < N - F; i++) text_buf[i] = ' ';
|
||||
r = N - F;
|
||||
|
||||
while (op < dstend) {
|
||||
range = high - low;
|
||||
sym = BinarySearchSym((unsigned long)
|
||||
(((value - low + 1) * sym_cum[0] - 1) / range));
|
||||
high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
|
||||
low += (range * sym_cum[sym ]) / sym_cum[0];
|
||||
for ( ; ; ) {
|
||||
if (low >= Q2) {
|
||||
value -= Q2; low -= Q2; high -= Q2;
|
||||
} else if (low >= Q1 && high <= Q3) {
|
||||
value -= Q1; low -= Q1; high -= Q1;
|
||||
} else if (high > Q2) break;
|
||||
low += low; high += high;
|
||||
value *= 2;
|
||||
if ((mask >>= 1) == 0) {
|
||||
buffer = (ip >= srcend) ? 0 : *(ip++);
|
||||
mask = 128;
|
||||
}
|
||||
value += ((buffer & mask) != 0);
|
||||
}
|
||||
c = sym_to_char[sym];
|
||||
UpdateModel(sym);
|
||||
if (c < 256) {
|
||||
if (op >= dstend) return -1;
|
||||
*(op++) = c;
|
||||
text_buf[r++] = c;
|
||||
r &= (N - 1);
|
||||
} else {
|
||||
j = c - 255 + THRESHOLD;
|
||||
range = high - low;
|
||||
i = BinarySearchPos((unsigned long)
|
||||
(((value - low + 1) * position_cum[0] - 1) / range));
|
||||
high = low + (range * position_cum[i ]) / position_cum[0];
|
||||
low += (range * position_cum[i + 1]) / position_cum[0];
|
||||
for ( ; ; ) {
|
||||
if (low >= Q2) {
|
||||
value -= Q2; low -= Q2; high -= Q2;
|
||||
} else if (low >= Q1 && high <= Q3) {
|
||||
value -= Q1; low -= Q1; high -= Q1;
|
||||
} else if (high > Q2) break;
|
||||
low += low; high += high;
|
||||
value *= 2;
|
||||
if ((mask >>= 1) == 0) {
|
||||
buffer = (ip >= srcend) ? 0 : *(ip++);
|
||||
mask = 128;
|
||||
}
|
||||
value += ((buffer & mask) != 0);
|
||||
}
|
||||
i = (r - i - 1) & (N - 1);
|
||||
for (k = 0; k < j; k++) {
|
||||
c = text_buf[(i + k) & (N - 1)];
|
||||
if (op >= dstend) return -1;
|
||||
*(op++) = c;
|
||||
text_buf[r++] = c;
|
||||
r &= (N - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lzari_decompress(unsigned char *data_in, unsigned char *cpage_out,
|
||||
u32 srclen, u32 destlen)
|
||||
{
|
||||
return Decode(data_in, cpage_out, srclen, destlen);
|
||||
}
|
||||
#endif /* ((CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_LZO_LZARI)) */
|
|
@ -1,405 +0,0 @@
|
|||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2004 Patrik Kluba,
|
||||
* University of Szeged, Hungary
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in the
|
||||
* jffs2 directory.
|
||||
*
|
||||
* $Id: compr_lzo.c,v 1.3 2004/06/23 16:34:39 havasi Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
LZO1X-1 (and -999) compression module for jffs2
|
||||
based on the original LZO sources
|
||||
*/
|
||||
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
|
||||
|
||||
/*
|
||||
Original copyright notice follows:
|
||||
|
||||
lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm
|
||||
lzo_ptr.h -- low-level pointer constructs
|
||||
lzo_swd.ch -- sliding window dictionary
|
||||
lzoconf.h -- configuration for the LZO real-time data compression library
|
||||
lzo_mchw.ch -- matching functions using a window
|
||||
minilzo.c -- mini subset of the LZO real-time data compression library
|
||||
config1x.h -- configuration for the LZO1X algorithm
|
||||
lzo1x.h -- public interface of the LZO1X compression algorithm
|
||||
|
||||
These files are part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library 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.
|
||||
|
||||
The LZO library 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 the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
|
||||
Initial release
|
||||
-removed all 16 bit code
|
||||
-all sensitive data will be on 4 byte boundary
|
||||
-removed check parts for library use
|
||||
-removed all but LZO1X-* compression
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#if ((CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_LZO_LZARI))
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#include <jffs2/jffs2.h>
|
||||
#include <jffs2/compr_rubin.h>
|
||||
|
||||
/* Integral types that have *exactly* the same number of bits as a lzo_voidp */
|
||||
typedef unsigned long lzo_ptr_t;
|
||||
typedef long lzo_sptr_t;
|
||||
|
||||
/* data type definitions */
|
||||
#define U32 unsigned long
|
||||
#define S32 signed long
|
||||
#define I32 long
|
||||
#define U16 unsigned short
|
||||
#define S16 signed short
|
||||
#define I16 short
|
||||
#define U8 unsigned char
|
||||
#define S8 signed char
|
||||
#define I8 char
|
||||
|
||||
#define M1_MAX_OFFSET 0x0400
|
||||
#define M2_MAX_OFFSET 0x0800
|
||||
#define M3_MAX_OFFSET 0x4000
|
||||
#define M4_MAX_OFFSET 0xbfff
|
||||
|
||||
#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
|
||||
#define COPY4(dst,src) __COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
|
||||
|
||||
#define TEST_IP (ip < ip_end)
|
||||
#define TEST_OP (op <= op_end)
|
||||
|
||||
#define NEED_IP(x) \
|
||||
if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun
|
||||
#define NEED_OP(x) \
|
||||
if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun
|
||||
#define TEST_LOOKBEHIND(m_pos,out) if (m_pos < out) goto lookbehind_overrun
|
||||
|
||||
typedef U32 lzo_uint32;
|
||||
typedef I32 lzo_int32;
|
||||
typedef U32 lzo_uint;
|
||||
typedef I32 lzo_int;
|
||||
typedef int lzo_bool;
|
||||
|
||||
#define lzo_byte U8
|
||||
#define lzo_bytep U8 *
|
||||
#define lzo_charp char *
|
||||
#define lzo_voidp void *
|
||||
#define lzo_shortp short *
|
||||
#define lzo_ushortp unsigned short *
|
||||
#define lzo_uint32p lzo_uint32 *
|
||||
#define lzo_int32p lzo_int32 *
|
||||
#define lzo_uintp lzo_uint *
|
||||
#define lzo_intp lzo_int *
|
||||
#define lzo_voidpp lzo_voidp *
|
||||
#define lzo_bytepp lzo_bytep *
|
||||
#define lzo_sizeof_dict_t sizeof(lzo_bytep)
|
||||
|
||||
#define LZO_E_OK 0
|
||||
#define LZO_E_ERROR (-1)
|
||||
#define LZO_E_OUT_OF_MEMORY (-2) /* not used right now */
|
||||
#define LZO_E_NOT_COMPRESSIBLE (-3) /* not used right now */
|
||||
#define LZO_E_INPUT_OVERRUN (-4)
|
||||
#define LZO_E_OUTPUT_OVERRUN (-5)
|
||||
#define LZO_E_LOOKBEHIND_OVERRUN (-6)
|
||||
#define LZO_E_EOF_NOT_FOUND (-7)
|
||||
#define LZO_E_INPUT_NOT_CONSUMED (-8)
|
||||
|
||||
#define PTR(a) ((lzo_ptr_t) (a))
|
||||
#define PTR_LINEAR(a) PTR(a)
|
||||
#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0)
|
||||
#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0)
|
||||
#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)
|
||||
#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)
|
||||
#define PTR_LT(a,b) (PTR(a) < PTR(b))
|
||||
#define PTR_GE(a,b) (PTR(a) >= PTR(b))
|
||||
#define PTR_DIFF(a,b) ((lzo_ptrdiff_t) (PTR(a) - PTR(b)))
|
||||
#define pd(a,b) ((lzo_uint) ((a)-(b)))
|
||||
|
||||
typedef ptrdiff_t lzo_ptrdiff_t;
|
||||
|
||||
static int
|
||||
lzo1x_decompress (const lzo_byte * in, lzo_uint in_len,
|
||||
lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
|
||||
{
|
||||
register lzo_byte *op;
|
||||
register const lzo_byte *ip;
|
||||
register lzo_uint t;
|
||||
|
||||
register const lzo_byte *m_pos;
|
||||
|
||||
const lzo_byte *const ip_end = in + in_len;
|
||||
lzo_byte *const op_end = out + *out_len;
|
||||
|
||||
*out_len = 0;
|
||||
|
||||
op = out;
|
||||
ip = in;
|
||||
|
||||
if (*ip > 17)
|
||||
{
|
||||
t = *ip++ - 17;
|
||||
if (t < 4)
|
||||
goto match_next;
|
||||
NEED_OP (t);
|
||||
NEED_IP (t + 1);
|
||||
do
|
||||
*op++ = *ip++;
|
||||
while (--t > 0);
|
||||
goto first_literal_run;
|
||||
}
|
||||
|
||||
while (TEST_IP && TEST_OP)
|
||||
{
|
||||
t = *ip++;
|
||||
if (t >= 16)
|
||||
goto match;
|
||||
if (t == 0)
|
||||
{
|
||||
NEED_IP (1);
|
||||
while (*ip == 0)
|
||||
{
|
||||
t += 255;
|
||||
ip++;
|
||||
NEED_IP (1);
|
||||
}
|
||||
t += 15 + *ip++;
|
||||
}
|
||||
NEED_OP (t + 3);
|
||||
NEED_IP (t + 4);
|
||||
if (PTR_ALIGNED2_4 (op, ip))
|
||||
{
|
||||
COPY4 (op, ip);
|
||||
|
||||
op += 4;
|
||||
ip += 4;
|
||||
if (--t > 0)
|
||||
{
|
||||
if (t >= 4)
|
||||
{
|
||||
do
|
||||
{
|
||||
COPY4 (op, ip);
|
||||
op += 4;
|
||||
ip += 4;
|
||||
t -= 4;
|
||||
}
|
||||
while (t >= 4);
|
||||
if (t > 0)
|
||||
do
|
||||
*op++ = *ip++;
|
||||
while (--t > 0);
|
||||
}
|
||||
else
|
||||
do
|
||||
*op++ = *ip++;
|
||||
while (--t > 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*op++ = *ip++;
|
||||
*op++ = *ip++;
|
||||
*op++ = *ip++;
|
||||
do
|
||||
*op++ = *ip++;
|
||||
while (--t > 0);
|
||||
}
|
||||
first_literal_run:
|
||||
|
||||
t = *ip++;
|
||||
if (t >= 16)
|
||||
goto match;
|
||||
|
||||
m_pos = op - (1 + M2_MAX_OFFSET);
|
||||
m_pos -= t >> 2;
|
||||
m_pos -= *ip++ << 2;
|
||||
TEST_LOOKBEHIND (m_pos, out);
|
||||
NEED_OP (3);
|
||||
*op++ = *m_pos++;
|
||||
*op++ = *m_pos++;
|
||||
*op++ = *m_pos;
|
||||
|
||||
goto match_done;
|
||||
|
||||
while (TEST_IP && TEST_OP)
|
||||
{
|
||||
match:
|
||||
if (t >= 64)
|
||||
{
|
||||
m_pos = op - 1;
|
||||
m_pos -= (t >> 2) & 7;
|
||||
m_pos -= *ip++ << 3;
|
||||
t = (t >> 5) - 1;
|
||||
TEST_LOOKBEHIND (m_pos, out);
|
||||
NEED_OP (t + 3 - 1);
|
||||
goto copy_match;
|
||||
|
||||
}
|
||||
else if (t >= 32)
|
||||
{
|
||||
t &= 31;
|
||||
if (t == 0)
|
||||
{
|
||||
NEED_IP (1);
|
||||
while (*ip == 0)
|
||||
{
|
||||
t += 255;
|
||||
ip++;
|
||||
NEED_IP (1);
|
||||
}
|
||||
t += 31 + *ip++;
|
||||
}
|
||||
|
||||
m_pos = op - 1;
|
||||
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
|
||||
|
||||
ip += 2;
|
||||
}
|
||||
else if (t >= 16)
|
||||
{
|
||||
m_pos = op;
|
||||
m_pos -= (t & 8) << 11;
|
||||
|
||||
t &= 7;
|
||||
if (t == 0)
|
||||
{
|
||||
NEED_IP (1);
|
||||
while (*ip == 0)
|
||||
{
|
||||
t += 255;
|
||||
ip++;
|
||||
NEED_IP (1);
|
||||
}
|
||||
t += 7 + *ip++;
|
||||
}
|
||||
|
||||
m_pos -= (ip[0] >> 2) + (ip[1] << 6);
|
||||
|
||||
ip += 2;
|
||||
if (m_pos == op)
|
||||
goto eof_found;
|
||||
m_pos -= 0x4000;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
m_pos = op - 1;
|
||||
m_pos -= t >> 2;
|
||||
m_pos -= *ip++ << 2;
|
||||
TEST_LOOKBEHIND (m_pos, out);
|
||||
NEED_OP (2);
|
||||
*op++ = *m_pos++;
|
||||
*op++ = *m_pos;
|
||||
|
||||
goto match_done;
|
||||
}
|
||||
|
||||
TEST_LOOKBEHIND (m_pos, out);
|
||||
NEED_OP (t + 3 - 1);
|
||||
if (t >= 2 * 4 - (3 - 1)
|
||||
&& PTR_ALIGNED2_4 (op, m_pos))
|
||||
{
|
||||
COPY4 (op, m_pos);
|
||||
op += 4;
|
||||
m_pos += 4;
|
||||
t -= 4 - (3 - 1);
|
||||
do
|
||||
{
|
||||
COPY4 (op, m_pos);
|
||||
op += 4;
|
||||
m_pos += 4;
|
||||
t -= 4;
|
||||
}
|
||||
while (t >= 4);
|
||||
if (t > 0)
|
||||
do
|
||||
*op++ = *m_pos++;
|
||||
while (--t > 0);
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
copy_match:
|
||||
*op++ = *m_pos++;
|
||||
*op++ = *m_pos++;
|
||||
do
|
||||
*op++ = *m_pos++;
|
||||
while (--t > 0);
|
||||
}
|
||||
|
||||
match_done:
|
||||
t = ip[-2] & 3;
|
||||
|
||||
if (t == 0)
|
||||
break;
|
||||
|
||||
match_next:
|
||||
NEED_OP (t);
|
||||
NEED_IP (t + 1);
|
||||
do
|
||||
*op++ = *ip++;
|
||||
while (--t > 0);
|
||||
t = *ip++;
|
||||
}
|
||||
}
|
||||
*out_len = op - out;
|
||||
return LZO_E_EOF_NOT_FOUND;
|
||||
|
||||
eof_found:
|
||||
*out_len = op - out;
|
||||
return (ip == ip_end ? LZO_E_OK :
|
||||
(ip <
|
||||
ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
|
||||
|
||||
input_overrun:
|
||||
*out_len = op - out;
|
||||
return LZO_E_INPUT_OVERRUN;
|
||||
|
||||
output_overrun:
|
||||
*out_len = op - out;
|
||||
return LZO_E_OUTPUT_OVERRUN;
|
||||
|
||||
lookbehind_overrun:
|
||||
*out_len = op - out;
|
||||
return LZO_E_LOOKBEHIND_OVERRUN;
|
||||
}
|
||||
|
||||
int lzo_decompress(unsigned char *data_in, unsigned char *cpage_out,
|
||||
u32 srclen, u32 destlen)
|
||||
{
|
||||
lzo_uint outlen = destlen;
|
||||
return lzo1x_decompress (data_in, srclen, cpage_out, &outlen, NULL);
|
||||
}
|
||||
|
||||
#endif /* ((CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_LZO_LZARI)) */
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001 Red Hat, Inc.
|
||||
*
|
||||
* Created by Arjan van de Ven <arjanv@redhat.com>
|
||||
*
|
||||
* The original JFFS, from which the design for JFFS2 was derived,
|
||||
* was designed and implemented by Axis Communications AB.
|
||||
*
|
||||
* The contents of this file are subject to the Red Hat eCos Public
|
||||
* License Version 1.1 (the "Licence"); you may not use this file
|
||||
* except in compliance with the Licence. You may obtain a copy of
|
||||
* the Licence at http://www.redhat.com/
|
||||
*
|
||||
* Software distributed under the Licence is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the Licence for the specific language governing rights and
|
||||
* limitations under the Licence.
|
||||
*
|
||||
* The Original Code is JFFS2 - Journalling Flash File System, version 2
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License version 2 (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of the
|
||||
* above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the RHEPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the RHEPL or the GPL.
|
||||
*
|
||||
* $Id: compr_rtime.c,v 1.2 2002/01/24 22:58:42 rfeany Exp $
|
||||
*
|
||||
*
|
||||
* Very simple lz77-ish encoder.
|
||||
*
|
||||
* Theory of operation: Both encoder and decoder have a list of "last
|
||||
* occurances" for every possible source-value; after sending the
|
||||
* first source-byte, the second byte indicated the "run" length of
|
||||
* matches
|
||||
*
|
||||
* The algorithm is intended to only send "whole bytes", no bit-messing.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
|
||||
|
||||
#include <jffs2/jffs2.h>
|
||||
|
||||
void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
|
||||
u32 srclen, u32 destlen)
|
||||
{
|
||||
int positions[256];
|
||||
int outpos;
|
||||
int pos;
|
||||
int i;
|
||||
|
||||
outpos = pos = 0;
|
||||
|
||||
for (i = 0; i < 256; positions[i++] = 0);
|
||||
|
||||
while (outpos<destlen) {
|
||||
unsigned char value;
|
||||
int backoffs;
|
||||
int repeat;
|
||||
|
||||
value = data_in[pos++];
|
||||
cpage_out[outpos++] = value; /* first the verbatim copied byte */
|
||||
repeat = data_in[pos++];
|
||||
backoffs = positions[value];
|
||||
|
||||
positions[value]=outpos;
|
||||
if (repeat) {
|
||||
if (backoffs + repeat >= outpos) {
|
||||
while(repeat) {
|
||||
cpage_out[outpos++] = cpage_out[backoffs++];
|
||||
repeat--;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < repeat; i++)
|
||||
*(cpage_out + outpos + i) = *(cpage_out + backoffs + i);
|
||||
outpos+=repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CFG_CMD_JFFS2 */
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001 Red Hat, Inc.
|
||||
*
|
||||
* Created by Arjan van de Ven <arjanv@redhat.com>
|
||||
*
|
||||
* Heavily modified by Russ Dill <Russ.Dill@asu.edu> in an attempt at
|
||||
* a little more speed.
|
||||
*
|
||||
* The original JFFS, from which the design for JFFS2 was derived,
|
||||
* was designed and implemented by Axis Communications AB.
|
||||
*
|
||||
* The contents of this file are subject to the Red Hat eCos Public
|
||||
* License Version 1.1 (the "Licence"); you may not use this file
|
||||
* except in compliance with the Licence. You may obtain a copy of
|
||||
* the Licence at http://www.redhat.com/
|
||||
*
|
||||
* Software distributed under the Licence is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the Licence for the specific language governing rights and
|
||||
* limitations under the Licence.
|
||||
*
|
||||
* The Original Code is JFFS2 - Journalling Flash File System, version 2
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License version 2 (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of the
|
||||
* above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the RHEPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the RHEPL or the GPL.
|
||||
*
|
||||
* $Id: compr_rubin.c,v 1.2 2002/01/24 22:58:42 rfeany Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
|
||||
|
||||
#include <jffs2/jffs2.h>
|
||||
#include <jffs2/compr_rubin.h>
|
||||
|
||||
|
||||
void rubin_do_decompress(unsigned char *bits, unsigned char *in,
|
||||
unsigned char *page_out, __u32 destlen)
|
||||
{
|
||||
register char *curr = (char *)page_out;
|
||||
char *end = (char *)(page_out + destlen);
|
||||
register unsigned long temp;
|
||||
register unsigned long result;
|
||||
register unsigned long p;
|
||||
register unsigned long q;
|
||||
register unsigned long rec_q;
|
||||
register unsigned long bit;
|
||||
register long i0;
|
||||
unsigned long i;
|
||||
|
||||
/* init_pushpull */
|
||||
temp = *(u32 *) in;
|
||||
bit = 16;
|
||||
|
||||
/* init_rubin */
|
||||
q = 0;
|
||||
p = (long) (2 * UPPER_BIT_RUBIN);
|
||||
|
||||
/* init_decode */
|
||||
rec_q = (in[0] << 8) | in[1];
|
||||
|
||||
while (curr < end) {
|
||||
/* in byte */
|
||||
|
||||
result = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
/* decode */
|
||||
|
||||
while ((q & UPPER_BIT_RUBIN) || ((p + q) <= UPPER_BIT_RUBIN)) {
|
||||
q &= ~UPPER_BIT_RUBIN;
|
||||
q <<= 1;
|
||||
p <<= 1;
|
||||
rec_q &= ~UPPER_BIT_RUBIN;
|
||||
rec_q <<= 1;
|
||||
rec_q |= (temp >> (bit++ ^ 7)) & 1;
|
||||
if (bit > 31) {
|
||||
u32 *p = (u32 *)in;
|
||||
bit = 0;
|
||||
temp = *(++p);
|
||||
in = (unsigned char *)p;
|
||||
}
|
||||
}
|
||||
i0 = (bits[i] * p) >> 8;
|
||||
|
||||
if (i0 <= 0) i0 = 1;
|
||||
/* if it fails, it fails, we have our crc
|
||||
if (i0 >= p) i0 = p - 1; */
|
||||
|
||||
result >>= 1;
|
||||
if (rec_q < q + i0) {
|
||||
/* result |= 0x00; */
|
||||
p = i0;
|
||||
} else {
|
||||
result |= 0x80;
|
||||
p -= i0;
|
||||
q += i0;
|
||||
}
|
||||
}
|
||||
*(curr++) = result;
|
||||
}
|
||||
}
|
||||
|
||||
void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out,
|
||||
unsigned long sourcelen, unsigned long dstlen)
|
||||
{
|
||||
unsigned char bits[8];
|
||||
int c;
|
||||
|
||||
for (c=0; c<8; c++)
|
||||
bits[c] = (256 - data_in[c]);
|
||||
|
||||
rubin_do_decompress(bits, data_in+8, cpage_out, dstlen);
|
||||
}
|
||||
|
||||
#endif /* CFG_CMD_JFFS2 */
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* JFFS2 -- Journalling Flash File System, Version 2.
|
||||
*
|
||||
* Copyright (C) 2001 Red Hat, Inc.
|
||||
*
|
||||
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
|
||||
*
|
||||
* The original JFFS, from which the design for JFFS2 was derived,
|
||||
* was designed and implemented by Axis Communications AB.
|
||||
*
|
||||
* The contents of this file are subject to the Red Hat eCos Public
|
||||
* License Version 1.1 (the "Licence"); you may not use this file
|
||||
* except in compliance with the Licence. You may obtain a copy of
|
||||
* the Licence at http://www.redhat.com/
|
||||
*
|
||||
* Software distributed under the Licence is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||
* See the Licence for the specific language governing rights and
|
||||
* limitations under the Licence.
|
||||
*
|
||||
* The Original Code is JFFS2 - Journalling Flash File System, version 2
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License version 2 (the "GPL"), in
|
||||
* which case the provisions of the GPL are applicable instead of the
|
||||
* above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the RHEPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the RHEPL or the GPL.
|
||||
*
|
||||
* $Id: compr_zlib.c,v 1.2 2002/01/24 22:58:42 rfeany Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <config.h>
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
|
||||
|
||||
#include <jffs2/jffs2.h>
|
||||
#include <jffs2/mini_inflate.h>
|
||||
|
||||
long zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
|
||||
__u32 srclen, __u32 destlen)
|
||||
{
|
||||
return (decompress_block(cpage_out, data_in + 2, ldr_memcpy));
|
||||
|
||||
}
|
||||
|
||||
#endif /* CFG_CMD_JFFS2 */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,966 +0,0 @@
|
|||
#include <common.h>
|
||||
|
||||
#if !defined(CFG_NAND_LEGACY) && (CONFIG_COMMANDS & CFG_CMD_JFFS2)
|
||||
|
||||
#include <malloc.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include <jffs2/jffs2.h>
|
||||
#include <jffs2/jffs2_1pass.h>
|
||||
#include <nand.h>
|
||||
|
||||
#include "jffs2_nand_private.h"
|
||||
|
||||
#define NODE_CHUNK 1024 /* size of memory allocation chunk in b_nodes */
|
||||
|
||||
/* Debugging switches */
|
||||
#undef DEBUG_DIRENTS /* print directory entry list after scan */
|
||||
#undef DEBUG_FRAGMENTS /* print fragment list after scan */
|
||||
#undef DEBUG /* enable debugging messages */
|
||||
|
||||
#ifdef DEBUG
|
||||
# define DEBUGF(fmt,args...) printf(fmt ,##args)
|
||||
#else
|
||||
# define DEBUGF(fmt,args...)
|
||||
#endif
|
||||
|
||||
static nand_info_t *nand;
|
||||
|
||||
/* Compression names */
|
||||
static char *compr_names[] = {
|
||||
"NONE",
|
||||
"ZERO",
|
||||
"RTIME",
|
||||
"RUBINMIPS",
|
||||
"COPY",
|
||||
"DYNRUBIN",
|
||||
"ZLIB",
|
||||
#if defined(CONFIG_JFFS2_LZO_LZARI)
|
||||
"LZO",
|
||||
"LZARI",
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Spinning wheel */
|
||||
static char spinner[] = { '|', '/', '-', '\\' };
|
||||
|
||||
/* Memory management */
|
||||
struct mem_block {
|
||||
unsigned index;
|
||||
struct mem_block *next;
|
||||
char nodes[0];
|
||||
};
|
||||
|
||||
static void
|
||||
free_nodes(struct b_list *list)
|
||||
{
|
||||
while (list->listMemBase != NULL) {
|
||||
struct mem_block *next = list->listMemBase->next;
|
||||
free(list->listMemBase);
|
||||
list->listMemBase = next;
|
||||
}
|
||||
}
|
||||
|
||||
static struct b_node *
|
||||
add_node(struct b_list *list, int size)
|
||||
{
|
||||
u32 index = 0;
|
||||
struct mem_block *memBase;
|
||||
struct b_node *b;
|
||||
|
||||
memBase = list->listMemBase;
|
||||
if (memBase != NULL)
|
||||
index = memBase->index;
|
||||
|
||||
if (memBase == NULL || index >= NODE_CHUNK) {
|
||||
/* we need more space before we continue */
|
||||
memBase = mmalloc(sizeof(struct mem_block) + NODE_CHUNK * size);
|
||||
if (memBase == NULL) {
|
||||
putstr("add_node: malloc failed\n");
|
||||
return NULL;
|
||||
}
|
||||
memBase->next = list->listMemBase;
|
||||
index = 0;
|
||||
}
|
||||
/* now we have room to add it. */
|
||||
b = (struct b_node *)&memBase->nodes[size * index];
|
||||
index ++;
|
||||
|
||||
memBase->index = index;
|
||||
list->listMemBase = memBase;
|
||||
list->listCount++;
|
||||
return b;
|
||||
}
|
||||
|
||||
static struct b_node *
|
||||
insert_node(struct b_list *list, struct b_node *new)
|
||||
{
|
||||
#ifdef CFG_JFFS2_SORT_FRAGMENTS
|
||||
struct b_node *b, *prev;
|
||||
|
||||
if (list->listTail != NULL && list->listCompare(new, list->listTail))
|
||||
prev = list->listTail;
|
||||
else if (list->listLast != NULL && list->listCompare(new, list->listLast))
|
||||
prev = list->listLast;
|
||||
else
|
||||
prev = NULL;
|
||||
|
||||
for (b = (prev ? prev->next : list->listHead);
|
||||
b != NULL && list->listCompare(new, b);
|
||||
prev = b, b = b->next) {
|
||||
list->listLoops++;
|
||||
}
|
||||
if (b != NULL)
|
||||
list->listLast = prev;
|
||||
|
||||
if (b != NULL) {
|
||||
new->next = b;
|
||||
if (prev != NULL)
|
||||
prev->next = new;
|
||||
else
|
||||
list->listHead = new;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
new->next = (struct b_node *) NULL;
|
||||
if (list->listTail != NULL) {
|
||||
list->listTail->next = new;
|
||||
list->listTail = new;
|
||||
} else {
|
||||
list->listTail = list->listHead = new;
|
||||
}
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static struct b_node *
|
||||
insert_inode(struct b_list *list, struct jffs2_raw_inode *node, u32 offset)
|
||||
{
|
||||
struct b_inode *new;
|
||||
|
||||
if (!(new = (struct b_inode *)add_node(list, sizeof(struct b_inode)))) {
|
||||
putstr("add_node failed!\r\n");
|
||||
return NULL;
|
||||
}
|
||||
new->offset = offset;
|
||||
new->version = node->version;
|
||||
new->ino = node->ino;
|
||||
new->isize = node->isize;
|
||||
new->csize = node->csize;
|
||||
|
||||
return insert_node(list, (struct b_node *)new);
|
||||
}
|
||||
|
||||
static struct b_node *
|
||||
insert_dirent(struct b_list *list, struct jffs2_raw_dirent *node, u32 offset)
|
||||
{
|
||||
struct b_dirent *new;
|
||||
|
||||
if (!(new = (struct b_dirent *)add_node(list, sizeof(struct b_dirent)))) {
|
||||
putstr("add_node failed!\r\n");
|
||||
return NULL;
|
||||
}
|
||||
new->offset = offset;
|
||||
new->version = node->version;
|
||||
new->pino = node->pino;
|
||||
new->ino = node->ino;
|
||||
new->nhash = full_name_hash(node->name, node->nsize);
|
||||
new->nsize = node->nsize;
|
||||
new->type = node->type;
|
||||
|
||||
return insert_node(list, (struct b_node *)new);
|
||||
}
|
||||
|
||||
#ifdef CFG_JFFS2_SORT_FRAGMENTS
|
||||
/* Sort data entries with the latest version last, so that if there
|
||||
* is overlapping data the latest version will be used.
|
||||
*/
|
||||
static int compare_inodes(struct b_node *new, struct b_node *old)
|
||||
{
|
||||
struct jffs2_raw_inode ojNew;
|
||||
struct jffs2_raw_inode ojOld;
|
||||
struct jffs2_raw_inode *jNew =
|
||||
(struct jffs2_raw_inode *)get_fl_mem(new->offset, sizeof(ojNew), &ojNew);
|
||||
struct jffs2_raw_inode *jOld =
|
||||
(struct jffs2_raw_inode *)get_fl_mem(old->offset, sizeof(ojOld), &ojOld);
|
||||
|
||||
return jNew->version > jOld->version;
|
||||
}
|
||||
|
||||
/* Sort directory entries so all entries in the same directory
|
||||
* with the same name are grouped together, with the latest version
|
||||
* last. This makes it easy to eliminate all but the latest version
|
||||
* by marking the previous version dead by setting the inode to 0.
|
||||
*/
|
||||
static int compare_dirents(struct b_node *new, struct b_node *old)
|
||||
{
|
||||
struct jffs2_raw_dirent ojNew;
|
||||
struct jffs2_raw_dirent ojOld;
|
||||
struct jffs2_raw_dirent *jNew =
|
||||
(struct jffs2_raw_dirent *)get_fl_mem(new->offset, sizeof(ojNew), &ojNew);
|
||||
struct jffs2_raw_dirent *jOld =
|
||||
(struct jffs2_raw_dirent *)get_fl_mem(old->offset, sizeof(ojOld), &ojOld);
|
||||
int cmp;
|
||||
|
||||
/* ascending sort by pino */
|
||||
if (jNew->pino != jOld->pino)
|
||||
return jNew->pino > jOld->pino;
|
||||
|
||||
/* pino is the same, so use ascending sort by nsize, so
|
||||
* we don't do strncmp unless we really must.
|
||||
*/
|
||||
if (jNew->nsize != jOld->nsize)
|
||||
return jNew->nsize > jOld->nsize;
|
||||
|
||||
/* length is also the same, so use ascending sort by name
|
||||
*/
|
||||
cmp = strncmp(jNew->name, jOld->name, jNew->nsize);
|
||||
if (cmp != 0)
|
||||
return cmp > 0;
|
||||
|
||||
/* we have duplicate names in this directory, so use ascending
|
||||
* sort by version
|
||||
*/
|
||||
if (jNew->version > jOld->version) {
|
||||
/* since jNew is newer, we know jOld is not valid, so
|
||||
* mark it with inode 0 and it will not be used
|
||||
*/
|
||||
jOld->ino = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static u32
|
||||
jffs_init_1pass_list(struct part_info *part)
|
||||
{
|
||||
struct b_lists *pL;
|
||||
|
||||
if (part->jffs2_priv != NULL) {
|
||||
pL = (struct b_lists *)part->jffs2_priv;
|
||||
free_nodes(&pL->frag);
|
||||
free_nodes(&pL->dir);
|
||||
free(pL);
|
||||
}
|
||||
if (NULL != (part->jffs2_priv = malloc(sizeof(struct b_lists)))) {
|
||||
pL = (struct b_lists *)part->jffs2_priv;
|
||||
|
||||
memset(pL, 0, sizeof(*pL));
|
||||
#ifdef CFG_JFFS2_SORT_FRAGMENTS
|
||||
pL->dir.listCompare = compare_dirents;
|
||||
pL->frag.listCompare = compare_inodes;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* find the inode from the slashless name given a parent */
|
||||
static long
|
||||
jffs2_1pass_read_inode(struct b_lists *pL, u32 ino, char *dest,
|
||||
struct stat *stat)
|
||||
{
|
||||
struct b_inode *jNode;
|
||||
u32 totalSize = 0;
|
||||
u32 latestVersion = 0;
|
||||
long ret;
|
||||
|
||||
#ifdef CFG_JFFS2_SORT_FRAGMENTS
|
||||
/* Find file size before loading any data, so fragments that
|
||||
* start past the end of file can be ignored. A fragment
|
||||
* that is partially in the file is loaded, so extra data may
|
||||
* be loaded up to the next 4K boundary above the file size.
|
||||
* This shouldn't cause trouble when loading kernel images, so
|
||||
* we will live with it.
|
||||
*/
|
||||
for (jNode = (struct b_inode *)pL->frag.listHead; jNode; jNode = jNode->next) {
|
||||
if ((ino == jNode->ino)) {
|
||||
/* get actual file length from the newest node */
|
||||
if (jNode->version >= latestVersion) {
|
||||
totalSize = jNode->isize;
|
||||
latestVersion = jNode->version;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (jNode = (struct b_inode *)pL->frag.listHead; jNode; jNode = jNode->next) {
|
||||
if ((ino != jNode->ino))
|
||||
continue;
|
||||
#ifndef CFG_JFFS2_SORT_FRAGMENTS
|
||||
/* get actual file length from the newest node */
|
||||
if (jNode->version >= latestVersion) {
|
||||
totalSize = jNode->isize;
|
||||
latestVersion = jNode->version;
|
||||
}
|
||||
#endif
|
||||
if (dest || stat) {
|
||||
char *src, *dst;
|
||||
char data[4096 + sizeof(struct jffs2_raw_inode)];
|
||||
struct jffs2_raw_inode *inode;
|
||||
size_t len;
|
||||
|
||||
inode = (struct jffs2_raw_inode *)&data;
|
||||
len = sizeof(struct jffs2_raw_inode);
|
||||
if (dest)
|
||||
len += jNode->csize;
|
||||
nand_read(nand, jNode->offset, &len, inode);
|
||||
/* ignore data behind latest known EOF */
|
||||
if (inode->offset > totalSize)
|
||||
continue;
|
||||
|
||||
if (stat) {
|
||||
stat->st_mtime = inode->mtime;
|
||||
stat->st_mode = inode->mode;
|
||||
stat->st_ino = inode->ino;
|
||||
stat->st_size = totalSize;
|
||||
}
|
||||
|
||||
if (!dest)
|
||||
continue;
|
||||
|
||||
src = ((char *) inode) + sizeof(struct jffs2_raw_inode);
|
||||
dst = (char *) (dest + inode->offset);
|
||||
|
||||
switch (inode->compr) {
|
||||
case JFFS2_COMPR_NONE:
|
||||
ret = 0;
|
||||
memcpy(dst, src, inode->dsize);
|
||||
break;
|
||||
case JFFS2_COMPR_ZERO:
|
||||
ret = 0;
|
||||
memset(dst, 0, inode->dsize);
|
||||
break;
|
||||
case JFFS2_COMPR_RTIME:
|
||||
ret = 0;
|
||||
rtime_decompress(src, dst, inode->csize, inode->dsize);
|
||||
break;
|
||||
case JFFS2_COMPR_DYNRUBIN:
|
||||
/* this is slow but it works */
|
||||
ret = 0;
|
||||
dynrubin_decompress(src, dst, inode->csize, inode->dsize);
|
||||
break;
|
||||
case JFFS2_COMPR_ZLIB:
|
||||
ret = zlib_decompress(src, dst, inode->csize, inode->dsize);
|
||||
break;
|
||||
#if defined(CONFIG_JFFS2_LZO_LZARI)
|
||||
case JFFS2_COMPR_LZO:
|
||||
ret = lzo_decompress(src, dst, inode->csize, inode->dsize);
|
||||
break;
|
||||
case JFFS2_COMPR_LZARI:
|
||||
ret = lzari_decompress(src, dst, inode->csize, inode->dsize);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* unknown */
|
||||
putLabeledWord("UNKOWN COMPRESSION METHOD = ", inode->compr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
/* find the inode from the slashless name given a parent */
|
||||
static u32
|
||||
jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino)
|
||||
{
|
||||
struct b_dirent *jDir;
|
||||
int len = strlen(name); /* name is assumed slash free */
|
||||
unsigned int nhash = full_name_hash(name, len);
|
||||
u32 version = 0;
|
||||
u32 inode = 0;
|
||||
|
||||
/* we need to search all and return the inode with the highest version */
|
||||
for (jDir = (struct b_dirent *)pL->dir.listHead; jDir; jDir = jDir->next) {
|
||||
if ((pino == jDir->pino) && (jDir->ino) && /* 0 for unlink */
|
||||
(len == jDir->nsize) && (nhash == jDir->nhash)) {
|
||||
/* TODO: compare name */
|
||||
if (jDir->version < version)
|
||||
continue;
|
||||
|
||||
if (jDir->version == version && inode != 0) {
|
||||
/* I'm pretty sure this isn't legal */
|
||||
putstr(" ** ERROR ** ");
|
||||
/* putnstr(jDir->name, jDir->nsize); */
|
||||
/* putLabeledWord(" has dup version =", version); */
|
||||
}
|
||||
inode = jDir->ino;
|
||||
version = jDir->version;
|
||||
}
|
||||
}
|
||||
return inode;
|
||||
}
|
||||
|
||||
static inline void dump_stat(struct stat *st, const char *name)
|
||||
{
|
||||
char str[20];
|
||||
char s[64], *p;
|
||||
|
||||
if (st->st_mtime == (time_t)(-1)) /* some ctimes really hate -1 */
|
||||
st->st_mtime = 1;
|
||||
|
||||
ctime_r(&st->st_mtime, s/*,64*/); /* newlib ctime doesn't have buflen */
|
||||
|
||||
if ((p = strchr(s,'\n')) != NULL) *p = '\0';
|
||||
if ((p = strchr(s,'\r')) != NULL) *p = '\0';
|
||||
|
||||
/*
|
||||
printf("%6lo %s %8ld %s %s\n", st->st_mode, mkmodestr(st->st_mode, str),
|
||||
st->st_size, s, name);
|
||||
*/
|
||||
|
||||
printf(" %s %8ld %s %s", mkmodestr(st->st_mode,str), st->st_size, s, name);
|
||||
}
|
||||
|
||||
static inline int
|
||||
dump_inode(struct b_lists *pL, struct b_dirent *d, struct b_inode *i)
|
||||
{
|
||||
char fname[JFFS2_MAX_NAME_LEN + 1];
|
||||
struct stat st;
|
||||
size_t len;
|
||||
|
||||
if(!d || !i) return -1;
|
||||
len = d->nsize;
|
||||
nand_read(nand, d->offset + sizeof(struct jffs2_raw_dirent),
|
||||
&len, &fname);
|
||||
fname[d->nsize] = '\0';
|
||||
|
||||
memset(&st, 0, sizeof(st));
|
||||
|
||||
jffs2_1pass_read_inode(pL, i->ino, NULL, &st);
|
||||
|
||||
dump_stat(&st, fname);
|
||||
/* FIXME
|
||||
if (d->type == DT_LNK) {
|
||||
unsigned char *src = (unsigned char *) (&i[1]);
|
||||
putstr(" -> ");
|
||||
putnstr(src, (int)i->dsize);
|
||||
}
|
||||
*/
|
||||
putstr("\r\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* list inodes with the given pino */
|
||||
static u32
|
||||
jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino)
|
||||
{
|
||||
struct b_dirent *jDir;
|
||||
u32 i_version = 0;
|
||||
|
||||
for (jDir = (struct b_dirent *)pL->dir.listHead; jDir; jDir = jDir->next) {
|
||||
if ((pino == jDir->pino) && (jDir->ino)) { /* ino=0 -> unlink */
|
||||
struct b_inode *jNode = (struct b_inode *)pL->frag.listHead;
|
||||
struct b_inode *i = NULL;
|
||||
|
||||
while (jNode) {
|
||||
if (jNode->ino == jDir->ino && jNode->version >= i_version) {
|
||||
i_version = jNode->version;
|
||||
i = jNode;
|
||||
}
|
||||
jNode = jNode->next;
|
||||
}
|
||||
dump_inode(pL, jDir, i);
|
||||
}
|
||||
}
|
||||
return pino;
|
||||
}
|
||||
|
||||
static u32
|
||||
jffs2_1pass_search_inode(struct b_lists * pL, const char *fname, u32 pino)
|
||||
{
|
||||
int i;
|
||||
char tmp[256];
|
||||
char working_tmp[256];
|
||||
char *c;
|
||||
|
||||
/* discard any leading slash */
|
||||
i = 0;
|
||||
while (fname[i] == '/')
|
||||
i++;
|
||||
strcpy(tmp, &fname[i]);
|
||||
|
||||
while ((c = (char *) strchr(tmp, '/'))) /* we are still dired searching */
|
||||
{
|
||||
strncpy(working_tmp, tmp, c - tmp);
|
||||
working_tmp[c - tmp] = '\0';
|
||||
for (i = 0; i < strlen(c) - 1; i++)
|
||||
tmp[i] = c[i + 1];
|
||||
tmp[i] = '\0';
|
||||
|
||||
if (!(pino = jffs2_1pass_find_inode(pL, working_tmp, pino))) {
|
||||
putstr("find_inode failed for name=");
|
||||
putstr(working_tmp);
|
||||
putstr("\r\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* this is for the bare filename, directories have already been mapped */
|
||||
if (!(pino = jffs2_1pass_find_inode(pL, tmp, pino))) {
|
||||
putstr("find_inode failed for name=");
|
||||
putstr(tmp);
|
||||
putstr("\r\n");
|
||||
return 0;
|
||||
}
|
||||
return pino;
|
||||
|
||||
}
|
||||
|
||||
static u32
|
||||
jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)
|
||||
{
|
||||
struct b_dirent *jDir;
|
||||
struct b_inode *jNode;
|
||||
u8 jDirFoundType = 0;
|
||||
u32 jDirFoundIno = 0;
|
||||
u32 jDirFoundPino = 0;
|
||||
char tmp[JFFS2_MAX_NAME_LEN + 1];
|
||||
u32 version = 0;
|
||||
u32 pino;
|
||||
|
||||
/* we need to search all and return the inode with the highest version */
|
||||
for (jDir = (struct b_dirent *)pL->dir.listHead; jDir; jDir = jDir->next) {
|
||||
if (ino == jDir->ino) {
|
||||
if (jDir->version < version)
|
||||
continue;
|
||||
|
||||
if (jDir->version == version && jDirFoundType) {
|
||||
/* I'm pretty sure this isn't legal */
|
||||
putstr(" ** ERROR ** ");
|
||||
/* putnstr(jDir->name, jDir->nsize); */
|
||||
/* putLabeledWord(" has dup version (resolve) = ", */
|
||||
/* version); */
|
||||
}
|
||||
|
||||
jDirFoundType = jDir->type;
|
||||
jDirFoundIno = jDir->ino;
|
||||
jDirFoundPino = jDir->pino;
|
||||
version = jDir->version;
|
||||
}
|
||||
}
|
||||
/* now we found the right entry again. (shoulda returned inode*) */
|
||||
if (jDirFoundType != DT_LNK)
|
||||
return jDirFoundIno;
|
||||
|
||||
/* it's a soft link so we follow it again. */
|
||||
for (jNode = (struct b_inode *)pL->frag.listHead; jNode; jNode = jNode->next) {
|
||||
if (jNode->ino == jDirFoundIno) {
|
||||
size_t len = jNode->csize;
|
||||
nand_read(nand, jNode->offset + sizeof(struct jffs2_raw_inode), &len, &tmp);
|
||||
tmp[jNode->csize] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* ok so the name of the new file to find is in tmp */
|
||||
/* if it starts with a slash it is root based else shared dirs */
|
||||
if (tmp[0] == '/')
|
||||
pino = 1;
|
||||
else
|
||||
pino = jDirFoundPino;
|
||||
|
||||
return jffs2_1pass_search_inode(pL, tmp, pino);
|
||||
}
|
||||
|
||||
static u32
|
||||
jffs2_1pass_search_list_inodes(struct b_lists * pL, const char *fname, u32 pino)
|
||||
{
|
||||
int i;
|
||||
char tmp[256];
|
||||
char working_tmp[256];
|
||||
char *c;
|
||||
|
||||
/* discard any leading slash */
|
||||
i = 0;
|
||||
while (fname[i] == '/')
|
||||
i++;
|
||||
strcpy(tmp, &fname[i]);
|
||||
working_tmp[0] = '\0';
|
||||
while ((c = (char *) strchr(tmp, '/'))) /* we are still dired searching */
|
||||
{
|
||||
strncpy(working_tmp, tmp, c - tmp);
|
||||
working_tmp[c - tmp] = '\0';
|
||||
for (i = 0; i < strlen(c) - 1; i++)
|
||||
tmp[i] = c[i + 1];
|
||||
tmp[i] = '\0';
|
||||
/* only a failure if we arent looking at top level */
|
||||
if (!(pino = jffs2_1pass_find_inode(pL, working_tmp, pino)) &&
|
||||
(working_tmp[0])) {
|
||||
putstr("find_inode failed for name=");
|
||||
putstr(working_tmp);
|
||||
putstr("\r\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp[0] && !(pino = jffs2_1pass_find_inode(pL, tmp, pino))) {
|
||||
putstr("find_inode failed for name=");
|
||||
putstr(tmp);
|
||||
putstr("\r\n");
|
||||
return 0;
|
||||
}
|
||||
/* this is for the bare filename, directories have already been mapped */
|
||||
if (!(pino = jffs2_1pass_list_inodes(pL, pino))) {
|
||||
putstr("find_inode failed for name=");
|
||||
putstr(tmp);
|
||||
putstr("\r\n");
|
||||
return 0;
|
||||
}
|
||||
return pino;
|
||||
|
||||
}
|
||||
|
||||
unsigned char
|
||||
jffs2_1pass_rescan_needed(struct part_info *part)
|
||||
{
|
||||
struct b_node *b;
|
||||
struct jffs2_unknown_node onode;
|
||||
struct jffs2_unknown_node *node;
|
||||
struct b_lists *pL = (struct b_lists *)part->jffs2_priv;
|
||||
|
||||
if (part->jffs2_priv == 0){
|
||||
DEBUGF ("rescan: First time in use\n");
|
||||
return 1;
|
||||
}
|
||||
/* if we have no list, we need to rescan */
|
||||
if (pL->frag.listCount == 0) {
|
||||
DEBUGF ("rescan: fraglist zero\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* or if we are scanning a new partition */
|
||||
if (pL->partOffset != part->offset) {
|
||||
DEBUGF ("rescan: different partition\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FRAGMENTS
|
||||
static void
|
||||
dump_fragments(struct b_lists *pL)
|
||||
{
|
||||
struct b_node *b;
|
||||
struct jffs2_raw_inode ojNode;
|
||||
struct jffs2_raw_inode *jNode;
|
||||
|
||||
putstr("\r\n\r\n******The fragment Entries******\r\n");
|
||||
b = pL->frag.listHead;
|
||||
while (b) {
|
||||
jNode = (struct jffs2_raw_inode *) get_fl_mem(b->offset,
|
||||
sizeof(ojNode), &ojNode);
|
||||
putLabeledWord("\r\n\tbuild_list: FLASH_OFFSET = ", b->offset);
|
||||
putLabeledWord("\tbuild_list: totlen = ", jNode->totlen);
|
||||
putLabeledWord("\tbuild_list: inode = ", jNode->ino);
|
||||
putLabeledWord("\tbuild_list: version = ", jNode->version);
|
||||
putLabeledWord("\tbuild_list: isize = ", jNode->isize);
|
||||
putLabeledWord("\tbuild_list: atime = ", jNode->atime);
|
||||
putLabeledWord("\tbuild_list: offset = ", jNode->offset);
|
||||
putLabeledWord("\tbuild_list: csize = ", jNode->csize);
|
||||
putLabeledWord("\tbuild_list: dsize = ", jNode->dsize);
|
||||
putLabeledWord("\tbuild_list: compr = ", jNode->compr);
|
||||
putLabeledWord("\tbuild_list: usercompr = ", jNode->usercompr);
|
||||
putLabeledWord("\tbuild_list: flags = ", jNode->flags);
|
||||
putLabeledWord("\tbuild_list: offset = ", b->offset); /* FIXME: ? [RS] */
|
||||
b = b->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_DIRENTS
|
||||
static void
|
||||
dump_dirents(struct b_lists *pL)
|
||||
{
|
||||
struct b_node *b;
|
||||
struct jffs2_raw_dirent *jDir;
|
||||
|
||||
putstr("\r\n\r\n******The directory Entries******\r\n");
|
||||
b = pL->dir.listHead;
|
||||
while (b) {
|
||||
jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset);
|
||||
putstr("\r\n");
|
||||
putnstr(jDir->name, jDir->nsize);
|
||||
putLabeledWord("\r\n\tbuild_list: magic = ", jDir->magic);
|
||||
putLabeledWord("\tbuild_list: nodetype = ", jDir->nodetype);
|
||||
putLabeledWord("\tbuild_list: hdr_crc = ", jDir->hdr_crc);
|
||||
putLabeledWord("\tbuild_list: pino = ", jDir->pino);
|
||||
putLabeledWord("\tbuild_list: version = ", jDir->version);
|
||||
putLabeledWord("\tbuild_list: ino = ", jDir->ino);
|
||||
putLabeledWord("\tbuild_list: mctime = ", jDir->mctime);
|
||||
putLabeledWord("\tbuild_list: nsize = ", jDir->nsize);
|
||||
putLabeledWord("\tbuild_list: type = ", jDir->type);
|
||||
putLabeledWord("\tbuild_list: node_crc = ", jDir->node_crc);
|
||||
putLabeledWord("\tbuild_list: name_crc = ", jDir->name_crc);
|
||||
putLabeledWord("\tbuild_list: offset = ", b->offset); /* FIXME: ? [RS] */
|
||||
b = b->next;
|
||||
put_fl_mem(jDir);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
jffs2_fill_scan_buf(nand_info_t *nand, unsigned char *buf,
|
||||
unsigned ofs, unsigned len)
|
||||
{
|
||||
int ret;
|
||||
unsigned olen;
|
||||
|
||||
olen = len;
|
||||
ret = nand_read(nand, ofs, &olen, buf);
|
||||
if (ret) {
|
||||
printf("nand_read(0x%x bytes from 0x%x) returned %d\n", len, ofs, ret);
|
||||
return ret;
|
||||
}
|
||||
if (olen < len) {
|
||||
printf("Read at 0x%x gave only 0x%x bytes\n", ofs, olen);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define EMPTY_SCAN_SIZE 1024
|
||||
static u32
|
||||
jffs2_1pass_build_lists(struct part_info * part)
|
||||
{
|
||||
struct b_lists *pL;
|
||||
struct jffs2_unknown_node *node;
|
||||
unsigned nr_blocks, sectorsize, ofs, offset;
|
||||
char *buf;
|
||||
int i;
|
||||
u32 counter = 0;
|
||||
u32 counter4 = 0;
|
||||
u32 counterF = 0;
|
||||
u32 counterN = 0;
|
||||
|
||||
struct mtdids *id = part->dev->id;
|
||||
nand = nand_info + id->num;
|
||||
|
||||
/* if we are building a list we need to refresh the cache. */
|
||||
jffs_init_1pass_list(part);
|
||||
pL = (struct b_lists *)part->jffs2_priv;
|
||||
pL->partOffset = part->offset;
|
||||
puts ("Scanning JFFS2 FS: ");
|
||||
|
||||
sectorsize = nand->erasesize;
|
||||
nr_blocks = part->size / sectorsize;
|
||||
buf = malloc(sectorsize);
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < nr_blocks; i++) {
|
||||
printf("\b\b%c ", spinner[counter++ % sizeof(spinner)]);
|
||||
|
||||
offset = part->offset + i * sectorsize;
|
||||
|
||||
if (nand_block_isbad(nand, offset))
|
||||
continue;
|
||||
|
||||
if (jffs2_fill_scan_buf(nand, buf, offset, EMPTY_SCAN_SIZE))
|
||||
return 0;
|
||||
|
||||
ofs = 0;
|
||||
/* Scan only 4KiB of 0xFF before declaring it's empty */
|
||||
while (ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
|
||||
ofs += 4;
|
||||
if (ofs == EMPTY_SCAN_SIZE)
|
||||
continue;
|
||||
|
||||
if (jffs2_fill_scan_buf(nand, buf + EMPTY_SCAN_SIZE, offset + EMPTY_SCAN_SIZE, sectorsize - EMPTY_SCAN_SIZE))
|
||||
return 0;
|
||||
offset += ofs;
|
||||
|
||||
while (ofs < sectorsize - sizeof(struct jffs2_unknown_node)) {
|
||||
node = (struct jffs2_unknown_node *)&buf[ofs];
|
||||
if (node->magic != JFFS2_MAGIC_BITMASK || !hdr_crc(node)) {
|
||||
offset += 4;
|
||||
ofs += 4;
|
||||
counter4++;
|
||||
continue;
|
||||
}
|
||||
/* if its a fragment add it */
|
||||
if (node->nodetype == JFFS2_NODETYPE_INODE &&
|
||||
inode_crc((struct jffs2_raw_inode *) node)) {
|
||||
if (insert_inode(&pL->frag, (struct jffs2_raw_inode *) node,
|
||||
offset) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
} else if (node->nodetype == JFFS2_NODETYPE_DIRENT &&
|
||||
dirent_crc((struct jffs2_raw_dirent *) node) &&
|
||||
dirent_name_crc((struct jffs2_raw_dirent *) node)) {
|
||||
if (! (counterN%100))
|
||||
puts ("\b\b. ");
|
||||
if (insert_dirent(&pL->dir, (struct jffs2_raw_dirent *) node,
|
||||
offset) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
counterN++;
|
||||
} else if (node->nodetype == JFFS2_NODETYPE_CLEANMARKER) {
|
||||
if (node->totlen != sizeof(struct jffs2_unknown_node))
|
||||
printf("OOPS Cleanmarker has bad size "
|
||||
"%d != %d\n", node->totlen,
|
||||
sizeof(struct jffs2_unknown_node));
|
||||
} else if (node->nodetype == JFFS2_NODETYPE_PADDING) {
|
||||
if (node->totlen < sizeof(struct jffs2_unknown_node))
|
||||
printf("OOPS Padding has bad size "
|
||||
"%d < %d\n", node->totlen,
|
||||
sizeof(struct jffs2_unknown_node));
|
||||
} else {
|
||||
printf("Unknown node type: %x len %d "
|
||||
"offset 0x%x\n", node->nodetype,
|
||||
node->totlen, offset);
|
||||
}
|
||||
offset += ((node->totlen + 3) & ~3);
|
||||
ofs += ((node->totlen + 3) & ~3);
|
||||
counterF++;
|
||||
}
|
||||
}
|
||||
|
||||
putstr("\b\b done.\r\n"); /* close off the dots */
|
||||
|
||||
|
||||
#ifdef DEBUG_DIRENTS
|
||||
dump_dirents(pL);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_FRAGMENTS
|
||||
dump_fragments(pL);
|
||||
#endif
|
||||
|
||||
/* give visual feedback that we are done scanning the flash */
|
||||
led_blink(0x0, 0x0, 0x1, 0x1); /* off, forever, on 100ms, off 100ms */
|
||||
free(buf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static u32
|
||||
jffs2_1pass_fill_info(struct b_lists * pL, struct b_jffs2_info * piL)
|
||||
{
|
||||
struct b_node *b;
|
||||
struct jffs2_raw_inode ojNode;
|
||||
struct jffs2_raw_inode *jNode;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < JFFS2_NUM_COMPR; i++) {
|
||||
piL->compr_info[i].num_frags = 0;
|
||||
piL->compr_info[i].compr_sum = 0;
|
||||
piL->compr_info[i].decompr_sum = 0;
|
||||
}
|
||||
/* FIXME
|
||||
b = pL->frag.listHead;
|
||||
while (b) {
|
||||
jNode = (struct jffs2_raw_inode *) get_fl_mem(b->offset,
|
||||
sizeof(ojNode), &ojNode);
|
||||
if (jNode->compr < JFFS2_NUM_COMPR) {
|
||||
piL->compr_info[jNode->compr].num_frags++;
|
||||
piL->compr_info[jNode->compr].compr_sum += jNode->csize;
|
||||
piL->compr_info[jNode->compr].decompr_sum += jNode->dsize;
|
||||
}
|
||||
b = b->next;
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct b_lists *
|
||||
jffs2_get_list(struct part_info * part, const char *who)
|
||||
{
|
||||
if (jffs2_1pass_rescan_needed(part)) {
|
||||
if (!jffs2_1pass_build_lists(part)) {
|
||||
printf("%s: Failed to scan JFFSv2 file structure\n", who);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return (struct b_lists *)part->jffs2_priv;
|
||||
}
|
||||
|
||||
|
||||
/* Print directory / file contents */
|
||||
u32
|
||||
jffs2_1pass_ls(struct part_info * part, const char *fname)
|
||||
{
|
||||
struct b_lists *pl;
|
||||
long ret = 0;
|
||||
u32 inode;
|
||||
|
||||
if (! (pl = jffs2_get_list(part, "ls")))
|
||||
return 0;
|
||||
|
||||
if (! (inode = jffs2_1pass_search_list_inodes(pl, fname, 1))) {
|
||||
putstr("ls: Failed to scan jffs2 file structure\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Load a file from flash into memory. fname can be a full path */
|
||||
u32
|
||||
jffs2_1pass_load(char *dest, struct part_info * part, const char *fname)
|
||||
{
|
||||
|
||||
struct b_lists *pl;
|
||||
long ret = 0;
|
||||
u32 inode;
|
||||
|
||||
if (! (pl = jffs2_get_list(part, "load")))
|
||||
return 0;
|
||||
|
||||
if (! (inode = jffs2_1pass_search_inode(pl, fname, 1))) {
|
||||
putstr("load: Failed to find inode\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resolve symlinks */
|
||||
if (! (inode = jffs2_1pass_resolve_inode(pl, inode))) {
|
||||
putstr("load: Failed to resolve inode structure\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((ret = jffs2_1pass_read_inode(pl, inode, dest, NULL)) < 0) {
|
||||
putstr("load: Failed to read inode\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUGF ("load: loaded '%s' to 0x%lx (%ld bytes)\n", fname,
|
||||
(unsigned long) dest, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return information about the fs on this partition */
|
||||
u32
|
||||
jffs2_1pass_info(struct part_info * part)
|
||||
{
|
||||
struct b_jffs2_info info;
|
||||
struct b_lists *pl;
|
||||
int i;
|
||||
|
||||
if (! (pl = jffs2_get_list(part, "info")))
|
||||
return 0;
|
||||
|
||||
jffs2_1pass_fill_info(pl, &info);
|
||||
for (i = 0; i < JFFS2_NUM_COMPR; i++) {
|
||||
printf ("Compression: %s\n"
|
||||
"\tfrag count: %d\n"
|
||||
"\tcompressed sum: %d\n"
|
||||
"\tuncompressed sum: %d\n",
|
||||
compr_names[i],
|
||||
info.compr_info[i].num_frags,
|
||||
info.compr_info[i].compr_sum,
|
||||
info.compr_info[i].decompr_sum);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* CFG_CMD_JFFS2 */
|
|
@ -1,126 +0,0 @@
|
|||
#ifndef jffs2_private_h
|
||||
#define jffs2_private_h
|
||||
|
||||
#include <jffs2/jffs2.h>
|
||||
|
||||
struct b_node {
|
||||
struct b_node *next;
|
||||
};
|
||||
|
||||
struct b_inode {
|
||||
struct b_inode *next;
|
||||
u32 offset; /* physical offset to beginning of real inode */
|
||||
u32 version;
|
||||
u32 ino;
|
||||
u32 isize;
|
||||
u32 csize;
|
||||
};
|
||||
|
||||
struct b_dirent {
|
||||
struct b_dirent *next;
|
||||
u32 offset; /* physical offset to beginning of real dirent */
|
||||
u32 version;
|
||||
u32 pino;
|
||||
u32 ino;
|
||||
unsigned int nhash;
|
||||
unsigned char nsize;
|
||||
unsigned char type;
|
||||
};
|
||||
|
||||
struct b_list {
|
||||
struct b_node *listTail;
|
||||
struct b_node *listHead;
|
||||
unsigned int listCount;
|
||||
struct mem_block *listMemBase;
|
||||
};
|
||||
|
||||
struct b_lists {
|
||||
char *partOffset;
|
||||
struct b_list dir;
|
||||
struct b_list frag;
|
||||
};
|
||||
|
||||
struct b_compr_info {
|
||||
u32 num_frags;
|
||||
u32 compr_sum;
|
||||
u32 decompr_sum;
|
||||
};
|
||||
|
||||
struct b_jffs2_info {
|
||||
struct b_compr_info compr_info[JFFS2_NUM_COMPR];
|
||||
};
|
||||
|
||||
static inline int
|
||||
hdr_crc(struct jffs2_unknown_node *node)
|
||||
{
|
||||
u32 crc = crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_unknown_node) - 4);
|
||||
if (node->hdr_crc != crc) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
dirent_crc(struct jffs2_raw_dirent *node)
|
||||
{
|
||||
if (node->node_crc != crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_raw_dirent) - 8)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
dirent_name_crc(struct jffs2_raw_dirent *node)
|
||||
{
|
||||
if (node->name_crc != crc32_no_comp(0, (unsigned char *)&(node->name), node->nsize)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
inode_crc(struct jffs2_raw_inode *node)
|
||||
{
|
||||
if (node->node_crc != crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_raw_inode) - 8)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Borrowed from include/linux/dcache.h */
|
||||
|
||||
/* Name hashing routines. Initial hash value */
|
||||
/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
|
||||
#define init_name_hash() 0
|
||||
|
||||
/* partial hash update function. Assume roughly 4 bits per character */
|
||||
static inline unsigned long
|
||||
partial_name_hash(unsigned long c, unsigned long prevhash)
|
||||
{
|
||||
return (prevhash + (c << 4) + (c >> 4)) * 11;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally: cut down the number of bits to a int value (and try to avoid
|
||||
* losing bits)
|
||||
*/
|
||||
static inline unsigned long end_name_hash(unsigned long hash)
|
||||
{
|
||||
return (unsigned int) hash;
|
||||
}
|
||||
|
||||
/* Compute the hash for a name string. */
|
||||
static inline unsigned int
|
||||
full_name_hash(const unsigned char *name, unsigned int len)
|
||||
{
|
||||
unsigned long hash = init_name_hash();
|
||||
while (len--)
|
||||
hash = partial_name_hash(*name++, hash);
|
||||
return end_name_hash(hash);
|
||||
}
|
||||
|
||||
#endif /* jffs2_private.h */
|
|
@ -1,93 +0,0 @@
|
|||
#ifndef jffs2_private_h
|
||||
#define jffs2_private_h
|
||||
|
||||
#include <jffs2/jffs2.h>
|
||||
|
||||
|
||||
struct b_node {
|
||||
u32 offset;
|
||||
struct b_node *next;
|
||||
};
|
||||
|
||||
struct b_list {
|
||||
struct b_node *listTail;
|
||||
struct b_node *listHead;
|
||||
#ifdef CFG_JFFS2_SORT_FRAGMENTS
|
||||
struct b_node *listLast;
|
||||
int (*listCompare)(struct b_node *new, struct b_node *node);
|
||||
u32 listLoops;
|
||||
#endif
|
||||
u32 listCount;
|
||||
struct mem_block *listMemBase;
|
||||
};
|
||||
|
||||
struct b_lists {
|
||||
struct b_list dir;
|
||||
struct b_list frag;
|
||||
|
||||
};
|
||||
|
||||
struct b_compr_info {
|
||||
u32 num_frags;
|
||||
u32 compr_sum;
|
||||
u32 decompr_sum;
|
||||
};
|
||||
|
||||
struct b_jffs2_info {
|
||||
struct b_compr_info compr_info[JFFS2_NUM_COMPR];
|
||||
};
|
||||
|
||||
static inline int
|
||||
hdr_crc(struct jffs2_unknown_node *node)
|
||||
{
|
||||
u32 crc = crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_unknown_node) - 4);
|
||||
if (node->hdr_crc != crc) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
dirent_crc(struct jffs2_raw_dirent *node)
|
||||
{
|
||||
if (node->node_crc != crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_raw_dirent) - 8)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
dirent_name_crc(struct jffs2_raw_dirent *node)
|
||||
{
|
||||
if (node->name_crc != crc32_no_comp(0, (unsigned char *)&(node->name), node->nsize)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
inode_crc(struct jffs2_raw_inode *node)
|
||||
{
|
||||
if (node->node_crc != crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_raw_inode) - 8)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
data_crc(struct jffs2_raw_inode *node)
|
||||
{
|
||||
if (node->data_crc != crc32_no_comp(0, (unsigned char *)
|
||||
((int) &node->node_crc + sizeof (node->node_crc)),
|
||||
node->csize)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* jffs2_private.h */
|
|
@ -1,389 +0,0 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
* Filename: mini_inflate.c
|
||||
* Version: $Id: mini_inflate.c,v 1.3 2002/01/24 22:58:42 rfeany Exp $
|
||||
* Copyright: Copyright (C) 2001, Russ Dill
|
||||
* Author: Russ Dill <Russ.Dill@asu.edu>
|
||||
* Description: Mini inflate implementation (RFC 1951)
|
||||
*-----------------------------------------------------------------------*/
|
||||
/*
|
||||
*
|
||||
* 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 <config.h>
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
|
||||
|
||||
#include <jffs2/mini_inflate.h>
|
||||
|
||||
/* The order that the code lengths in section 3.2.7 are in */
|
||||
static unsigned char huffman_order[] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5,
|
||||
11, 4, 12, 3, 13, 2, 14, 1, 15};
|
||||
|
||||
inline void cramfs_memset(int *s, const int c, size n)
|
||||
{
|
||||
n--;
|
||||
for (;n > 0; n--) s[n] = c;
|
||||
s[0] = c;
|
||||
}
|
||||
|
||||
/* associate a stream with a block of data and reset the stream */
|
||||
static void init_stream(struct bitstream *stream, unsigned char *data,
|
||||
void *(*inflate_memcpy)(void *, const void *, size))
|
||||
{
|
||||
stream->error = NO_ERROR;
|
||||
stream->memcpy = inflate_memcpy;
|
||||
stream->decoded = 0;
|
||||
stream->data = data;
|
||||
stream->bit = 0; /* The first bit of the stream is the lsb of the
|
||||
* first byte */
|
||||
|
||||
/* really sorry about all this initialization, think of a better way,
|
||||
* let me know and it will get cleaned up */
|
||||
stream->codes.bits = 8;
|
||||
stream->codes.num_symbols = 19;
|
||||
stream->codes.lengths = stream->code_lengths;
|
||||
stream->codes.symbols = stream->code_symbols;
|
||||
stream->codes.count = stream->code_count;
|
||||
stream->codes.first = stream->code_first;
|
||||
stream->codes.pos = stream->code_pos;
|
||||
|
||||
stream->lengths.bits = 16;
|
||||
stream->lengths.num_symbols = 288;
|
||||
stream->lengths.lengths = stream->length_lengths;
|
||||
stream->lengths.symbols = stream->length_symbols;
|
||||
stream->lengths.count = stream->length_count;
|
||||
stream->lengths.first = stream->length_first;
|
||||
stream->lengths.pos = stream->length_pos;
|
||||
|
||||
stream->distance.bits = 16;
|
||||
stream->distance.num_symbols = 32;
|
||||
stream->distance.lengths = stream->distance_lengths;
|
||||
stream->distance.symbols = stream->distance_symbols;
|
||||
stream->distance.count = stream->distance_count;
|
||||
stream->distance.first = stream->distance_first;
|
||||
stream->distance.pos = stream->distance_pos;
|
||||
|
||||
}
|
||||
|
||||
/* pull 'bits' bits out of the stream. The last bit pulled it returned as the
|
||||
* msb. (section 3.1.1)
|
||||
*/
|
||||
inline unsigned long pull_bits(struct bitstream *stream,
|
||||
const unsigned int bits)
|
||||
{
|
||||
unsigned long ret;
|
||||
int i;
|
||||
|
||||
ret = 0;
|
||||
for (i = 0; i < bits; i++) {
|
||||
ret += ((*(stream->data) >> stream->bit) & 1) << i;
|
||||
|
||||
/* if, before incrementing, we are on bit 7,
|
||||
* go to the lsb of the next byte */
|
||||
if (stream->bit++ == 7) {
|
||||
stream->bit = 0;
|
||||
stream->data++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline int pull_bit(struct bitstream *stream)
|
||||
{
|
||||
int ret = ((*(stream->data) >> stream->bit) & 1);
|
||||
if (stream->bit++ == 7) {
|
||||
stream->bit = 0;
|
||||
stream->data++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* discard bits up to the next whole byte */
|
||||
static void discard_bits(struct bitstream *stream)
|
||||
{
|
||||
if (stream->bit != 0) {
|
||||
stream->bit = 0;
|
||||
stream->data++;
|
||||
}
|
||||
}
|
||||
|
||||
/* No decompression, the data is all literals (section 3.2.4) */
|
||||
static void decompress_none(struct bitstream *stream, unsigned char *dest)
|
||||
{
|
||||
unsigned int length;
|
||||
|
||||
discard_bits(stream);
|
||||
length = *(stream->data++);
|
||||
length += *(stream->data++) << 8;
|
||||
pull_bits(stream, 16); /* throw away the inverse of the size */
|
||||
|
||||
stream->decoded += length;
|
||||
stream->memcpy(dest, stream->data, length);
|
||||
stream->data += length;
|
||||
}
|
||||
|
||||
/* Read in a symbol from the stream (section 3.2.2) */
|
||||
static int read_symbol(struct bitstream *stream, struct huffman_set *set)
|
||||
{
|
||||
int bits = 0;
|
||||
int code = 0;
|
||||
while (!(set->count[bits] && code < set->first[bits] +
|
||||
set->count[bits])) {
|
||||
code = (code << 1) + pull_bit(stream);
|
||||
if (++bits > set->bits) {
|
||||
/* error decoding (corrupted data?) */
|
||||
stream->error = CODE_NOT_FOUND;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return set->symbols[set->pos[bits] + code - set->first[bits]];
|
||||
}
|
||||
|
||||
/* decompress a stream of data encoded with the passed length and distance
|
||||
* huffman codes */
|
||||
static void decompress_huffman(struct bitstream *stream, unsigned char *dest)
|
||||
{
|
||||
struct huffman_set *lengths = &(stream->lengths);
|
||||
struct huffman_set *distance = &(stream->distance);
|
||||
|
||||
int symbol, length, dist, i;
|
||||
|
||||
do {
|
||||
if ((symbol = read_symbol(stream, lengths)) < 0) return;
|
||||
if (symbol < 256) {
|
||||
*(dest++) = symbol; /* symbol is a literal */
|
||||
stream->decoded++;
|
||||
} else if (symbol > 256) {
|
||||
/* Determine the length of the repitition
|
||||
* (section 3.2.5) */
|
||||
if (symbol < 265) length = symbol - 254;
|
||||
else if (symbol == 285) length = 258;
|
||||
else {
|
||||
length = pull_bits(stream, (symbol - 261) >> 2);
|
||||
length += (4 << ((symbol - 261) >> 2)) + 3;
|
||||
length += ((symbol - 1) % 4) <<
|
||||
((symbol - 261) >> 2);
|
||||
}
|
||||
|
||||
/* Determine how far back to go */
|
||||
if ((symbol = read_symbol(stream, distance)) < 0)
|
||||
return;
|
||||
if (symbol < 4) dist = symbol + 1;
|
||||
else {
|
||||
dist = pull_bits(stream, (symbol - 2) >> 1);
|
||||
dist += (2 << ((symbol - 2) >> 1)) + 1;
|
||||
dist += (symbol % 2) << ((symbol - 2) >> 1);
|
||||
}
|
||||
stream->decoded += length;
|
||||
for (i = 0; i < length; i++) {
|
||||
*dest = dest[-dist];
|
||||
dest++;
|
||||
}
|
||||
}
|
||||
} while (symbol != 256); /* 256 is the end of the data block */
|
||||
}
|
||||
|
||||
/* Fill the lookup tables (section 3.2.2) */
|
||||
static void fill_code_tables(struct huffman_set *set)
|
||||
{
|
||||
int code = 0, i, length;
|
||||
|
||||
/* fill in the first code of each bit length, and the pos pointer */
|
||||
set->pos[0] = 0;
|
||||
for (i = 1; i < set->bits; i++) {
|
||||
code = (code + set->count[i - 1]) << 1;
|
||||
set->first[i] = code;
|
||||
set->pos[i] = set->pos[i - 1] + set->count[i - 1];
|
||||
}
|
||||
|
||||
/* Fill in the table of symbols in order of their huffman code */
|
||||
for (i = 0; i < set->num_symbols; i++) {
|
||||
if ((length = set->lengths[i]))
|
||||
set->symbols[set->pos[length]++] = i;
|
||||
}
|
||||
|
||||
/* reset the pos pointer */
|
||||
for (i = 1; i < set->bits; i++) set->pos[i] -= set->count[i];
|
||||
}
|
||||
|
||||
static void init_code_tables(struct huffman_set *set)
|
||||
{
|
||||
cramfs_memset(set->lengths, 0, set->num_symbols);
|
||||
cramfs_memset(set->count, 0, set->bits);
|
||||
cramfs_memset(set->first, 0, set->bits);
|
||||
}
|
||||
|
||||
/* read in the huffman codes for dynamic decoding (section 3.2.7) */
|
||||
static void decompress_dynamic(struct bitstream *stream, unsigned char *dest)
|
||||
{
|
||||
/* I tried my best to minimize the memory footprint here, while still
|
||||
* keeping up performance. I really dislike the _lengths[] tables, but
|
||||
* I see no way of eliminating them without a sizable performance
|
||||
* impact. The first struct table keeps track of stats on each bit
|
||||
* length. The _length table keeps a record of the bit length of each
|
||||
* symbol. The _symbols table is for looking up symbols by the huffman
|
||||
* code (the pos element points to the first place in the symbol table
|
||||
* where that bit length occurs). I also hate the initization of these
|
||||
* structs, if someone knows how to compact these, lemme know. */
|
||||
|
||||
struct huffman_set *codes = &(stream->codes);
|
||||
struct huffman_set *lengths = &(stream->lengths);
|
||||
struct huffman_set *distance = &(stream->distance);
|
||||
|
||||
int hlit = pull_bits(stream, 5) + 257;
|
||||
int hdist = pull_bits(stream, 5) + 1;
|
||||
int hclen = pull_bits(stream, 4) + 4;
|
||||
int length, curr_code, symbol, i, last_code;
|
||||
|
||||
last_code = 0;
|
||||
|
||||
init_code_tables(codes);
|
||||
init_code_tables(lengths);
|
||||
init_code_tables(distance);
|
||||
|
||||
/* fill in the count of each bit length' as well as the lengths
|
||||
* table */
|
||||
for (i = 0; i < hclen; i++) {
|
||||
length = pull_bits(stream, 3);
|
||||
codes->lengths[huffman_order[i]] = length;
|
||||
if (length) codes->count[length]++;
|
||||
|
||||
}
|
||||
fill_code_tables(codes);
|
||||
|
||||
/* Do the same for the length codes, being carefull of wrap through
|
||||
* to the distance table */
|
||||
curr_code = 0;
|
||||
while (curr_code < hlit) {
|
||||
if ((symbol = read_symbol(stream, codes)) < 0) return;
|
||||
if (symbol == 0) {
|
||||
curr_code++;
|
||||
last_code = 0;
|
||||
} else if (symbol < 16) { /* Literal length */
|
||||
lengths->lengths[curr_code] = last_code = symbol;
|
||||
lengths->count[symbol]++;
|
||||
curr_code++;
|
||||
} else if (symbol == 16) { /* repeat the last symbol 3 - 6
|
||||
* times */
|
||||
length = 3 + pull_bits(stream, 2);
|
||||
for (;length; length--, curr_code++)
|
||||
if (curr_code < hlit) {
|
||||
lengths->lengths[curr_code] =
|
||||
last_code;
|
||||
lengths->count[last_code]++;
|
||||
} else { /* wrap to the distance table */
|
||||
distance->lengths[curr_code - hlit] =
|
||||
last_code;
|
||||
distance->count[last_code]++;
|
||||
}
|
||||
} else if (symbol == 17) { /* repeat a bit length 0 */
|
||||
curr_code += 3 + pull_bits(stream, 3);
|
||||
last_code = 0;
|
||||
} else { /* same, but more times */
|
||||
curr_code += 11 + pull_bits(stream, 7);
|
||||
last_code = 0;
|
||||
}
|
||||
}
|
||||
fill_code_tables(lengths);
|
||||
|
||||
/* Fill the distance table, don't need to worry about wrapthrough
|
||||
* here */
|
||||
curr_code -= hlit;
|
||||
while (curr_code < hdist) {
|
||||
if ((symbol = read_symbol(stream, codes)) < 0) return;
|
||||
if (symbol == 0) {
|
||||
curr_code++;
|
||||
last_code = 0;
|
||||
} else if (symbol < 16) {
|
||||
distance->lengths[curr_code] = last_code = symbol;
|
||||
distance->count[symbol]++;
|
||||
curr_code++;
|
||||
} else if (symbol == 16) {
|
||||
length = 3 + pull_bits(stream, 2);
|
||||
for (;length; length--, curr_code++) {
|
||||
distance->lengths[curr_code] =
|
||||
last_code;
|
||||
distance->count[last_code]++;
|
||||
}
|
||||
} else if (symbol == 17) {
|
||||
curr_code += 3 + pull_bits(stream, 3);
|
||||
last_code = 0;
|
||||
} else {
|
||||
curr_code += 11 + pull_bits(stream, 7);
|
||||
last_code = 0;
|
||||
}
|
||||
}
|
||||
fill_code_tables(distance);
|
||||
|
||||
decompress_huffman(stream, dest);
|
||||
}
|
||||
|
||||
/* fill in the length and distance huffman codes for fixed encoding
|
||||
* (section 3.2.6) */
|
||||
static void decompress_fixed(struct bitstream *stream, unsigned char *dest)
|
||||
{
|
||||
/* let gcc fill in the initial values */
|
||||
struct huffman_set *lengths = &(stream->lengths);
|
||||
struct huffman_set *distance = &(stream->distance);
|
||||
|
||||
cramfs_memset(lengths->count, 0, 16);
|
||||
cramfs_memset(lengths->first, 0, 16);
|
||||
cramfs_memset(lengths->lengths, 8, 144);
|
||||
cramfs_memset(lengths->lengths + 144, 9, 112);
|
||||
cramfs_memset(lengths->lengths + 256, 7, 24);
|
||||
cramfs_memset(lengths->lengths + 280, 8, 8);
|
||||
lengths->count[7] = 24;
|
||||
lengths->count[8] = 152;
|
||||
lengths->count[9] = 112;
|
||||
|
||||
cramfs_memset(distance->count, 0, 16);
|
||||
cramfs_memset(distance->first, 0, 16);
|
||||
cramfs_memset(distance->lengths, 5, 32);
|
||||
distance->count[5] = 32;
|
||||
|
||||
|
||||
fill_code_tables(lengths);
|
||||
fill_code_tables(distance);
|
||||
|
||||
|
||||
decompress_huffman(stream, dest);
|
||||
}
|
||||
|
||||
/* returns the number of bytes decoded, < 0 if there was an error. Note that
|
||||
* this function assumes that the block starts on a byte boundry
|
||||
* (non-compliant, but I don't see where this would happen). section 3.2.3 */
|
||||
long decompress_block(unsigned char *dest, unsigned char *source,
|
||||
void *(*inflate_memcpy)(void *, const void *, size))
|
||||
{
|
||||
int bfinal, btype;
|
||||
struct bitstream stream;
|
||||
|
||||
init_stream(&stream, source, inflate_memcpy);
|
||||
do {
|
||||
bfinal = pull_bit(&stream);
|
||||
btype = pull_bits(&stream, 2);
|
||||
if (btype == NO_COMP) decompress_none(&stream, dest + stream.decoded);
|
||||
else if (btype == DYNAMIC_COMP)
|
||||
decompress_dynamic(&stream, dest + stream.decoded);
|
||||
else if (btype == FIXED_COMP) decompress_fixed(&stream, dest + stream.decoded);
|
||||
else stream.error = COMP_UNKNOWN;
|
||||
} while (!bfinal && !stream.error);
|
||||
|
||||
return stream.error ? -stream.error : stream.decoded;
|
||||
}
|
||||
|
||||
#endif /* CFG_CMD_JFFS2 */
|
|
@ -1,52 +0,0 @@
|
|||
#
|
||||
# (C) Copyright 2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# (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 = $(obj)libreiserfs.a
|
||||
|
||||
AOBJS =
|
||||
COBJS = reiserfs.o dev.o mode_string.o
|
||||
|
||||
SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS))
|
||||
|
||||
#CPPFLAGS +=
|
||||
|
||||
all: $(LIB) $(AOBJS)
|
||||
|
||||
$(LIB): $(obj).depend $(OBJS)
|
||||
$(AR) $(ARFLAGS) $@ $(OBJS)
|
||||
|
||||
#########################################################################
|
||||
|
||||
# defines $(obj).depend target
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* (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 */
|
|
@ -1,142 +0,0 @@
|
|||
/* 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???";
|
||||
/* 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 */
|
|
@ -1,978 +0,0 @@
|
|||
/*
|
||||
* 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);
|
||||
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 */
|
|
@ -1,520 +0,0 @@
|
|||
/*
|
||||
* 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) ((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);
|
Loading…
Reference in New Issue