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