diff options
| -rw-r--r-- | Makefile | 12 | ||||
| -rw-r--r-- | common/Makefile | 6 | ||||
| -rw-r--r-- | common/cmd_ext2.c | 219 | ||||
| -rw-r--r-- | common/cmd_ext4.c | 96 | ||||
| -rw-r--r-- | common/cmd_ext_common.c | 259 | ||||
| -rw-r--r-- | fs/Makefile | 5 | ||||
| -rw-r--r-- | fs/ext2/dev.c | 131 | ||||
| -rw-r--r-- | fs/ext2/ext2fs.c | 919 | ||||
| -rw-r--r-- | fs/ext4/Makefile (renamed from fs/ext2/Makefile) | 8 | ||||
| -rw-r--r-- | fs/ext4/dev.c | 145 | ||||
| -rw-r--r-- | fs/ext4/ext4_common.c | 875 | ||||
| -rw-r--r-- | fs/ext4/ext4_common.h | 63 | ||||
| -rw-r--r-- | fs/ext4/ext4fs.c | 228 | ||||
| -rw-r--r-- | include/ext2fs.h | 81 | ||||
| -rw-r--r-- | include/ext4fs.h | 132 | ||||
| -rw-r--r-- | include/ext_common.h | 197 | 
16 files changed, 2036 insertions, 1340 deletions
| @@ -245,9 +245,15 @@ ifeq ($(CONFIG_OF_EMBED),y)  LIBS += dts/libdts.o  endif  LIBS += arch/$(ARCH)/lib/lib$(ARCH).o -LIBS += fs/cramfs/libcramfs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o \ -	fs/reiserfs/libreiserfs.o fs/ext2/libext2fs.o fs/yaffs2/libyaffs2.o \ -	fs/ubifs/libubifs.o fs/zfs/libzfs.o +LIBS += fs/cramfs/libcramfs.o \ +	fs/ext4/libext4fs.o \ +	fs/fat/libfat.o \ +	fs/fdos/libfdos.o \ +	fs/jffs2/libjffs2.o \ +	fs/reiserfs/libreiserfs.o \ +	fs/ubifs/libubifs.o \ +	fs/yaffs2/libyaffs2.o \ +	fs/zfs/libzfs.o  LIBS += net/libnet.o  LIBS += disk/libdisk.o  LIBS += drivers/bios_emulator/libatibiosemu.o diff --git a/common/Makefile b/common/Makefile index 3d62775dc..427348437 100644 --- a/common/Makefile +++ b/common/Makefile @@ -86,7 +86,13 @@ COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o  COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o  COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o  COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o +COBJS-$(CONFIG_CMD_EXT4) += cmd_ext4.o  COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o +ifdef CONFIG_CMD_EXT4 +COBJS-y	+= cmd_ext_common.o +else +COBJS-$(CONFIG_CMD_EXT2) += cmd_ext_common.o +endif  COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o  COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o  COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o diff --git a/common/cmd_ext2.c b/common/cmd_ext2.c index 79b1e2fb6..c27d9c7ed 100644 --- a/common/cmd_ext2.c +++ b/common/cmd_ext2.c @@ -1,4 +1,9 @@  /* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> +   * (C) Copyright 2004   * esd gmbh <www.esd-electronics.com>   * Reinhard Arlt <reinhard.arlt@esd-electronics.com> @@ -33,225 +38,35 @@   * Ext2fs support   */  #include <common.h> -#include <part.h> -#include <config.h> -#include <command.h> -#include <image.h> -#include <linux/ctype.h> -#include <asm/byteorder.h> -#include <ext2fs.h> -#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) -#include <usb.h> -#endif - -#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION) -#error DOS or EFI partition support must be selected -#endif - -/* #define	EXT2_DEBUG */ - -#ifdef	EXT2_DEBUG -#define	PRINTF(fmt,args...)	printf (fmt ,##args) -#else -#define PRINTF(fmt,args...) -#endif +#include <ext_common.h>  int do_ext2ls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  { -	char *filename = "/"; -	int dev=0; -	int part=1; -	char *ep; -	block_dev_desc_t *dev_desc=NULL; -	int part_length; - -	if (argc < 3) -		return CMD_RET_USAGE; - -	dev = (int)simple_strtoul (argv[2], &ep, 16); -	dev_desc = get_dev(argv[1],dev); - -	if (dev_desc == NULL) { -		printf ("\n** Block device %s %d not supported\n", argv[1], dev); -		return 1; -	} - -	if (*ep) { -		if (*ep != ':') { -			puts ("\n** Invalid boot device, use `dev[:part]' **\n"); -			return 1; -		} -		part = (int)simple_strtoul(++ep, NULL, 16); -	} - -	if (argc == 4) -		filename = argv[3]; - -	PRINTF("Using device %s %d:%d, directory: %s\n", argv[1], dev, part, filename); - -	if ((part_length = ext2fs_set_blk_dev(dev_desc, part)) == 0) { -		printf ("** Bad partition - %s %d:%d **\n",  argv[1], dev, part); -		ext2fs_close(); -		return 1; -	} - -	if (!ext2fs_mount(part_length)) { -		printf ("** Bad ext2 partition or disk - %s %d:%d **\n",  argv[1], dev, part); -		ext2fs_close(); -		return 1; -	} - -	if (ext2fs_ls (filename)) { -		printf ("** Error ext2fs_ls() **\n"); -		ext2fs_close(); -		return 1; -	}; - -	ext2fs_close(); +	if (do_ext_ls(cmdtp, flag, argc, argv)) +		return -1;  	return 0;  } -U_BOOT_CMD( -	ext2ls,	4,	1,	do_ext2ls, -	"list files in a directory (default /)", -	"<interface> <dev[:part]> [directory]\n" -	"    - list files from 'dev' on 'interface' in a 'directory'" -); -  /******************************************************************************   * Ext2fs boot command intepreter. Derived from diskboot   */  int do_ext2load (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  { -	char *filename = NULL; -	char *ep; -	int dev, part = 1; -	ulong addr = 0, part_length; -	int filelen; -	disk_partition_t info; -	block_dev_desc_t *dev_desc = NULL; -	char buf [12]; -	unsigned long count; -	char *addr_str; - -	switch (argc) { -	case 3: -		addr_str = getenv("loadaddr"); -		if (addr_str != NULL) -			addr = simple_strtoul (addr_str, NULL, 16); -		else -			addr = CONFIG_SYS_LOAD_ADDR; - -		filename = getenv ("bootfile"); -		count = 0; -		break; -	case 4: -		addr = simple_strtoul (argv[3], NULL, 16); -		filename = getenv ("bootfile"); -		count = 0; -		break; -	case 5: -		addr = simple_strtoul (argv[3], NULL, 16); -		filename = argv[4]; -		count = 0; -		break; -	case 6: -		addr = simple_strtoul (argv[3], NULL, 16); -		filename = argv[4]; -		count = simple_strtoul (argv[5], NULL, 16); -		break; - -	default: -		return CMD_RET_USAGE; -	} - -	if (!filename) { -		puts ("** No boot file defined **\n"); -		return 1; -	} - -	dev = (int)simple_strtoul (argv[2], &ep, 16); -	dev_desc = get_dev(argv[1],dev); -	if (dev_desc==NULL) { -		printf ("** Block device %s %d not supported\n", argv[1], dev); -		return 1; -	} -	if (*ep) { -		if (*ep != ':') { -			puts ("** Invalid boot device, use `dev[:part]' **\n"); -			return 1; -		} -		part = (int)simple_strtoul(++ep, NULL, 16); -	} - -	PRINTF("Using device %s%d, partition %d\n", argv[1], dev, part); - -	if (part != 0) { -		if (get_partition_info (dev_desc, part, &info)) { -			printf ("** Bad partition %d **\n", part); -			return 1; -		} - -		if (strncmp((char *)info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) { -			printf ("** Invalid partition type \"%.32s\"" -				" (expect \"" BOOT_PART_TYPE "\")\n", -				info.type); -			return 1; -		} -		printf ("Loading file \"%s\" " -			"from %s device %d:%d (%.32s)\n", -			filename, -			argv[1], dev, part, info.name); -	} else { -		printf ("Loading file \"%s\" from %s device %d\n", -			filename, argv[1], dev); -	} - - -	if ((part_length = ext2fs_set_blk_dev(dev_desc, part)) == 0) { -		printf ("** Bad partition - %s %d:%d **\n",  argv[1], dev, part); -		ext2fs_close(); -		return 1; -	} - -	if (!ext2fs_mount(part_length)) { -		printf ("** Bad ext2 partition or disk - %s %d:%d **\n", -			argv[1], dev, part); -		ext2fs_close(); -		return 1; -	} - -	filelen = ext2fs_open(filename); -	if (filelen < 0) { -		printf("** File not found %s\n", filename); -		ext2fs_close(); -		return 1; -	} -	if ((count < filelen) && (count != 0)) { -	    filelen = count; -	} - -	if (ext2fs_read((char *)addr, filelen) != filelen) { -		printf("** Unable to read \"%s\" from %s %d:%d **\n", -			filename, argv[1], dev, part); -		ext2fs_close(); -		return 1; -	} - -	ext2fs_close(); - -	/* Loading ok, update default load address */ -	load_addr = addr; - -	printf ("%d bytes read\n", filelen); -	sprintf(buf, "%X", filelen); -	setenv("filesize", buf); +	if (do_ext_load(cmdtp, flag, argc, argv)) +		return -1;  	return 0;  }  U_BOOT_CMD( +	ext2ls,	4,	1,	do_ext2ls, +	"list files in a directory (default /)", +	"<interface> <dev[:part]> [directory]\n" +	"    - list files from 'dev' on 'interface' in a 'directory'" +); + +U_BOOT_CMD(  	ext2load,	6,	0,	do_ext2load,  	"load binary file from a Ext2 filesystem",  	"<interface> <dev[:part]> [addr] [filename] [bytes]\n" diff --git a/common/cmd_ext4.c b/common/cmd_ext4.c new file mode 100644 index 000000000..3298fee78 --- /dev/null +++ b/common/cmd_ext4.c @@ -0,0 +1,96 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> + * + * Ext4fs support + * made from existing cmd_ext2.c file of Uboot + * + * (C) Copyright 2004 + * esd gmbh <www.esd-electronics.com> + * Reinhard Arlt <reinhard.arlt@esd-electronics.com> + * + * made from cmd_reiserfs by + * + * (C) Copyright 2003 - 2004 + * Sysgo Real-Time Solutions, 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + * Changelog: + *	0.1 - Newly created file for ext4fs support. Taken from cmd_ext2.c + *	        file in uboot. Added ext4fs ls load and write support. + */ + +#include <common.h> +#include <part.h> +#include <config.h> +#include <command.h> +#include <image.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> +#include <ext_common.h> +#include <ext4fs.h> +#include <linux/stat.h> +#include <malloc.h> + +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) +#include <usb.h> +#endif + +#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION) +#error DOS or EFI partition support must be selected +#endif + +uint64_t total_sector; +uint64_t part_offset; + +#define DOS_PART_MAGIC_OFFSET		0x1fe +#define DOS_FS_TYPE_OFFSET		0x36 +#define DOS_FS32_TYPE_OFFSET		0x52 + +int do_ext4_load(cmd_tbl_t *cmdtp, int flag, int argc, +						char *const argv[]) +{ +	if (do_ext_load(cmdtp, flag, argc, argv)) +		return -1; + +	return 0; +} + +int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	if (do_ext_ls(cmdtp, flag, argc, argv)) +		return -1; + +	return 0; +} + +U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls, +	   "list files in a directory (default /)", +	   "<interface> <dev[:part]> [directory]\n" +	   "	  - list files from 'dev' on 'interface' in a 'directory'"); + +U_BOOT_CMD(ext4load, 6, 0, do_ext4_load, +	   "load binary file from a Ext4 filesystem", +	   "<interface> <dev[:part]> [addr] [filename] [bytes]\n" +	   "	  - load binary file 'filename' from 'dev' on 'interface'\n" +	   "		 to address 'addr' from ext4 filesystem"); diff --git a/common/cmd_ext_common.c b/common/cmd_ext_common.c new file mode 100644 index 000000000..56ee9a55b --- /dev/null +++ b/common/cmd_ext_common.c @@ -0,0 +1,259 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT2/4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> + * + * Ext4fs support + * made from existing cmd_ext2.c file of Uboot + * + * (C) Copyright 2004 + * esd gmbh <www.esd-electronics.com> + * Reinhard Arlt <reinhard.arlt@esd-electronics.com> + * + * made from cmd_reiserfs by + * + * (C) Copyright 2003 - 2004 + * Sysgo Real-Time Solutions, 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* + * Changelog: + *	0.1 - Newly created file for ext4fs support. Taken from cmd_ext2.c + *	        file in uboot. Added ext4fs ls load and write support. + */ + +#include <common.h> +#include <part.h> +#include <config.h> +#include <command.h> +#include <image.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> +#include <ext_common.h> +#include <ext4fs.h> +#include <linux/stat.h> +#include <malloc.h> + +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) +#include <usb.h> +#endif + +#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION) +#error DOS or EFI partition support must be selected +#endif + +#define DOS_PART_MAGIC_OFFSET		0x1fe +#define DOS_FS_TYPE_OFFSET		0x36 +#define DOS_FS32_TYPE_OFFSET		0x52 + +int do_ext_load(cmd_tbl_t *cmdtp, int flag, int argc, +						char *const argv[]) +{ +	char *filename = NULL; +	char *ep; +	int dev; +	unsigned long part = 1; +	ulong addr = 0; +	ulong part_length; +	int filelen; +	disk_partition_t info; +	struct ext_filesystem *fs; +	char buf[12]; +	unsigned long count; +	const char *addr_str; + +	count = 0; +	addr = simple_strtoul(argv[3], NULL, 16); +	filename = getenv("bootfile"); +	switch (argc) { +	case 3: +		addr_str = getenv("loadaddr"); +		if (addr_str != NULL) +			addr = simple_strtoul(addr_str, NULL, 16); +		else +			addr = CONFIG_SYS_LOAD_ADDR; + +		break; +	case 4: +		break; +	case 5: +		filename = argv[4]; +		break; +	case 6: +		filename = argv[4]; +		count = simple_strtoul(argv[5], NULL, 16); +		break; + +	default: +		return cmd_usage(cmdtp); +	} + +	if (!filename) { +		puts("** No boot file defined **\n"); +		return 1; +	} + +	dev = (int)simple_strtoul(argv[2], &ep, 16); +	ext4_dev_desc = get_dev(argv[1], dev); +	if (ext4_dev_desc == NULL) { +		printf("** Block device %s %d not supported\n", argv[1], dev); +		return 1; +	} +	if (init_fs(ext4_dev_desc)) +		return 1; + +	fs = get_fs(); +	if (*ep) { +		if (*ep != ':') { +			puts("** Invalid boot device, use `dev[:part]' **\n"); +			goto fail; +		} +		part = simple_strtoul(++ep, NULL, 16); +	} + +	if (part != 0) { +		if (get_partition_info(fs->dev_desc, part, &info)) { +			printf("** Bad partition %lu **\n", part); +			goto fail; +		} + +		if (strncmp((char *)info.type, BOOT_PART_TYPE, +			    strlen(BOOT_PART_TYPE)) != 0) { +			printf("** Invalid partition type \"%s\"" +			       " (expect \"" BOOT_PART_TYPE "\")\n", info.type); +			goto fail; +		} +		printf("Loading file \"%s\" " +		       "from %s device %d:%lu %s\n", +		       filename, argv[1], dev, part, info.name); +	} else { +		printf("Loading file \"%s\" from %s device %d\n", +		       filename, argv[1], dev); +	} + +	part_length = ext4fs_set_blk_dev(fs->dev_desc, part); +	if (part_length == 0) { +		printf("**Bad partition - %s %d:%lu **\n", argv[1], dev, part); +		ext4fs_close(); +		goto fail; +	} + +	if (!ext4fs_mount(part_length)) { +		printf("** Bad ext2 partition or disk - %s %d:%lu **\n", +		       argv[1], dev, part); +		ext4fs_close(); +		goto fail; +	} + +	filelen = ext4fs_open(filename); +	if (filelen < 0) { +		printf("** File not found %s\n", filename); +		ext4fs_close(); +		goto fail; +	} +	if ((count < filelen) && (count != 0)) +		filelen = count; + +	if (ext4fs_read((char *)addr, filelen) != filelen) { +		printf("** Unable to read \"%s\" from %s %d:%lu **\n", +		       filename, argv[1], dev, part); +		ext4fs_close(); +		goto fail; +	} + +	ext4fs_close(); +	deinit_fs(fs->dev_desc); +	/* Loading ok, update default load address */ +	load_addr = addr; + +	printf("%d bytes read\n", filelen); +	sprintf(buf, "%X", filelen); +	setenv("filesize", buf); + +	return 0; +fail: +	deinit_fs(fs->dev_desc); +	return 1; +} + +int do_ext_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	const char *filename = "/"; +	int dev; +	unsigned long part = 1; +	char *ep; +	struct ext_filesystem *fs; +	int part_length; +	if (argc < 3) +		return cmd_usage(cmdtp); + +	dev = (int)simple_strtoul(argv[2], &ep, 16); + +	ext4_dev_desc = get_dev(argv[1], dev); + +	if (ext4_dev_desc == NULL) { +		printf("\n** Block device %s %d not supported\n", argv[1], dev); +		return 1; +	} + +	if (init_fs(ext4_dev_desc)) +		return 1; + +	fs = get_fs(); +	if (*ep) { +		if (*ep != ':') { +			puts("\n** Invalid boot device, use `dev[:part]' **\n"); +			goto fail; +		} +		part = simple_strtoul(++ep, NULL, 16); +	} + +	if (argc == 4) +		filename = argv[3]; + +	part_length = ext4fs_set_blk_dev(fs->dev_desc, part); +	if (part_length == 0) { +		printf("** Bad partition - %s %d:%lu **\n", argv[1], dev, part); +		ext4fs_close(); +		goto fail; +	} + +	if (!ext4fs_mount(part_length)) { +		printf("** Bad ext2 partition or disk - %s %d:%lu **\n", +		       argv[1], dev, part); +		ext4fs_close(); +		goto fail; +	} + +	if (ext4fs_ls(filename)) { +		printf("** Error extfs_ls() **\n"); +		ext4fs_close(); +		goto fail; +	}; + +	ext4fs_close(); +	deinit_fs(fs->dev_desc); +	return 0; + +fail: +	deinit_fs(fs->dev_desc); +	return 1; +} diff --git a/fs/Makefile b/fs/Makefile index 28da76e95..901e1894b 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -23,7 +23,10 @@  #  subdirs-$(CONFIG_CMD_CRAMFS) := cramfs -subdirs-$(CONFIG_CMD_EXT2) += ext2 +subdirs-$(CONFIG_CMD_EXT4) += ext4 +ifndef CONFIG_CMD_EXT4 +subdirs-$(CONFIG_CMD_EXT2) += ext4 +endif  subdirs-$(CONFIG_CMD_FAT) += fat  subdirs-$(CONFIG_CMD_FDOS) += fdos  subdirs-$(CONFIG_CMD_JFFS2) += jffs2 diff --git a/fs/ext2/dev.c b/fs/ext2/dev.c deleted file mode 100644 index 874e21161..000000000 --- a/fs/ext2/dev.c +++ /dev/null @@ -1,131 +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> -#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) -{ -	ALLOC_CACHE_ALIGN_BUFFER(char, sec_buf, SECTOR_SIZE); -	unsigned sectors; - -	/* -	 *  Check partition boundaries -	 */ -	if ((sector < 0) || -	    ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS)) >= -		part_info.size)) { -		/* errnum = ERR_OUTSIDE_PART; */ -		printf(" ** %s read outside partition sector %d\n", -		       __func__, -		       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(" ** %s Invalid Block Device Descriptor (NULL)\n", -		       __func__); -		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(" ** %s read error **\n", __func__); -			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 */ -	sectors = byte_len / SECTOR_SIZE; - -	if (sectors > 0) { -		if (ext2fs_block_dev_desc->block_read( -			ext2fs_block_dev_desc->dev, -			part_info.start + sector, -			sectors, -			(unsigned long *) buf) != sectors) { -			printf(" ** %s read error - block\n", __func__); -			return 0; -		} - -		buf += sectors * SECTOR_SIZE; -		byte_len -= sectors * SECTOR_SIZE; -		sector += sectors; -	} - -	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(" ** %s read error - last part\n", __func__); -			return 0; -		} -		memcpy(buf, sec_buf, byte_len); -	} -	return 1; -} diff --git a/fs/ext2/ext2fs.c b/fs/ext2/ext2fs.c deleted file mode 100644 index 418404e60..000000000 --- a/fs/ext2/ext2fs.c +++ /dev/null @@ -1,919 +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> -#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 used_dir_cnt; -	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 unsigned int inode_size; - - -static int ext2fs_blockgroup -	(struct ext2_data *data, int group, struct ext2_block_group *blkgrp) { -	unsigned int blkno; -	unsigned int blkoff; -	unsigned int desc_per_blk; - -	desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group); - -	blkno = __le32_to_cpu(data->sblock.first_data_block) + 1 + -	group / desc_per_blk; -	blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group); -#ifdef DEBUG -	printf ("ext2fs read %d group descriptor (blkno %d blkoff %d)\n", -		group, blkno, blkoff); -#endif -	return (ext2fs_devread (blkno << LOG2_EXT2_BLOCK_SIZE(data), -		blkoff, 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; - -#ifdef DEBUG -	printf ("ext2fs read inode %d, inode_size %d\n", ino, inode_size); -#endif -	/* It is easier to calculate if the first inode is 0.  */ -	ino--; -	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) / inode_size; - -	blkno = __le32_to_cpu (blkgrp.inode_table_id) + -		(ino % __le32_to_cpu (sblock->inodes_per_group)) -		/ inodes_per_block; -	blkoff = (ino % inodes_per_block) * inode_size; -#ifdef DEBUG -	printf ("ext2fs read inode blkno %d blkoff %d\n", blkno, blkoff); -#endif -	/* Read the inode.  */ -	status = ext2fs_devread (blkno << LOG2_EXT2_BLOCK_SIZE (data), 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 *) memalign(ARCH_DMA_MINALIGN, -							     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 *) memalign(ARCH_DMA_MINALIGN, -							     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 *) memalign(ARCH_DMA_MINALIGN, -							     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 *) memalign(ARCH_DMA_MINALIGN, -							     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 *) memalign(ARCH_DMA_MINALIGN, -							     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 *) memalign(ARCH_DMA_MINALIGN, -							     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) != indir2_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); -		} - -		/* 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; -		} - -		/* grab middle blocks in one go */ -		if (i != pos / blocksize && i < blockcnt - 1 && blockcnt > 3) { -			int oldblk = blknr; -			int blocknxt = ext2fs_read_block(node, i + 1); -			while (i < blockcnt - 1) { -				if (blocknxt == (oldblk + 1)) { -					oldblk = blocknxt; -					i++; -				} else { -					blocknxt = ext2fs_read_block(node, i); -					break; -				} -				blocknxt = ext2fs_read_block(node, i); -			} - -			if (oldblk == blknr) -				blockend = blocksize; -			else -				blockend = (1 + blocknxt - blknr) * blocksize; -		} - -		blknr = blknr << log2blocksize; - -		/* 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, 0, blocksize - skipfirst); -		} -		buf += blockend - 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 (const 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 (const 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; -	} -	if (__le32_to_cpu(data->sblock.revision_level == 0)) { -		inode_size = 128; -	} else { -		inode_size = __le16_to_cpu(data->sblock.inode_size); -	} -#ifdef DEBUG -	printf("EXT2 rev %d, inode_size %d\n", -			__le32_to_cpu(data->sblock.revision_level), inode_size); -#endif -	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); -} diff --git a/fs/ext2/Makefile b/fs/ext4/Makefile index 3c65d252f..7b7fcbd9f 100644 --- a/fs/ext2/Makefile +++ b/fs/ext4/Makefile @@ -27,15 +27,17 @@  include $(TOPDIR)/config.mk -LIB	= $(obj)libext2fs.o +LIB	= $(obj)libext4fs.o  AOBJS	= -COBJS-$(CONFIG_CMD_EXT2) := ext2fs.o dev.o +COBJS-$(CONFIG_CMD_EXT4) := ext4fs.o ext4_common.o dev.o +ifndef CONFIG_CMD_EXT4 +COBJS-$(CONFIG_CMD_EXT2) := ext4fs.o ext4_common.o dev.o +endif  SRCS	:= $(AOBJS:.o=.S) $(COBJS-y:.o=.c)  OBJS	:= $(addprefix $(obj),$(AOBJS) $(COBJS-y)) -#CPPFLAGS +=  all:	$(LIB) $(AOBJS) diff --git a/fs/ext4/dev.c b/fs/ext4/dev.c new file mode 100644 index 000000000..fb62f241e --- /dev/null +++ b/fs/ext4/dev.c @@ -0,0 +1,145 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> + * + * made from existing ext2/dev.c file of Uboot + * (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. + * + */ + +/* + * Changelog: + *	0.1 - Newly created file for ext4fs support. Taken from + *		fs/ext2/dev.c file in uboot. + */ + +#include <common.h> +#include <config.h> +#include <ext_common.h> + +static block_dev_desc_t *ext4fs_block_dev_desc; +static disk_partition_t part_info; + +int ext4fs_set_blk_dev(block_dev_desc_t *rbdd, int part) +{ +	ext4fs_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(ext4fs_block_dev_desc, +					part, &part_info)) +			return 0; +	} +	return part_info.size; +} + +int ext4fs_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)) { +		printf("%s read outside partition %d\n", __func__, 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 (ext4fs_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 (ext4fs_block_dev_desc-> +		    block_read(ext4fs_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++; +	} + +	if (byte_len == 0) +		return 1; + +	/* read sector aligned part */ +	block_len = byte_len & ~(SECTOR_SIZE - 1); + +	if (block_len == 0) { +		u8 p[SECTOR_SIZE]; + +		block_len = SECTOR_SIZE; +		ext4fs_block_dev_desc->block_read(ext4fs_block_dev_desc->dev, +						  part_info.start + sector, +						  1, (unsigned long *)p); +		memcpy(buf, p, byte_len); +		return 1; +	} + +	if (ext4fs_block_dev_desc->block_read(ext4fs_block_dev_desc->dev, +					       part_info.start + sector, +					       block_len / SECTOR_SIZE, +					       (unsigned long *) buf) != +					       block_len / SECTOR_SIZE) { +		printf(" ** %s read error - block\n", __func__); +		return 0; +	} +	block_len = byte_len & ~(SECTOR_SIZE - 1); +	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 (ext4fs_block_dev_desc-> +		    block_read(ext4fs_block_dev_desc->dev, +				part_info.start + sector, 1, +				(unsigned long *) sec_buf) != 1) { +			printf("* %s read error - last part\n", __func__); +			return 0; +		} +		memcpy(buf, sec_buf, byte_len); +	} +	return 1; +} diff --git a/fs/ext4/ext4_common.c b/fs/ext4/ext4_common.c new file mode 100644 index 000000000..2ddbb50e8 --- /dev/null +++ b/fs/ext4/ext4_common.c @@ -0,0 +1,875 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> + * + * ext4ls and ext4load : Based on ext2 ls load support in Uboot. + * + * (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> +#include <ext_common.h> +#include <ext4fs.h> +#include <malloc.h> +#include <stddef.h> +#include <linux/stat.h> +#include <linux/time.h> +#include <asm/byteorder.h> +#include "ext4_common.h" + +struct ext2_data *ext4fs_root; +struct ext2fs_node *ext4fs_file; +uint32_t *ext4fs_indir1_block; +int ext4fs_indir1_size; +int ext4fs_indir1_blkno = -1; +uint32_t *ext4fs_indir2_block; +int ext4fs_indir2_size; +int ext4fs_indir2_blkno = -1; + +uint32_t *ext4fs_indir3_block; +int ext4fs_indir3_size; +int ext4fs_indir3_blkno = -1; +struct ext2_inode *g_parent_inode; +static int symlinknest; + +static struct ext4_extent_header *ext4fs_get_extent_block +	(struct ext2_data *data, char *buf, +		struct ext4_extent_header *ext_block, +		uint32_t fileblock, int log2_blksz) +{ +	struct ext4_extent_idx *index; +	unsigned long long block; +	struct ext_filesystem *fs = get_fs(); +	int i; + +	while (1) { +		index = (struct ext4_extent_idx *)(ext_block + 1); + +		if (le32_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC) +			return 0; + +		if (ext_block->eh_depth == 0) +			return ext_block; +		i = -1; +		do { +			i++; +			if (i >= le32_to_cpu(ext_block->eh_entries)) +				break; +		} while (fileblock > le32_to_cpu(index[i].ei_block)); + +		if (--i < 0) +			return 0; + +		block = le32_to_cpu(index[i].ei_leaf_hi); +		block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo); + +		if (ext4fs_devread(block << log2_blksz, 0, fs->blksz, buf)) +			ext_block = (struct ext4_extent_header *)buf; +		else +			return 0; +	} +} + +static int ext4fs_blockgroup +	(struct ext2_data *data, int group, struct ext2_block_group *blkgrp) +{ +	long int blkno; +	unsigned int blkoff, desc_per_blk; + +	desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group); + +	blkno = __le32_to_cpu(data->sblock.first_data_block) + 1 + +			group / desc_per_blk; +	blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group); + +	debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n", +	      group, blkno, blkoff); + +	return ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data), +			      blkoff, sizeof(struct ext2_block_group), +			      (char *)blkgrp); +} + +int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode) +{ +	struct ext2_block_group blkgrp; +	struct ext2_sblock *sblock = &data->sblock; +	struct ext_filesystem *fs = get_fs(); +	int inodes_per_block, status; +	long int blkno; +	unsigned int blkoff; + +	/* It is easier to calculate if the first inode is 0. */ +	ino--; +	status = ext4fs_blockgroup(data, ino / __le32_to_cpu +				   (sblock->inodes_per_group), &blkgrp); +	if (status == 0) +		return 0; + +	inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz; +	blkno = __le32_to_cpu(blkgrp.inode_table_id) + +	    (ino % __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; +	blkoff = (ino % inodes_per_block) * fs->inodesz; +	/* Read the inode. */ +	status = ext4fs_devread(blkno << LOG2_EXT2_BLOCK_SIZE(data), blkoff, +				sizeof(struct ext2_inode), (char *)inode); +	if (status == 0) +		return 0; + +	return 1; +} + +long int read_allocated_block(struct ext2_inode *inode, int fileblock) +{ +	long int blknr; +	int blksz; +	int log2_blksz; +	int status; +	long int rblock; +	long int perblock_parent; +	long int perblock_child; +	unsigned long long start; +	/* get the blocksize of the filesystem */ +	blksz = EXT2_BLOCK_SIZE(ext4fs_root); +	log2_blksz = LOG2_EXT2_BLOCK_SIZE(ext4fs_root); +	if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) { +		char *buf = zalloc(blksz); +		if (!buf) +			return -ENOMEM; +		struct ext4_extent_header *ext_block; +		struct ext4_extent *extent; +		int i = -1; +		ext_block = ext4fs_get_extent_block(ext4fs_root, buf, +						    (struct ext4_extent_header +						     *)inode->b. +						    blocks.dir_blocks, +						    fileblock, log2_blksz); +		if (!ext_block) { +			printf("invalid extent block\n"); +			free(buf); +			return -EINVAL; +		} + +		extent = (struct ext4_extent *)(ext_block + 1); + +		do { +			i++; +			if (i >= le32_to_cpu(ext_block->eh_entries)) +				break; +		} while (fileblock >= le32_to_cpu(extent[i].ee_block)); +		if (--i >= 0) { +			fileblock -= le32_to_cpu(extent[i].ee_block); +			if (fileblock >= le32_to_cpu(extent[i].ee_len)) { +				free(buf); +				return 0; +			} + +			start = le32_to_cpu(extent[i].ee_start_hi); +			start = (start << 32) + +					le32_to_cpu(extent[i].ee_start_lo); +			free(buf); +			return fileblock + start; +		} + +		printf("Extent Error\n"); +		free(buf); +		return -1; +	} + +	/* 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 (ext4fs_indir1_block == NULL) { +			ext4fs_indir1_block = zalloc(blksz); +			if (ext4fs_indir1_block == NULL) { +				printf("** SI ext2fs read block (indir 1)" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir1_size = blksz; +			ext4fs_indir1_blkno = -1; +		} +		if (blksz != ext4fs_indir1_size) { +			free(ext4fs_indir1_block); +			ext4fs_indir1_block = NULL; +			ext4fs_indir1_size = 0; +			ext4fs_indir1_blkno = -1; +			ext4fs_indir1_block = zalloc(blksz); +			if (ext4fs_indir1_block == NULL) { +				printf("** SI ext2fs read block (indir 1):" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir1_size = blksz; +		} +		if ((__le32_to_cpu(inode->b.blocks.indir_block) << +		     log2_blksz) != ext4fs_indir1_blkno) { +			status = +			    ext4fs_devread(__le32_to_cpu +					   (inode->b.blocks. +					    indir_block) << log2_blksz, 0, +					   blksz, (char *)ext4fs_indir1_block); +			if (status == 0) { +				printf("** SI ext2fs read block (indir 1)" +					"failed. **\n"); +				return 0; +			} +			ext4fs_indir1_blkno = +				__le32_to_cpu(inode->b.blocks. +					       indir_block) << log2_blksz; +		} +		blknr = __le32_to_cpu(ext4fs_indir1_block +				      [fileblock - INDIRECT_BLOCKS]); +	} +	/* Double indirect. */ +	else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4 * +					(blksz / 4 + 1)))) { + +		long int perblock = blksz / 4; +		long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4); + +		if (ext4fs_indir1_block == NULL) { +			ext4fs_indir1_block = zalloc(blksz); +			if (ext4fs_indir1_block == NULL) { +				printf("** DI ext2fs read block (indir 2 1)" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir1_size = blksz; +			ext4fs_indir1_blkno = -1; +		} +		if (blksz != ext4fs_indir1_size) { +			free(ext4fs_indir1_block); +			ext4fs_indir1_block = NULL; +			ext4fs_indir1_size = 0; +			ext4fs_indir1_blkno = -1; +			ext4fs_indir1_block = zalloc(blksz); +			if (ext4fs_indir1_block == NULL) { +				printf("** DI ext2fs read block (indir 2 1)" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir1_size = blksz; +		} +		if ((__le32_to_cpu(inode->b.blocks.double_indir_block) << +		     log2_blksz) != ext4fs_indir1_blkno) { +			status = +			    ext4fs_devread(__le32_to_cpu +					   (inode->b.blocks. +					    double_indir_block) << log2_blksz, +					   0, blksz, +					   (char *)ext4fs_indir1_block); +			if (status == 0) { +				printf("** DI ext2fs read block (indir 2 1)" +					"failed. **\n"); +				return -1; +			} +			ext4fs_indir1_blkno = +			    __le32_to_cpu(inode->b.blocks.double_indir_block) << +			    log2_blksz; +		} + +		if (ext4fs_indir2_block == NULL) { +			ext4fs_indir2_block = zalloc(blksz); +			if (ext4fs_indir2_block == NULL) { +				printf("** DI ext2fs read block (indir 2 2)" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir2_size = blksz; +			ext4fs_indir2_blkno = -1; +		} +		if (blksz != ext4fs_indir2_size) { +			free(ext4fs_indir2_block); +			ext4fs_indir2_block = NULL; +			ext4fs_indir2_size = 0; +			ext4fs_indir2_blkno = -1; +			ext4fs_indir2_block = zalloc(blksz); +			if (ext4fs_indir2_block == NULL) { +				printf("** DI ext2fs read block (indir 2 2)" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir2_size = blksz; +		} +		if ((__le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) << +		     log2_blksz) != ext4fs_indir2_blkno) { +			status = ext4fs_devread(__le32_to_cpu +						(ext4fs_indir1_block +						 [rblock / +						  perblock]) << log2_blksz, 0, +						blksz, +						(char *)ext4fs_indir2_block); +			if (status == 0) { +				printf("** DI ext2fs read block (indir 2 2)" +					"failed. **\n"); +				return -1; +			} +			ext4fs_indir2_blkno = +			    __le32_to_cpu(ext4fs_indir1_block[rblock +							      / +							      perblock]) << +			    log2_blksz; +		} +		blknr = __le32_to_cpu(ext4fs_indir2_block[rblock % perblock]); +	} +	/* Tripple indirect. */ +	else { +		rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 + +				      (blksz / 4 * blksz / 4)); +		perblock_child = blksz / 4; +		perblock_parent = ((blksz / 4) * (blksz / 4)); + +		if (ext4fs_indir1_block == NULL) { +			ext4fs_indir1_block = zalloc(blksz); +			if (ext4fs_indir1_block == NULL) { +				printf("** TI ext2fs read block (indir 2 1)" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir1_size = blksz; +			ext4fs_indir1_blkno = -1; +		} +		if (blksz != ext4fs_indir1_size) { +			free(ext4fs_indir1_block); +			ext4fs_indir1_block = NULL; +			ext4fs_indir1_size = 0; +			ext4fs_indir1_blkno = -1; +			ext4fs_indir1_block = zalloc(blksz); +			if (ext4fs_indir1_block == NULL) { +				printf("** TI ext2fs read block (indir 2 1)" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir1_size = blksz; +		} +		if ((__le32_to_cpu(inode->b.blocks.triple_indir_block) << +		     log2_blksz) != ext4fs_indir1_blkno) { +			status = ext4fs_devread +			    (__le32_to_cpu(inode->b.blocks.triple_indir_block) +			     << log2_blksz, 0, blksz, +			     (char *)ext4fs_indir1_block); +			if (status == 0) { +				printf("** TI ext2fs read block (indir 2 1)" +					"failed. **\n"); +				return -1; +			} +			ext4fs_indir1_blkno = +			    __le32_to_cpu(inode->b.blocks.triple_indir_block) << +			    log2_blksz; +		} + +		if (ext4fs_indir2_block == NULL) { +			ext4fs_indir2_block = zalloc(blksz); +			if (ext4fs_indir2_block == NULL) { +				printf("** TI ext2fs read block (indir 2 2)" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir2_size = blksz; +			ext4fs_indir2_blkno = -1; +		} +		if (blksz != ext4fs_indir2_size) { +			free(ext4fs_indir2_block); +			ext4fs_indir2_block = NULL; +			ext4fs_indir2_size = 0; +			ext4fs_indir2_blkno = -1; +			ext4fs_indir2_block = zalloc(blksz); +			if (ext4fs_indir2_block == NULL) { +				printf("** TI ext2fs read block (indir 2 2)" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir2_size = blksz; +		} +		if ((__le32_to_cpu(ext4fs_indir1_block[rblock / +						       perblock_parent]) << +		     log2_blksz) +		    != ext4fs_indir2_blkno) { +			status = ext4fs_devread(__le32_to_cpu +						(ext4fs_indir1_block +						 [rblock / +						  perblock_parent]) << +						log2_blksz, 0, blksz, +						(char *)ext4fs_indir2_block); +			if (status == 0) { +				printf("** TI ext2fs read block (indir 2 2)" +					"failed. **\n"); +				return -1; +			} +			ext4fs_indir2_blkno = +			    __le32_to_cpu(ext4fs_indir1_block[rblock / +							      perblock_parent]) +			    << log2_blksz; +		} + +		if (ext4fs_indir3_block == NULL) { +			ext4fs_indir3_block = zalloc(blksz); +			if (ext4fs_indir3_block == NULL) { +				printf("** TI ext2fs read block (indir 2 2)" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir3_size = blksz; +			ext4fs_indir3_blkno = -1; +		} +		if (blksz != ext4fs_indir3_size) { +			free(ext4fs_indir3_block); +			ext4fs_indir3_block = NULL; +			ext4fs_indir3_size = 0; +			ext4fs_indir3_blkno = -1; +			ext4fs_indir3_block = zalloc(blksz); +			if (ext4fs_indir3_block == NULL) { +				printf("** TI ext2fs read block (indir 2 2)" +					"malloc failed. **\n"); +				return -1; +			} +			ext4fs_indir3_size = blksz; +		} +		if ((__le32_to_cpu(ext4fs_indir2_block[rblock +						       / +						       perblock_child]) << +		     log2_blksz) != ext4fs_indir3_blkno) { +			status = +			    ext4fs_devread(__le32_to_cpu +					   (ext4fs_indir2_block +					    [(rblock / perblock_child) +					     % (blksz / 4)]) << log2_blksz, 0, +					   blksz, (char *)ext4fs_indir3_block); +			if (status == 0) { +				printf("** TI ext2fs read block (indir 2 2)" +				       "failed. **\n"); +				return -1; +			} +			ext4fs_indir3_blkno = +			    __le32_to_cpu(ext4fs_indir2_block[(rblock / +							       perblock_child) % +							      (blksz / +							       4)]) << +			    log2_blksz; +		} + +		blknr = __le32_to_cpu(ext4fs_indir3_block +				      [rblock % perblock_child]); +	} +	debug("ext4fs_read_block %ld\n", blknr); + +	return blknr; +} + +void ext4fs_close(void) +{ +	if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) { +		ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen); +		ext4fs_file = NULL; +	} +	if (ext4fs_root != NULL) { +		free(ext4fs_root); +		ext4fs_root = NULL; +	} +	if (ext4fs_indir1_block != NULL) { +		free(ext4fs_indir1_block); +		ext4fs_indir1_block = NULL; +		ext4fs_indir1_size = 0; +		ext4fs_indir1_blkno = -1; +	} +	if (ext4fs_indir2_block != NULL) { +		free(ext4fs_indir2_block); +		ext4fs_indir2_block = NULL; +		ext4fs_indir2_size = 0; +		ext4fs_indir2_blkno = -1; +	} +	if (ext4fs_indir3_block != NULL) { +		free(ext4fs_indir3_block); +		ext4fs_indir3_block = NULL; +		ext4fs_indir3_size = 0; +		ext4fs_indir3_blkno = -1; +	} +} + +int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, +				struct ext2fs_node **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 = ext4fs_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 = ext4fs_read_file(diro, fpos, +					   sizeof(struct ext2_dirent), +					   (char *) &dirent); +		if (status < 1) +			return 0; + +		if (dirent.namelen != 0) { +			char filename[dirent.namelen + 1]; +			struct ext2fs_node *fdiro; +			int type = FILETYPE_UNKNOWN; + +			status = ext4fs_read_file(diro, +						  fpos + +						  sizeof(struct ext2_dirent), +						  dirent.namelen, filename); +			if (status < 1) +				return 0; + +			fdiro = zalloc(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 { +				status = ext4fs_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 = ext4fs_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 *ext4fs_read_symlink(struct ext2fs_node *node) +{ +	char *symlink; +	struct ext2fs_node *diro = node; +	int status; + +	if (!diro->inode_read) { +		status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode); +		if (status == 0) +			return 0; +	} +	symlink = zalloc(__le32_to_cpu(diro->inode.size) + 1); +	if (!symlink) +		return 0; + +	if (__le32_to_cpu(diro->inode.size) <= 60) { +		strncpy(symlink, diro->inode.b.symlink, +			 __le32_to_cpu(diro->inode.size)); +	} else { +		status = ext4fs_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; +} + +static int ext4fs_find_file1(const char *currpath, +			     struct ext2fs_node *currroot, +			     struct ext2fs_node **currfound, int *foundtype) +{ +	char fpath[strlen(currpath) + 1]; +	char *name = fpath; +	char *next; +	int status; +	int type = FILETYPE_DIRECTORY; +	struct ext2fs_node *currnode = currroot; +	struct ext2fs_node *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'; +		} + +		if (type != FILETYPE_DIRECTORY) { +			ext4fs_free_node(currnode, currroot); +			return 0; +		} + +		oldnode = currnode; + +		/* Iterate over the directory. */ +		found = ext4fs_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) { +				ext4fs_free_node(currnode, currroot); +				ext4fs_free_node(oldnode, currroot); +				return 0; +			} + +			symlink = ext4fs_read_symlink(currnode); +			ext4fs_free_node(currnode, currroot); + +			if (!symlink) { +				ext4fs_free_node(oldnode, currroot); +				return 0; +			} + +			debug("Got symlink >%s<\n", symlink); + +			if (symlink[0] == '/') { +				ext4fs_free_node(oldnode, currroot); +				oldnode = &ext4fs_root->diropen; +			} + +			/* Lookup the node the symlink points to. */ +			status = ext4fs_find_file1(symlink, oldnode, +						    &currnode, &type); + +			free(symlink); + +			if (status == 0) { +				ext4fs_free_node(oldnode, currroot); +				return 0; +			} +		} + +		ext4fs_free_node(oldnode, currroot); + +		/* Found the node! */ +		if (!next || *next == '\0') { +			*currfound = currnode; +			*foundtype = type; +			return 1; +		} +		name = next; +	} +	return -1; +} + +int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode, +	struct ext2fs_node **foundnode, int expecttype) +{ +	int status; +	int foundtype = FILETYPE_DIRECTORY; + +	symlinknest = 0; +	if (!path) +		return 0; + +	status = ext4fs_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 ext4fs_open(const char *filename) +{ +	struct ext2fs_node *fdiro = NULL; +	int status; +	int len; + +	if (ext4fs_root == NULL) +		return -1; + +	ext4fs_file = NULL; +	status = ext4fs_find_file(filename, &ext4fs_root->diropen, &fdiro, +				  FILETYPE_REG); +	if (status == 0) +		goto fail; + +	if (!fdiro->inode_read) { +		status = ext4fs_read_inode(fdiro->data, fdiro->ino, +				&fdiro->inode); +		if (status == 0) +			goto fail; +	} +	len = __le32_to_cpu(fdiro->inode.size); +	ext4fs_file = fdiro; + +	return len; +fail: +	ext4fs_free_node(fdiro, &ext4fs_root->diropen); + +	return -1; +} + +int ext4fs_mount(unsigned part_length) +{ +	struct ext2_data *data; +	int status; +	struct ext_filesystem *fs = get_fs(); +	data = zalloc(sizeof(struct ext2_data)); +	if (!data) +		return 0; + +	/* Read the superblock. */ +	status = ext4fs_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; + +	if (__le32_to_cpu(data->sblock.revision_level == 0)) +		fs->inodesz = 128; +	else +		fs->inodesz = __le16_to_cpu(data->sblock.inode_size); + +	debug("EXT2 rev %d, inode_size %d\n", +	       __le32_to_cpu(data->sblock.revision_level), fs->inodesz); + +	data->diropen.data = data; +	data->diropen.ino = 2; +	data->diropen.inode_read = 1; +	data->inode = &data->diropen.inode; + +	status = ext4fs_read_inode(data, 2, data->inode); +	if (status == 0) +		goto fail; + +	ext4fs_root = data; + +	return 1; +fail: +	printf("Failed to mount ext2 filesystem...\n"); +	free(data); +	ext4fs_root = NULL; + +	return 0; +} diff --git a/fs/ext4/ext4_common.h b/fs/ext4/ext4_common.h new file mode 100644 index 000000000..8e8bcbc0f --- /dev/null +++ b/fs/ext4/ext4_common.h @@ -0,0 +1,63 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> + * + * ext4ls and ext4load :  based on ext2 ls load support in Uboot. + * + * (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. + */ + +#ifndef __EXT4_COMMON__ +#define __EXT4_COMMON__ +#include <ext_common.h> +#include <ext4fs.h> +#include <malloc.h> +#include <asm/errno.h> + +#define YES		1 +#define NO		0 +#define TRUE		1 +#define FALSE		0 +#define RECOVER	1 +#define SCAN		0 + +#define S_IFLNK		0120000		/* symbolic link */ +#define BLOCK_NO_ONE		1 +#define SUPERBLOCK_SECTOR	2 +#define SUPERBLOCK_SIZE	1024 +#define F_FILE			1 + +#define zalloc(size) calloc(1, size) + +extern unsigned long part_offset; +int ext4fs_read_inode(struct ext2_data *data, int ino, +		      struct ext2_inode *inode); +int ext4fs_read_file(struct ext2fs_node *node, int pos, +		unsigned int len, char *buf); +int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode, +			struct ext2fs_node **foundnode, int expecttype); +int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name, +			struct ext2fs_node **fnode, int *ftype); +#endif diff --git a/fs/ext4/ext4fs.c b/fs/ext4/ext4fs.c new file mode 100644 index 000000000..1287bf0e1 --- /dev/null +++ b/fs/ext4/ext4fs.c @@ -0,0 +1,228 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> + * + * ext4ls and ext4load : Based on ext2 ls and load support in Uboot. + *		       Ext4 read optimization taken from Open-Moko + *		       Qi bootloader + * + * (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> +#include <malloc.h> +#include <ext_common.h> +#include <ext4fs.h> +#include <linux/stat.h> +#include <linux/time.h> +#include <asm/byteorder.h> +#include "ext4_common.h" + +int ext4fs_symlinknest; +block_dev_desc_t *ext4_dev_desc; + +struct ext_filesystem *get_fs(void) +{ +	if (ext4_dev_desc == NULL || ext4_dev_desc->priv == NULL) +		printf("Invalid Input Arguments %s\n", __func__); + +	return ext4_dev_desc->priv; +} + +int init_fs(block_dev_desc_t *dev_desc) +{ +	struct ext_filesystem *fs; +	if (dev_desc == NULL) { +		printf("Invalid Input Arguments %s\n", __func__); +		return -EINVAL; +	} + +	fs = zalloc(sizeof(struct ext_filesystem)); +	if (fs == NULL) { +		printf("malloc failed: %s\n", __func__); +		return -ENOMEM; +	} + +	fs->dev_desc = dev_desc; +	dev_desc->priv = fs; + +	return 0; +} + +void deinit_fs(block_dev_desc_t *dev_desc) +{ +	if (dev_desc == NULL) { +		printf("Invalid Input Arguments %s\n", __func__); +		return; +	} +	free(dev_desc->priv); +	dev_desc->priv = NULL; +} + +void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot) +{ +	if ((node != &ext4fs_root->diropen) && (node != currroot)) +		free(node); +} + +/* + * Taken from openmoko-kernel mailing list: By Andy green + * Optimized read file API : collects and defers contiguous sector + * reads into one potentially more efficient larger sequential read action + */ +int ext4fs_read_file(struct ext2fs_node *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); +	int previous_block_number = -1; +	int delayed_start = 0; +	int delayed_extent = 0; +	int delayed_skipfirst = 0; +	int delayed_next = 0; +	char *delayed_buf = NULL; +	short status; + +	/* 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 = read_allocated_block(&(node->inode), 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 (blknr) { +			int status; + +			if (previous_block_number != -1) { +				if (delayed_next == blknr) { +					delayed_extent += blockend; +					delayed_next += blockend >> SECTOR_BITS; +				} else {	/* spill */ +					status = ext4fs_devread(delayed_start, +							delayed_skipfirst, +							delayed_extent, +							delayed_buf); +					if (status == 0) +						return -1; +					previous_block_number = blknr; +					delayed_start = blknr; +					delayed_extent = blockend; +					delayed_skipfirst = skipfirst; +					delayed_buf = buf; +					delayed_next = blknr + +						(blockend >> SECTOR_BITS); +				} +			} else { +				previous_block_number = blknr; +				delayed_start = blknr; +				delayed_extent = blockend; +				delayed_skipfirst = skipfirst; +				delayed_buf = buf; +				delayed_next = blknr + +					(blockend >> SECTOR_BITS); +			} +		} else { +			if (previous_block_number != -1) { +				/* spill */ +				status = ext4fs_devread(delayed_start, +							delayed_skipfirst, +							delayed_extent, +							delayed_buf); +				if (status == 0) +					return -1; +				previous_block_number = -1; +			} +			memset(buf, 0, blocksize - skipfirst); +		} +		buf += blocksize - skipfirst; +	} +	if (previous_block_number != -1) { +		/* spill */ +		status = ext4fs_devread(delayed_start, +					delayed_skipfirst, delayed_extent, +					delayed_buf); +		if (status == 0) +			return -1; +		previous_block_number = -1; +	} + +	return len; +} + +int ext4fs_ls(const char *dirname) +{ +	struct ext2fs_node *dirnode; +	int status; + +	if (dirname == NULL) +		return 0; + +	status = ext4fs_find_file(dirname, &ext4fs_root->diropen, &dirnode, +				  FILETYPE_DIRECTORY); +	if (status != 1) { +		printf("** Can not find directory. **\n"); +		return 1; +	} + +	ext4fs_iterate_dir(dirnode, NULL, NULL, NULL); +	ext4fs_free_node(dirnode, &ext4fs_root->diropen); + +	return 0; +} + +int ext4fs_read(char *buf, unsigned len) +{ +	if (ext4fs_root == NULL || ext4fs_file == NULL) +		return 0; + +	return ext4fs_read_file(ext4fs_file, 0, len, buf); +} diff --git a/include/ext2fs.h b/include/ext2fs.h deleted file mode 100644 index 163a9bbc0..000000000 --- a/include/ext2fs.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - *  GRUB  --  GRand Unified Bootloader - *  Copyright (C) 2000, 2001  Free Software Foundation, Inc. - * - *  (C) Copyright 2003 Sysgo Real-Time Solutions, AG <www.elinos.com> - *  Pavel Bartusek <pba@sysgo.de> - * - *  This program is free software; you can redistribute it and/or modify - *  it under the terms of the GNU General Public License as published by - *  the Free Software Foundation; either version 2 of the License, or - *  (at your option) any later version. - * - *  This program is distributed in the hope that it will be useful, - *  but WITHOUT ANY WARRANTY; without even the implied warranty of - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - *  GNU General Public License for more details. - * - *  You should have received a copy of the GNU General Public License - *  along with this program; if not, write to the Free Software - *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* An implementation for the Ext2FS filesystem ported from GRUB. - * Some parts of this code (mainly the structures and defines) are - * from the original ext2 fs code, as found in the linux kernel. - */ - - -#define SECTOR_SIZE		0x200 -#define SECTOR_BITS		9 - -/* Error codes */ -typedef enum -{ -  ERR_NONE = 0, -  ERR_BAD_FILENAME, -  ERR_BAD_FILETYPE, -  ERR_BAD_GZIP_DATA, -  ERR_BAD_GZIP_HEADER, -  ERR_BAD_PART_TABLE, -  ERR_BAD_VERSION, -  ERR_BELOW_1MB, -  ERR_BOOT_COMMAND, -  ERR_BOOT_FAILURE, -  ERR_BOOT_FEATURES, -  ERR_DEV_FORMAT, -  ERR_DEV_VALUES, -  ERR_EXEC_FORMAT, -  ERR_FILELENGTH, -  ERR_FILE_NOT_FOUND, -  ERR_FSYS_CORRUPT, -  ERR_FSYS_MOUNT, -  ERR_GEOM, -  ERR_NEED_LX_KERNEL, -  ERR_NEED_MB_KERNEL, -  ERR_NO_DISK, -  ERR_NO_PART, -  ERR_NUMBER_PARSING, -  ERR_OUTSIDE_PART, -  ERR_READ, -  ERR_SYMLINK_LOOP, -  ERR_UNRECOGNIZED, -  ERR_WONT_FIT, -  ERR_WRITE, -  ERR_BAD_ARGUMENT, -  ERR_UNALIGNED, -  ERR_PRIVILEGED, -  ERR_DEV_NEED_INIT, -  ERR_NO_DISK_SPACE, -  ERR_NUMBER_OVERFLOW, - -  MAX_ERR_NUM -} ext2fs_error_t; - - -extern int ext2fs_set_blk_dev(block_dev_desc_t *rbdd, int part); -extern int ext2fs_ls (const char *dirname); -extern int ext2fs_open (const char *filename); -extern int ext2fs_read (char *buf, unsigned len); -extern int ext2fs_mount (unsigned part_length); -extern int ext2fs_close(void); diff --git a/include/ext4fs.h b/include/ext4fs.h new file mode 100644 index 000000000..58a6a1dcf --- /dev/null +++ b/include/ext4fs.h @@ -0,0 +1,132 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> + * + * Ext4 Extent data structures are taken from  original ext4 fs code + * as found in the linux kernel. + * + * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com + * Written by Alex Tomas <alex@clusterfs.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + */ + +#ifndef __EXT4__ +#define __EXT4__ +#include <ext_common.h> + +#define EXT4_EXTENTS_FL		0x00080000 /* Inode uses extents */ +#define EXT4_EXT_MAGIC			0xf30a +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM	0x0010 +#define EXT4_FEATURE_INCOMPAT_EXTENTS	0x0040 +#define EXT4_INDIRECT_BLOCKS		12 + +#define EXT4_BG_INODE_UNINIT		0x0001 +#define EXT4_BG_BLOCK_UNINIT		0x0002 +#define EXT4_BG_INODE_ZEROED		0x0004 + +/* + * ext4_inode has i_block array (60 bytes total). + * The first 12 bytes store ext4_extent_header; + * the remainder stores an array of ext4_extent. + */ + +/* + * This is the extent on-disk structure. + * It's used at the bottom of the tree. + */ +struct ext4_extent { +	__le32	ee_block;	/* first logical block extent covers */ +	__le16	ee_len;		/* number of blocks covered by extent */ +	__le16	ee_start_hi;	/* high 16 bits of physical block */ +	__le32	ee_start_lo;	/* low 32 bits of physical block */ +}; + +/* + * This is index on-disk structure. + * It's used at all the levels except the bottom. + */ +struct ext4_extent_idx { +	__le32	ei_block;	/* index covers logical blocks from 'block' */ +	__le32	ei_leaf_lo;	/* pointer to the physical block of the next * +				 * level. leaf or next index could be there */ +	__le16	ei_leaf_hi;	/* high 16 bits of physical block */ +	__u16	ei_unused; +}; + +/* Each block (leaves and indexes), even inode-stored has header. */ +struct ext4_extent_header { +	__le16	eh_magic;	/* probably will support different formats */ +	__le16	eh_entries;	/* number of valid entries */ +	__le16	eh_max;		/* capacity of store in entries */ +	__le16	eh_depth;	/* has tree real underlying blocks? */ +	__le32	eh_generation;	/* generation of the tree */ +}; + +struct ext_filesystem { +	/* Total Sector of partition */ +	uint64_t total_sect; +	/* Block size  of partition */ +	uint32_t blksz; +	/* Inode size of partition */ +	uint32_t inodesz; +	/* Sectors per Block */ +	uint32_t sect_perblk; +	/* Group Descriptor Block Number */ +	uint32_t gdtable_blkno; +	/* Total block groups of partition */ +	uint32_t no_blkgrp; +	/* No of blocks required for bgdtable */ +	uint32_t no_blk_pergdt; +	/* Superblock */ +	struct ext2_sblock *sb; +	/* Block group descritpor table */ +	struct ext2_block_group *gd; +	char *gdtable; + +	/* Block Bitmap Related */ +	unsigned char **blk_bmaps; +	long int curr_blkno; +	uint16_t first_pass_bbmap; + +	/* Inode Bitmap Related */ +	unsigned char **inode_bmaps; +	int curr_inode_no; +	uint16_t first_pass_ibmap; + +	/* Journal Related */ + +	/* Block Device Descriptor */ +	block_dev_desc_t *dev_desc; +}; + +extern block_dev_desc_t *ext4_dev_desc; +extern struct ext2_data *ext4fs_root; +extern struct ext2fs_node *ext4fs_file; + +struct ext_filesystem *get_fs(void); +int init_fs(block_dev_desc_t *dev_desc); +void deinit_fs(block_dev_desc_t *dev_desc); +int ext4fs_open(const char *filename); +int ext4fs_read(char *buf, unsigned len); +int ext4fs_mount(unsigned part_length); +void ext4fs_close(void); +int ext4fs_ls(const char *dirname); +void ext4fs_free_node(struct ext2fs_node *node, struct ext2fs_node *currroot); +int ext4fs_devread(int sector, int byte_offset, int byte_len, char *buf); +int ext4fs_set_blk_dev(block_dev_desc_t *rbdd, int part); +long int read_allocated_block(struct ext2_inode *inode, int fileblock); +#endif diff --git a/include/ext_common.h b/include/ext_common.h new file mode 100644 index 000000000..c90d95b00 --- /dev/null +++ b/include/ext_common.h @@ -0,0 +1,197 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> + * + * Data structures and headers for ext4 support have been taken from + * ext2 ls load support in Uboot + * + * (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. + */ + +#ifndef __EXT_COMMON__ +#define __EXT_COMMON__ +#include <command.h> +#define SECTOR_SIZE		0x200 +#define SECTOR_BITS		9 + +/* 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 +#define EXT2_ROOT_INO			2 /* Root inode */ + +/* Bits used as offset in sector */ +#define DISK_SECTOR_BITS		9 +/* The size of an ext2 block in bytes.  */ +#define EXT2_BLOCK_SIZE(data)	   (1 << LOG2_BLOCK_SIZE(data)) + +/* 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) +#define INODE_SIZE_FILESYSTEM(data)	(__le32_to_cpu \ +			(data->sblock.inode_size)) + +#define EXT2_FT_DIR	2 +#define SUCCESS	1 + +/* Macro-instructions used to manage several block sizes  */ +#define EXT2_MIN_BLOCK_LOG_SIZE	10 /* 1024 */ +#define EXT2_MAX_BLOCK_LOG_SIZE	16 /* 65536 */ +#define EXT2_MIN_BLOCK_SIZE		(1 << EXT2_MIN_BLOCK_LOG_SIZE) +#define EXT2_MAX_BLOCK_SIZE		(1 << EXT2_MAX_BLOCK_LOG_SIZE) + +/* 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; +}; + +struct ext2_block_group { +	__u32 block_id;	/* Blocks bitmap block */ +	__u32 inode_id;	/* Inodes bitmap block */ +	__u32 inode_table_id;	/* Inodes table block */ +	__u16 free_blocks;	/* Free blocks count */ +	__u16 free_inodes;	/* Free inodes count */ +	__u16 used_dir_cnt;	/* Directories count */ +	__u16 bg_flags; +	__u32 bg_reserved[2]; +	__u16 bg_itable_unused; /* Unused inodes count */ +	__u16 bg_checksum;	/* crc16(s_uuid+grouo_num+group_desc)*/ +}; + +/* 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 triple_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; +}; + +int do_ext2ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); +int do_ext2load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); +int do_ext4_load(cmd_tbl_t *cmdtp, int flag, int argc, +					char *const argv[]); +int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]); +int do_ext_load(cmd_tbl_t *cmdtp, int flag, int argc, +					char *const argv[]); +int do_ext_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]); +#endif |