yaffs2: Yaffs endian support
authorCharles Manning <cdhmanning@gmail.com>
Sat, 2 Jul 2016 00:11:34 +0000 (12:11 +1200)
committerCharles Manning <cdhmanning@gmail.com>
Thu, 7 Jul 2016 04:40:41 +0000 (16:40 +1200)
Allow the forcing of endians so that Yaffs can be used on mixed endian
machines, or a flash image can be extracted and used elsewhere.

Signed-off-by: Charles Manning <cdhmanning@gmail.com>
22 files changed:
Makefile
direct/handle_common.sh
direct/test-framework/FrameworkRules.mk
direct/test-framework/yaffs_nandsim_file.c
direct/test-framework/yaffs_ramem2k.c
direct/yportenv.h
yaffs_attribs.c
yaffs_checkptrw.c
yaffs_endian.c [new file with mode: 0644]
yaffs_endian.h [new file with mode: 0644]
yaffs_guts.c
yaffs_guts.h
yaffs_nameval.c
yaffs_nameval.h
yaffs_packedtags1.c
yaffs_packedtags2.c
yaffs_packedtags2.h
yaffs_summary.c
yaffs_tagscompat.c
yaffs_tagsmarshall.c
yaffs_yaffs1.c
yaffs_yaffs2.c

index a346458..c82fdbd 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -39,6 +39,7 @@ ifneq ($(KERNELRELEASE),)
        yaffs2-objs += yaffs_yaffs1.o
        yaffs2-objs += yaffs_yaffs2.o
        yaffs2-objs += yaffs_verify.o
+       yaffs2-objs += yaffs_endian.o
        yaffs2-objs += yaffs_summary.o
 
        yaffs2multi-objs := yaffs_mtdif_multi.o
@@ -53,6 +54,7 @@ ifneq ($(KERNELRELEASE),)
        yaffs2multi-objs += yaffs_yaffs1.o
        yaffs2multi-objs += yaffs_yaffs2.o
        yaffs2multi-objs += yaffs_verify.o
+       yaffs2multi-objs += yaffs_endian.o
        yaffs2multi-objs += yaffs_summary.o
 
 else
index 2b5a043..1da0c75 100755 (executable)
@@ -14,6 +14,7 @@ YAFFS_COMMON_SOURCES="\
           yaffs_yaffs1.c yaffs_yaffs1.h \
           yaffs_yaffs2.c yaffs_yaffs2.h \
           yaffs_bitmap.c yaffs_bitmap.h \
+          yaffs_endian.c yaffs_endian.h \
           yaffs_verify.c yaffs_verify.h \
           yaffs_summary.c yaffs_summary.h \
           "
index 5f77f99..e33cde5 100644 (file)
@@ -35,6 +35,7 @@ COMMONTESTOBJS = yaffscfg2k.o yaffs_osglue.o yaffs_hweight.o yaffs_error.o\
                 yaffs_tagscompat.o yaffs_tagsmarshall.o \
                 yaffs_packedtags2.o yaffs_nand.o \
                 yaffs_checkptrw.o  \
+                yaffs_endian.o \
                 yaffs_nameval.o yaffs_attribs.o \
                 yaffs_m18_drv.o  yaffs_nor_drv.o ynorsim.o \
                 yaffs_nand_drv.o \
@@ -59,6 +60,7 @@ YAFFSDIRECTSYMLINKS =  \
           yaffs_attribs.c \
           yportenv.h \
           yaffs_hweight.c yaffs_hweight.h \
+          yaffs_endian.c yaffs_endian.h \
          yaffs_error.c \
           yaffs_ecc.c yaffs_ecc.h yaffs_guts.c yaffs_guts.h \
           yaffs_tagscompat.c yaffs_tagscompat.h \
index 3beac5a..16e69a0 100644 (file)
@@ -54,7 +54,7 @@ struct yaffs_dev *yaffs_nandsim_install_drv(const char *dev_name,
        param->is_yaffs2 = 1;
        param->use_nand_ecc = 1;
        param->n_caches = 10;
-       /* param->hide_lost_n_found = 1; */
+       param->stored_endian = 2;
 
        if(yaffs_nand_install_drv(dev, chip) != YAFFS_OK)
                goto fail;
index 715ae77..cfb0f4f 100644 (file)
@@ -49,7 +49,7 @@
 #define BLOCKS_PER_MEG ((1<<20)/(PAGES_PER_BLOCK * PAGE_DATA_SIZE))
 
 
-typedef struct 
+typedef struct
 {
        u8 data[PAGE_TOTAL_SIZE]; // Data + spare
        int empty;      // is this empty?
@@ -59,7 +59,7 @@ typedef struct
 typedef struct
 {
        nandemul_Page *page[PAGES_PER_BLOCK];
-       int damaged;    
+       int damaged;
 } nandemul_Block;
 
 
@@ -87,16 +87,16 @@ static void nandemul_yield(int n)
 static void nandemul_ReallyEraseBlock(int blockNumber)
 {
        int i;
-       
+
        nandemul_Block *blk;
-       
+
        if(blockNumber < 0 || blockNumber >= ned.nBlocks)
        {
                return;
        }
-       
+
        blk = ned.block[blockNumber];
-       
+
        for(i = 0; i < PAGES_PER_BLOCK; i++)
        {
                memset(blk->page[i],0xff,sizeof(nandemul_Page));
@@ -116,40 +116,40 @@ static int nandemul2k_CalcNBlocks(void)
 static int  CheckInit(void)
 {
        static int initialised = 0;
-       
+
        int i,j;
-       
+
        int fail = 0;
-       int nBlocks; 
+       int nBlocks;
 
        int nAllocated = 0;
-       
-       if(initialised) 
+
+       if(initialised)
        {
                return YAFFS_OK;
        }
-       
-       
+
+
        ned.nBlocks = nBlocks = nandemul2k_CalcNBlocks();
 
-       
+
        ned.block = malloc(sizeof(nandemul_Block*) * nBlocks );
-       
+
        if(!ned.block) return YAFFS_FAIL;
-       
-       
-       
 
-               
+
+
+
+
        for(i=fail=0; i <nBlocks; i++)
        {
-               
+
                nandemul_Block *blk;
-               
+
                if(!(blk = ned.block[i] = malloc(sizeof(nandemul_Block))))
                {
                 fail = 1;
-               }  
+               }
                else
                {
                        for(j = 0; j < PAGES_PER_BLOCK; j++)
@@ -164,27 +164,27 @@ static int  CheckInit(void)
                        nAllocated++;
                }
        }
-       
+
        if(fail)
        {
                //Todo thump pages
-               
+
                for(i = 0; i < nAllocated; i++)
                {
                        kfree(ned.block[i]);
                }
                kfree(ned.block);
-               
+
                yaffs_trace(YAFFS_TRACE_ALWAYS,
                        "Allocation failed, could only allocate %dMB of %dMB requested.\n",
                        nAllocated/64,sizeInMB);
                return 0;
        }
-       
+
        ned.nBlocks = nBlocks;
-       
+
        initialised = 1;
-       
+
        return 1;
 }
 
@@ -193,18 +193,18 @@ int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_dev *dev,int nand_chunk,con
        int blk;
        int pg;
        int i;
-       
+
        u8 *x;
 
-       
+
        blk = nand_chunk/PAGES_PER_BLOCK;
        pg = nand_chunk%PAGES_PER_BLOCK;
-       
-       
+
+
        if(data)
        {
                x = ned.block[blk]->page[pg]->data;
-               
+
                for(i = 0; i < PAGE_DATA_SIZE; i++)
                {
                        x[i] &=data[i];
@@ -212,16 +212,16 @@ int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_dev *dev,int nand_chunk,con
 
                ned.block[blk]->page[pg]->empty = 0;
        }
-       
-       
+
+
        if(tags)
        {
                x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE];
-               
-               yaffs_pack_tags2((struct yaffs_packed_tags2 *)x,tags, !dev->param.no_tags_ecc);
-                       
+
+               yaffs_pack_tags2(dev, (struct yaffs_packed_tags2 *)x,tags, !dev->param.no_tags_ecc);
+
        }
-       
+
        if(tags || data)
        {
                nandemul_yield(1);
@@ -235,26 +235,26 @@ int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev,int nand_chunk, u
 {
        int blk;
        int pg;
-       
+
        u8 *x;
 
-       
-       
+
+
        blk = nand_chunk/PAGES_PER_BLOCK;
        pg = nand_chunk%PAGES_PER_BLOCK;
-       
-       
+
+
        if(data)
        {
                memcpy(data,ned.block[blk]->page[pg]->data,PAGE_DATA_SIZE);
        }
-       
-       
+
+
        if(tags)
        {
                x = &ned.block[blk]->page[pg]->data[PAGE_DATA_SIZE];
-               
-               yaffs_unpack_tags2(tags,(struct yaffs_packed_tags2 *)x, !dev->param.no_tags_ecc);
+
+               yaffs_unpack_tags2(dev, tags,(struct yaffs_packed_tags2 *)x, !dev->param.no_tags_ecc);
        }
 
        return YAFFS_OK;
@@ -267,12 +267,12 @@ static int nandemul2k_CheckChunkErased(struct yaffs_dev *dev,int nand_chunk)
        int pg;
        int i;
 
-       
-       
+
+
        blk = nand_chunk/PAGES_PER_BLOCK;
        pg = nand_chunk%PAGES_PER_BLOCK;
-       
-       
+
+
        for(i = 0; i < PAGE_TOTAL_SIZE; i++)
        {
                if(ned.block[blk]->page[pg]->data[i] != 0xFF)
@@ -287,8 +287,8 @@ static int nandemul2k_CheckChunkErased(struct yaffs_dev *dev,int nand_chunk)
 
 int nandemul2k_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
 {
-       
-       
+
+
        if(blockNumber < 0 || blockNumber >= ned.nBlocks)
        {
                yaffs_trace(YAFFS_TRACE_ALWAYS,
@@ -305,7 +305,7 @@ int nandemul2k_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber)
        {
                nandemul_ReallyEraseBlock(blockNumber);
        }
-       
+
        return YAFFS_OK;
 }
 
@@ -314,19 +314,19 @@ int nandemul2k_InitialiseNAND(struct yaffs_dev *dev)
        CheckInit();
        return YAFFS_OK;
 }
+
 int nandemul2k_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no)
 {
-       
+
        u8 *x;
-       
+
        x = &ned.block[block_no]->page[0]->data[PAGE_DATA_SIZE];
-       
+
        memset(x,0,sizeof(struct yaffs_packed_tags2));
-       
-       
+
+
        return YAFFS_OK;
-       
+
 }
 
 int nandemul2k_QueryNANDBlock(struct yaffs_dev *dev, int block_no, enum yaffs_block_state *state, u32  *seq_number)
@@ -335,9 +335,9 @@ int nandemul2k_QueryNANDBlock(struct yaffs_dev *dev, int block_no, enum yaffs_bl
        int chunkNo;
 
        *seq_number = 0;
-       
+
        chunkNo = block_no * dev->param.chunks_per_block;
-       
+
        nandemul2k_ReadChunkWithTagsFromNAND(dev,chunkNo,NULL,&tags);
        if(tags.block_bad)
        {
index 5b7d188..81da08e 100644 (file)
@@ -23,6 +23,7 @@
 typedef unsigned char u8;
 typedef unsigned short u16;
 typedef unsigned int u32;
+typedef unsigned long long u64;
 typedef signed int s32;
 #endif
 
index 711941f..5eb7c5a 100644 (file)
 #define IATTR_GID ia_gid.val
 #endif
 
+/*
+ * Loading attibs from/to object header assumes the object header
+ * is in cpu endian.
+ */
 void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
 {
        obj->yst_uid = oh->yst_uid;
index 16ee1e0..59ca34a 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "yaffs_checkptrw.h"
 #include "yaffs_getblockinfo.h"
+#include "yaffs_endian.h"
 
 struct yaffs_checkpt_chunk_hdr {
        int version;
@@ -32,6 +33,18 @@ static int apply_block_offset(struct yaffs_dev *dev, int block)
        return block - dev->block_offset;
 }
 
+
+static void yaffs2_do_endian_hdr(struct yaffs_dev *dev,
+                                struct yaffs_checkpt_chunk_hdr *hdr)
+{
+       if (!dev->swap_endian)
+               return;
+       hdr->version = swap_s32(hdr->version);
+       hdr->seq     = swap_s32(hdr->seq);
+       hdr->sum     = swap_u32(hdr->sum);
+       hdr->xor     = swap_u32(hdr->xor);
+}
+
 static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
 {
        struct yaffs_checkpt_chunk_hdr hdr;
@@ -43,6 +56,7 @@ static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
 
        dev->checkpt_byte_offs = sizeof(hdr);
 
+       yaffs2_do_endian_hdr(dev, &hdr);
        memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
 }
 
@@ -51,6 +65,7 @@ static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
        struct yaffs_checkpt_chunk_hdr hdr;
 
        memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
+       yaffs2_do_endian_hdr(dev, &hdr);
 
        dev->checkpt_byte_offs = sizeof(hdr);
 
diff --git a/yaffs_endian.c b/yaffs_endian.c
new file mode 100644 (file)
index 0000000..0bc67fe
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ *
+ * Endian processing functions.
+ */
+
+#include "yaffs_endian.h"
+#include "yaffs_guts.h"
+
+
+void yaffs_do_endian_u32(struct yaffs_dev *dev, u32 *val)
+{
+       if (!dev->swap_endian)
+               return;
+       *val = swap_u32(*val);
+}
+
+void yaffs_do_endian_s32(struct yaffs_dev *dev, s32 *val)
+{
+       if (!dev->swap_endian)
+               return;
+       *val = swap_s32(*val);
+}
+
+void yaffs_do_endian_oh(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh)
+{
+       if (!dev->swap_endian)
+               return;
+       /* Change every field */
+       oh->type = swap_u32(oh->type);
+       oh->parent_obj_id = swap_s32(oh->parent_obj_id);
+
+       oh->yst_mode = swap_u32(oh->yst_mode);
+
+       oh->yst_uid = swap_u32(oh->yst_uid);
+       oh->yst_gid = swap_u32(oh->yst_gid);
+       oh->yst_atime = swap_u32(oh->yst_atime);
+       oh->yst_mtime = swap_u32(oh->yst_mtime);
+       oh->yst_ctime = swap_u32(oh->yst_ctime);
+
+       oh->file_size_low = swap_u32(oh->file_size_low);
+
+       oh->equiv_id = swap_u32(oh->equiv_id);
+
+       oh->yst_rdev = swap_u32(oh->yst_rdev);
+
+       oh->win_ctime[0] = swap_u32(oh->win_ctime[0]);
+       oh->win_ctime[1] = swap_u32(oh->win_ctime[1]);
+       oh->win_atime[0] = swap_u32(oh->win_atime[0]);
+       oh->win_atime[1] = swap_u32(oh->win_atime[1]);
+       oh->win_mtime[0] = swap_u32(oh->win_mtime[0]);
+       oh->win_mtime[1] = swap_u32(oh->win_mtime[1]);
+
+       oh->inband_shadowed_obj_id = swap_u32(oh->inband_shadowed_obj_id);
+       oh->inband_is_shrink = swap_u32(oh->inband_is_shrink);
+
+       oh->file_size_high = swap_u32(oh->file_size_high);
+       oh->reserved[0] = swap_u32(oh->reserved[0]);
+       oh->shadows_obj = swap_s32(oh->shadows_obj);
+
+       oh->is_shrink = swap_u32(oh->is_shrink);
+}
+
+
+void yaffs_do_endian_packed_tags2(struct yaffs_dev *dev,
+                               struct yaffs_packed_tags2_tags_only *ptt)
+{
+       if (!dev->swap_endian)
+               return;
+       ptt->seq_number = swap_u32(ptt->seq_number);
+       ptt->obj_id = swap_u32(ptt->obj_id);
+       ptt->chunk_id = swap_u32(ptt->chunk_id);
+       ptt->n_bytes = swap_u32(ptt->n_bytes);
+}
+
+void yaffs_endian_config(struct yaffs_dev *dev)
+{
+       u32 x = 1;
+
+       if (dev->tnode_size < 1)
+               BUG();
+
+       dev->swap_endian = 0;
+
+       if (((char *)&x)[0] == 1) {
+               /* Little Endian. */
+               if (dev->param.stored_endian == 2 /* big endian */)
+                       dev->swap_endian = 1;
+       } else  {
+               /* Big Endian. */
+               if (dev->param.stored_endian == 1 /* little endian */)
+                       dev->swap_endian = 1;
+       }
+
+       if (dev->swap_endian)
+               dev->tn_swap_buffer = kmalloc(dev->tnode_size, GFP_NOFS);
+}
diff --git a/yaffs_endian.h b/yaffs_endian.h
new file mode 100644 (file)
index 0000000..d37bc50
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2011 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+#ifndef __YAFFS_ENDIAN_H__
+#define __YAFFS_ENDIAN_H__
+#include "yaffs_guts.h"
+#include "yaffs_packedtags2.h"
+
+static inline u32 swap_u32(u32 val)
+{
+       return ((val >>24) & 0x000000ff) |
+              ((val >> 8) & 0x0000ff00) |
+              ((val << 8) & 0x00ff0000) |
+              ((val <<24) & 0xff000000);
+}
+
+#define swap_s32(val) \
+       (s32)(swap_u32((u32)(val)))
+
+static inline Y_LOFF_T swap_loff_t(Y_LOFF_T lval)
+{
+       u32 vall = swap_u32((u32) (lval & 0xffffffff));
+       u32 valh;
+
+       if (sizeof(Y_LOFF_T) == sizeof(u32))
+               return (Y_LOFF_T) vall;
+
+       valh = swap_u32((u32) ((lval >> 32) & 0xffffffff));
+
+       return (Y_LOFF_T)((((u64)vall) << 32) | valh);
+}
+
+void yaffs_do_endian_s32(struct yaffs_dev *dev, s32 *val);
+void yaffs_do_endian_u32(struct yaffs_dev *dev, u32 *val);
+void yaffs_do_endian_oh(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh);
+void yaffs_do_endian_packed_tags2(struct yaffs_dev *dev,
+                               struct yaffs_packed_tags2_tags_only *ptt);
+void yaffs_endian_config(struct yaffs_dev *dev);
+
+#endif
index c89b29c..72555d5 100644 (file)
@@ -15,6 +15,7 @@
 #include "yaffs_trace.h"
 
 #include "yaffs_guts.h"
+#include "yaffs_endian.h"
 #include "yaffs_getblockinfo.h"
 #include "yaffs_tagscompat.h"
 #include "yaffs_tagsmarshall.h"
@@ -755,7 +756,7 @@ void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
 
 loff_t yaffs_max_file_size(struct yaffs_dev *dev)
 {
-       if(sizeof(loff_t) < 8)
+       if (sizeof(loff_t) < 8)
                return YAFFS_MAX_FILE_SIZE_32;
        else
                return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
@@ -2529,12 +2530,14 @@ static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
 
                if (tags.chunk_id == 0) {
                        /* It is an object Id,
-                        * We need to nuke the
-                        * shrinkheader flags since its
+                        * We need to nuke the shrinkheader flags since its
                         * work is done.
-                        * Also need to clean up
-                        * shadowing.
+                        * Also need to clean up shadowing.
+                        * NB We don't want to do all the work of translating
+                        * object header endianism back and forth so we leave
+                        * the oh endian in its stored order.
                         */
+
                        struct yaffs_obj_hdr *oh;
                        oh = (struct yaffs_obj_hdr *) buffer;
 
@@ -2546,8 +2549,8 @@ static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
 
                        /* Update file size */
                        if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
-                               yaffs_oh_size_load(oh,
-                                   object->variant.file_variant.stored_size);
+                               yaffs_oh_size_load(dev, oh,
+                                   object->variant.file_variant.stored_size, 1);
                                tags.extra_file_size =
                                    object->variant.file_variant.stored_size;
                        }
@@ -3139,12 +3142,12 @@ static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
 
        if (xmod->set)
                retval =
-                   nval_set(x_buffer, x_size, xmod->name, xmod->data,
+                   nval_set(dev, x_buffer, x_size, xmod->name, xmod->data,
                             xmod->size, xmod->flags);
        else
-               retval = nval_del(x_buffer, x_size, xmod->name);
+               retval = nval_del(dev, x_buffer, x_size, xmod->name);
 
-       obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+       obj->has_xattr = nval_hasvalues(dev, x_buffer, x_size);
        obj->xattr_known = 1;
        xmod->result = retval;
 
@@ -3189,14 +3192,15 @@ static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
                x_buffer = buffer + x_offs;
 
                if (!obj->xattr_known) {
-                       obj->has_xattr = nval_hasvalues(x_buffer, x_size);
+                       obj->has_xattr = nval_hasvalues(dev, x_buffer, x_size);
                        obj->xattr_known = 1;
                }
 
                if (name)
-                       retval = nval_get(x_buffer, x_size, name, value, size);
+                       retval = nval_get(dev, x_buffer, x_size,
+                                               name, value, size);
                else
-                       retval = nval_list(x_buffer, x_size, value, size);
+                       retval = nval_list(dev, x_buffer, x_size, value, size);
        }
        yaffs_release_temp_buffer(dev, (u8 *) buffer);
        return retval;
@@ -3243,6 +3247,8 @@ static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
        result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
        oh = (struct yaffs_obj_hdr *)buf;
 
+       yaffs_do_endian_oh(dev, oh);
+
        in->yst_mode = oh->yst_mode;
        yaffs_load_attribs(in, oh);
        yaffs_set_obj_name_from_oh(in, oh);
@@ -3258,7 +3264,18 @@ static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
 
 /* UpdateObjectHeader updates the header on NAND for an object.
  * If name is not NULL, then that new name is used.
+ *
+ * We're always creating the obj header from scratch (except reading
+ * the old name) so first set up in cpu endianness then run it through
+ * endian fixing at the end.
+ *
+ * However, a twist: If there are xattribs we leave them as they were.
+ *
+ * Careful! The buffer holds the whole chunk. Part of the chunk holds the
+ * object header and the rest holds the xattribs, therefore we use a buffer
+ * pointer and an oh pointer to point to the same memory.
  */
+
 int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
                    int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
 {
@@ -3291,12 +3308,18 @@ int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
        prev_chunk_id = in->hdr_chunk;
 
        if (prev_chunk_id > 0) {
+               /* Access the old obj header just to read the name. */
                result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
                                                  buffer, &old_tags);
 
                yaffs_verify_oh(in, oh, &old_tags, 0);
                memcpy(old_name, oh->name, sizeof(oh->name));
-               memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
+
+               /*
+                * NB We only wipe the object header area because the rest of
+                * the buffer might contain xattribs.
+                */
+               memset(oh, 0xff, sizeof(*oh));
        } else {
                memset(buffer, 0xff, dev->data_bytes_per_chunk);
        }
@@ -3331,7 +3354,7 @@ int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
                if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
                    oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
                        file_size = in->variant.file_variant.stored_size;
-               yaffs_oh_size_load(oh, file_size);
+               yaffs_oh_size_load(dev, oh, file_size, 0);
                break;
        case YAFFS_OBJECT_TYPE_HARDLINK:
                oh->equiv_id = in->variant.hardlink_variant.equiv_id;
@@ -3370,6 +3393,10 @@ int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
        new_tags.extra_equiv_id = oh->equiv_id;
        new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
        new_tags.extra_obj_type = in->variant_type;
+
+       /* Now endian swizzle the oh if needed. */
+       yaffs_do_endian_oh(dev, oh);
+
        yaffs_verify_oh(in, oh, &new_tags, 1);
 
        /* Create new chunk in NAND */
@@ -4872,12 +4899,14 @@ int yaffs_guts_initialise(struct yaffs_dev *dev)
        dev->n_erase_failures = 0;
        dev->n_erased_blocks = 0;
        dev->gc_disable = 0;
-       dev->has_pending_prioritised_gc = 1;
-               /* Assume the worst for now, will get fixed on first GC */
+       dev->has_pending_prioritised_gc = 1; /* Assume the worst for now,
+                                             * will get fixed on first GC */
        INIT_LIST_HEAD(&dev->dirty_dirs);
        dev->oldest_dirty_seq = 0;
        dev->oldest_dirty_block = 0;
 
+       yaffs_endian_config(dev);
+
        /* Initialise temporary buffers and caches. */
        if (!yaffs_init_tmp_buffers(dev))
                init_failed = 1;
@@ -5116,26 +5145,47 @@ int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
 }
 
 
-
 /*
  * Marshalling functions to get loff_t file sizes into and out of
  * object headers.
  */
-void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
+void yaffs_oh_size_load(struct yaffs_dev *dev,
+                       struct yaffs_obj_hdr *oh,
+                       loff_t fsize,
+                       int do_endian)
 {
        oh->file_size_low = (fsize & 0xFFFFFFFF);
        oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
+
+       if (do_endian) {
+               yaffs_do_endian_u32(dev, &oh->file_size_low);
+               yaffs_do_endian_u32(dev, &oh->file_size_high);
+       }
 }
 
-loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
+loff_t yaffs_oh_to_size(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh,
+                       int do_endian)
 {
        loff_t retval;
 
-       if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
-               retval = (((loff_t) oh->file_size_high) << 32) |
-                       (((loff_t) oh->file_size_low) & 0xFFFFFFFF);
-       else
-               retval = (loff_t) oh->file_size_low;
+
+       if (sizeof(loff_t) >= 8 && ~(oh->file_size_high)) {
+               u32 low = oh->file_size_low;
+               u32 high = oh->file_size_high;
+
+               if (do_endian) {
+                       yaffs_do_endian_u32 (dev, &low);
+                       yaffs_do_endian_u32 (dev, &high);
+               }
+               retval = (((loff_t) high) << 32) |
+                       (((loff_t) low) & 0xFFFFFFFF);
+       } else {
+               u32 low = oh->file_size_low;
+
+               if (do_endian)
+                       yaffs_do_endian_u32(dev, &low);
+               retval = (loff_t)low;
+       }
 
        return retval;
 }
index b0aca33..c7e201c 100644 (file)
@@ -153,7 +153,8 @@ struct yaffs_tags {
 
 union yaffs_tags_union {
        struct yaffs_tags as_tags;
-       u8 as_bytes[8];
+       u8  as_bytes[8];
+       u32 as_u32[2];
 };
 
 
@@ -311,6 +312,11 @@ struct yaffs_block_info {
 
 };
 
+union yaffs_block_info_union {
+       struct yaffs_block_info bi;
+       u32     as_u32[2];
+};
+
 /* -------------------------- Object structure -------------------------------*/
 /* This is the object structure as stored on NAND */
 
@@ -560,6 +566,8 @@ struct yaffs_param {
 
        int hide_lost_n_found;  /* Set non-zero to hide the lost-n-found dir. */
 
+       int stored_endian; /* 0=cpu endian, 1=little endian, 2=big endian */
+
        /* The remove_obj_fn function must be supplied by OS flavours that
         * need it.
         * yaffs direct uses it to implement the faster readdir.
@@ -644,6 +652,8 @@ struct yaffs_dev {
                                 */
        u16 chunk_grp_size;     /* == 2^^chunk_grp_bits */
 
+       struct yaffs_tnode *tn_swap_buffer;
+
        /* Stuff to support wide tnodes */
        u32 tnode_width;
        u32 tnode_mask;
@@ -657,6 +667,7 @@ struct yaffs_dev {
        int is_mounted;
        int read_only;
        int is_checkpointed;
+       int swap_endian;        /* Stored endian needs endian swap. */
 
        /* Stuff to support block offsetting to support start block zero */
        int internal_start_block;
@@ -1018,11 +1029,13 @@ int yaffs_guts_format_dev(struct yaffs_dev *dev);
 void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
                                int *chunk_out, u32 *offset_out);
 /*
- * Marshalling functions to get loff_t file sizes into aand out of
+ * Marshalling functions to get loff_t file sizes into and out of
  * object headers.
  */
-void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
-loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
+void yaffs_oh_size_load(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh,
+                       loff_t fsize, int do_endian);
+loff_t yaffs_oh_to_size(struct yaffs_dev *dev, struct yaffs_obj_hdr *oh,
+                       int do_endian);
 loff_t yaffs_max_file_size(struct yaffs_dev *dev);
 
 /*
index 4bdf4ed..478248e 100644 (file)
@@ -16,7 +16,7 @@
 * values and fits into a small finite buffer.
  *
  * Each attribute is stored as a record:
- *  sizeof(int) bytes   record size.
+ *  sizeof(size) bytes   record size.
  *  strnlen+1 bytes name null terminated.
  *  nbytes    value.
  *  ----------
  */
 
 #include "yaffs_nameval.h"
-
+#include "yaffs_guts.h"
 #include "yportenv.h"
 
-static int nval_find(const char *xb, int xb_size, const YCHAR *name,
+static int nval_find(struct yaffs_dev *dev,
+                    const char *xb, int xb_size, const YCHAR *name,
                     int *exist_size)
 {
        int pos = 0;
-       int size;
+       s32 size;
+
+       memcpy(&size, xb, sizeof(size));
+       yaffs_do_endian_s32(dev, &size);
 
-       memcpy(&size, xb, sizeof(int));
        while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
-               if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
+               if (!strncmp((YCHAR *) (xb + pos + sizeof(size)),
                                name, size)) {
                        if (exist_size)
                                *exist_size = size;
                        return pos;
                }
                pos += size;
-               if (pos < xb_size - sizeof(int))
-                       memcpy(&size, xb + pos, sizeof(int));
-               else
+               if (pos < xb_size - sizeof(size)) {
+                       memcpy(&size, xb + pos, sizeof(size));
+                       yaffs_do_endian_s32(dev, &size);
+
+               } else
                        size = 0;
        }
        if (exist_size)
@@ -54,89 +59,101 @@ static int nval_find(const char *xb, int xb_size, const YCHAR *name,
        return -ENODATA;
 }
 
-static int nval_used(const char *xb, int xb_size)
+static int nval_used(struct yaffs_dev *dev, const char *xb, int xb_size)
 {
        int pos = 0;
-       int size;
+       s32 size;
+
+       memcpy(&size, xb + pos, sizeof(size));
+       yaffs_do_endian_s32(dev, &size);
 
-       memcpy(&size, xb + pos, sizeof(int));
        while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
                pos += size;
-               if (pos < xb_size - sizeof(int))
-                       memcpy(&size, xb + pos, sizeof(int));
-               else
+               if (pos < xb_size - sizeof(size)) {
+                       memcpy(&size, xb + pos, sizeof(size));
+                       yaffs_do_endian_s32(dev, &size);
+               } else
                        size = 0;
        }
        return pos;
 }
 
-int nval_del(char *xb, int xb_size, const YCHAR *name)
+int nval_del(struct yaffs_dev *dev, char *xb, int xb_size, const YCHAR *name)
 {
-       int pos = nval_find(xb, xb_size, name, NULL);
-       int size;
+       int pos = nval_find(dev, xb, xb_size, name, NULL);
+       s32 size;
 
        if (pos < 0 || pos >= xb_size)
                return -ENODATA;
 
        /* Find size, shift rest over this record,
         * then zero out the rest of buffer */
-       memcpy(&size, xb + pos, sizeof(int));
+       memcpy(&size, xb + pos, sizeof(size));
+       yaffs_do_endian_s32(dev, &size);
+
        memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
        memset(xb + (xb_size - size), 0, size);
        return 0;
 }
 
-int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
-               int bsize, int flags)
+int nval_set(struct yaffs_dev *dev,
+            char *xb, int xb_size, const YCHAR *name, const char *buf,
+            int bsize, int flags)
 {
        int pos;
        int namelen = strnlen(name, xb_size);
-       int reclen;
        int size_exist = 0;
        int space;
        int start;
+       s32 reclen;
+       s32 reclen_endianised;
 
-       pos = nval_find(xb, xb_size, name, &size_exist);
+       pos = nval_find(dev, xb, xb_size, name, &size_exist);
 
        if (flags & XATTR_CREATE && pos >= 0)
                return -EEXIST;
        if (flags & XATTR_REPLACE && pos < 0)
                return -ENODATA;
 
-       start = nval_used(xb, xb_size);
+       start = nval_used(dev, xb, xb_size);
        space = xb_size - start + size_exist;
 
-       reclen = (sizeof(int) + namelen + 1 + bsize);
+       reclen = (sizeof(reclen) + namelen + 1 + bsize);
 
        if (reclen > space)
                return -ENOSPC;
 
        if (pos >= 0) {
-               nval_del(xb, xb_size, name);
-               start = nval_used(xb, xb_size);
+               /* Exists, so delete it. */
+               nval_del(dev, xb, xb_size, name);
+               start = nval_used(dev, xb, xb_size);
        }
 
        pos = start;
 
-       memcpy(xb + pos, &reclen, sizeof(int));
-       pos += sizeof(int);
+       reclen_endianised = reclen;
+       yaffs_do_endian_s32(dev, &reclen_endianised);
+       memcpy(xb + pos, &reclen_endianised, sizeof(reclen_endianised));
+       pos += sizeof(reclen_endianised);
        strncpy((YCHAR *) (xb + pos), name, reclen);
        pos += (namelen + 1);
        memcpy(xb + pos, buf, bsize);
        return 0;
 }
 
-int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
+int nval_get(struct yaffs_dev *dev,
+            const char *xb, int xb_size, const YCHAR * name, char *buf,
             int bsize)
 {
-       int pos = nval_find(xb, xb_size, name, NULL);
-       int size;
+       int pos = nval_find(dev, xb, xb_size, name, NULL);
+       s32 size;
 
        if (pos >= 0 && pos < xb_size) {
 
-               memcpy(&size, xb + pos, sizeof(int));
-               pos += sizeof(int);     /* advance past record length */
-               size -= sizeof(int);
+               memcpy(&size, xb + pos, sizeof(size));
+               yaffs_do_endian_s32(dev, &size);
+               pos += sizeof(size);    /* advance past record length */
+               size -= sizeof(size);
 
                /* Advance over name string */
                while (xb[pos] && size > 0 && pos < xb_size) {
@@ -164,21 +181,23 @@ int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
        return -ENODATA;
 }
 
-int nval_list(const char *xb, int xb_size, char *buf, int bsize)
+int nval_list(struct yaffs_dev *dev, const char *xb, int xb_size, char *buf, int bsize)
 {
        int pos = 0;
-       int size;
+       s32 size;
        int name_len;
        int ncopied = 0;
        int filled = 0;
 
-       memcpy(&size, xb + pos, sizeof(int));
-       while (size > sizeof(int) &&
+       memcpy(&size, xb + pos, sizeof(size));
+       yaffs_do_endian_s32(dev, &size);
+
+       while (size > sizeof(size) &&
                size <= xb_size &&
                (pos + size) < xb_size &&
                !filled) {
-               pos += sizeof(int);
-               size -= sizeof(int);
+               pos += sizeof(size);
+               size -= sizeof(size);
                name_len = strnlen((YCHAR *) (xb + pos), size);
                if (ncopied + name_len + 1 < bsize) {
                        memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
@@ -194,15 +213,17 @@ int nval_list(const char *xb, int xb_size, char *buf, int bsize)
                        filled = 1;
                }
                pos += size;
-               if (pos < xb_size - sizeof(int))
-                       memcpy(&size, xb + pos, sizeof(int));
+               if (pos < xb_size - sizeof(size)) {
+                       memcpy(&size, xb + pos, sizeof(size));
+                       yaffs_do_endian_s32(dev, &size);
+               }
                else
                        size = 0;
        }
        return ncopied;
 }
 
-int nval_hasvalues(const char *xb, int xb_size)
+int nval_hasvalues(struct yaffs_dev *dev, const char *xb, int xb_size)
 {
-       return nval_used(xb, xb_size) > 0;
+       return nval_used(dev, xb, xb_size) > 0;
 }
index 951e64f..b0bd81c 100644 (file)
 
 #include "yportenv.h"
 
-int nval_del(char *xb, int xb_size, const YCHAR * name);
-int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
+int nval_del(struct yaffs_dev *dev, char *xb, int xb_size, const YCHAR * name);
+int nval_set(struct yaffs_dev *dev,
+            char *xb, int xb_size, const YCHAR * name, const char *buf,
             int bsize, int flags);
-int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
+int nval_get(struct yaffs_dev *dev,
+            const char *xb, int xb_size, const YCHAR * name, char *buf,
             int bsize);
-int nval_list(const char *xb, int xb_size, char *buf, int bsize);
-int nval_hasvalues(const char *xb, int xb_size);
+int nval_list(struct yaffs_dev *dev,
+             const char *xb, int xb_size, char *buf, int bsize);
+int nval_hasvalues(struct yaffs_dev *dev, const char *xb, int xb_size);
 #endif
index dd9a331..0928b8e 100644 (file)
@@ -38,7 +38,6 @@ void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
 void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
                        const struct yaffs_packed_tags1 *pt)
 {
-
        if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
                t->block_bad = 0;
                if (pt->should_be_ff != 0xffffffff)
index e1d18cc..d5291fc 100644 (file)
@@ -14,6 +14,7 @@
 #include "yaffs_packedtags2.h"
 #include "yportenv.h"
 #include "yaffs_trace.h"
+#include "yaffs_endian.h"
 
 /* This code packs a set of extended tags into a binary structure for
  * NAND storage
@@ -72,7 +73,8 @@ static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
        return 1;
 }
 
-void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
+void yaffs_pack_tags2_tags_only(struct yaffs_dev *dev,
+                               struct yaffs_packed_tags2_tags_only *ptt,
                                const struct yaffs_ext_tags *t)
 {
        ptt->chunk_id = t->chunk_id;
@@ -106,12 +108,14 @@ void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
 
        yaffs_dump_packed_tags2_tags_only(ptt);
        yaffs_dump_tags2(t);
+       yaffs_do_endian_packed_tags2(dev, ptt);
 }
 
-void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
+void yaffs_pack_tags2(struct yaffs_dev *dev,
+                     struct yaffs_packed_tags2 *pt,
                      const struct yaffs_ext_tags *t, int tags_ecc)
 {
-       yaffs_pack_tags2_tags_only(&pt->t, t);
+       yaffs_pack_tags2_tags_only(dev, &pt->t, t);
 
        if (tags_ecc)
                yaffs_ecc_calc_other((unsigned char *)&pt->t,
@@ -119,45 +123,52 @@ void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
                                    &pt->ecc);
 }
 
-void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
-                                 struct yaffs_packed_tags2_tags_only *ptt)
+void yaffs_unpack_tags2_tags_only(struct yaffs_dev *dev,
+                                 struct yaffs_ext_tags *t,
+                                 struct yaffs_packed_tags2_tags_only *ptt_ptr)
 {
+       struct yaffs_packed_tags2_tags_only ptt_copy = *ptt_ptr;
+
        memset(t, 0, sizeof(struct yaffs_ext_tags));
 
-       if (ptt->seq_number == 0xffffffff)
+       if (ptt_copy.seq_number == 0xffffffff)
                return;
 
+       yaffs_do_endian_packed_tags2(dev, &ptt_copy);
+
        t->block_bad = 0;
        t->chunk_used = 1;
-       t->obj_id = ptt->obj_id;
-       t->chunk_id = ptt->chunk_id;
-       t->n_bytes = ptt->n_bytes;
+       t->obj_id = ptt_copy.obj_id;
+       t->chunk_id = ptt_copy.chunk_id;
+       t->n_bytes = ptt_copy.n_bytes;
        t->is_deleted = 0;
        t->serial_number = 0;
-       t->seq_number = ptt->seq_number;
+       t->seq_number = ptt_copy.seq_number;
 
        /* Do extra header info stuff */
-       if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
+       if (ptt_copy.chunk_id & EXTRA_HEADER_INFO_FLAG) {
                t->chunk_id = 0;
                t->n_bytes = 0;
 
                t->extra_available = 1;
-               t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
-               t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
-               t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
-               t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
+               t->extra_parent_id = ptt_copy.chunk_id & (~(ALL_EXTRA_FLAGS));
+               t->extra_is_shrink = ptt_copy.chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
+               t->extra_shadows = ptt_copy.chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
+               t->extra_obj_type = ptt_copy.obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
                t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
 
                if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
-                       t->extra_equiv_id = ptt->n_bytes;
+                       t->extra_equiv_id = ptt_copy.n_bytes;
                else
-                       t->extra_file_size = ptt->n_bytes;
+                       t->extra_file_size = ptt_copy.n_bytes;
        }
-       yaffs_dump_packed_tags2_tags_only(ptt);
+       yaffs_dump_packed_tags2_tags_only(ptt_ptr);
        yaffs_dump_tags2(t);
 }
 
-void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
+void yaffs_unpack_tags2(struct yaffs_dev *dev,
+                       struct yaffs_ext_tags *t,
+                       struct yaffs_packed_tags2 *pt,
                        int tags_ecc)
 {
        enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
@@ -188,7 +199,7 @@ void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
                        ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
                }
        }
-       yaffs_unpack_tags2_tags_only(t, &pt->t);
+       yaffs_unpack_tags2_tags_only(dev, t, &pt->t);
 
        t->ecc_result = ecc_result;
 
index 675e719..9cafe0e 100644 (file)
@@ -34,14 +34,18 @@ struct yaffs_packed_tags2 {
 };
 
 /* Full packed tags with ECC, used for oob tags */
-void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
+void yaffs_pack_tags2(struct yaffs_dev *dev,
+                     struct yaffs_packed_tags2 *pt,
                      const struct yaffs_ext_tags *t, int tags_ecc);
-void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
+void yaffs_unpack_tags2(struct yaffs_dev *dev,
+                       struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
                        int tags_ecc);
 
 /* Only the tags part (no ECC for use with inband tags */
-void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
+void yaffs_pack_tags2_tags_only(struct yaffs_dev *dev,
+                               struct yaffs_packed_tags2_tags_only *pt,
                                const struct yaffs_ext_tags *t);
-void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
+void yaffs_unpack_tags2_tags_only(struct yaffs_dev *dev,
+                                 struct yaffs_ext_tags *t,
                                  struct yaffs_packed_tags2_tags_only *pt);
 #endif
index 3c9e723..0250963 100644 (file)
@@ -259,8 +259,9 @@ int yaffs_summary_add(struct yaffs_dev *dev,
                return YAFFS_OK;
 
        if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
-               yaffs_pack_tags2_tags_only(&tags_only, tags);
+               yaffs_pack_tags2_tags_only(dev, &tags_only, tags);
                sum_tags = &dev->sum_tags[chunk_in_block];
+
                sum_tags->chunk_id = tags_only.chunk_id;
                sum_tags->n_bytes = tags_only.n_bytes;
                sum_tags->obj_id = tags_only.obj_id;
@@ -286,7 +287,7 @@ int yaffs_summary_fetch(struct yaffs_dev *dev,
                tags_only.chunk_id = sum_tags->chunk_id;
                tags_only.n_bytes = sum_tags->n_bytes;
                tags_only.obj_id = sum_tags->obj_id;
-               yaffs_unpack_tags2_tags_only(tags, &tags_only);
+               yaffs_unpack_tags2_tags_only(dev, tags, &tags_only);
                return YAFFS_OK;
        }
        return YAFFS_FAIL;
index 092430b..e57c2d3 100644 (file)
@@ -9,6 +9,9 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
+ *
+ * This file handles yaffs1-style tags to allow compatibility with Yaffs1 style
+ * flash layouts.
  */
 
 #include "yaffs_guts.h"
 #include "yaffs_ecc.h"
 #include "yaffs_getblockinfo.h"
 #include "yaffs_trace.h"
+#include "yaffs_endian.h"
 
 static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
 
 
 /********** Tags ECC calculations  *********/
 
-
 void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
 {
        /* Calculate an ecc */
@@ -73,21 +76,30 @@ int yaffs_check_tags_ecc(struct yaffs_tags *tags)
 
 /********** Tags **********/
 
-static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
+/*
+ * During tags storing/retireval we use a copy of the tags so that
+ * we can modify the endian etc without damaging the previous structure.
+ */
+static void yaffs_load_tags_to_spare(struct yaffs_dev *dev,
+                                    struct yaffs_spare *spare_ptr,
                                     struct yaffs_tags *tags_ptr)
 {
-       union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
-
-       yaffs_calc_tags_ecc(tags_ptr);
-
-       spare_ptr->tb0 = tu->as_bytes[0];
-       spare_ptr->tb1 = tu->as_bytes[1];
-       spare_ptr->tb2 = tu->as_bytes[2];
-       spare_ptr->tb3 = tu->as_bytes[3];
-       spare_ptr->tb4 = tu->as_bytes[4];
-       spare_ptr->tb5 = tu->as_bytes[5];
-       spare_ptr->tb6 = tu->as_bytes[6];
-       spare_ptr->tb7 = tu->as_bytes[7];
+       union yaffs_tags_union *tu_ptr = (union yaffs_tags_union *)tags_ptr;
+       union yaffs_tags_union tags_stored = *tu_ptr;
+
+       yaffs_calc_tags_ecc(&tags_stored.as_tags);
+
+       yaffs_do_endian_u32(dev, &tags_stored.as_u32[0]);
+       yaffs_do_endian_u32(dev, &tags_stored.as_u32[1]);
+
+       spare_ptr->tb0 = tags_stored.as_bytes[0];
+       spare_ptr->tb1 = tags_stored.as_bytes[1];
+       spare_ptr->tb2 = tags_stored.as_bytes[2];
+       spare_ptr->tb3 = tags_stored.as_bytes[3];
+       spare_ptr->tb4 = tags_stored.as_bytes[4];
+       spare_ptr->tb5 = tags_stored.as_bytes[5];
+       spare_ptr->tb6 = tags_stored.as_bytes[6];
+       spare_ptr->tb7 = tags_stored.as_bytes[7];
 }
 
 static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
@@ -95,16 +107,22 @@ static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
                                      struct yaffs_tags *tags_ptr)
 {
        union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
+       union yaffs_tags_union tags_stored;
        int result;
 
-       tu->as_bytes[0] = spare_ptr->tb0;
-       tu->as_bytes[1] = spare_ptr->tb1;
-       tu->as_bytes[2] = spare_ptr->tb2;
-       tu->as_bytes[3] = spare_ptr->tb3;
-       tu->as_bytes[4] = spare_ptr->tb4;
-       tu->as_bytes[5] = spare_ptr->tb5;
-       tu->as_bytes[6] = spare_ptr->tb6;
-       tu->as_bytes[7] = spare_ptr->tb7;
+       tags_stored.as_bytes[0] = spare_ptr->tb0;
+       tags_stored.as_bytes[1] = spare_ptr->tb1;
+       tags_stored.as_bytes[2] = spare_ptr->tb2;
+       tags_stored.as_bytes[3] = spare_ptr->tb3;
+       tags_stored.as_bytes[4] = spare_ptr->tb4;
+       tags_stored.as_bytes[5] = spare_ptr->tb5;
+       tags_stored.as_bytes[6] = spare_ptr->tb6;
+       tags_stored.as_bytes[7] = spare_ptr->tb7;
+
+       yaffs_do_endian_u32(dev, &tags_stored.as_u32[0]);
+       yaffs_do_endian_u32(dev, &tags_stored.as_u32[1]);
+
+       *tu = tags_stored;
 
        result = yaffs_check_tags_ecc(tags_ptr);
        if (result > 0)
@@ -263,7 +281,7 @@ static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
                        yaffs_ecc_calc(&data[256], spare.ecc2);
                }
 
-               yaffs_load_tags_to_spare(&spare, &tags);
+               yaffs_load_tags_to_spare(dev, &spare, &tags);
        }
        return yaffs_wr_nand(dev, nand_chunk, data, &spare);
 }
@@ -303,6 +321,7 @@ static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
 
        if (ext_tags->chunk_used) {
                yaffs_get_tags_from_spare(dev, &spare, &tags);
+
                ext_tags->obj_id = tags.obj_id;
                ext_tags->chunk_id = tags.chunk_id;
                ext_tags->n_bytes = tags.n_bytes_lsb;
index 44a83b1..c2e2369 100644 (file)
@@ -9,6 +9,10 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
+ *
+ * This file handles the marshalling (ie internal<-->external structure
+ * translation between the internal tags and the stored tags in Yaffs2-style
+ * tags storage.
  */
 
 #include "yaffs_guts.h"
@@ -43,9 +47,9 @@ static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
                    (struct yaffs_packed_tags2_tags_only *)(data +
                                                        dev->
                                                        data_bytes_per_chunk);
-               yaffs_pack_tags2_tags_only(pt2tp, tags);
+               yaffs_pack_tags2_tags_only(dev, pt2tp, tags);
        } else {
-               yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
+               yaffs_pack_tags2(dev, &pt, tags, !dev->param.no_tags_ecc);
        }
 
        retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
@@ -103,11 +107,11 @@ static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
                        pt2tp =
                                (struct yaffs_packed_tags2_tags_only *)
                                &data[dev->data_bytes_per_chunk];
-                       yaffs_unpack_tags2_tags_only(tags, pt2tp);
+                       yaffs_unpack_tags2_tags_only(dev, tags, pt2tp);
                }
        } else if (tags) {
                memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
-               yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
+               yaffs_unpack_tags2(dev, tags, &pt, !dev->param.no_tags_ecc);
        }
 
        if (local_data)
index 4f2e768..e98d04d 100644 (file)
@@ -325,7 +325,7 @@ int yaffs1_scan(struct yaffs_dev *dev)
                                                    use_header_file_size)
                                                        in->variant.
                                                        file_variant.file_size
-                                                       = yaffs_oh_to_size(oh);
+                                                       = yaffs_oh_to_size(dev, oh, 0);
                                                break;
                                        case YAFFS_OBJECT_TYPE_HARDLINK:
                                                in->variant.
index 688211e..6d46817 100644 (file)
@@ -21,6 +21,7 @@
 #include "yaffs_verify.h"
 #include "yaffs_attribs.h"
 #include "yaffs_summary.h"
+#include "yaffs_endian.h"
 
 /*
  * Checkpoints are really no benefit on very small partitions.
@@ -248,6 +249,18 @@ int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
 
 /*--------------------- Checkpointing --------------------*/
 
+static void yaffs2_do_endian_validity_marker(struct yaffs_dev *dev,
+                                            struct yaffs_checkpt_validity *v)
+{
+
+       if (!dev->swap_endian)
+               return;
+       v->struct_type = swap_s32(v->struct_type);
+       v->magic = swap_u32(v->magic);
+       v->version = swap_u32(v->version);
+       v->head = swap_u32(v->head);
+}
+
 static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
 {
        struct yaffs_checkpt_validity cp;
@@ -259,6 +272,8 @@ static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
        cp.version = YAFFS_CHECKPOINT_VERSION;
        cp.head = (head) ? 1 : 0;
 
+       yaffs2_do_endian_validity_marker(dev, &cp);
+
        return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
 }
 
@@ -268,6 +283,7 @@ static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
        int ok;
 
        ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
+       yaffs2_do_endian_validity_marker(dev, &cp);
 
        if (ok)
                ok = (cp.struct_type == sizeof(cp)) &&
@@ -280,6 +296,8 @@ static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
 static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
                                      struct yaffs_dev *dev)
 {
+       cp->struct_type = sizeof(*cp);
+
        cp->n_erased_blocks = dev->n_erased_blocks;
        cp->alloc_block = dev->alloc_block;
        cp->alloc_page = dev->alloc_page;
@@ -306,28 +324,63 @@ static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
        dev->seq_number = cp->seq_number;
 }
 
+static void yaffs2_do_endian_checkpt_dev(struct yaffs_dev *dev,
+                                    struct yaffs_checkpt_dev *cp)
+{
+       if (!dev->swap_endian)
+               return;
+       cp->struct_type = swap_s32(cp->struct_type);
+       cp->n_erased_blocks = swap_s32(cp->n_erased_blocks);
+       cp->alloc_block = swap_s32(cp->alloc_block);
+       cp->alloc_page = swap_u32(cp->alloc_page);
+       cp->n_free_chunks = swap_s32(cp->n_free_chunks);
+       cp->n_deleted_files = swap_s32(cp->n_deleted_files);
+       cp->n_unlinked_files = swap_s32(cp->n_unlinked_files);
+       cp->n_bg_deletions = swap_s32(cp->n_bg_deletions);
+}
+
 static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
 {
        struct yaffs_checkpt_dev cp;
        u32 n_bytes;
        u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
        int ok;
+       int i;
+       union yaffs_block_info_union bu;
 
        /* Write device runtime values */
        yaffs2_dev_to_checkpt_dev(&cp, dev);
-       cp.struct_type = sizeof(cp);
+       yaffs2_do_endian_checkpt_dev(dev, &cp);
 
        ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
        if (!ok)
                return 0;
 
-       /* Write block info */
-       n_bytes = n_blocks * sizeof(struct yaffs_block_info);
-       ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
+       /* Write block info. */
+       if (!dev->swap_endian) {
+               n_bytes = n_blocks * sizeof(struct yaffs_block_info);
+               ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
+       } else {
+               /*
+                * Need to swap the endianisms. We can't do this in place
+                * since that would damage live data,
+                * so write one block info at a time using a copy.
+                */
+               for (i = 0; i < n_blocks && ok; i++) {
+                       bu.bi = dev->block_info[i];
+                       bu.as_u32[0] = swap_u32(bu.as_u32[0]);
+                       bu.as_u32[1] = swap_u32(bu.as_u32[1]);
+                       ok = (yaffs2_checkpt_wr(dev, &bu, sizeof(bu)) == sizeof(bu));
+               }
+       }
+
        if (!ok)
                return 0;
 
-       /* Write chunk bits */
+       /*
+        * Write chunk bits. Chunk bits are in bytes so
+        * no endian conversion is needed.
+        */
        n_bytes = n_blocks * dev->chunk_bit_stride;
        ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
 
@@ -345,6 +398,7 @@ static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
        ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
        if (!ok)
                return 0;
+       yaffs2_do_endian_checkpt_dev(dev, &cp);
 
        if (cp.struct_type != sizeof(cp))
                return 0;
@@ -358,10 +412,21 @@ static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
        if (!ok)
                return 0;
 
+       if (dev->swap_endian) {
+               /* The block info can just be handled as a list of u32s. */
+               u32 *as_u32 = (u32 *) dev->block_info;
+               u32 n_u32s = n_bytes/sizeof(u32);
+               u32 i;
+
+               for (i=0; i < n_u32s; i++)
+                       as_u32[i] = swap_u32(as_u32[i]);
+       }
+
        n_bytes = n_blocks * dev->chunk_bit_stride;
 
        ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
 
+
        return ok ? 1 : 0;
 }
 
@@ -473,6 +538,33 @@ static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
        return 1;
 }
 
+static void yaffs2_do_endian_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
+{
+       int i;
+       u32 *as_u32 = (u32 *)tn;
+       int tnode_size_u32 = dev->tnode_size / sizeof(u32);
+
+       if (!dev->swap_endian)
+               return;
+       /* Swap all the tnode data as u32s to fix endianisms. */
+       for (i = 0; i<tnode_size_u32; i++)
+               as_u32[i] = swap_u32(as_u32[i]);
+}
+
+struct yaffs_tnode *yaffs2_do_endian_tnode_copy(struct yaffs_dev *dev,
+                                              struct yaffs_tnode *tn)
+{
+       if (!dev->swap_endian)
+               return tn;
+
+       memcpy(dev->tn_swap_buffer, tn, dev->tnode_size);
+       tn = dev->tn_swap_buffer;
+
+       yaffs2_do_endian_tnode(dev, tn);
+
+       return tn;
+}
+
 static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
                                       struct yaffs_tnode *tn, u32 level,
                                       int chunk_offset)
@@ -500,12 +592,20 @@ static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
 
        /* Level 0 tnode */
        base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
+       yaffs_do_endian_u32(dev, &base_offset);
+
        ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
                        sizeof(base_offset));
-       if (ok)
+       if (ok) {
+               /*
+                * NB Can't do an in-place endian swizzle since that would
+                * damage current tnode data.
+                * If a tnode endian conversion is required we do a copy.
+                */
+               tn = yaffs2_do_endian_tnode_copy(dev, tn);
                ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
                        dev->tnode_size);
-
+       }
        return ok;
 }
 
@@ -540,14 +640,18 @@ static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
        ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
              sizeof(base_chunk));
 
+       yaffs_do_endian_u32(dev, &base_chunk);
+
        while (ok && (~base_chunk)) {
                nread++;
                /* Read level 0 tnode */
 
                tn = yaffs_get_tnode(dev);
-               if (tn)
+               if (tn) {
                        ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
                                dev->tnode_size);
+                       yaffs2_do_endian_tnode(dev, tn);
+               }
                else
                        ok = 0;
 
@@ -556,10 +660,13 @@ static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
                                                    file_stuct_ptr,
                                                    base_chunk, tn) ? 1 : 0;
 
-               if (ok)
+               if (ok) {
                        ok = (yaffs2_checkpt_rd
                              (dev, &base_chunk,
                               sizeof(base_chunk)) == sizeof(base_chunk));
+                       yaffs_do_endian_u32(dev, &base_chunk);
+               }
+
        }
 
        yaffs_trace(YAFFS_TRACE_CHECKPOINT,
@@ -569,6 +676,21 @@ static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
        return ok ? 1 : 0;
 }
 
+
+static void yaffs2_do_endian_checkpt_obj(struct yaffs_dev *dev,
+                                        struct yaffs_checkpt_obj *cp)
+{
+       if (!dev->swap_endian)
+               return;
+       cp->struct_type = swap_s32(cp->struct_type);
+       cp->obj_id = swap_u32(cp->obj_id);
+       cp->parent_id = swap_u32(cp->parent_id);
+       cp->hdr_chunk = swap_s32(cp->hdr_chunk);
+       cp->bit_field = swap_u32(cp->bit_field);
+       cp->n_data_chunks = swap_s32(cp->n_data_chunks);
+       cp->size_or_equiv_obj = swap_loff_t(cp->size_or_equiv_obj);
+}
+
 static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
 {
        struct yaffs_obj *obj;
@@ -595,6 +717,7 @@ static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
                                        cp.obj_id, cp.parent_id,
                                        cp_variant_type, cp.hdr_chunk, obj);
 
+                               yaffs2_do_endian_checkpt_obj (dev, &cp);
                                ok = (yaffs2_checkpt_wr(dev, &cp,
                                                sizeof(cp)) == sizeof(cp));
 
@@ -609,6 +732,7 @@ static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
        /* Dump end of list */
        memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
        cp.struct_type = sizeof(cp);
+       yaffs2_do_endian_checkpt_obj (dev, &cp);
 
        if (ok)
                ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
@@ -628,6 +752,8 @@ static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
 
        while (ok && !done) {
                ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
+               yaffs2_do_endian_checkpt_obj (dev, &cp);
+
                if (cp.struct_type != sizeof(cp)) {
                        yaffs_trace(YAFFS_TRACE_CHECKPOINT,
                                "struct size %d instead of %d ok %d",
@@ -678,6 +804,8 @@ static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
 
        yaffs2_get_checkpt_sum(dev, &checkpt_sum);
 
+       yaffs_do_endian_u32(dev, &checkpt_sum);
+
        ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
                sizeof(checkpt_sum));
 
@@ -700,6 +828,7 @@ static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
 
        if (!ok)
                return 0;
+       yaffs_do_endian_u32(dev, &checkpt_sum1);
 
        if (checkpt_sum0 != checkpt_sum1)
                return 0;
@@ -864,6 +993,10 @@ int yaffs2_checkpt_restore(struct yaffs_dev *dev)
        return retval;
 }
 
+/* End of checkpointing */
+
+/* Hole handling logic for truncate past end of file */
+
 int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
 {
        /* if new_size > old_file_size.
@@ -948,6 +1081,8 @@ int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
        return result;
 }
 
+/* Yaffs2 scanning */
+
 struct yaffs_block_index {
        int seq;
        int block;
@@ -1157,6 +1292,8 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
 
                        oh = (struct yaffs_obj_hdr *)chunk_data;
 
+                       yaffs_do_endian_oh(dev, oh);
+
                        if (dev->param.inband_tags) {
                                /* Fix up the header if they got
                                 * corrupted by inband tags */
@@ -1194,7 +1331,7 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
                                  tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
                                )) {
                                loff_t this_size = (oh) ?
-                                       yaffs_oh_to_size(oh) :
+                                       yaffs_oh_to_size(dev, oh, 0) :
                                        tags.extra_file_size;
                                u32 parent_obj_id = (oh) ?
                                        oh->parent_obj_id :
@@ -1271,7 +1408,7 @@ static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
                                parent = yaffs_find_or_create_by_number(dev,
                                                oh->parent_obj_id,
                                                YAFFS_OBJECT_TYPE_DIRECTORY);
-                               file_size = yaffs_oh_to_size(oh);
+                               file_size = yaffs_oh_to_size(dev, oh, 0);
                                is_shrink = oh->is_shrink;
                                equiv_id = oh->equiv_id;
                        } else {