Index: bin/Ltibutils.pm =================================================================== --- bin/Ltibutils.pm (revision 8401) +++ bin/Ltibutils.pm (working copy) @@ -66,7 +66,7 @@ $proxy_tested $pp_list_tested $app_checks $verbose $hl $cf); @ISA = qw(Exporter); address@hidden = qw( parse_dotconfig gm_yyyymmdd parse_config address@hidden = qw( parse_dotconfig gm_yyyymmdd yyyymmdd parse_config parse_spec get_file touch g2larch get_ver cmp_ver mk_uboot_kernel mk_fs_image cmd_w_to system_nb caller_stack test_remote_file @@ -109,6 +109,13 @@ return sprintf("%04d%02d%02d", $year+1900, $month+1, $day); } +# Same as gm_yyyymmdd, but return date in localtime, not GMT. +sub yyyymmdd +{ + my($day, $month, $year) = (localtime)[3,4,5]; + return sprintf("%04d%02d%02d", $year+1900, $month+1, $day); +} + sub parse_config { my $args = { fn => '', @@ -264,6 +271,12 @@ my @ldirs = grep { ! m,^\s*$, && ! m,\s*#, } split(/\s+/, $cf->{ldirs}); my @sdirs = ($cf->{lpp}, @ldirs, "$cf->{top}/pkgs"); foreach my $dir ( @sdirs ) { + # if $dir is relative, then prefix it with "$cf->{top}/" + # to make it absolute - this allows %ldirs entries to be relative + # to LTIB base directory. + if ($dir !~ m/^\//) { + $dir = "$cf->{top}/$dir"; + } $path = "$dir/$file"; if(-f $path) { return $path if ! $force_md5 || $cf->{dry}; @@ -661,6 +674,7 @@ my $x = $verbose ? '-x' : ''; my $v = $verbose ? '-v' : ''; my $cmd; + my $cur_date = yyyymmdd(); system_nb(<{DEPLOYMENT_YAFFS}" = "y" ] +then + rm -f $tdir/rootfs.yaffs2 +fi if [ "$pcf->{DEPLOYMENT_CRAMFS}" = "y" ] then rm -f $tdir/cramfs.* @@ -869,6 +887,11 @@ mkfs.jffs2 -n $pad_opt -D $dev_tab -U $endian -e $pcf->{DEPLOYMENT_ERASE_BLOCK_SIZE} -d $stage -o $tdir/rootfs.jffs2 ln -sf $tdir/rootfs.jffs2 $tdir/rootfs_image fi +if [ "$pcf->{DEPLOYMENT_YAFFS2}" = "y" ] +then + mkfs.yaffs2 -r -p $stage/etc/passwd -N -D $dev_tab $endian $stage $tdir/rootfs.yaffs2 + ln -sf $tdir/rootfs.yaffs2 $tdir/rootfs_image +fi if [ "$pcf->{DEPLOYMENT_CRAMFS}" = "y" ] then mkfs.cramfs -q -D $dev_tab $endian $stage $tdir/rootfs.cramfs @@ -927,6 +950,20 @@ ln -sf $tdir/initramfs.cpio.gz.uboot $tdir/rootfs_image fi fi +if [ "$pcf->{DEPLOYMENT_ELF}" = "y" ] +then + elf_image="linux-demo-$pcf->{PLATFORM_ELF}-$cur_date.elf" + if [ "$pcf->{DEPLOY_RAMDISK_AND_ELF}" = "y" ] + then + echo "creating elf file that contains u-boot, kernel, ramdisk" + make -C \$PLATFORM_PATH/elf-image elf-with-rootfs UBOOT=$cf->{top}/rootfs/boot/u-boot.bin KERNEL=$cf->{top}/rootfs/boot/uImage ROOTFS=$cf->{top}/rootfs.ext2.gz.uboot IMAGE=$cf->{top}/\$elf_image + else + echo "creating elf file that contains u-boot, kernel, rootfs assumed elsewhere" + make -C \$PLATFORM_PATH/elf-image elf-without-rootfs UBOOT=$cf->{top}/rootfs/boot/u-boot.bin KERNEL=$cf->{top}/rootfs/boot/uImage IMAGE=$cf->{top}/\$elf_image + fi + ln -sf \$elf_image image.elf +fi + if [ "$pcf->{DEPLOYMENT_ROOTFS_KEEPSTAGE}" = "y" ] then echo "Saving temporary staging directory: $stage" Index: config/userspace/deployment.lkc =================================================================== --- config/userspace/deployment.lkc (revision 8401) +++ config/userspace/deployment.lkc (working copy) @@ -5,36 +5,62 @@ comment 'Choose your root filesystem image type' choice prompt "Target image:" - default DEPLOYMENT_NFS + default DEPLOY_NFS help By default just the NFS staging area (rootfs) will be left. This area is always available - config DEPLOYMENT_JFFS2 + config DEPLOY_JFFS2 bool "jffs2" help build a jffs2 flash filesystem image - config DEPLOYMENT_RAMDISK + config DEPLOY_JFFS2_AND_ELF + bool "jffs2 and ELF image" + depends CAP_DEPLOYMENT_ELF + help + build a jffs2 flash filesystem image, as well as an elf image + that contains u-boot and the kernel + + config DEPLOY_YAFFS2 + bool "yaffs2" + help + build a yaffs2 flash filesystem image + + config DEPLOY_YAFFS2_AND_ELF + bool "yaffs2 and ELF image" + depends CAP_DEPLOYMENT_ELF + help + build a yaffs2 flash filesystem image, as well as an elf image + that contains u-boot and the kernel + + config DEPLOY_RAMDISK bool "ext2.gz ramdisk" help build a compress ext2 filesystem that can be used as a ramdisk - config DEPLOYMENT_CRAMFS + config DEPLOY_RAMDISK_AND_ELF + bool "ext2.gz ramdisk and ELF image" + depends CAP_DEPLOYMENT_ELF + help + build a compress ext2 filesystem that can be used as a ramdisk, + as well as an elf image that contains u-boot and the kernel + + config DEPLOY_CRAMFS bool "cramfs" select SYSCFG_READONLY_FS help This is a read-only compressed root filesystem, see: http://sourceforge.net/projects/cramfs/ - config DEPLOYMENT_INITRAMFS + config DEPLOY_INITRAMFS bool "initramfs" help Build a compressed cpio archive that can be used with initramfs. This can be attached to the kernel or used in place of an initrd image. - config DEPLOYMENT_ROMFS + config DEPLOY_ROMFS depends CAP_DEPLOYMENT_ROMFS select SYSCFG_READONLY_FS bool "romfs (uClinux)" @@ -42,16 +68,49 @@ This option creates a rom filesystem that is appended to the kernel. This type of system is common in the uClinux environment - config DEPLOYMENT_NFS + config DEPLOY_NFS bool "NFS only" help By default just the NFS staging area (rootfs) will be left. This area is always available endchoice +config DEPLOYMENT_JFFS2 + bool + default y if DEPLOY_JFFS2 || DEPLOY_JFFS2_AND_ELF + +config DEPLOYMENT_YAFFS2 + bool + default y if DEPLOY_YAFFS2 || DEPLOY_YAFFS2_AND_ELF + +config DEPLOYMENT_RAMDISK + bool + default y if DEPLOY_RAMDISK || DEPLOY_RAMDISK_AND_ELF + +config DEPLOYMENT_CRAMFS + bool + default y if DEPLOY_CRAMFS + +config DEPLOYMENT_INITRAMFS + bool + default y if DEPLOY_INITRAMFS + +config DEPLOYMENT_ROMFS + bool + default y if DEPLOY_ROMFS + +config DEPLOYMENT_NFS + bool + default y if DEPLOY_NFS + +config DEPLOYMENT_ELF + bool + default y if DEPLOY_JFFS2_AND_ELF || DEPLOY_YAFFS2_AND_ELF || DEPLOY_RAMDISK_AND_ELF + config SYSCFG_DEPLOYMENT_STYLE string default JFFS2 if DEPLOYMENT_JFFS2 + default YAFFS2 if DEPLOYMENT_YAFFS2 default RAMDISK if DEPLOYMENT_RAMDISK default CRAMFS if DEPLOYMENT_CRAMFS default ROMFS if DEPLOYMENT_ROMFS @@ -60,15 +119,16 @@ source ../../userspace/post_build_script.lkc -if DEPLOYMENT_JFFS2 +if DEPLOYMENT_JFFS2 || DEPLOYMENT_YAFFS2 config DEPLOYMENT_ERASE_BLOCK_SIZE - string "jffs2 erase block size in KB" + string "jffs2/yaffs2 erase block size in KB" default ERASE_BLOCK_SIZE help This sets the erase block size. This should be in kilo bytes. config DEPLOYMENT_JFFS2_PAD + depends DEPLOYMENT_JFFS2 bool "Pad out image size" help This allows you to control the total size of the jffs2 image @@ -113,7 +173,7 @@ default n config SYSCFG_TMPFS_SIZE - depends SYSCFG_READONLY_FS || DEPLOYMENT_JFFS2 + depends SYSCFG_READONLY_FS || DEPLOYMENT_JFFS2 || DEPLOYMENT_YAFFS2 string "tmpfs size" default "512k" help @@ -124,10 +184,10 @@ from the total available RAM to the system. config SYSCFG_RAM_DIRS - depends SYSCFG_READONLY_FS || DEPLOYMENT_JFFS2 + depends SYSCFG_READONLY_FS || DEPLOYMENT_JFFS2 || DEPLOYMENT_YAFFS2 string "Place these dirs in writable RAM" default "/tmp /etc /var" if SYSCFG_READONLY_FS - default "/tmp /var" if DEPLOYMENT_JFFS2 + default "/tmp /var" if DEPLOYMENT_JFFS2 || DEPLOYMENT_YAFFS2 help Flash may only be erased a finite number of times (of the order of 100000 times for a NOR device). If you deploy to Flash, @@ -256,7 +316,7 @@ .ko are stripped like this. config DEPLOYMENT_PADDING_KB - depends ! DEPLOYMENT_NFS && ! DEPLOYMENT_JFFS2 + depends ! DEPLOYMENT_NFS && ! DEPLOYMENT_JFFS2 && ! DEPLOYMENT_YAFFS2 default "0" string "Allocate extra space (Kbytes)" help Index: dist/lfs-5.1/yaffs-utils/yaffs-utils.spec =================================================================== --- dist/lfs-5.1/yaffs-utils/yaffs-utils.spec (revision 8401) +++ dist/lfs-5.1/yaffs-utils/yaffs-utils.spec (working copy) @@ -12,6 +12,7 @@ Patch0 : yaffs_mxc.patch Patch1 : yaffs_utils-20060418-mtd-include.patch Patch2 : yaffs_utils-20060418-include-order.patch +Patch3 : yaffs_utils-20060418-mkyaffs2image.patch BuildRoot : %{_tmppath}/%{name} Prefix : %{pfx} @@ -26,14 +27,15 @@ %patch0 -p1 %patch1 -p1 %patch2 -p1 +%patch3 -p1 %Build -make KERNELDIR=$DEV_IMAGE/usr/src/linux -C yaffs/utils +make KERNELDIR=$DEV_IMAGE/usr/src/linux -C yaffs2/utils %Install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/%{pfx}/%{_prefix}/bin -make -C yaffs/utils install DESTDIR=$RPM_BUILD_ROOT/%{pfx} SBINDIR=%{_prefix}/bin +make -C yaffs2/utils install DESTDIR=$RPM_BUILD_ROOT/%{pfx} SBINDIR=%{_prefix}/bin %Clean rm -rf $RPM_BUILD_ROOT diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/devextras.h yaffs_utils-20060418.modified/yaffs2/devextras.h --- yaffs_utils-20060418/yaffs2/devextras.h 2006-04-24 07:39:43.000000000 -0400 +++ yaffs_utils-20060418.modified/yaffs2/devextras.h 2009-11-03 12:18:09.000000000 -0500 @@ -200,6 +200,8 @@ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) +#ifdef CONFIG_YAFFS_PROVIDE_DEFS + /* * File types */ @@ -245,7 +247,7 @@ unsigned int ia_attr_flags; }; -#define KERN_DEBUG +#endif #else diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/devextras.h~ yaffs_utils-20060418.modified/yaffs2/devextras.h~ --- yaffs_utils-20060418/yaffs2/devextras.h~ 1969-12-31 19:00:00.000000000 -0500 +++ yaffs_utils-20060418.modified/yaffs2/devextras.h~ 2006-04-24 07:39:43.000000000 -0400 @@ -0,0 +1,265 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * devextras.h + * + * Copyright (C) 2002 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + * + * This file is just holds extra declarations used during development. + * Most of these are from kernel includes placed here so we can use them in + * applications. + * + * $Id: devextras.h,v 1.2 2005/08/11 02:37:49 marty Exp $ + * + */ + +#ifndef __EXTRAS_H__ +#define __EXTRAS_H__ + +#if defined WIN32 +#define __inline__ __inline +#define new newHack +#endif + +#if !(defined __KERNEL__) || (defined WIN32) + +/* User space defines */ + +typedef unsigned char __u8; +typedef unsigned short __u16; +typedef unsigned __u32; + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#define prefetch(x) 1 + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static __inline__ void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static __inline__ void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static __inline__ void list_add_tail(struct list_head *new, + struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static __inline__ void __list_del(struct list_head *prev, + struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static __inline__ void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static __inline__ void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static __inline__ int list_empty(struct list_head *head) +{ + return head->next == head; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static __inline__ void list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + + if (first != list) { + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * list_for_each_safe - iterate over a list safe against removal + * of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/* + * File types + */ +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + +#ifndef WIN32 +#include +#endif + +/* + * Attribute flags. These should be or-ed together to figure out what + * has been changed! + */ +#define ATTR_MODE 1 +#define ATTR_UID 2 +#define ATTR_GID 4 +#define ATTR_SIZE 8 +#define ATTR_ATIME 16 +#define ATTR_MTIME 32 +#define ATTR_CTIME 64 +#define ATTR_ATIME_SET 128 +#define ATTR_MTIME_SET 256 +#define ATTR_FORCE 512 /* Not a change, but a change it */ +#define ATTR_ATTR_FLAG 1024 + +struct iattr { + unsigned int ia_valid; + unsigned ia_mode; + unsigned ia_uid; + unsigned ia_gid; + unsigned ia_size; + unsigned ia_atime; + unsigned ia_mtime; + unsigned ia_ctime; + unsigned int ia_attr_flags; +}; + +#define KERN_DEBUG + +#else + +#ifndef WIN32 +#include +#include +#include +#include +#endif + +#endif + +#if defined WIN32 +#undef new +#endif + +#endif diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/Makefile yaffs_utils-20060418.modified/yaffs2/utils/Makefile --- yaffs_utils-20060418/yaffs2/utils/Makefile 2006-04-24 07:38:44.000000000 -0400 +++ yaffs_utils-20060418.modified/yaffs2/utils/Makefile 2009-11-03 12:08:45.000000000 -0500 @@ -16,7 +16,8 @@ #KERNELDIR = /usr/src/kernel-headers-2.4.18 -CFLAGS = -I/usr/include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL +INCDIR=-I$(KHDR_DIR) +CFLAGS = -O2 -Wall -DCONFIG_YAFFS_UTIL -I.. $(INCDIR) CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline @@ -31,11 +32,12 @@ MKYAFFSSOURCES = mkyaffsimage.c MKYAFFSIMAGEOBJS = $(MKYAFFSSOURCES:.c=.o) -MKYAFFS2SOURCES = mkyaffs2image.c +MKYAFFS2SOURCES = mkyaffs2image.c dev_table.c MKYAFFS2LINKS = yaffs_packedtags2.c yaffs_tagsvalidity.c MKYAFFS2IMAGEOBJS = $(MKYAFFS2SOURCES:.c=.o) $(MKYAFFS2LINKS:.c=.o) -all: mkyaffsimage mkyaffs2image +TARGETS=mkyaffsimage mkyaffs2image +all: $(TARGETS) $(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS): ln -s ../$@ $@ @@ -49,6 +51,9 @@ mkyaffs2image: $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS) $(CC) -o $@ $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS) +install: + mkdir -p ${DESDIR}/${SBINDIR} + install $(TARGETS) ${DESTDIR}/${SBINDIR}/ clean: - rm -f $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) $(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS) mkyaffsimage mkyaffs2image core + rm -f $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) $(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS) $(TARGETS) core diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/Makefile~ yaffs_utils-20060418.modified/yaffs2/utils/Makefile~ --- yaffs_utils-20060418/yaffs2/utils/Makefile~ 1969-12-31 19:00:00.000000000 -0500 +++ yaffs_utils-20060418.modified/yaffs2/utils/Makefile~ 2006-04-24 07:38:44.000000000 -0400 @@ -0,0 +1,54 @@ +#Makefile for mkyaffs +# +# NB this is not yet suitable for putting into the kernel tree. +# YAFFS: Yet another FFS. A NAND-flash specific file system. +# +# Copyright (C) 2002 Aleph One Ltd. +# for Toby Churchill Ltd and Brightstar Engineering +# +# Created by Charles Manning +# +# 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. + +## Change or override KERNELDIR to your kernel + +#KERNELDIR = /usr/src/kernel-headers-2.4.18 + +CFLAGS = -I/usr/include -I.. -O2 -Wall -DCONFIG_YAFFS_UTIL +CFLAGS+= -Wshadow -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations +CFLAGS+= -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Winline + +## Change if you are using a cross-compiler +MAKETOOLS = + +CC=$(MAKETOOLS)gcc + +COMMONLINKS = yaffs_ecc.c +COMMONOBJS = $(COMMONLINKS:.c=.o) + +MKYAFFSSOURCES = mkyaffsimage.c +MKYAFFSIMAGEOBJS = $(MKYAFFSSOURCES:.c=.o) + +MKYAFFS2SOURCES = mkyaffs2image.c +MKYAFFS2LINKS = yaffs_packedtags2.c yaffs_tagsvalidity.c +MKYAFFS2IMAGEOBJS = $(MKYAFFS2SOURCES:.c=.o) $(MKYAFFS2LINKS:.c=.o) + +all: mkyaffsimage mkyaffs2image + +$(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS): + ln -s ../$@ $@ + +$(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) : %.o: %.c + $(CC) -c $(CFLAGS) $< -o $@ + +mkyaffsimage: $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) + $(CC) -o $@ $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) + +mkyaffs2image: $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS) + $(CC) -o $@ $(COMMONOBJS) $(MKYAFFS2IMAGEOBJS) + + +clean: + rm -f $(COMMONOBJS) $(MKYAFFSIMAGEOBJS) $(MKYAFFS2IMAGEOBJS) $(COMMONLINKS) $(MKYAFFSLINKS) $(MKYAFFS2LINKS) mkyaffsimage mkyaffs2image core diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/dev_table.c yaffs_utils-20060418.modified/yaffs2/utils/dev_table.c --- yaffs_utils-20060418/yaffs2/utils/dev_table.c 1969-12-31 19:00:00.000000000 -0500 +++ yaffs_utils-20060418.modified/yaffs2/utils/dev_table.c 2009-11-03 12:22:12.000000000 -0500 @@ -0,0 +1,456 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev_table.h" + +extern int progress; +static const char *const app_name = "mkfs.yaffs"; + +static void verror_msg(const char *s, va_list p) +{ + fflush(stdout); + fprintf(stderr, "%s: ", app_name); + vfprintf(stderr, s, p); +} + +static void error_msg_and_die(const char *s, ...) +{ + va_list p; + + va_start(p, s); + verror_msg(s, p); + va_end(p); + putc('\n', stderr); + exit(EXIT_FAILURE); +} + +struct deventry { + char *name; // name of entry + char full_name[511]; // full name of entry + int dumped; // !0 if entry dumped + int ino; // increments from 0 + unsigned long uid; + unsigned long gid; + unsigned long mode; + dev_t rdev; + int parentId; + struct deventry *child; // children + struct deventry *next; // next at this level + struct deventry *parent_next; // next at parent level + int skip; // !0 if entry is to be skipped +}; + +struct deventry *root; + +struct path_component { + char *next_component; // ptr to where next component starts(if one) +} pc; + +// Finds first or next path comoponent of a string +static char *find_next_component(char *path, char **next) +{ + char *r; + + // Skip leading '/' + while(*path && *path == '/') + path++; + + // Search for next separator + r = path; + if (*r) { + while (*r && *r != '/') + r++; + *next = r; + if (*r) { + *r = 0; + } else + *next = NULL; + } else + *next = NULL; + + return path; +} + + +static int dev_table_ino = 0; + +static void add_dev_entry(const char *name, unsigned long uid, unsigned long gid, unsigned long mode, dev_t rdev) +{ + struct deventry *e; + struct deventry *p, **q; + char nbuf[128]; + char *next, *path; + + e = malloc(sizeof(*p)); + if (!e) + error_msg_and_die("No memory for dirent"); + + memset(e, 0, sizeof(*e)); + // e->name = strdup(name); + e->uid = uid; + e->gid = gid; + e->mode = mode; + e->rdev = rdev; + e->ino = ++dev_table_ino; + strcpy(e->full_name, name); + + strcpy(nbuf, name); + + // Find first component, return in s, set t to following + path = find_next_component(nbuf, &next); + + p = *(q = &root); + while (p) { + if (!strcmp (p->name, path)) { + p = *(q=&p->child); // Move to child + if (next) + path = find_next_component(next+1, &next); + else + break; + } else + p = *(q = &p->next); + } + e->name = strdup(path); + *q = e; +} + +static struct deventry *find_dev_dir(const char *name) +{ + struct deventry *p, **q; + char nbuf[128]; + char *next, *path; + + strcpy(nbuf, name); + + // Find first component, return in s, set t to following + path = find_next_component(nbuf, &next); + + p = *(q = &root); + while (p) { + if (!strcmp (p->name, path)) { + if (!next) + return p; + p = *(q=&p->child); // Move to child + path = find_next_component(next+1, &next); + } else + p = *(q = &p->next); + } + return NULL; +} + +extern char *in_file; +static struct deventry *find_dev_table_entry(const char *path) +{ + struct deventry *p; + char *q = in_file; + + while (*q && *q == *path) { + q++, path++; + } + + if (*path == '/') + path++; + + if (*path) { + p = find_dev_dir(path); + return p; + } + return 0; +} + +DIR *my_opendir(const char *path) +{ + struct deventry *p; + if ((p = find_dev_table_entry(path))) { + p->dumped = 1; + } + return opendir(path); +} + +struct dirent *my_readdir(DIR *dir) +{ + return readdir(dir); +} + +int lstat_dev_table(char *path, struct stat *stat) +{ + struct deventry *p; + + p = find_dev_table_entry(path); + if (!p || p->dumped) + return 0; + + p->dumped = 1; + + memset(stat, 0, sizeof(*stat)); + stat->st_dev = 0; + stat->st_ino = p->ino; + stat->st_mode = p->mode; + stat->st_rdev = p->rdev; + + return 1; +} + +void dev_table_set_parent(char *path, int parentId) +{ + struct deventry *p; + + if ((p = find_dev_table_entry(path))) { + if (progress) + printf("%s: path %s parentId %d\n", __FUNCTION__, path, parentId); + p->parentId = parentId; + p->skip = 1; // as we already have the object, no need to create it again + } +} + +void +add_dev_table_entries(void) +{ + struct deventry *p; + struct dirent d; + char name[128]; + p = root; + while (p) { + if (!p->dumped && !p->skip) { + strcpy(d.d_name, p->name); + sprintf(name, "%s%s", in_file, p->full_name); + process_entry(&d, p->parentId, name); + } + if (p->child) { + p = p->child; + } else if (p->next) + p = p->next; + else { + p = p->parent_next; + } + } +} + +static void add_host_filesystem_entry(char *name, char *hostpath, unsigned long uid, unsigned long gid, unsigned long mode, dev_t rdev) +{ + struct dirent d; + + if (progress) + printf("%s - %s 0x%lx 0x%lx 0x%lx 0x%llx\n", + name, hostpath, uid, gid, mode, rdev); + + add_dev_entry(name, uid, gid, mode, rdev); + +} + +static void recurse_post_build_dev_tree(struct deventry *p, struct deventry *q, int parentId) +{ + while (p) { + if (p->child) { + if (!p->parentId) + fprintf(stderr, "%s doesn't have a parentId\n", p->full_name); + recurse_post_build_dev_tree(p->child, p->next, p->parentId); + } else if (!p->parentId) + p->parentId = parentId; + if (p->next) + p = p->next; + else { + p->parent_next = q; + break; + } + } +} + +void post_build_dev_tree(void) +{ + recurse_post_build_dev_tree(root, NULL, 0); +} + +void dump_dev_tree(void) +{ + struct deventry *p; + + p = root; + while (p) { + printf("name %s\n", p->name); + if (p->child) { + printf("Add /\n"); + p = p->child; + } else if (p->next) + p = p->next; + else { + printf("pop\n"); + p = p->parent_next; + } + } +} + + +/* device table entries take the form of: + + /dev/mem c 640 0 0 1 1 0 0 - + + type can be one of: + f A regular file + d Directory + c Character special device file + b Block special device file + p Fifo (named pipe) + + I don't bother with symlinks (permissions are irrelevant), hard + links (special cases of regular files), or sockets (why bother). + + Regular files must exist in the target root directory. If a char, + block, fifo, or directory does not exist, it will be created. +*/ + +#ifdef __GNUC__ +#define SCANF_PREFIX "a" +#define SCANF_STRING(s) (&s) +#define GETCWD_SIZE 0 +#else +#define SCANF_PREFIX "511" +#define SCANF_STRING(s) (s = malloc(512)) +#define GETCWD_SIZE -1 +#endif + +static char default_rootdir[] = "."; +static char *rootdir = default_rootdir; + +static int interpret_table_entry(char *line) +{ + char *hostpath; + char type, *name = NULL, *tmp, *dir; + unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; + unsigned long start = 0, increment = 1, count = 0; + struct filesystem_entry *parent, *entry; + + if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu", + SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor, + &start, &increment, &count) < 0) + { + return 1; + } + + if (!strcmp(name, "/")) { + fprintf(stderr, "Device table entries require absolute paths"); + exit(-1); + } + + asprintf(&hostpath, "%s%s", rootdir, name); + + /* Check if this file already exists... */ + switch (type) { + case 'd': + mode |= S_IFDIR; + break; + case 'f': + mode |= S_IFREG; + break; + case 'p': + mode |= S_IFIFO; + break; + case 'c': + mode |= S_IFCHR; + break; + case 'b': + mode |= S_IFBLK; + break; + default: + fprintf(stderr, "Unsupported file type"); + exit(-1); + } + + switch (type) { + case 'd': + add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0); + break; + case 'f': + add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0); + break; + case 'p': + add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0); + break; + case 'c': + case 'b': + if (count > 0) { + dev_t rdev; + unsigned long i; + char *dname, *hpath; + + for (i = start; i < count; i++) { + dname = hpath = NULL; + asprintf(&dname, "%s%lu", name, i); + asprintf(&hpath, "%s/%s%lu", rootdir, name, i); + rdev = makedev(major, minor + (i * increment - start)); + add_host_filesystem_entry(dname, hpath, uid, gid, + mode, rdev); + free(dname); + free(hpath); + } + } else { + dev_t rdev = makedev(major, minor); + add_host_filesystem_entry(name, hostpath, uid, gid, + mode, rdev); + } + break; + default: + fprintf(stderr, "Unsupported file type"); + exit(-1); + } + free(name); + free(hostpath); + return 0; +} + +int parse_device_table(FILE * file) +{ + char *line; + int status = 0; + size_t length = 0; + +#if 0 + /* Turn off squash, since we must ensure that values + * entered via the device table are not squashed */ + squash_uids = 0; + squash_perms = 0; +#endif + /* Looks ok so far. The general plan now is to read in one + * line at a time, check for leading comment delimiters ('#'), + * then try and parse the line as a device table. If we fail + * to parse things, try and help the poor fool to fix their + * device table with a useful error msg... */ + line = NULL; + while (getline(&line, &length, file) != -1) { + /* First trim off any whitespace */ + int len = strlen(line); + + /* trim trailing whitespace */ + while (len > 0 && isspace(line[len - 1])) + line[--len] = '\0'; + /* trim leading whitespace */ + memmove(line, &line[strspn(line, " \n\r\t\v")], len); + + /* How long are we after trimming? */ + len = strlen(line); + + /* If this is NOT a comment line, try to interpret it */ + if (len && *line != '#') { + if (interpret_table_entry(line)) + status = 1; + } + + free(line); + line = NULL; + } + return status; +} diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/dev_table.c~ yaffs_utils-20060418.modified/yaffs2/utils/dev_table.c~ --- yaffs_utils-20060418/yaffs2/utils/dev_table.c~ 1969-12-31 19:00:00.000000000 -0500 +++ yaffs_utils-20060418.modified/yaffs2/utils/dev_table.c~ 2009-11-03 12:01:44.000000000 -0500 @@ -0,0 +1,457 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev_table.h" + +extern int progress; +static const char *const app_name = "mkfs.yaffs"; + +static void verror_msg(const char *s, va_list p) +{ + fflush(stdout); + fprintf(stderr, "%s: ", app_name); + vfprintf(stderr, s, p); +} + +static void error_msg_and_die(const char *s, ...) +{ + va_list p; + + va_start(p, s); + verror_msg(s, p); + va_end(p); + putc('\n', stderr); + exit(EXIT_FAILURE); +} + +struct deventry { + char *name; // name of entry + char full_name[511]; // full name of entry + int dumped; // !0 if entry dumped + int ino; // increments from 0 + unsigned long uid; + unsigned long gid; + unsigned long mode; + dev_t rdev; + int parentId; + struct deventry *child; // children + struct deventry *next; // next at this level + struct deventry *parent_next; // next at parent level + int skip; // !0 if entry is to be skipped +}; + +struct deventry *root; + +struct path_component { + char *next_component; // ptr to where next component starts(if one) +} pc; + +// Finds first or next path comoponent of a string +char *find_next_component(char *path, char **next) +{ + char *r; + + // Skip leading '/' + while(*path && *path == '/') + path++; + + // Search for next separator + r = path; + if (*r) { + while (*r && *r != '/') + r++; + *next = r; + if (*r) { + *r = 0; + } else + *next = NULL; + } else + *next = NULL; + + return path; +} + + +static int dev_table_ino = 0; + +void add_dev_entry(const char *name, unsigned long uid, unsigned long gid, unsigned long mode, dev_t rdev) +{ + struct deventry *e; + struct deventry *p, **q; + char nbuf[128]; + char *next, *path; + + e = malloc(sizeof(*p)); + if (!e) + error_msg_and_die("No memory for dirent"); + + memset(e, 0, sizeof(*e)); + // e->name = strdup(name); + e->uid = uid; + e->gid = gid; + e->mode = mode; + e->rdev = rdev; + e->ino = ++dev_table_ino; + strcpy(e->full_name, name); + + strcpy(nbuf, name); + + // Find first component, return in s, set t to following + path = find_next_component(nbuf, &next); + + p = *(q = &root); + while (p) { + if (!strcmp (p->name, path)) { + p = *(q=&p->child); // Move to child + if (next) + path = find_next_component(next+1, &next); + else + break; + } else + p = *(q = &p->next); + } + e->name = strdup(path); + *q = e; +} + +struct deventry *find_dev_dir(const char *name) +{ + struct deventry *p, **q; + char nbuf[128]; + char *next, *path; + + strcpy(nbuf, name); + + // Find first component, return in s, set t to following + path = find_next_component(nbuf, &next); + + p = *(q = &root); + while (p) { + if (!strcmp (p->name, path)) { + if (!next) + return p; + p = *(q=&p->child); // Move to child + path = find_next_component(next+1, &next); + } else + p = *(q = &p->next); + } + return NULL; +} + +extern char *in_file; +struct deventry *find_dev_table_entry(const char *path) +{ + struct deventry *p; + char *q = in_file; + + while (*q && *q == *path) { + q++, path++; + } + + if (*path == '/') + path++; + + if (*path) { + p = find_dev_dir(path); + return p; + } + return 0; +} + +DIR *my_opendir(const char *path) +{ + struct deventry *p; + if ((p = find_dev_table_entry(path))) { + p->dumped = 1; + } + return opendir(path); +} + +struct dirent *my_readdir(DIR *dir) +{ + return readdir(dir); +} + +int lstat_dev_table(char *path, struct stat *stat) +{ + struct deventry *p; + + p = find_dev_table_entry(path); + if (!p || p->dumped) + return 0; + + p->dumped = 1; + + memset(stat, 0, sizeof(*stat)); + stat->st_dev = 0; + stat->st_ino = p->ino; + stat->st_mode = p->mode; + stat->st_rdev = p->rdev; + + return 1; +} + +void dev_table_set_parent(char *path, int parentId) +{ + struct deventry *p; + + if ((p = find_dev_table_entry(path))) { + if (progress) + printf("%s: path %s parentId %d\n", __FUNCTION__, path, parentId); + p->parentId = parentId; + p->skip = 1; // as we already have the object, no need to create it again + } +} + +void +add_dev_table_entries(void) +{ + struct deventry *p; + struct dirent d; + char name[128]; + p = root; + while (p) { + if (!p->dumped && !p->skip) { + strcpy(d.d_name, p->name); + sprintf(name, "%s%s", in_file, p->full_name); + process_entry(&d, p->parentId, name); + } + if (p->child) { + p = p->child; + } else if (p->next) + p = p->next; + else { + p = p->parent_next; + } + } +} + +void +add_host_filesystem_entry(char *name, char *hostpath, unsigned long uid, unsigned long gid, unsigned long mode, dev_t rdev) +{ + struct dirent d; + + if (progress) + printf("%s - %s 0x%lx 0x%lx 0x%lx 0x%llx\n", + name, hostpath, uid, gid, mode, rdev); + + add_dev_entry(name, uid, gid, mode, rdev); + +} + +void recurse_post_build_dev_tree(struct deventry *p, struct deventry *q, int parentId) +{ + while (p) { + if (p->child) { + if (!p->parentId) + fprintf(stderr, "%s doesn't have a parentId\n", p->full_name); + recurse_post_build_dev_tree(p->child, p->next, p->parentId); + } else if (!p->parentId) + p->parentId = parentId; + if (p->next) + p = p->next; + else { + p->parent_next = q; + break; + } + } +} + +void post_build_dev_tree(void) +{ + recurse_post_build_dev_tree(root, NULL, 0); +} + +void dump_dev_tree(void) +{ + struct deventry *p; + + p = root; + while (p) { + printf("name %s\n", p->name); + if (p->child) { + printf("Add /\n"); + p = p->child; + } else if (p->next) + p = p->next; + else { + printf("pop\n"); + p = p->parent_next; + } + } +} + + +/* device table entries take the form of: + + /dev/mem c 640 0 0 1 1 0 0 - + + type can be one of: + f A regular file + d Directory + c Character special device file + b Block special device file + p Fifo (named pipe) + + I don't bother with symlinks (permissions are irrelevant), hard + links (special cases of regular files), or sockets (why bother). + + Regular files must exist in the target root directory. If a char, + block, fifo, or directory does not exist, it will be created. +*/ + +#ifdef __GNUC__ +#define SCANF_PREFIX "a" +#define SCANF_STRING(s) (&s) +#define GETCWD_SIZE 0 +#else +#define SCANF_PREFIX "511" +#define SCANF_STRING(s) (s = malloc(512)) +#define GETCWD_SIZE -1 +#endif + +static char default_rootdir[] = "."; +static char *rootdir = default_rootdir; + +static int interpret_table_entry(char *line) +{ + char *hostpath; + char type, *name = NULL, *tmp, *dir; + unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0; + unsigned long start = 0, increment = 1, count = 0; + struct filesystem_entry *parent, *entry; + + if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu", + SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor, + &start, &increment, &count) < 0) + { + return 1; + } + + if (!strcmp(name, "/")) { + fprintf(stderr, "Device table entries require absolute paths"); + exit(-1); + } + + asprintf(&hostpath, "%s%s", rootdir, name); + + /* Check if this file already exists... */ + switch (type) { + case 'd': + mode |= S_IFDIR; + break; + case 'f': + mode |= S_IFREG; + break; + case 'p': + mode |= S_IFIFO; + break; + case 'c': + mode |= S_IFCHR; + break; + case 'b': + mode |= S_IFBLK; + break; + default: + fprintf(stderr, "Unsupported file type"); + exit(-1); + } + + switch (type) { + case 'd': + add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0); + break; + case 'f': + add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0); + break; + case 'p': + add_host_filesystem_entry(name, hostpath, uid, gid, mode, 0); + break; + case 'c': + case 'b': + if (count > 0) { + dev_t rdev; + unsigned long i; + char *dname, *hpath; + + for (i = start; i < count; i++) { + dname = hpath = NULL; + asprintf(&dname, "%s%lu", name, i); + asprintf(&hpath, "%s/%s%lu", rootdir, name, i); + rdev = makedev(major, minor + (i * increment - start)); + add_host_filesystem_entry(dname, hpath, uid, gid, + mode, rdev); + free(dname); + free(hpath); + } + } else { + dev_t rdev = makedev(major, minor); + add_host_filesystem_entry(name, hostpath, uid, gid, + mode, rdev); + } + break; + default: + fprintf(stderr, "Unsupported file type"); + exit(-1); + } + free(name); + free(hostpath); + return 0; +} + +int parse_device_table(FILE * file) +{ + char *line; + int status = 0; + size_t length = 0; + +#if 0 + /* Turn off squash, since we must ensure that values + * entered via the device table are not squashed */ + squash_uids = 0; + squash_perms = 0; +#endif + /* Looks ok so far. The general plan now is to read in one + * line at a time, check for leading comment delimiters ('#'), + * then try and parse the line as a device table. If we fail + * to parse things, try and help the poor fool to fix their + * device table with a useful error msg... */ + line = NULL; + while (getline(&line, &length, file) != -1) { + /* First trim off any whitespace */ + int len = strlen(line); + + /* trim trailing whitespace */ + while (len > 0 && isspace(line[len - 1])) + line[--len] = '\0'; + /* trim leading whitespace */ + memmove(line, &line[strspn(line, " \n\r\t\v")], len); + + /* How long are we after trimming? */ + len = strlen(line); + + /* If this is NOT a comment line, try to interpret it */ + if (len && *line != '#') { + if (interpret_table_entry(line)) + status = 1; + } + + free(line); + line = NULL; + } + return status; +} diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/dev_table.h yaffs_utils-20060418.modified/yaffs2/utils/dev_table.h --- yaffs_utils-20060418/yaffs2/utils/dev_table.h 1969-12-31 19:00:00.000000000 -0500 +++ yaffs_utils-20060418.modified/yaffs2/utils/dev_table.h 2009-11-03 12:01:26.000000000 -0500 @@ -0,0 +1,11 @@ +#include + +extern DIR *my_opendir(const char *path); +extern struct dirent *my_readdir(DIR *dir); +extern void post_build_dev_tree(void); +extern void dump_dev_tree(void); +extern void add_dev_table_entries(void); +extern int lstat_dev_table(char *path, struct stat *stat); +extern void dev_table_set_parent(char *path, int parentId); +extern int parse_device_table(FILE * file); +extern void process_entry(struct dirent *entry, int parent, char *full_name); diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/dev_table.h~ yaffs_utils-20060418.modified/yaffs2/utils/dev_table.h~ --- yaffs_utils-20060418/yaffs2/utils/dev_table.h~ 1969-12-31 19:00:00.000000000 -0500 +++ yaffs_utils-20060418.modified/yaffs2/utils/dev_table.h~ 2009-11-03 12:01:16.000000000 -0500 @@ -0,0 +1,22 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * Nick Bane modifications flagged NCB + * Endian handling patches by James Ng. + * mkyaffs2image hacks by NCB + * + * 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. + */ + +/* + * makeyaffs2image.c + * + * Makes a YAFFS2 file system image that can be used to load up a file system. + * Uses default Linux MTD layout - change if you need something different. + */ Binary files yaffs_utils-20060418/yaffs2/utils/dev_table.o and yaffs_utils-20060418.modified/yaffs2/utils/dev_table.o differ Binary files yaffs_utils-20060418/yaffs2/utils/mkyaffs2image and yaffs_utils-20060418.modified/yaffs2/utils/mkyaffs2image differ diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/mkyaffs2image.c yaffs_utils-20060418.modified/yaffs2/utils/mkyaffs2image.c --- yaffs_utils-20060418/yaffs2/utils/mkyaffs2image.c 2006-04-24 07:39:48.000000000 -0400 +++ yaffs_utils-20060418.modified/yaffs2/utils/mkyaffs2image.c 2009-11-03 12:23:24.000000000 -0500 @@ -1,37 +1,38 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * makeyaffsimage.c - * - * Makes a YAFFS file system image that can be used to load up a file system. - * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning + * Nick Bane modifications flagged NCB + * Endian handling patches by James Ng. + * mkyaffs2image hacks by NCB * * 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. + */ + +/* + * makeyaffs2image.c * - * - * Nick Bane modifications flagged NCB - * - * Endian handling patches by James Ng. - * - * mkyaffs2image hacks by NCB - * + * Makes a YAFFS2 file system image that can be used to load up a file system. + * Uses default Linux MTD layout - change if you need something different. */ #include #include #include #include +#include #include #include #include #include +#include #include "yaffs_ecc.h" +#include "dev_table.h" #include "yaffs_guts.h" #include "yaffs_tagsvalidity.h" @@ -44,7 +45,7 @@ #define chunkSize 2048 #define spareSize 64 -const char * mkyaffsimage_c_version = "$Id: mkyaffs2image.c,v 1.2 2005/12/13 00:34:58 tpoynor Exp $"; +const char * mkyaffsimage_c_version = "$Id: mkyaffs2image.c,v 1.4 2007-02-14 01:09:06 wookey Exp $"; typedef struct @@ -67,6 +68,84 @@ static int convert_endian = 0; +static int big_endian, little_endian; +static int want_big_endian, want_little_endian; + +static int debug; // should add options to turn on... +int progress; // !0 for progress output + +struct passwd *passwd_list; +struct passwd *root_passwd; +int passwd_list_size; + +struct passwd *find_entry_by_uid(int uid) +{ + struct passwd *p; + int i; + for (p=passwd_list, i=0; ipw_uid) + return p; + } + return root_passwd; +} + +struct passwd *find_entry_by_name(const char *name) +{ + struct passwd *p; + int i; + for (p=passwd_list, i=0; ipw_name)) + return p; + } + return root_passwd; +} + +static char *dev_table_name; // name of device table +static char *pw_name; // file to pull permission information out of +int remap_ownership = 0; // !0 -> remap unknown ownership to root + +void process_pw_file(const char *fname) +{ + struct passwd *new_passwd_list, *p; + FILE *f; + struct passwd *tmp_passwd; + f = fopen(fname, "r"); + if (!f) { + fprintf(stderr, "%s: can't open %s, %s\n", __FUNCTION__, fname, strerror(errno)); + exit(1); + } + + while ((tmp_passwd = fgetpwent(f)) != NULL) { + if (passwd_list) + new_passwd_list = realloc(passwd_list, (passwd_list_size+1) * sizeof(*passwd_list)); + else + new_passwd_list = malloc(sizeof(*passwd_list)); + if(!new_passwd_list) { + fprintf(stderr, "%s: realloc/malloc failed, %s\n", __FUNCTION__, strerror(errno)); + exit(1); + } + passwd_list = new_passwd_list; + p = &passwd_list[passwd_list_size++]; + p->pw_name = strdup(tmp_passwd->pw_name); + p->pw_passwd = strdup(tmp_passwd->pw_passwd); + p->pw_uid = tmp_passwd->pw_uid; + p->pw_gid = tmp_passwd->pw_gid; + p->pw_gecos = strdup(tmp_passwd->pw_gecos); + p->pw_dir = strdup(tmp_passwd->pw_dir); + p->pw_shell = strdup(tmp_passwd->pw_shell); + } + if (!passwd_list) { + fprintf(stderr, "%s: fgetpwent failed, %s\n", __FUNCTION__, strerror(errno)); + exit(1); + } + root_passwd = find_entry_by_name("root"); + if (remap_ownership && !root_passwd) { + fprintf(stderr, "%s: No root entry in passwd file!\n", __FUNCTION__); + exit(1); + } +} + + static int obj_compare(const void *a, const void * b) { objItem *oa, *ob; @@ -160,6 +239,7 @@ { yaffs_ExtendedTags t; yaffs_PackedTags2 pt; + unsigned char spareBuf[spareSize]; error = write(outFile,data,chunkSize); if(error < 0) return error; @@ -187,7 +267,9 @@ yaffs_PackTags2(&pt,&t); // return write(outFile,&pt,sizeof(yaffs_PackedTags2)); - return write(outFile,&pt,spareSize); + memset(spareBuf, 0xff, sizeof(spareBuf)); + memcpy(spareBuf, &pt, sizeof(pt)); + return write(outFile,&spareBuf,spareSize); } @@ -252,16 +334,12 @@ oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]); oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]); oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]); - oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]); - oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]); #endif } static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias) { __u8 bytes[chunkSize]; - - yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes; memset(bytes,0xff,sizeof(bytes)); @@ -309,6 +387,155 @@ } +#define PATH_LEN 1024 + +static int process_directory(int parent, const char *path); + +void process_entry(struct dirent *entry, int parent, char *full_name) +{ + int ret; + struct stat stats; + int equivalentObj; + int newObj; + + ret = lstat(full_name,&stats); + if (ret) { + // Hmm, not found - is it in the + // device tree + if (!lstat_dev_table(full_name, &stats)) + return; + } + + if (remap_ownership) { + struct passwd *p; + p = find_entry_by_uid(stats.st_uid); + if (p) { + stats.st_uid = p->pw_uid; + stats.st_gid = p->pw_gid; + } + + } + + if(S_ISLNK(stats.st_mode) || + S_ISREG(stats.st_mode) || + S_ISDIR(stats.st_mode) || + S_ISFIFO(stats.st_mode) || + S_ISBLK(stats.st_mode) || + S_ISCHR(stats.st_mode) || + S_ISSOCK(stats.st_mode)) + { + + newObj = obj_id++; + nObjects++; + + if (progress) + printf("Object %d, parent %d, %s is a ",newObj,parent,full_name); + + /* We're going to create an object for it */ + if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0) + { + /* we need to make a hard link */ + if (progress) + printf("hard link to object %d\n",equivalentObj); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL); + } + else + { + + add_obj_to_list(stats.st_dev,stats.st_ino,newObj); + + if(S_ISLNK(stats.st_mode)) + { + + char symname[500]; + + memset(symname,0, sizeof(symname)); + + readlink(full_name,symname,sizeof(symname) -1); + + if (progress) + printf("symlink to \"%s\"\n",symname); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname); + + } + else if(S_ISREG(stats.st_mode)) + { + if (progress) + printf("file, "); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL); + + if(error >= 0) + { + int h; + __u8 bytes[chunkSize]; + int nBytes; + int chunk = 0; + + h = open(full_name,O_RDONLY); + if(h >= 0) + { + memset(bytes,0xff,sizeof(bytes)); + while((nBytes = read(h,bytes,sizeof(bytes))) > 0) + { + chunk++; + write_chunk(bytes,newObj,chunk,nBytes); + memset(bytes,0xff,sizeof(bytes)); + } + if(nBytes < 0) + error = nBytes; + + if (progress) + printf("%d data chunks written\n",chunk); + } + else + { + perror("Error opening file"); + } + close(h); + + } + + } + else if(S_ISSOCK(stats.st_mode)) + { + if (progress) + printf("socket\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISFIFO(stats.st_mode)) + { + if (progress) + printf("fifo\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISCHR(stats.st_mode)) + { + if (progress) + printf("character device\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISBLK(stats.st_mode)) + { + if (progress) + printf("block device\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISDIR(stats.st_mode)) + { + if (progress) + printf("directory\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL); + // process_directory(1,full_name); + process_directory(newObj,full_name); + dev_table_set_parent(full_name, newObj); + } + } + } + else + { + printf(" we don't handle this type\n"); + } +} static int process_directory(int parent, const char *path) { @@ -324,129 +551,15 @@ { while((entry = readdir(dir)) != NULL) { - /* Ignore . and .. */ if(strcmp(entry->d_name,".") && strcmp(entry->d_name,"..")) { - char full_name[500]; - struct stat stats; - int equivalentObj; - int newObj; - + char full_name[PATH_LEN]; sprintf(full_name,"%s/%s",path,entry->d_name); - - lstat(full_name,&stats); - - if(S_ISLNK(stats.st_mode) || - S_ISREG(stats.st_mode) || - S_ISDIR(stats.st_mode) || - S_ISFIFO(stats.st_mode) || - S_ISBLK(stats.st_mode) || - S_ISCHR(stats.st_mode) || - S_ISSOCK(stats.st_mode)) - { - - newObj = obj_id++; - nObjects++; - - printf("Object %d, %s is a ",newObj,full_name); - - /* We're going to create an object for it */ - if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0) - { - /* we need to make a hard link */ - printf("hard link to object %d\n",equivalentObj); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL); - } - else - { - - add_obj_to_list(stats.st_dev,stats.st_ino,newObj); - - if(S_ISLNK(stats.st_mode)) - { - - char symname[500]; - - memset(symname,0, sizeof(symname)); - - readlink(full_name,symname,sizeof(symname) -1); - - printf("symlink to \"%s\"\n",symname); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname); - - } - else if(S_ISREG(stats.st_mode)) - { - printf("file, "); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL); - - if(error >= 0) - { - int h; - __u8 bytes[chunkSize]; - int nBytes; - int chunk = 0; - - h = open(full_name,O_RDONLY); - if(h >= 0) - { - memset(bytes,0xff,sizeof(bytes)); - while((nBytes = read(h,bytes,sizeof(bytes))) > 0) - { - chunk++; - write_chunk(bytes,newObj,chunk,nBytes); - memset(bytes,0xff,sizeof(bytes)); - } - if(nBytes < 0) - error = nBytes; - - printf("%d data chunks written\n",chunk); - } - else - { - perror("Error opening file"); - } - close(h); - - } - - } - else if(S_ISSOCK(stats.st_mode)) - { - printf("socket\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISFIFO(stats.st_mode)) - { - printf("fifo\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISCHR(stats.st_mode)) - { - printf("character device\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISBLK(stats.st_mode)) - { - printf("block device\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); - } - else if(S_ISDIR(stats.st_mode)) - { - printf("directory\n"); - error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL); -// NCB modified 10/9/2001 process_directory(1,full_name); - process_directory(newObj,full_name); - } - } - } - else - { - printf(" we don't handle this type\n"); - } + process_entry(entry, parent, full_name); } + } } @@ -455,27 +568,113 @@ } +char *in_file, *out_file; + +void usage() +{ + printf("usage: mkyaffsimage -c -s dir image_file\n"); + printf(" -c produce a big-endian image from a little-endian machine\n"); + printf(" -P show progress\n"); + printf(" -b produce a big-endian image\n"); + printf(" -l produce a little-endian image\n"); + + printf(" -s size of block in flash(minus spares in NAND)\n"); + printf(" -N produce a NAND image(if not set assume NOR)\n"); + printf(" -p permission file to remap owner/group from\n"); + printf(" -r If no user/group in file, make root/wheel\n"); + printf(" -D Device table file to create in target image\n"); + printf(" dir the directory tree to be converted\n"); + printf(" image_file the output file to hold the image\n"); + exit(1); +} + +union { + unsigned char c[2]; + unsigned short s; +} u_endian; + +void determine_endianess(void) +{ + + u_endian.c[0] = '6'; + u_endian.c[1] = '8'; + + if (u_endian.s == (('6'<<8)|'8')) + big_endian = 1; + if (u_endian.s == (('8'<<8)|'6')) + little_endian = 1; +} + + int main(int argc, char *argv[]) { struct stat stats; - - printf("mkyaffs2image: image building tool for YAFFS2 built "__DATE__"\n"); - - if(argc < 3) + int i; + + determine_endianess(); + + for (i=1; i + * + * 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. + * + * + * Nick Bane modifications flagged NCB + * + * Endian handling patches by James Ng. + * + * mkyaffs2image hacks by NCB + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "yaffs_ecc.h" +#include "yaffs_guts.h" + +#include "yaffs_tagsvalidity.h" +#include "yaffs_packedtags2.h" + +unsigned yaffs_traceMask=0; + +#define MAX_OBJECTS 10000 + +#define chunkSize 2048 +#define spareSize 64 + +const char * mkyaffsimage_c_version = "$Id: mkyaffs2image.c,v 1.2 2005/12/13 00:34:58 tpoynor Exp $"; + + +typedef struct +{ + dev_t dev; + ino_t ino; + int obj; +} objItem; + + +static objItem obj_list[MAX_OBJECTS]; +static int n_obj = 0; +static int obj_id = YAFFS_NOBJECT_BUCKETS + 1; + +static int nObjects, nDirectories, nPages; + +static int outFile; + +static int error; + +static int convert_endian = 0; + +static int obj_compare(const void *a, const void * b) +{ + objItem *oa, *ob; + + oa = (objItem *)a; + ob = (objItem *)b; + + if(oa->dev < ob->dev) return -1; + if(oa->dev > ob->dev) return 1; + if(oa->ino < ob->ino) return -1; + if(oa->ino > ob->ino) return 1; + + return 0; +} + + +static void add_obj_to_list(dev_t dev, ino_t ino, int obj) +{ + if(n_obj < MAX_OBJECTS) + { + obj_list[n_obj].dev = dev; + obj_list[n_obj].ino = ino; + obj_list[n_obj].obj = obj; + n_obj++; + qsort(obj_list,n_obj,sizeof(objItem),obj_compare); + + } + else + { + // oops! not enough space in the object array + fprintf(stderr,"Not enough space in object array\n"); + exit(2); + } +} + + +static int find_obj_in_list(dev_t dev, ino_t ino) +{ + objItem *i = NULL; + objItem test; + + test.dev = dev; + test.ino = ino; + + if(n_obj > 0) + { + i = bsearch(&test,obj_list,n_obj,sizeof(objItem),obj_compare); + } + + if(i) + { + return i->obj; + } + return -1; +} + +/* This little function converts a little endian tag to a big endian tag. + * NOTE: The tag is not usable after this other than calculating the CRC + * with. + */ +static void little_to_big_endian(yaffs_Tags *tagsPtr) +{ +#if 0 // FIXME NCB + yaffs_TagsUnion * tags = (yaffs_TagsUnion* )tagsPtr; // Work in bytes. + yaffs_TagsUnion temp; + + memset(&temp, 0, sizeof(temp)); + // Ick, I hate magic numbers. + temp.asBytes[0] = ((tags->asBytes[2] & 0x0F) << 4) | ((tags->asBytes[1] & 0xF0) >> 4); + temp.asBytes[1] = ((tags->asBytes[1] & 0x0F) << 4) | ((tags->asBytes[0] & 0xF0) >> 4); + temp.asBytes[2] = ((tags->asBytes[0] & 0x0F) << 4) | ((tags->asBytes[2] & 0x30) >> 2) | ((tags->asBytes[3] & 0xC0) >> 6); + temp.asBytes[3] = ((tags->asBytes[3] & 0x3F) << 2) | ((tags->asBytes[2] & 0xC0) >> 6); + temp.asBytes[4] = ((tags->asBytes[6] & 0x03) << 6) | ((tags->asBytes[5] & 0xFC) >> 2); + temp.asBytes[5] = ((tags->asBytes[5] & 0x03) << 6) | ((tags->asBytes[4] & 0xFC) >> 2); + temp.asBytes[6] = ((tags->asBytes[4] & 0x03) << 6) | (tags->asBytes[7] & 0x3F); + temp.asBytes[7] = (tags->asBytes[6] & 0xFC) | ((tags->asBytes[7] & 0xC0) >> 6); + + // Now copy it back. + tags->asBytes[0] = temp.asBytes[0]; + tags->asBytes[1] = temp.asBytes[1]; + tags->asBytes[2] = temp.asBytes[2]; + tags->asBytes[3] = temp.asBytes[3]; + tags->asBytes[4] = temp.asBytes[4]; + tags->asBytes[5] = temp.asBytes[5]; + tags->asBytes[6] = temp.asBytes[6]; + tags->asBytes[7] = temp.asBytes[7]; +#endif +} + +static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes) +{ + yaffs_ExtendedTags t; + yaffs_PackedTags2 pt; + + error = write(outFile,data,chunkSize); + if(error < 0) return error; + + yaffs_InitialiseTags(&t); + + t.chunkId = chunkId; +// t.serialNumber = 0; + t.serialNumber = 1; // **CHECK** + t.byteCount = nBytes; + t.objectId = objId; + + t.sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER; + +// added NCB **CHECK** + t.chunkUsed = 1; + + if (convert_endian) + { + little_to_big_endian(&t); + } + + nPages++; + + yaffs_PackTags2(&pt,&t); + +// return write(outFile,&pt,sizeof(yaffs_PackedTags2)); + return write(outFile,&pt,spareSize); + +} + +#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \ + (((x) & 0x0000FF00) << 8 ) | \ + (((x) & 0x00FF0000) >> 8 ) | \ + (((x) & 0xFF000000) >> 24)) + +#define SWAP16(x) ((((x) & 0x00FF) << 8) | \ + (((x) & 0xFF00) >> 8)) + +// This one is easier, since the types are more standard. No funky shifts here. +static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh) +{ + oh->type = SWAP32(oh->type); // GCC makes enums 32 bits. + oh->parentObjectId = SWAP32(oh->parentObjectId); // int + oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness. + // name = skip. Char array. Not swapped. + oh->yst_mode = SWAP32(oh->yst_mode); +#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case. + // In fact, WinCE would be *THE* place where this would be an issue! + oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]); + oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]); + oh->notForWinCE[2] = SWAP32(oh->notForWinCE[2]); + oh->notForWinCE[3] = SWAP32(oh->notForWinCE[3]); + oh->notForWinCE[4] = SWAP32(oh->notForWinCE[4]); +#else + // Regular POSIX. + oh->yst_uid = SWAP32(oh->yst_uid); + oh->yst_gid = SWAP32(oh->yst_gid); + oh->yst_atime = SWAP32(oh->yst_atime); + oh->yst_mtime = SWAP32(oh->yst_mtime); + oh->yst_ctime = SWAP32(oh->yst_ctime); +#endif + + oh->fileSize = SWAP32(oh->fileSize); // Aiee. An int... signed, at that! + oh->equivalentObjectId = SWAP32(oh->equivalentObjectId); + // alias - char array. + oh->yst_rdev = SWAP32(oh->yst_rdev); + +#ifdef CONFIG_YAFFS_WINCE + oh->win_ctime[0] = SWAP32(oh->win_ctime[0]); + oh->win_ctime[1] = SWAP32(oh->win_ctime[1]); + oh->win_atime[0] = SWAP32(oh->win_atime[0]); + oh->win_atime[1] = SWAP32(oh->win_atime[1]); + oh->win_mtime[0] = SWAP32(oh->win_mtime[0]); + oh->win_mtime[1] = SWAP32(oh->win_mtime[1]); + oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); + oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); + oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); + oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); + oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); + oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); +#else + oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); + oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); + oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); + oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); + oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); + oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); + oh->roomToGrow[6] = SWAP32(oh->roomToGrow[6]); + oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]); + oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]); + oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]); + oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]); + oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]); +#endif +} + +static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias) +{ + __u8 bytes[chunkSize]; + + + yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes; + + memset(bytes,0xff,sizeof(bytes)); + + oh->type = t; + + oh->parentObjectId = parent; + + strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH); + + + if(t != YAFFS_OBJECT_TYPE_HARDLINK) + { + oh->yst_mode = s->st_mode; + oh->yst_uid = s->st_uid; +// NCB 12/9/02 oh->yst_gid = s->yst_uid; + oh->yst_gid = s->st_gid; + oh->yst_atime = s->st_atime; + oh->yst_mtime = s->st_mtime; + oh->yst_ctime = s->st_ctime; + oh->yst_rdev = s->st_rdev; + } + + if(t == YAFFS_OBJECT_TYPE_FILE) + { + oh->fileSize = s->st_size; + } + + if(t == YAFFS_OBJECT_TYPE_HARDLINK) + { + oh->equivalentObjectId = equivalentObj; + } + + if(t == YAFFS_OBJECT_TYPE_SYMLINK) + { + strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH); + } + + if (convert_endian) + { + object_header_little_to_big_endian(oh); + } + + return write_chunk(bytes,objId,0,0xffff); + +} + + +static int process_directory(int parent, const char *path) +{ + + DIR *dir; + struct dirent *entry; + + nDirectories++; + + dir = opendir(path); + + if(dir) + { + while((entry = readdir(dir)) != NULL) + { + + /* Ignore . and .. */ + if(strcmp(entry->d_name,".") && + strcmp(entry->d_name,"..")) + { + char full_name[500]; + struct stat stats; + int equivalentObj; + int newObj; + + sprintf(full_name,"%s/%s",path,entry->d_name); + + lstat(full_name,&stats); + + if(S_ISLNK(stats.st_mode) || + S_ISREG(stats.st_mode) || + S_ISDIR(stats.st_mode) || + S_ISFIFO(stats.st_mode) || + S_ISBLK(stats.st_mode) || + S_ISCHR(stats.st_mode) || + S_ISSOCK(stats.st_mode)) + { + + newObj = obj_id++; + nObjects++; + + printf("Object %d, %s is a ",newObj,full_name); + + /* We're going to create an object for it */ + if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0) + { + /* we need to make a hard link */ + printf("hard link to object %d\n",equivalentObj); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL); + } + else + { + + add_obj_to_list(stats.st_dev,stats.st_ino,newObj); + + if(S_ISLNK(stats.st_mode)) + { + + char symname[500]; + + memset(symname,0, sizeof(symname)); + + readlink(full_name,symname,sizeof(symname) -1); + + printf("symlink to \"%s\"\n",symname); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname); + + } + else if(S_ISREG(stats.st_mode)) + { + printf("file, "); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL); + + if(error >= 0) + { + int h; + __u8 bytes[chunkSize]; + int nBytes; + int chunk = 0; + + h = open(full_name,O_RDONLY); + if(h >= 0) + { + memset(bytes,0xff,sizeof(bytes)); + while((nBytes = read(h,bytes,sizeof(bytes))) > 0) + { + chunk++; + write_chunk(bytes,newObj,chunk,nBytes); + memset(bytes,0xff,sizeof(bytes)); + } + if(nBytes < 0) + error = nBytes; + + printf("%d data chunks written\n",chunk); + } + else + { + perror("Error opening file"); + } + close(h); + + } + + } + else if(S_ISSOCK(stats.st_mode)) + { + printf("socket\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISFIFO(stats.st_mode)) + { + printf("fifo\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISCHR(stats.st_mode)) + { + printf("character device\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISBLK(stats.st_mode)) + { + printf("block device\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISDIR(stats.st_mode)) + { + printf("directory\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL); +// NCB modified 10/9/2001 process_directory(1,full_name); + process_directory(newObj,full_name); + } + } + } + else + { + printf(" we don't handle this type\n"); + } + } + } + } + + return 0; + +} + + +int main(int argc, char *argv[]) +{ + struct stat stats; + + printf("mkyaffs2image: image building tool for YAFFS2 built "__DATE__"\n"); + + if(argc < 3) + { + printf("usage: mkyaffs2image dir image_file [convert]\n"); + printf(" dir the directory tree to be converted\n"); + printf(" image_file the output file to hold the image\n"); + printf(" 'convert' produce a big-endian image from a little-endian machine\n"); + exit(1); + } + + if ((argc == 4) && (!strncmp(argv[3], "convert", strlen("convert")))) + { + convert_endian = 1; + } + + if(stat(argv[1],&stats) < 0) + { + printf("Could not stat %s\n",argv[1]); + exit(1); + } + + if(!S_ISDIR(stats.st_mode)) + { + printf(" %s is not a directory\n",argv[1]); + exit(1); + } + + outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); + + + if(outFile < 0) + { + printf("Could not open output file %s\n",argv[2]); + exit(1); + } + + printf("Processing directory %s into image file %s\n",argv[1],argv[2]); + error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL); + if(error) + error = process_directory(YAFFS_OBJECTID_ROOT,argv[1]); + + close(outFile); + + if(error < 0) + { + perror("operation incomplete"); + exit(1); + } + else + { + printf("Operation complete.\n" + "%d objects in %d directories\n" + "%d NAND pages\n",nObjects, nDirectories, nPages); + } + + close(outFile); + + exit(0); +} + Binary files yaffs_utils-20060418/yaffs2/utils/mkyaffs2image.o and yaffs_utils-20060418.modified/yaffs2/utils/mkyaffs2image.o differ Binary files yaffs_utils-20060418/yaffs2/utils/mkyaffsimage and yaffs_utils-20060418.modified/yaffs2/utils/mkyaffsimage differ diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/mkyaffsimage.c yaffs_utils-20060418.modified/yaffs2/utils/mkyaffsimage.c --- yaffs_utils-20060418/yaffs2/utils/mkyaffsimage.c 2006-04-24 07:39:48.000000000 -0400 +++ yaffs_utils-20060418.modified/yaffs2/utils/mkyaffsimage.c 2009-11-03 12:29:01.000000000 -0500 @@ -115,6 +115,7 @@ return -1; } +#if 0 // NCB added 10/9/2002 static __u16 yaffs_CalcNameSum(const char *name) { @@ -131,6 +132,7 @@ } return sum; } +#endif static void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) @@ -323,8 +325,6 @@ oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]); oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]); oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]); - oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]); - oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]); #endif } diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/mkyaffsimage.c~ yaffs_utils-20060418.modified/yaffs2/utils/mkyaffsimage.c~ --- yaffs_utils-20060418/yaffs2/utils/mkyaffsimage.c~ 1969-12-31 19:00:00.000000000 -0500 +++ yaffs_utils-20060418.modified/yaffs2/utils/mkyaffsimage.c~ 2006-04-24 07:39:48.000000000 -0400 @@ -0,0 +1,593 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * + * makeyaffsimage.c + * + * Makes a YAFFS file system image that can be used to load up a file system. + * + * Copyright (C) 2002 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + * + * + * Nick Bane modifications flagged NCB + * + * Endian handling patches by James Ng. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "yaffs_ecc.h" +#include "yaffs_guts.h" + + +#define MAX_OBJECTS 10000 + +const char * mkyaffsimage_c_version = "$Id: mkyaffsimage.c,v 1.7 2003/07/16 03:00:48 charles Exp $"; + + +typedef struct +{ + dev_t dev; + ino_t ino; + int obj; +} objItem; + + +static objItem obj_list[MAX_OBJECTS]; +static int n_obj = 0; +static int obj_id = YAFFS_NOBJECT_BUCKETS + 1; + +static int nObjects, nDirectories, nPages; + +static int outFile; + +static int error; + +static int convert_endian = 0; + +static int obj_compare(const void *a, const void * b) +{ + objItem *oa, *ob; + + oa = (objItem *)a; + ob = (objItem *)b; + + if(oa->dev < ob->dev) return -1; + if(oa->dev > ob->dev) return 1; + if(oa->ino < ob->ino) return -1; + if(oa->ino > ob->ino) return 1; + + return 0; +} + + +static void add_obj_to_list(dev_t dev, ino_t ino, int obj) +{ + if(n_obj < MAX_OBJECTS) + { + obj_list[n_obj].dev = dev; + obj_list[n_obj].ino = ino; + obj_list[n_obj].obj = obj; + n_obj++; + qsort(obj_list,n_obj,sizeof(objItem),obj_compare); + + } + else + { + // oops! not enough space in the object array + fprintf(stderr,"Not enough space in object array\n"); + exit(2); + } +} + + +static int find_obj_in_list(dev_t dev, ino_t ino) +{ + objItem *i = NULL; + objItem test; + + test.dev = dev; + test.ino = ino; + + if(n_obj > 0) + { + i = bsearch(&test,obj_list,n_obj,sizeof(objItem),obj_compare); + } + + if(i) + { + return i->obj; + } + return -1; +} + +// NCB added 10/9/2002 +static __u16 yaffs_CalcNameSum(const char *name) +{ + __u16 sum = 0; + __u16 i = 1; + + __u8 *bname = (__u8 *)name; + + while (*bname) + { + sum += (*bname) * i; + i++; + bname++; + } + return sum; +} + + +static void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) +{ + yaffs_ECCCalculate(data , spare->ecc1); + yaffs_ECCCalculate(&data[256] , spare->ecc2); +} + +static void yaffs_CalcTagsECC(yaffs_Tags *tags) +{ + // Todo don't do anything yet. Need to calculate ecc + unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes; + unsigned i,j; + unsigned ecc = 0; + unsigned bit = 0; + + // Clear ECC fields + if (!convert_endian) + { + tags->ecc = 0; + } + else + { + // Because we're in "munged tag" mode, we have to clear it manually + b[6] &= 0xC0; + b[7] &= 0x03; + } + + for(i = 0; i < 8; i++) + { +// NCB modified 20-9-02 for(j = 1; j &0x7f; j<<=1) + for(j = 1; j &0xff; j<<=1) + { + bit++; + if(b[i] & j) + { + ecc ^= bit; + } + } + } + + // Write out ECC + if (!convert_endian) + { + tags->ecc = ecc; + } + else + { + // We have to munge the ECC again. + b[6] |= ((ecc >> 6) & 0x3F); + b[7] |= ((ecc & 0x3F) << 2); + } +} +static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr) +{ + yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr; + + //yaffs_CalcTagsECC(tagsPtr); + + sparePtr->tagByte0 = tu->asBytes[0]; + sparePtr->tagByte1 = tu->asBytes[1]; + sparePtr->tagByte2 = tu->asBytes[2]; + sparePtr->tagByte3 = tu->asBytes[3]; + sparePtr->tagByte4 = tu->asBytes[4]; + sparePtr->tagByte5 = tu->asBytes[5]; + sparePtr->tagByte6 = tu->asBytes[6]; + sparePtr->tagByte7 = tu->asBytes[7]; +} + +/* This little function converts a little endian tag to a big endian tag. + * NOTE: The tag is not usable after this other than calculating the CRC + * with. + */ +static void little_to_big_endian(yaffs_Tags *tagsPtr) +{ + yaffs_TagsUnion * tags = (yaffs_TagsUnion* )tagsPtr; // Work in bytes. + yaffs_TagsUnion temp; + + memset(&temp, 0, sizeof(temp)); + // Ick, I hate magic numbers. + temp.asBytes[0] = ((tags->asBytes[2] & 0x0F) << 4) | ((tags->asBytes[1] & 0xF0) >> 4); + temp.asBytes[1] = ((tags->asBytes[1] & 0x0F) << 4) | ((tags->asBytes[0] & 0xF0) >> 4); + temp.asBytes[2] = ((tags->asBytes[0] & 0x0F) << 4) | ((tags->asBytes[2] & 0x30) >> 2) | ((tags->asBytes[3] & 0xC0) >> 6); + temp.asBytes[3] = ((tags->asBytes[3] & 0x3F) << 2) | ((tags->asBytes[2] & 0xC0) >> 6); + temp.asBytes[4] = ((tags->asBytes[6] & 0x03) << 6) | ((tags->asBytes[5] & 0xFC) >> 2); + temp.asBytes[5] = ((tags->asBytes[5] & 0x03) << 6) | ((tags->asBytes[4] & 0xFC) >> 2); + temp.asBytes[6] = ((tags->asBytes[4] & 0x03) << 6) | (tags->asBytes[7] & 0x3F); + temp.asBytes[7] = (tags->asBytes[6] & 0xFC) | ((tags->asBytes[7] & 0xC0) >> 6); + + // Now copy it back. + tags->asBytes[0] = temp.asBytes[0]; + tags->asBytes[1] = temp.asBytes[1]; + tags->asBytes[2] = temp.asBytes[2]; + tags->asBytes[3] = temp.asBytes[3]; + tags->asBytes[4] = temp.asBytes[4]; + tags->asBytes[5] = temp.asBytes[5]; + tags->asBytes[6] = temp.asBytes[6]; + tags->asBytes[7] = temp.asBytes[7]; +} + +static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes) +{ + yaffs_Tags t; + yaffs_Spare s; + + error = write(outFile,data,512); + if(error < 0) return error; + + memset(&t,0xff,sizeof (yaffs_Tags)); + memset(&s,0xff,sizeof (yaffs_Spare)); + + t.chunkId = chunkId; + t.serialNumber = 0; + t.byteCount = nBytes; + t.objectId = objId; + + if (convert_endian) + { + little_to_big_endian(&t); + } + + yaffs_CalcTagsECC(&t); + yaffs_LoadTagsIntoSpare(&s,&t); + yaffs_CalcECC(data,&s); + + nPages++; + + return write(outFile,&s,sizeof(yaffs_Spare)); + +} + +#define SWAP32(x) ((((x) & 0x000000FF) << 24) | \ + (((x) & 0x0000FF00) << 8 ) | \ + (((x) & 0x00FF0000) >> 8 ) | \ + (((x) & 0xFF000000) >> 24)) + +#define SWAP16(x) ((((x) & 0x00FF) << 8) | \ + (((x) & 0xFF00) >> 8)) + +// This one is easier, since the types are more standard. No funky shifts here. +static void object_header_little_to_big_endian(yaffs_ObjectHeader* oh) +{ + oh->type = SWAP32(oh->type); // GCC makes enums 32 bits. + oh->parentObjectId = SWAP32(oh->parentObjectId); // int + oh->sum__NoLongerUsed = SWAP16(oh->sum__NoLongerUsed); // __u16 - Not used, but done for completeness. + // name = skip. Char array. Not swapped. + oh->yst_mode = SWAP32(oh->yst_mode); +#ifdef CONFIG_YAFFS_WINCE // WinCE doesn't implement this, but we need to just in case. + // In fact, WinCE would be *THE* place where this would be an issue! + oh->notForWinCE[0] = SWAP32(oh->notForWinCE[0]); + oh->notForWinCE[1] = SWAP32(oh->notForWinCE[1]); + oh->notForWinCE[2] = SWAP32(oh->notForWinCE[2]); + oh->notForWinCE[3] = SWAP32(oh->notForWinCE[3]); + oh->notForWinCE[4] = SWAP32(oh->notForWinCE[4]); +#else + // Regular POSIX. + oh->yst_uid = SWAP32(oh->yst_uid); + oh->yst_gid = SWAP32(oh->yst_gid); + oh->yst_atime = SWAP32(oh->yst_atime); + oh->yst_mtime = SWAP32(oh->yst_mtime); + oh->yst_ctime = SWAP32(oh->yst_ctime); +#endif + + oh->fileSize = SWAP32(oh->fileSize); // Aiee. An int... signed, at that! + oh->equivalentObjectId = SWAP32(oh->equivalentObjectId); + // alias - char array. + oh->yst_rdev = SWAP32(oh->yst_rdev); + +#ifdef CONFIG_YAFFS_WINCE + oh->win_ctime[0] = SWAP32(oh->win_ctime[0]); + oh->win_ctime[1] = SWAP32(oh->win_ctime[1]); + oh->win_atime[0] = SWAP32(oh->win_atime[0]); + oh->win_atime[1] = SWAP32(oh->win_atime[1]); + oh->win_mtime[0] = SWAP32(oh->win_mtime[0]); + oh->win_mtime[1] = SWAP32(oh->win_mtime[1]); + oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); + oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); + oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); + oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); + oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); + oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); +#else + oh->roomToGrow[0] = SWAP32(oh->roomToGrow[0]); + oh->roomToGrow[1] = SWAP32(oh->roomToGrow[1]); + oh->roomToGrow[2] = SWAP32(oh->roomToGrow[2]); + oh->roomToGrow[3] = SWAP32(oh->roomToGrow[3]); + oh->roomToGrow[4] = SWAP32(oh->roomToGrow[4]); + oh->roomToGrow[5] = SWAP32(oh->roomToGrow[5]); + oh->roomToGrow[6] = SWAP32(oh->roomToGrow[6]); + oh->roomToGrow[7] = SWAP32(oh->roomToGrow[7]); + oh->roomToGrow[8] = SWAP32(oh->roomToGrow[8]); + oh->roomToGrow[9] = SWAP32(oh->roomToGrow[9]); + oh->roomToGrow[10] = SWAP32(oh->roomToGrow[10]); + oh->roomToGrow[11] = SWAP32(oh->roomToGrow[11]); +#endif +} + +static int write_object_header(int objId, yaffs_ObjectType t, struct stat *s, int parent, const char *name, int equivalentObj, const char * alias) +{ + __u8 bytes[512]; + + + yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bytes; + + memset(bytes,0xff,512); + + oh->type = t; + + oh->parentObjectId = parent; + + strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH); + + + if(t != YAFFS_OBJECT_TYPE_HARDLINK) + { + oh->yst_mode = s->st_mode; + oh->yst_uid = s->st_uid; +// NCB 12/9/02 oh->yst_gid = s->yst_uid; + oh->yst_gid = s->st_gid; + oh->yst_atime = s->st_atime; + oh->yst_mtime = s->st_mtime; + oh->yst_ctime = s->st_ctime; + oh->yst_rdev = s->st_rdev; + } + + if(t == YAFFS_OBJECT_TYPE_FILE) + { + oh->fileSize = s->st_size; + } + + if(t == YAFFS_OBJECT_TYPE_HARDLINK) + { + oh->equivalentObjectId = equivalentObj; + } + + if(t == YAFFS_OBJECT_TYPE_SYMLINK) + { + strncpy(oh->alias,alias,YAFFS_MAX_ALIAS_LENGTH); + } + + if (convert_endian) + { + object_header_little_to_big_endian(oh); + } + + return write_chunk(bytes,objId,0,0xffff); + +} + + +static int process_directory(int parent, const char *path) +{ + + DIR *dir; + struct dirent *entry; + + nDirectories++; + + dir = opendir(path); + + if(dir) + { + while((entry = readdir(dir)) != NULL) + { + + /* Ignore . and .. */ + if(strcmp(entry->d_name,".") && + strcmp(entry->d_name,"..")) + { + char full_name[500]; + struct stat stats; + int equivalentObj; + int newObj; + + sprintf(full_name,"%s/%s",path,entry->d_name); + + lstat(full_name,&stats); + + if(S_ISLNK(stats.st_mode) || + S_ISREG(stats.st_mode) || + S_ISDIR(stats.st_mode) || + S_ISFIFO(stats.st_mode) || + S_ISBLK(stats.st_mode) || + S_ISCHR(stats.st_mode) || + S_ISSOCK(stats.st_mode)) + { + + newObj = obj_id++; + nObjects++; + + printf("Object %d, %s is a ",newObj,full_name); + + /* We're going to create an object for it */ + if((equivalentObj = find_obj_in_list(stats.st_dev, stats.st_ino)) > 0) + { + /* we need to make a hard link */ + printf("hard link to object %d\n",equivalentObj); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_HARDLINK, &stats, parent, entry->d_name, equivalentObj, NULL); + } + else + { + + add_obj_to_list(stats.st_dev,stats.st_ino,newObj); + + if(S_ISLNK(stats.st_mode)) + { + + char symname[500]; + + memset(symname,0, sizeof(symname)); + + readlink(full_name,symname,sizeof(symname) -1); + + printf("symlink to \"%s\"\n",symname); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SYMLINK, &stats, parent, entry->d_name, -1, symname); + + } + else if(S_ISREG(stats.st_mode)) + { + printf("file, "); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_FILE, &stats, parent, entry->d_name, -1, NULL); + + if(error >= 0) + { + int h; + __u8 bytes[512]; + int nBytes; + int chunk = 0; + + h = open(full_name,O_RDONLY); + if(h >= 0) + { + memset(bytes,0xff,512); + while((nBytes = read(h,bytes,512)) > 0) + { + chunk++; + write_chunk(bytes,newObj,chunk,nBytes); + memset(bytes,0xff,512); + } + if(nBytes < 0) + error = nBytes; + + printf("%d data chunks written\n",chunk); + } + else + { + perror("Error opening file"); + } + close(h); + + } + + } + else if(S_ISSOCK(stats.st_mode)) + { + printf("socket\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISFIFO(stats.st_mode)) + { + printf("fifo\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISCHR(stats.st_mode)) + { + printf("character device\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISBLK(stats.st_mode)) + { + printf("block device\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_SPECIAL, &stats, parent, entry->d_name, -1, NULL); + } + else if(S_ISDIR(stats.st_mode)) + { + printf("directory\n"); + error = write_object_header(newObj, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, parent, entry->d_name, -1, NULL); +// NCB modified 10/9/2001 process_directory(1,full_name); + process_directory(newObj,full_name); + } + } + } + else + { + printf(" we don't handle this type\n"); + } + } + } + } + + return 0; + +} + + +int main(int argc, char *argv[]) +{ + struct stat stats; + + printf("mkyaffsimage: image building tool for YAFFS built "__DATE__"\n"); + + if(argc < 3) + { + printf("usage: mkyaffsimage dir image_file [convert]\n"); + printf(" dir the directory tree to be converted\n"); + printf(" image_file the output file to hold the image\n"); + printf(" 'convert' produce a big-endian image from a little-endian machine\n"); + exit(1); + } + + if ((argc == 4) && (!strncmp(argv[3], "convert", strlen("convert")))) + { + convert_endian = 1; + } + + if(stat(argv[1],&stats) < 0) + { + printf("Could not stat %s\n",argv[1]); + exit(1); + } + + if(!S_ISDIR(stats.st_mode)) + { + printf(" %s is not a directory\n",argv[1]); + exit(1); + } + + outFile = open(argv[2],O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); + + + if(outFile < 0) + { + printf("Could not open output file %s\n",argv[2]); + exit(1); + } + + printf("Processing directory %s into image file %s\n",argv[1],argv[2]); + error = write_object_header(1, YAFFS_OBJECT_TYPE_DIRECTORY, &stats, 1,"", -1, NULL); + if(error) + error = process_directory(YAFFS_OBJECTID_ROOT,argv[1]); + + close(outFile); + + if(error < 0) + { + perror("operation incomplete"); + exit(1); + } + else + { + printf("Operation complete.\n" + "%d objects in %d directories\n" + "%d NAND pages\n",nObjects, nDirectories, nPages); + } + + close(outFile); + + exit(0); +} + Binary files yaffs_utils-20060418/yaffs2/utils/mkyaffsimage.o and yaffs_utils-20060418.modified/yaffs2/utils/mkyaffsimage.o differ diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/yaffs_ecc.c yaffs_utils-20060418.modified/yaffs2/utils/yaffs_ecc.c --- yaffs_utils-20060418/yaffs2/utils/yaffs_ecc.c 1969-12-31 19:00:00.000000000 -0500 +++ yaffs_utils-20060418.modified/yaffs2/utils/yaffs_ecc.c 2006-04-24 07:39:43.000000000 -0400 @@ -0,0 +1,329 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * + * yaffs_ecc.c: ECC generation/correction algorithms. + * + * Copyright (C) 2002 Aleph One Ltd. + * + * Created by Charles Manning + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + */ + + /* + * This code implements the ECC algorithm used in SmartMedia. + * + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. + * The two unused bit are set to 1. + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC + * blocks are used on a 512-byte NAND page. + * + */ + +/* Table generated by gen-ecc.c + * Using a table means we do not have to calculate p1..p4 and p1'..p4' + * for each byte of data. These are instead provided in a table in bits7..2. + * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore + * this bytes influence on the line parity. + */ + +const char *yaffs_ecc_c_version = + "$Id: yaffs_ecc.c,v 1.6 2005/08/11 02:51:49 charles Exp $"; + +#include "yportenv.h" + +#include "yaffs_ecc.h" + +static const unsigned char column_parity_table[] = { + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, +}; + +/* Count the bits in an unsigned char or a U32 */ + +static int yaffs_CountBits(unsigned char x) +{ + int r = 0; + while (x) { + if (x & 1) + r++; + x >>= 1; + } + return r; +} + +static int yaffs_CountBits32(unsigned x) +{ + int r = 0; + while (x) { + if (x & 1) + r++; + x >>= 1; + } + return r; +} + +/* Calculate the ECC for a 256-byte block of data */ +void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc) +{ + unsigned int i; + + unsigned char col_parity = 0; + unsigned char line_parity = 0; + unsigned char line_parity_prime = 0; + unsigned char t; + unsigned char b; + + for (i = 0; i < 256; i++) { + b = column_parity_table[*data++]; + col_parity ^= b; + + if (b & 0x01) // odd number of bits in the byte + { + line_parity ^= i; + line_parity_prime ^= ~i; + } + + } + + ecc[2] = (~col_parity) | 0x03; + + t = 0; + if (line_parity & 0x80) + t |= 0x80; + if (line_parity_prime & 0x80) + t |= 0x40; + if (line_parity & 0x40) + t |= 0x20; + if (line_parity_prime & 0x40) + t |= 0x10; + if (line_parity & 0x20) + t |= 0x08; + if (line_parity_prime & 0x20) + t |= 0x04; + if (line_parity & 0x10) + t |= 0x02; + if (line_parity_prime & 0x10) + t |= 0x01; + ecc[1] = ~t; + + t = 0; + if (line_parity & 0x08) + t |= 0x80; + if (line_parity_prime & 0x08) + t |= 0x40; + if (line_parity & 0x04) + t |= 0x20; + if (line_parity_prime & 0x04) + t |= 0x10; + if (line_parity & 0x02) + t |= 0x08; + if (line_parity_prime & 0x02) + t |= 0x04; + if (line_parity & 0x01) + t |= 0x02; + if (line_parity_prime & 0x01) + t |= 0x01; + ecc[0] = ~t; + +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER + // Swap the bytes into the wrong order + t = ecc[0]; + ecc[0] = ecc[1]; + ecc[1] = t; +#endif +} + + +/* Correct the ECC on a 256 byte block of data */ + +int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc, + const unsigned char *test_ecc) +{ + unsigned char d0, d1, d2; /* deltas */ + + d0 = read_ecc[0] ^ test_ecc[0]; + d1 = read_ecc[1] ^ test_ecc[1]; + d2 = read_ecc[2] ^ test_ecc[2]; + + if ((d0 | d1 | d2) == 0) + return 0; /* no error */ + + if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && + ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && + ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { + /* Single bit (recoverable) error in data */ + + unsigned byte; + unsigned bit; + +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER + // swap the bytes to correct for the wrong order + unsigned char t; + + t = d0; + d0 = d1; + d1 = t; +#endif + + bit = byte = 0; + + if (d1 & 0x80) + byte |= 0x80; + if (d1 & 0x20) + byte |= 0x40; + if (d1 & 0x08) + byte |= 0x20; + if (d1 & 0x02) + byte |= 0x10; + if (d0 & 0x80) + byte |= 0x08; + if (d0 & 0x20) + byte |= 0x04; + if (d0 & 0x08) + byte |= 0x02; + if (d0 & 0x02) + byte |= 0x01; + + if (d2 & 0x80) + bit |= 0x04; + if (d2 & 0x20) + bit |= 0x02; + if (d2 & 0x08) + bit |= 0x01; + + data[byte] ^= (1 << bit); + + return 1; /* Corrected the error */ + } + + if ((yaffs_CountBits(d0) + + yaffs_CountBits(d1) + + yaffs_CountBits(d2)) == 1) { + /* Reccoverable error in ecc */ + + read_ecc[0] = test_ecc[0]; + read_ecc[1] = test_ecc[1]; + read_ecc[2] = test_ecc[2]; + + return 1; /* Corrected the error */ + } + + /* Unrecoverable error */ + + return -1; + +} + + +/* + * ECCxxxOther does ECC calcs on arbitrary n bytes of data + */ +void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes, + yaffs_ECCOther * eccOther) +{ + unsigned int i; + + unsigned char col_parity = 0; + unsigned line_parity = 0; + unsigned line_parity_prime = 0; + unsigned char b; + + for (i = 0; i < nBytes; i++) { + b = column_parity_table[*data++]; + col_parity ^= b; + + if (b & 0x01) { + /* odd number of bits in the byte */ + line_parity ^= i; + line_parity_prime ^= ~i; + } + + } + + eccOther->colParity = (col_parity >> 2) & 0x3f; + eccOther->lineParity = line_parity; + eccOther->lineParityPrime = line_parity_prime; +} + +int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes, + yaffs_ECCOther * read_ecc, + const yaffs_ECCOther * test_ecc) +{ + unsigned char cDelta; /* column parity delta */ + unsigned lDelta; /* line parity delta */ + unsigned lDeltaPrime; /* line parity delta */ + unsigned bit; + + cDelta = read_ecc->colParity ^ test_ecc->colParity; + lDelta = read_ecc->lineParity ^ test_ecc->lineParity; + lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime; + + if ((cDelta | lDelta | lDeltaPrime) == 0) + return 0; /* no error */ + + if (lDelta == ~lDeltaPrime && (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) + { + /* Single bit (recoverable) error in data */ + + bit = 0; + + if (cDelta & 0x20) + bit |= 0x04; + if (cDelta & 0x08) + bit |= 0x02; + if (cDelta & 0x02) + bit |= 0x01; + + data[lDelta] ^= (1 << bit); + + return 1; /* corrected */ + } + + if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) + + yaffs_CountBits(cDelta)) == 1) { + /* Reccoverable error in ecc */ + + *read_ecc = *test_ecc; + return 1; /* corrected */ + } + + /* Unrecoverable error */ + + return -1; + +} + Binary files yaffs_utils-20060418/yaffs2/utils/yaffs_ecc.o and yaffs_utils-20060418.modified/yaffs2/utils/yaffs_ecc.o differ diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/yaffs_packedtags2.c yaffs_utils-20060418.modified/yaffs2/utils/yaffs_packedtags2.c --- yaffs_utils-20060418/yaffs2/utils/yaffs_packedtags2.c 1969-12-31 19:00:00.000000000 -0500 +++ yaffs_utils-20060418.modified/yaffs2/utils/yaffs_packedtags2.c 2006-04-24 07:39:43.000000000 -0400 @@ -0,0 +1,170 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * + * yaffs_packedtags2.c: Tags packing for YAFFS2 + * + * Copyright (C) 2002 Aleph One Ltd. + * + * Created by Charles Manning + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. + */ + +#include "yaffs_packedtags2.h" +#include "yportenv.h" +#include "yaffs_tagsvalidity.h" + +/* This code packs a set of extended tags into a binary structure for + * NAND storage + */ + +/* Some of the information is "extra" struff which can be packed in to + * speed scanning + * This is defined by having the EXTRA_HEADER_INFO_FLAG set. + */ + +/* Extra flags applied to chunkId */ + +#define EXTRA_HEADER_INFO_FLAG 0x80000000 +#define EXTRA_SHRINK_FLAG 0x40000000 +#define EXTRA_SHADOWS_FLAG 0x20000000 +#define EXTRA_SPARE_FLAGS 0x10000000 + +#define ALL_EXTRA_FLAGS 0xF0000000 + +/* Also, the top 4 bits of the object Id are set to the object type. */ +#define EXTRA_OBJECT_TYPE_SHIFT (28) +#define EXTRA_OBJECT_TYPE_MASK ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT) + +static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 * pt) +{ + T(YAFFS_TRACE_MTD, + (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR), + pt->t.objectId, pt->t.chunkId, pt->t.byteCount, + pt->t.sequenceNumber)); +} + +static void yaffs_DumpTags2(const yaffs_ExtendedTags * t) +{ + T(YAFFS_TRACE_MTD, + (TSTR + ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte " + "%d del %d ser %d seq %d" + TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId, + t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber, + t->sequenceNumber)); + +} + +void yaffs_PackTags2(yaffs_PackedTags2 * pt, const yaffs_ExtendedTags * t) +{ + pt->t.chunkId = t->chunkId; + pt->t.sequenceNumber = t->sequenceNumber; + pt->t.byteCount = t->byteCount; + pt->t.objectId = t->objectId; + + if (t->chunkId == 0 && t->extraHeaderInfoAvailable) { + /* Store the extra header info instead */ + /* We save the parent object in the chunkId */ + pt->t.chunkId = EXTRA_HEADER_INFO_FLAG + | t->extraParentObjectId; + if (t->extraIsShrinkHeader) { + pt->t.chunkId |= EXTRA_SHRINK_FLAG; + } + if (t->extraShadows) { + pt->t.chunkId |= EXTRA_SHADOWS_FLAG; + } + + pt->t.objectId &= ~EXTRA_OBJECT_TYPE_MASK; + pt->t.objectId |= + (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT); + + if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { + pt->t.byteCount = t->extraEquivalentObjectId; + } else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE) { + pt->t.byteCount = t->extraFileLength; + } else { + pt->t.byteCount = 0; + } + } + + yaffs_DumpPackedTags2(pt); + yaffs_DumpTags2(t); + +#ifndef YAFFS_IGNORE_TAGS_ECC + { + yaffs_ECCCalculateOther((unsigned char *)&pt->t, + sizeof(yaffs_PackedTags2TagsPart), + &pt->ecc); + } +#endif +} + +void yaffs_UnpackTags2(yaffs_ExtendedTags * t, yaffs_PackedTags2 * pt) +{ + + memset(t, 0, sizeof(yaffs_ExtendedTags)); + + yaffs_InitialiseTags(t); + + if (pt->t.sequenceNumber != 0xFFFFFFFF) { + /* Page is in use */ +#ifdef YAFFS_IGNORE_TAGS_ECC + { + t->eccResult = 0; + } +#else + { + yaffs_ECCOther ecc; + yaffs_ECCCalculateOther((unsigned char *)&pt->t, + sizeof + (yaffs_PackedTags2TagsPart), + &ecc); + t->eccResult = + yaffs_ECCCorrectOther((unsigned char *)&pt->t, + sizeof + (yaffs_PackedTags2TagsPart), + &pt->ecc, &ecc); + } +#endif + t->blockBad = 0; + t->chunkUsed = 1; + t->objectId = pt->t.objectId; + t->chunkId = pt->t.chunkId; + t->byteCount = pt->t.byteCount; + t->chunkDeleted = 0; + t->serialNumber = 0; + t->sequenceNumber = pt->t.sequenceNumber; + + /* Do extra header info stuff */ + + if (pt->t.chunkId & EXTRA_HEADER_INFO_FLAG) { + t->chunkId = 0; + t->byteCount = 0; + + t->extraHeaderInfoAvailable = 1; + t->extraParentObjectId = + pt->t.chunkId & (~(ALL_EXTRA_FLAGS)); + t->extraIsShrinkHeader = + (pt->t.chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0; + t->extraShadows = + (pt->t.chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0; + t->extraObjectType = + pt->t.objectId >> EXTRA_OBJECT_TYPE_SHIFT; + t->objectId &= ~EXTRA_OBJECT_TYPE_MASK; + + if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK) { + t->extraEquivalentObjectId = pt->t.byteCount; + } else { + t->extraFileLength = pt->t.byteCount; + } + } + } + + yaffs_DumpPackedTags2(pt); + yaffs_DumpTags2(t); + +} Binary files yaffs_utils-20060418/yaffs2/utils/yaffs_packedtags2.o and yaffs_utils-20060418.modified/yaffs2/utils/yaffs_packedtags2.o differ diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/utils/yaffs_tagsvalidity.c yaffs_utils-20060418.modified/yaffs2/utils/yaffs_tagsvalidity.c --- yaffs_utils-20060418/yaffs2/utils/yaffs_tagsvalidity.c 1969-12-31 19:00:00.000000000 -0500 +++ yaffs_utils-20060418.modified/yaffs2/utils/yaffs_tagsvalidity.c 2006-04-24 07:39:43.000000000 -0400 @@ -0,0 +1,31 @@ + +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * + * Copyright (C) 2002 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * 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. + * + * $Id: yaffs_tagsvalidity.c,v 1.2 2005/08/11 02:33:03 marty Exp $ + */ + +#include "yaffs_tagsvalidity.h" + +void yaffs_InitialiseTags(yaffs_ExtendedTags * tags) +{ + memset(tags, 0, sizeof(yaffs_ExtendedTags)); + tags->validMarker0 = 0xAAAAAAAA; + tags->validMarker1 = 0x55555555; +} + +int yaffs_ValidateTags(yaffs_ExtendedTags * tags) +{ + return (tags->validMarker0 == 0xAAAAAAAA && + tags->validMarker1 == 0x55555555); + +} Binary files yaffs_utils-20060418/yaffs2/utils/yaffs_tagsvalidity.o and yaffs_utils-20060418.modified/yaffs2/utils/yaffs_tagsvalidity.o differ diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/yaffs_guts.h yaffs_utils-20060418.modified/yaffs2/yaffs_guts.h --- yaffs_utils-20060418/yaffs2/yaffs_guts.h 2006-04-24 07:39:43.000000000 -0400 +++ yaffs_utils-20060418.modified/yaffs2/yaffs_guts.h 2009-11-03 12:22:29.000000000 -0500 @@ -691,8 +691,10 @@ unsigned yaffs_GetObjectType(yaffs_Object * obj); int yaffs_GetObjectLinkCount(yaffs_Object * obj); +#if !defined(CONFIG_YAFFS_UTIL) int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr); int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr); +#endif /* File operations */ int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, __u32 offset, diff --exclude CVS --exclude .git -uNr yaffs_utils-20060418/yaffs2/yaffs_guts.h~ yaffs_utils-20060418.modified/yaffs2/yaffs_guts.h~ --- yaffs_utils-20060418/yaffs2/yaffs_guts.h~ 1969-12-31 19:00:00.000000000 -0500 +++ yaffs_utils-20060418.modified/yaffs2/yaffs_guts.h~ 2006-04-24 07:39:43.000000000 -0400 @@ -0,0 +1,757 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * yaffs_guts.h: Configuration etc for yaffs_guts + * + * Copyright (C) 2002 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + * + * $Id: yaffs_guts.h,v 1.20 2006/03/08 07:59:20 charles Exp $ + */ + +#ifndef __YAFFS_GUTS_H__ +#define __YAFFS_GUTS_H__ + +#include "devextras.h" +#include "yportenv.h" + +#define YAFFS_OK 1 +#define YAFFS_FAIL 0 + +/* Give us a Y=0x59, + * Give us an A=0x41, + * Give us an FF=0xFF + * Give us an S=0x53 + * And what have we got... + */ +#define YAFFS_MAGIC 0x5941FF53 + +#define YAFFS_NTNODES_LEVEL0 16 +#define YAFFS_TNODES_LEVEL0_BITS 4 +#define YAFFS_TNODES_LEVEL0_MASK 0xf + +#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2) +#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1) +#define YAFFS_TNODES_INTERNAL_MASK 0x7 +#define YAFFS_TNODES_MAX_LEVEL 6 + +#ifndef CONFIG_YAFFS_NO_YAFFS1 +#define YAFFS_BYTES_PER_SPARE 16 +#define YAFFS_BYTES_PER_CHUNK 512 +#define YAFFS_CHUNK_SIZE_SHIFT 9 +#define YAFFS_CHUNKS_PER_BLOCK 32 +#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) +#endif + +#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024 +#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32 + +#define YAFFS_MAX_CHUNK_ID 0x000FFFFF + +#define YAFFS_UNUSED_OBJECT_ID 0x0003FFFF + +#define YAFFS_ALLOCATION_NOBJECTS 100 +#define YAFFS_ALLOCATION_NTNODES 100 +#define YAFFS_ALLOCATION_NLINKS 100 + +#define YAFFS_NOBJECT_BUCKETS 256 + +#define YAFFS_OBJECT_SPACE 0x40000 + +#ifdef CONFIG_YAFFS_UNICODE +#define YAFFS_MAX_NAME_LENGTH 127 +#define YAFFS_MAX_ALIAS_LENGTH 79 +#else +#define YAFFS_MAX_NAME_LENGTH 255 +#define YAFFS_MAX_ALIAS_LENGTH 159 +#endif + +#define YAFFS_SHORT_NAME_LENGTH 15 + +/* Some special object ids */ +#define YAFFS_OBJECTID_ROOT 1 +#define YAFFS_OBJECTID_LOSTNFOUND 2 +#define YAFFS_OBJECTID_UNLINKED 3 +#define YAFFS_OBJECTID_DELETED 4 + +#define YAFFS_MAX_SHORT_OP_CACHES 20 + +#define YAFFS_N_TEMP_BUFFERS 4 + +/* Sequence numbers are used in YAFFS2 to determine block allocation order. + * The range is limited slightly to help distinguish bad numbers from good. + * This also allows us to perhaps in the future use special numbers for + * special purposes. + * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years, + * and is a larger number than the lifetime of a 2GB device. + */ +#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 +#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xEFFFFF00 + +/* ChunkCache is used for short read/write operations.*/ +typedef struct { + struct yaffs_ObjectStruct *object; + int chunkId; + int lastUse; + int dirty; + int nBytes; /* Only valid if the cache is dirty */ + int locked; /* Can't push out or flush while locked. */ +#ifdef CONFIG_YAFFS_YAFFS2 + __u8 *data; +#else + __u8 data[YAFFS_BYTES_PER_CHUNK]; +#endif +} yaffs_ChunkCache; + + + +/* Tags structures in RAM + * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise + * the structure size will get blown out. + */ + +#ifndef CONFIG_YAFFS_NO_YAFFS1 +typedef struct { + unsigned chunkId:20; + unsigned serialNumber:2; + unsigned byteCount:10; + unsigned objectId:18; + unsigned ecc:12; + unsigned unusedStuff:2; + +} yaffs_Tags; + +typedef union { + yaffs_Tags asTags; + __u8 asBytes[8]; +} yaffs_TagsUnion; + +#endif + +/* Stuff used for extended tags in YAFFS2 */ + +typedef enum { + YAFFS_ECC_RESULT_UNKNOWN, + YAFFS_ECC_RESULT_NO_ERROR, + YAFFS_ECC_RESULT_FIXED, + YAFFS_ECC_RESULT_UNFIXED +} yaffs_ECCResult; + +typedef enum { + YAFFS_OBJECT_TYPE_UNKNOWN, + YAFFS_OBJECT_TYPE_FILE, + YAFFS_OBJECT_TYPE_SYMLINK, + YAFFS_OBJECT_TYPE_DIRECTORY, + YAFFS_OBJECT_TYPE_HARDLINK, + YAFFS_OBJECT_TYPE_SPECIAL +} yaffs_ObjectType; + +typedef struct { + + unsigned validMarker0; + unsigned chunkUsed; /* Status of the chunk: used or unused */ + unsigned objectId; /* If 0 then this is not part of an object (unused) */ + unsigned chunkId; /* If 0 then this is a header, else a data chunk */ + unsigned byteCount; /* Only valid for data chunks */ + + /* The following stuff only has meaning when we read */ + yaffs_ECCResult eccResult; + unsigned blockBad; + + /* YAFFS 1 stuff */ + unsigned chunkDeleted; /* The chunk is marked deleted */ + unsigned serialNumber; /* Yaffs1 2-bit serial number */ + + /* YAFFS2 stuff */ + unsigned sequenceNumber; /* The sequence number of this block */ + + /* Extra info if this is an object header (YAFFS2 only) */ + + unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */ + unsigned extraParentObjectId; /* The parent object */ + unsigned extraIsShrinkHeader; /* Is it a shrink header? */ + unsigned extraShadows; /* Does this shadow another object? */ + + yaffs_ObjectType extraObjectType; /* What object type? */ + + unsigned extraFileLength; /* Length if it is a file */ + unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */ + + unsigned validMarker1; + +} yaffs_ExtendedTags; + +/* Spare structure for YAFFS1 */ +typedef struct { + __u8 tagByte0; + __u8 tagByte1; + __u8 tagByte2; + __u8 tagByte3; + __u8 pageStatus; /* set to 0 to delete the chunk */ + __u8 blockStatus; + __u8 tagByte4; + __u8 tagByte5; + __u8 ecc1[3]; + __u8 tagByte6; + __u8 tagByte7; + __u8 ecc2[3]; +} yaffs_Spare; + +/*Special structure for passing through to mtd */ +struct yaffs_NANDSpare { + yaffs_Spare spare; + int eccres1; + int eccres2; +}; + +/* Block data in RAM */ + +typedef enum { + YAFFS_BLOCK_STATE_UNKNOWN = 0, + + YAFFS_BLOCK_STATE_SCANNING, + YAFFS_BLOCK_STATE_NEEDS_SCANNING, + /* The block might have something on it (ie it is allocating or full, perhaps empty) + * but it needs to be scanned to determine its true state. + * This state is only valid during yaffs_Scan. + * NB We tolerate empty because the pre-scanner might be incapable of deciding + * However, if this state is returned on a YAFFS2 device, then we expect a sequence number + */ + + YAFFS_BLOCK_STATE_EMPTY, + /* This block is empty */ + + YAFFS_BLOCK_STATE_ALLOCATING, + /* This block is partially allocated. + * This is the one currently being used for page + * allocation. Should never be more than one of these + */ + + YAFFS_BLOCK_STATE_FULL, + /* All the pages in this block have been allocated. + * At least one page holds valid data. + */ + + YAFFS_BLOCK_STATE_DIRTY, + /* All pages have been allocated and deleted. + * Erase me, reuse me. + */ + + YAFFS_BLOCK_STATE_COLLECTING, + /* This block is being garbage collected */ + + YAFFS_BLOCK_STATE_DEAD + /* This block has failed and is not in use */ +} yaffs_BlockState; + +typedef struct { + + int softDeletions:12; /* number of soft deleted pages */ + int pagesInUse:12; /* number of pages in use */ + yaffs_BlockState blockState:4; /* One of the above block states */ + __u32 needsRetiring:1; /* Data has failed on this block, need to get valid data off */ + /* and retire the block. */ +#ifdef CONFIG_YAFFS_YAFFS2 + __u32 hasShrinkHeader:1; /* This block has at least one shrink object header */ + __u32 sequenceNumber; /* block sequence number for yaffs2 */ +#endif + +} yaffs_BlockInfo; + +/* -------------------------- Object structure -------------------------------*/ +/* This is the object structure as stored on NAND */ + +typedef struct { + yaffs_ObjectType type; + + /* Apply to everything */ + int parentObjectId; + __u16 sum__NoLongerUsed; /* checksum of name. No longer used */ + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; + + /* Thes following apply to directories, files, symlinks - not hard links */ + __u32 yst_mode; /* protection */ + +#ifdef CONFIG_YAFFS_WINCE + __u32 notForWinCE[5]; +#else + __u32 yst_uid; + __u32 yst_gid; + __u32 yst_atime; + __u32 yst_mtime; + __u32 yst_ctime; +#endif + + /* File size applies to files only */ + int fileSize; + + /* Equivalent object id applies to hard links only. */ + int equivalentObjectId; + + /* Alias is for symlinks only. */ + YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; + + __u32 yst_rdev; /* device stuff for block and char devices (major/min) */ + +#ifdef CONFIG_YAFFS_WINCE + __u32 win_ctime[2]; + __u32 win_atime[2]; + __u32 win_mtime[2]; + __u32 roomToGrow[4]; +#else + __u32 roomToGrow[10]; +#endif + + int shadowsObject; /* This object header shadows the specified object if > 0 */ + + /* isShrink applies to object headers written when we shrink the file (ie resize) */ + __u32 isShrink; + +} yaffs_ObjectHeader; + +/*--------------------------- Tnode -------------------------- */ + +union yaffs_Tnode_union { +#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG + union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1]; +#else + union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL]; +#endif +/* __u16 level0[YAFFS_NTNODES_LEVEL0]; */ + +}; + +typedef union yaffs_Tnode_union yaffs_Tnode; + +struct yaffs_TnodeList_struct { + struct yaffs_TnodeList_struct *next; + yaffs_Tnode *tnodes; +}; + +typedef struct yaffs_TnodeList_struct yaffs_TnodeList; + +/*------------------------ Object -----------------------------*/ +/* An object can be one of: + * - a directory (no data, has children links + * - a regular file (data.... not prunes :->). + * - a symlink [symbolic link] (the alias). + * - a hard link + */ + +typedef struct { + __u32 fileSize; + __u32 scannedFileSize; + __u32 shrinkSize; + int topLevel; + yaffs_Tnode *top; +} yaffs_FileStructure; + +typedef struct { + struct list_head children; /* list of child links */ +} yaffs_DirectoryStructure; + +typedef struct { + YCHAR *alias; +} yaffs_SymLinkStructure; + +typedef struct { + struct yaffs_ObjectStruct *equivalentObject; + __u32 equivalentObjectId; +} yaffs_HardLinkStructure; + +typedef union { + yaffs_FileStructure fileVariant; + yaffs_DirectoryStructure directoryVariant; + yaffs_SymLinkStructure symLinkVariant; + yaffs_HardLinkStructure hardLinkVariant; +} yaffs_ObjectVariant; + +struct yaffs_ObjectStruct { + __u8 deleted:1; /* This should only apply to unlinked files. */ + __u8 softDeleted:1; /* it has also been soft deleted */ + __u8 unlinked:1; /* An unlinked file. The file should be in the unlinked directory.*/ + __u8 fake:1; /* A fake object has no presence on NAND. */ + __u8 renameAllowed:1; /* Some objects are not allowed to be renamed. */ + __u8 unlinkAllowed:1; + __u8 dirty:1; /* the object needs to be written to flash */ + __u8 valid:1; /* When the file system is being loaded up, this + * object might be created before the data + * is available (ie. file data records appear before the header). + */ + __u8 lazyLoaded:1; /* This object has been lazy loaded and is missing some detail */ + + __u8 deferedFree:1; /* For Linux kernel. Object is removed from NAND, but is + * still in the inode cache. Free of object is defered. + * until the inode is released. + */ + + __u8 serial; /* serial number of chunk in NAND. Cached here */ + __u16 sum; /* sum of the name to speed searching */ + + struct yaffs_DeviceStruct *myDev; /* The device I'm on */ + + struct list_head hashLink; /* list of objects in this hash bucket */ + + struct list_head hardLinks; /* all the equivalent hard linked objects */ + + /* directory structure stuff */ + /* also used for linking up the free list */ + struct yaffs_ObjectStruct *parent; + struct list_head siblings; + + /* Where's my object header in NAND? */ + int chunkId; + + int nDataChunks; /* Number of data chunks attached to the file. */ + + __u32 objectId; /* the object id value */ + + __u32 yst_mode; + +#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM + YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1]; +#endif + +#ifndef __KERNEL__ + __u32 inUse; +#endif + +#ifdef CONFIG_YAFFS_WINCE + __u32 win_ctime[2]; + __u32 win_mtime[2]; + __u32 win_atime[2]; +#else + __u32 yst_uid; + __u32 yst_gid; + __u32 yst_atime; + __u32 yst_mtime; + __u32 yst_ctime; +#endif + + __u32 yst_rdev; + +#ifdef __KERNEL__ + struct inode *myInode; + +#endif + + yaffs_ObjectType variantType; + + yaffs_ObjectVariant variant; + +}; + +typedef struct yaffs_ObjectStruct yaffs_Object; + +struct yaffs_ObjectList_struct { + yaffs_Object *objects; + struct yaffs_ObjectList_struct *next; +}; + +typedef struct yaffs_ObjectList_struct yaffs_ObjectList; + +typedef struct { + struct list_head list; + int count; +} yaffs_ObjectBucket; + +/*--------------------- Temporary buffers ---------------- + * + * These are chunk-sized working buffers. Each device has a few + */ + +typedef struct { + __u8 *buffer; + int line; /* track from whence this buffer was allocated */ + int maxLine; +} yaffs_TempBuffer; + +/*----------------- Device ---------------------------------*/ + +struct yaffs_DeviceStruct { + struct list_head devList; + const char *name; + + /* Entry parameters set up way early. Yaffs sets up the rest.*/ + int nBytesPerChunk; /* Should be a power of 2 >= 512 */ + int nChunksPerBlock; /* does not need to be a power of 2 */ + int nBytesPerSpare; /* spare area size */ + int startBlock; /* Start block we're allowed to use */ + int endBlock; /* End block we're allowed to use */ + int nReservedBlocks; /* We want this tuneable so that we can reduce */ + /* reserved blocks on NOR and RAM. */ + + int nShortOpCaches; /* If <= 0, then short op caching is disabled, else + * the number of short op caches (don't use too many) + */ + + int useHeaderFileSize; /* Flag to determine if we should use file sizes from the header */ + + int useNANDECC; /* Flag to decide whether or not to use NANDECC */ + + void *genericDevice; /* Pointer to device context + * On an mtd this holds the mtd pointer. + */ + /* NAND access functions (Must be set before calling YAFFS)*/ + + int (*writeChunkToNAND) (struct yaffs_DeviceStruct * dev, + int chunkInNAND, const __u8 * data, + const yaffs_Spare * spare); + int (*readChunkFromNAND) (struct yaffs_DeviceStruct * dev, + int chunkInNAND, __u8 * data, + yaffs_Spare * spare); + int (*eraseBlockInNAND) (struct yaffs_DeviceStruct * dev, + int blockInNAND); + int (*initialiseNAND) (struct yaffs_DeviceStruct * dev); + +#ifdef CONFIG_YAFFS_YAFFS2 + int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct * dev, + int chunkInNAND, const __u8 * data, + const yaffs_ExtendedTags * tags); + int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct * dev, + int chunkInNAND, __u8 * data, + yaffs_ExtendedTags * tags); + int (*markNANDBlockBad) (struct yaffs_DeviceStruct * dev, int blockNo); + int (*queryNANDBlock) (struct yaffs_DeviceStruct * dev, int blockNo, + yaffs_BlockState * state, int *sequenceNumber); +#endif + + int isYaffs2; + + /* The removeObjectCallback function must be supplied by OS flavours that + * need it. The Linux kernel does not use this, but yaffs direct does use + * it to implement the faster readdir + */ + void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj); + + int wideTnodesDisabled; /* Set to disable wide tnodes */ + + + /* End of stuff that must be set before initialisation. */ + + /* Runtime parameters. Set up by YAFFS. */ + + __u16 chunkGroupBits; /* 0 for devices <= 32MB. else log2(nchunks) - 16 */ + __u16 chunkGroupSize; /* == 2^^chunkGroupBits */ + + /* Stuff to support wide tnodes */ + __u32 tnodeWidth; + __u32 tnodeMask; + + +#ifdef __KERNEL__ + + struct semaphore sem; /* Semaphore for waiting on erasure.*/ + struct semaphore grossLock; /* Gross locking semaphore */ + __u8 *spareBuffer; /* For mtdif2 use. Don't know the size of the buffer + * at compile time so we have to allocate it. + */ + void (*putSuperFunc) (struct super_block * sb); +#endif + + int isMounted; + + /* Stuff to support block offsetting to support start block zero */ + int internalStartBlock; + int internalEndBlock; + int blockOffset; + int chunkOffset; + + /* Block Info */ + yaffs_BlockInfo *blockInfo; + __u8 *chunkBits; /* bitmap of chunks in use */ + unsigned blockInfoAlt:1; /* was allocated using alternative strategy */ + unsigned chunkBitsAlt:1; /* was allocated using alternative strategy */ + int chunkBitmapStride; /* Number of bytes of chunkBits per block. + * Must be consistent with nChunksPerBlock. + */ + + int nErasedBlocks; + int allocationBlock; /* Current block being allocated off */ + __u32 allocationPage; + int allocationBlockFinder; /* Used to search for next allocation block */ + + /* Runtime state */ + int nTnodesCreated; + yaffs_Tnode *freeTnodes; + int nFreeTnodes; + yaffs_TnodeList *allocatedTnodeList; + + int isDoingGC; + + int nObjectsCreated; + yaffs_Object *freeObjects; + int nFreeObjects; + + yaffs_ObjectList *allocatedObjectList; + + yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS]; + + int nFreeChunks; + + int currentDirtyChecker; /* Used to find current dirtiest block */ + + __u32 *gcCleanupList; /* objects to delete at the end of a GC. */ + + /* Statistcs */ + int nPageWrites; + int nPageReads; + int nBlockErasures; + int nErasureFailures; + int nGCCopies; + int garbageCollections; + int passiveGarbageCollections; + int nRetriedWrites; + int nRetiredBlocks; + int eccFixed; + int eccUnfixed; + int tagsEccFixed; + int tagsEccUnfixed; + int nDeletions; + int nUnmarkedDeletions; + + /* Special directories */ + yaffs_Object *rootDir; + yaffs_Object *lostNFoundDir; + + /* Buffer areas for storing data to recover from write failures TODO + * __u8 bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK]; + * yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK]; + */ + + int bufferedBlock; /* Which block is buffered here? */ + int doingBufferedBlockRewrite; + + yaffs_ChunkCache *srCache; + int srLastUse; + + int cacheHits; + + /* Stuff for background deletion and unlinked files.*/ + yaffs_Object *unlinkedDir; /* Directory where unlinked and deleted files live. */ + yaffs_Object *deletedDir; /* Directory where deleted objects are sent to disappear. */ + yaffs_Object *unlinkedDeletion; /* Current file being background deleted.*/ + int nDeletedFiles; /* Count of files awaiting deletion;*/ + int nUnlinkedFiles; /* Count of unlinked files. */ + int nBackgroundDeletions; /* Count of background deletions. */ + + + yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS]; + int maxTemp; + int unmanagedTempAllocations; + int unmanagedTempDeallocations; + + /* yaffs2 runtime stuff */ + unsigned sequenceNumber; /* Sequence number of currently allocating block */ + unsigned oldestDirtySequence; + +}; + +typedef struct yaffs_DeviceStruct yaffs_Device; + +/* Function to manipulate block info */ +static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk) +{ + if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR), + blk)); + YBUG(); + } + return &dev->blockInfo[blk - dev->internalStartBlock]; +} + +/*----------------------- YAFFS Functions -----------------------*/ + +int yaffs_GutsInitialise(yaffs_Device * dev); +void yaffs_Deinitialise(yaffs_Device * dev); + +void yaffs_FlushEntireDeviceCache(yaffs_Device *dev); + +int yaffs_GetNumberOfFreeChunks(yaffs_Device * dev); + +int yaffs_RenameObject(yaffs_Object * oldDir, const YCHAR * oldName, + yaffs_Object * newDir, const YCHAR * newName); + +int yaffs_Unlink(yaffs_Object * dir, const YCHAR * name); +int yaffs_DeleteFile(yaffs_Object * obj); + +int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize); +int yaffs_GetObjectFileLength(yaffs_Object * obj); +int yaffs_GetObjectInode(yaffs_Object * obj); +unsigned yaffs_GetObjectType(yaffs_Object * obj); +int yaffs_GetObjectLinkCount(yaffs_Object * obj); + +int yaffs_SetAttributes(yaffs_Object * obj, struct iattr *attr); +int yaffs_GetAttributes(yaffs_Object * obj, struct iattr *attr); + +/* File operations */ +int yaffs_ReadDataFromFile(yaffs_Object * obj, __u8 * buffer, __u32 offset, + int nBytes); +int yaffs_WriteDataToFile(yaffs_Object * obj, const __u8 * buffer, __u32 offset, + int nBytes, int writeThrough); +int yaffs_ResizeFile(yaffs_Object * obj, int newSize); + +yaffs_Object *yaffs_MknodFile(yaffs_Object * parent, const YCHAR * name, + __u32 mode, __u32 uid, __u32 gid); +int yaffs_FlushFile(yaffs_Object * obj, int updateTime); + +/* Directory operations */ +yaffs_Object *yaffs_MknodDirectory(yaffs_Object * parent, const YCHAR * name, + __u32 mode, __u32 uid, __u32 gid); +yaffs_Object *yaffs_FindObjectByName(yaffs_Object * theDir, const YCHAR * name); +int yaffs_ApplyToDirectoryChildren(yaffs_Object * theDir, + int (*fn) (yaffs_Object *)); + +yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device * dev, __u32 number); + +/* Link operations */ +yaffs_Object *yaffs_Link(yaffs_Object * parent, const YCHAR * name, + yaffs_Object * equivalentObject); + +yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object * obj); + +/* Symlink operations */ +yaffs_Object *yaffs_MknodSymLink(yaffs_Object * parent, const YCHAR * name, + __u32 mode, __u32 uid, __u32 gid, + const YCHAR * alias); +YCHAR *yaffs_GetSymlinkAlias(yaffs_Object * obj); + +/* Special inodes (fifos, sockets and devices) */ +yaffs_Object *yaffs_MknodSpecial(yaffs_Object * parent, const YCHAR * name, + __u32 mode, __u32 uid, __u32 gid, __u32 rdev); + +/* Special directories */ +yaffs_Object *yaffs_Root(yaffs_Device * dev); +yaffs_Object *yaffs_LostNFound(yaffs_Device * dev); + +#ifdef CONFIG_YAFFS_WINCE +/* CONFIG_YAFFS_WINCE special stuff */ +void yfsd_WinFileTimeNow(__u32 target[2]); +#endif + +#ifdef __KERNEL__ + +void yaffs_HandleDeferedFree(yaffs_Object * obj); +#endif + +/* Debug dump */ +int yaffs_DumpObject(yaffs_Object * obj); + +void yaffs_GutsTest(yaffs_Device * dev); + +/* A few useful functions */ +void yaffs_InitialiseTags(yaffs_ExtendedTags * tags); +void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn); +int yaffs_CheckFF(__u8 * buffer, int nBytes); + +#endif Index: config/platform/host/ltib.preconfig =================================================================== --- config/platform/host/ltib.preconfig (revision 8401) +++ config/platform/host/ltib.preconfig (working copy) @@ -377,7 +377,7 @@ # CONFIG_PKG_XORG_X11_XKB_UTILS is not set # CONFIG_PKG_XORG_X11_TWM is not set # CONFIG_PKG_XTERM is not set -# CONFIG_PKG_YAFFS_UTILS is not set +CONFIG_PKG_YAFFS_UTILS=y # CONFIG_PKG_ZAPTEL is not set # CONFIG_PKG_ZLIB is not set