*** empty log message ***
authorcharles <charles>
Tue, 14 Jan 2003 23:15:29 +0000 (23:15 +0000)
committercharles <charles>
Tue, 14 Jan 2003 23:15:29 +0000 (23:15 +0000)
14 files changed:
Documentation/yaffs2.html
mtdemul/nandemul.c
snMakefile
utils/Makefile
utils/mkyaffs
wince/yaffsfsd.c
yaffs_fileem.c
yaffs_fs.c
yaffs_guts.c
yaffs_guts.h
yaffs_mtdif.c
yaffsdev.c
yaffsdev.proj
yportenv.h

index e83dcc667d8474087320b10245b8e2e97bc082f0..9014465ba399097aa8fa7a64ff0a9899e63e64bd 100644 (file)
@@ -7,7 +7,7 @@
        <META NAME="AUTHOR" CONTENT=" ">
        <META NAME="CREATED" CONTENT="20021004;15061000">
        <META NAME="CHANGEDBY" CONTENT=" ">
-       <META NAME="CHANGED" CONTENT="20021126;13574600">
+       <META NAME="CHANGED" CONTENT="20021206;6000500">
 </HEAD>
 <BODY>
 <H1>YAFFS2</H1>
@@ -224,7 +224,7 @@ sequence Id order) rather than in their order on the media. This
 implies that at start up, the blocks must be read and their block
 sequence determined.</P>
 <H4>Performance</H4>
-<P>These  numbers are indicative of relative performance. These only
+<P>These numbers are indicative of relative performance. These only
 apply to the NAND data transfer and do not include other overheads.</P>
 <P>As an example, read/write cycle times of 100nS are used (though
 NAND can typically do 50nS), &quot;seek time&quot; of 10uS and
@@ -747,7 +747,41 @@ transfer time relative to an 8-bit bus.</P>
 </TABLE>
 <P><BR><BR>
 </P>
-<P>$Id: yaffs2.html,v 1.1 2002-11-26 01:15:37 charles Exp $</P>
+<H2>MTD Interface</H2>
+<P>As mentioned before, YAFFS2 requires a chunk-size of at least 1kB
+to get a large enough spare area to support the increased size of the
+tags. This is not really a disadvantage, but should rather be viewed
+as an opportunity to exploit the NAND hardware more effectively. In
+particular:</P>
+<UL>
+       <LI><P>Newer, larger, NAND with 2kB pages can be used in chunks of
+       2kB. Keeping the relationship of one chunk per page improves
+       robustness and performance (rather than say trying to &quot;fake&quot;
+       512byte  pages). A block comprises 64x2kB pages.</P>
+       <LI><P>Some devices have 512byte pages, but are arranged as multiple
+       &quot;bit planes&quot; which can be programmed and erased in
+       parallel. For example, the Samsung K9K1G08U0M can support 4
+       simultaneous operations. YAFFS2 can exploit this by using 2kB chunks
+        by using  groups of 4 pages - one on each bitplane. Virtual blocks
+       would be built which comprise 32x2kB chunks.</P>
+</UL>
+<P>To this end, yaffs_guts is being re-crafted to support arbitrary
+chunk size (power of 2, &gt;= 1024), with arbitrary block size.</P>
+<P>Currently, YAFFS also makes some other assumptions which will need
+to be changed:</P>
+<UL>
+       <LI><P>Spare layout. Might need to be changed. This is relatively
+       simple to shuffle around.</P>
+       <LI><P>Bad block detection. Currently YAFFS uses the SmartMedia
+       detection (checks first two pages for bad block markers). Needs to
+       be more flexible. eg. Sandisk/Toshiba MLC parts mark the last two
+       pages in a block.</P>
+       <LI><P>ECC was on this list, but now seems flexible enough. Thanx
+       Thomas.</P>
+</UL>
+<P>Some of these differences can be absorbed in the yaffs_mtd layer.
+Some will need to be handles inside the mtd itself.</P>
+<P>$Id: yaffs2.html,v 1.2 2003-01-14 23:15:41 charles Exp $</P>
 <P><BR><BR>
 </P>
 <P><BR><BR>
index 12fe39dc04320d14ca535f90830059e4f4bf663f..52a6a64b62773a5a7156d4fd3910a766e07fcd2f 100644 (file)
@@ -30,7 +30,7 @@
 #include <asm/uaccess.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
-
+#include <linux/mtd/nand.h>
 
 #define T(x) printk x
 #define ALLOCATE(x) kmalloc(x,GFP_KERNEL)
index c27a5cbeff9a75821e119542ef8ba92a27a32b6a..cbd34dfda16e0fc8373a739b78c2c843990c3f7b 100644 (file)
@@ -1,6 +1,6 @@
 #########################################################
 # Makefile auto generated by Cygnus Source Navigator.
-# Target: yaffsdev_disk Date: Nov 26 2002 Time: 01:05:25 PM
+# Target: yaffsdev_disk Date: Dec 18 2002 Time: 04:44:42 PM
 #
 
 
@@ -70,9 +70,9 @@ yaffsdev: $(yaffsdev_disk_OBJECTS)
 
 
 nand_ecc.o: /opt/yaffs/yportenv.h
-yaffs_fileem.o: /opt/2.4.18/linux/include/linux/stat.h /opt/2.4.18/linux/include/linux/types.h /usr/include/fcntl.h /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h /usr/include/unistd.h /opt/yaffs/yaffs_fileem.h /opt/yaffs/yaffs_guts.h /opt/yaffs/yaffsinterface.h
+yaffs_fileem.o: /opt/yaffs/yaffs_fileem.h /opt/yaffs/yaffs_guts.h /opt/yaffs/yaffsinterface.h
 yaffs_guts.o: /opt/yaffs/yaffs_guts.h /opt/yaffs/yaffsinterface.h /opt/yaffs/yportenv.h
-yaffsdev.o: /usr/include/fcntl.h /usr/include/stdio.h /usr/include/stdlib.h /usr/include/string.h /usr/include/unistd.h /opt/yaffs/yaffs_fileem.h /opt/yaffs/yaffs_guts.h /opt/yaffs/yaffs_nandemul.h /opt/yaffs/yaffsinterface.h /opt/yaffs/yportenv.h
+yaffsdev.o: /opt/yaffs/yaffs_fileem.h /opt/yaffs/yaffs_guts.h /opt/yaffs/yaffs_nandemul.h /opt/yaffs/yaffsinterface.h /opt/yaffs/yportenv.h
 
 clean:
        rm -f *.o
index 1e0d4328d5a8de02bda5ca89f217a4f7b1440267..f4f94c05f59a7965ec5a772d0cf954d6c8290447 100644 (file)
@@ -16,7 +16,7 @@
 
 KERNELDIR = /usr/src/kernel-headers-2.4.18
 
-CFLAGS =   -I$(KERNELDIR)/include -I.. -O2 -Wall
+CFLAGS =   -I$(KERNELDIR)/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
 
index 5ed31f26b564af6b8a6523109ab970bf6083aa4f..28870e6b1680b473b66eae66a0c0a3652651968b 100755 (executable)
Binary files a/utils/mkyaffs and b/utils/mkyaffs differ
index dc64c1aa03a792d9a1860824d2c3b607e8ab9d17..7e202bfe17e60ab44912a09b6ec8b0af253b4830 100644 (file)
@@ -1,6 +1,6 @@
 /*\r
  * YAFFS: Yet another FFS. A NAND-flash specific file system.\r
- * yaffsfsd.c: The FSD layer for the WinCE version of YAFFS.\r
+ * ynandif.c: NAND interface functions for the WinCE port of YAFFS.\r
  *\r
  * Copyright (C) 2002 Trimble Navigation Ltd.\r
  *\r
  * if not, write to the Free Software Foundation, Inc., \r
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. \r
  *\r
- * $Id: yaffsfsd.c,v 1.1 2002-11-08 07:30:00 charles Exp $\r
+ * Acknowledgements:\r
+ *  Various clean-ups and WinCE4 support by Steve Fogle\r
+ * $Id: yaffsfsd.c,v 1.2 2003-01-14 23:15:41 charles Exp $\r
  */
 #include <windows.h>
 #include <extfile.h>
 #include <yaffs_guts.h>
-#include <ynandif.h>
+#include <ynandif.h>\r
+//slf021104b begin\r
+#include <diskio.h>\r
+//slf021104b end
 
 #define MAX_WIN_FILE   200
 #define YFSD_NAME_LENGTH 128
 #define YFSD_FULL_PATH_NAME_SIZE 500
 
-
+\r
 #define YFSD_DISK_NAME L"Disk"
-#define YFSD_BOOT_NAME L"Boot"
+#define YFSD_BOOT_NAME L"Boot"\r
 
 #define PARTITION_START_NUMBER (1280)          
 
-#define MSGSTATE 1
+//#define MSGSTATE 1\r
+#define MSGSTATE 0
 //#define DISABLE_BOOT_PARTITION\r
-\r
-unsigned yaffs_traceMask=0xffffffff;
+//slf021105a begin\r
+// Define DO_PARTITION_TABLE to cause the partition table \r
+// information to be retrieved from the block driver.\r
+//#define DO_PARTITION_TABLE\r
+// How many partitions the disk might have.  2 gives \r
+// space for the "Disk" and "Boot" partitions.\r
+#define MAXPARTITIONS (2)\r
+//slf021105a end
+
+//unsigned yaffs_traceMask=0xffffffff;
+unsigned yaffs_traceMask=0;\r
 
 
 typedef struct
@@ -59,10 +74,13 @@ typedef struct
        yaffs_Object *obj;
        DWORD offset;
        BOOL isopen;
-       BOOL writePermitted;
        BOOL dirty;
        WCHAR *fullName;
        yfsd_Volume *myVolume;
+       BOOL writePermitted;\r
+       BOOL readPermitted;\r
+       BOOL shareRead;\r
+       BOOL shareWrite;\r
 
 }      yfsd_WinFile;
 
@@ -92,9 +110,11 @@ typedef struct
 
 #include <fsdmgr.h>
 
-
-static yfsd_Volume disk_volume;
-static yfsd_Volume boot_volume;
+//slf021105a begin\r
+//static yfsd_Volume disk_volume;
+//static yfsd_Volume boot_volume;\r
+static yfsd_Volume * disk_volumes[MAXPARTITIONS];\r
+//slf021105a end;
 
 static CRITICAL_SECTION yaffsLock;
 static CRITICAL_SECTION winFileLock;
@@ -192,7 +212,10 @@ yfsd_WinFile * yfsd_GetWinFile(void)
                if(!yfsd_winFile[i].isopen)
                {
                        yfsd_winFile[i].isopen = 1;
-                       yfsd_winFile[i].writePermitted = 0;
+                       yfsd_winFile[i].writePermitted = 0;\r
+                       yfsd_winFile[i].readPermitted = 0;\r
+                       yfsd_winFile[i].shareRead = 0;\r
+                       yfsd_winFile[i].shareWrite = 0;\r
                        yfsd_winFile[i].dirty = 0;
                        yfsd_winFile[i].fullName = NULL;
                        yfsd_winFile[i].obj = NULL;
@@ -238,19 +261,47 @@ void yfsd_FlushAllFiles(void)
                if(yfsd_winFile[i].isopen &&
                   yfsd_winFile[i].obj)
                {
-                       yaffs_FlushFile(yfsd_winFile[i].obj);
+                       yaffs_FlushFile(yfsd_winFile[i].obj,1);
                }
        }
        yfsd_UnlockWinFiles();
        yfsd_UnlockYAFFS();
-}
+}\r
+\r
+//slf021104d begin\r
+//////////////////////////////////////////////////////////////////////\r
+// Search through winFiles to see if any are open.  \r
+\r
+BOOL yfsd_FilesOpen(void)\r
+{\r
+       int i;\r
+       BOOL rval;\r
+       RETAILMSG (MSGSTATE, (L"YAFFS::FilesOpen?\r\n"));\r
+\r
+       yfsd_LockWinFiles();\r
+       for(i = 0, rval = FALSE; i < MAX_WIN_FILE; i++)\r
+       {\r
+               if(yfsd_winFile[i].isopen)\r
+               {\r
+                       rval = TRUE;\r
+                       break;\r
+               }\r
+       }\r
+       yfsd_UnlockWinFiles();\r
+       return rval;\r
+}\r
+//slf021104d end
 
 PWSTR yfsd_FullPathName(PVOLUME vol, PWSTR fpn,int slength,PCWSTR pathName)
 {
 
-       // todo check for bounds
-       wcscpy(fpn,L"\\");
-       wcscat(fpn,vol->volName);
+       // todo check for bounds\r
+       //slf021104b begin\r
+       //volName already has the initial backslash if it needs it.
+       //wcscpy(fpn,L"\\");\r
+       //wcscat(fpn,vol->volName);
+       wcscpy(fpn,vol->volName);\r
+       //slf021104b end\r
        if(pathName[0] != '\\')
        {
                wcscat(fpn,L"\\");
@@ -263,7 +314,7 @@ PWSTR yfsd_FullPathName(PVOLUME vol, PWSTR fpn,int slength,PCWSTR pathName)
 
 
 // FILETIME is a 64-bit value as 100-nanosecond intervals since January 1, 1601.
-\r
+
 void yfsd_U32sToWinFileTime(__u32 target[2], FILETIME *wft)
 {
        
@@ -347,15 +398,15 @@ void yfsd_ShellDirectoryChanged(PVOLUME pVolume, PWSTR fullPathName)
 
 
 }
-\r
-\r
-// Minimal name test for now\r
-BOOL yfsd_NameIsValid (const char *name)\r
-{\r
-       int length = strlen(name);\r
-\r
-       return (length > 0 && length <= YFSD_NAME_LENGTH);\r
-\r
+
+
+// Minimal name test for now
+BOOL yfsd_NameIsValid (const char *name)
+{
+       int length = strlen(name);
+
+       return (length > 0 && length <= YFSD_NAME_LENGTH);
+
 }
 
 // File attributes:
@@ -375,58 +426,58 @@ BOOL yfsd_NameIsValid (const char *name)
 //
 //
 // in addition, GetAttributes also returns FILE_ATTRIBUTE_DIRECTORY
-\r
-// The following are valid ones we get presented with,\r
-// but must filter out the stuff we don't unserstand\r
-//#define FILE_ATTRIBUTE_READONLY             0x00000001  \r
-//#define FILE_ATTRIBUTE_HIDDEN               0x00000002  \r
-//#define FILE_ATTRIBUTE_SYSTEM               0x00000004  \r
-//#define FILE_ATTRIBUTE_DIRECTORY            0x00000010  \r
-//#define FILE_ATTRIBUTE_ARCHIVE              0x00000020  \r
-//#define FILE_ATTRIBUTE_INROM                           0x00000040\r
-//#define FILE_ATTRIBUTE_ENCRYPTED            0x00000040  \r
-//#define FILE_ATTRIBUTE_NORMAL               0x00000080  \r
-//#define FILE_ATTRIBUTE_TEMPORARY            0x00000100  \r
-//#define FILE_ATTRIBUTE_SPARSE_FILE          0x00000200  \r
-//#define FILE_ATTRIBUTE_REPARSE_POINT        0x00000400  \r
-//#define FILE_ATTRIBUTE_COMPRESSED           0x00000800  \r
-//#define FILE_ATTRIBUTE_OFFLINE              0x00001000  \r
-//#define FILE_ATTRIBUTE_ROMSTATICREF            0x00001000\r
-//#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED  0x00002000  \r
-//#define FILE_ATTRIBUTE_ROMMODULE                       0x00002000\r
-\r
-\r
-BOOL yfsd_CheckValidAttributes(DWORD attribs)\r
-{\r
-\r
-       RETAILMSG (MSGSTATE, (L"Attributes:%X\r\n", attribs));\r
-\r
-#if 0\r
-               // If NORMAL, then nothing else\r
-               if(attribs & FILE_ATTRIBUTE_NORMAL && attribs != FILE_ATTRIBUTE_NORMAL)\r
-                       return FALSE;\r
-               if(attribs == FILE_ATTRIBUTE_NORMAL) \r
-                       return TRUE;\r
-#endif\r
-               // Check that the bits are in the valid set\r
-               if(attribs & ~(0x3FE7))\r
-                       return FALSE;\r
-\r
-               return TRUE;\r
-\r
+
+// The following are valid ones we get presented with,
+// but must filter out the stuff we don't unserstand
+//#define FILE_ATTRIBUTE_READONLY             0x00000001  
+//#define FILE_ATTRIBUTE_HIDDEN               0x00000002  
+//#define FILE_ATTRIBUTE_SYSTEM               0x00000004  
+//#define FILE_ATTRIBUTE_DIRECTORY            0x00000010  
+//#define FILE_ATTRIBUTE_ARCHIVE              0x00000020  
+//#define FILE_ATTRIBUTE_INROM                           0x00000040
+//#define FILE_ATTRIBUTE_ENCRYPTED            0x00000040  
+//#define FILE_ATTRIBUTE_NORMAL               0x00000080  
+//#define FILE_ATTRIBUTE_TEMPORARY            0x00000100  
+//#define FILE_ATTRIBUTE_SPARSE_FILE          0x00000200  
+//#define FILE_ATTRIBUTE_REPARSE_POINT        0x00000400  
+//#define FILE_ATTRIBUTE_COMPRESSED           0x00000800  
+//#define FILE_ATTRIBUTE_OFFLINE              0x00001000  
+//#define FILE_ATTRIBUTE_ROMSTATICREF            0x00001000
+//#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED  0x00002000  
+//#define FILE_ATTRIBUTE_ROMMODULE                       0x00002000
+
+
+BOOL yfsd_CheckValidAttributes(DWORD attribs)
+{
+
+       RETAILMSG (MSGSTATE, (L"Attributes:%X\r\n", attribs));
+
+#if 0
+               // If NORMAL, then nothing else
+               if(attribs & FILE_ATTRIBUTE_NORMAL && attribs != FILE_ATTRIBUTE_NORMAL)
+                       return FALSE;
+               if(attribs == FILE_ATTRIBUTE_NORMAL) 
+                       return TRUE;
+#endif
+               // Check that the bits are in the valid set
+               if(attribs & ~(0x3FE7))
+                       return FALSE;
+
+               return TRUE;
+
 }
 DWORD yfsd_GetObjectWinAttributes(yaffs_Object *obj)
 {
 
                DWORD result;
                
-               result = obj->st_mode & \r
-                                       (FILE_ATTRIBUTE_READONLY | \r
-                                        FILE_ATTRIBUTE_ARCHIVE | \r
-                                        FILE_ATTRIBUTE_HIDDEN |\r
+               result = obj->st_mode & 
+                                       (FILE_ATTRIBUTE_READONLY | 
+                                        FILE_ATTRIBUTE_ARCHIVE | 
+                                        FILE_ATTRIBUTE_HIDDEN |
                                         FILE_ATTRIBUTE_SYSTEM);
-\r
-               if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) result |= FILE_ATTRIBUTE_DIRECTORY;\r
+
+               if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) result |= FILE_ATTRIBUTE_DIRECTORY;
 
                if(result & ~FILE_ATTRIBUTE_NORMAL)
                { 
@@ -436,7 +487,7 @@ DWORD yfsd_GetObjectWinAttributes(yaffs_Object *obj)
                {
                        result = FILE_ATTRIBUTE_NORMAL;
                }
-\r
+
 
                return result;
 }
@@ -496,7 +547,7 @@ yaffs_Object *yfsd_FindDirectoryByWinPath(yaffs_Device *device, const wchar_t *p
 
        RETAILMSG (MSGSTATE, (L"YAFFS::FindByWinPath (%s) : ", path));
        // start at the root of this device
-       current = yaffs_Root(device);\r
+       current = yaffs_Root(device);
        *processed = '\0';
 
        do
@@ -553,8 +604,14 @@ yaffs_Object *yfsd_FindObjectByWinPath(yaffs_Device *dev, PCWSTR pwsFileName )
 
 BOOL YFSD_InitVolume(HDSK hdsk, yfsd_Volume *vol, int startBlock, int endBlock, PWSTR volName)
 {
-       RETAILMSG (MSGSTATE, (L"YAFFS::InitVolume\r\n"));
-       vol->volName = volName;
+       //slf021104b Begin\r
+       WCHAR szName[MAX_PATH];\r
+    DWORD dwAvail;\r
+       //slf021104b end\r
+       RETAILMSG (MSGSTATE, (L"YAFFS::InitVolume\r\n"));\r
+       //slf021104b Begin filled in later.
+       //vol->volName = volName;\r
+       //slf021104b end
 
 
        yfsd_LockYAFFS();
@@ -568,7 +625,8 @@ BOOL YFSD_InitVolume(HDSK hdsk, yfsd_Volume *vol, int startBlock, int endBlock,
        vol->dev.initialiseNAND = ynandif_InitialiseNAND;
        vol->dev.startBlock = startBlock;
        if (endBlock != -1)
-               vol->dev.endBlock = endBlock;
+               vol->dev.endBlock = endBlock;\r
+       vol->dev.nShortOpCaches = 10; // a nice number of caches.
 
        // nBlocks is set the total size of the disk, not the partition
 //     vol->dev.nBlocks = endBlock - startBlock + 1;
@@ -611,11 +669,51 @@ BOOL YFSD_InitVolume(HDSK hdsk, yfsd_Volume *vol, int startBlock, int endBlock,
        yfsd_UnlockYAFFS();
 
        vol->isMounted = 1;
-       
-       vol->mgrVolume = FSDMGR_RegisterVolume(hdsk,vol->volName,vol);
+       \r
+       //slf021104b begin
+       //vol->mgrVolume = FSDMGR_RegisterVolume(hdsk,vol->volName,vol);\r
+       // If the caller passed a volume name use it.\r
+       if (volName[0])\r
+        wcscpy( szName, volName);\r
+#if WINCEOSVER >= 400\r
+       // The user passed an empty volume name.  On CE 4.xx try to get\r
+       // if from the block driver (which got it from the registry).\r
+       else if (!FSDMGR_DiskIoControl(hdsk, DISK_IOCTL_GETNAME, NULL, 0, (LPVOID)szName, sizeof(szName), &dwAvail, NULL)) \r
+#else\r
+       else\r
+#endif\r
+       { \r
+               // Didn't get a volume name so use "Disk" by default.\r
+        wcscpy( szName, YFSD_DISK_NAME);\r
+    }    \r
+       vol->mgrVolume = FSDMGR_RegisterVolume(hdsk,szName,vol);\r
+       //slf021104b end
 
        if(vol->mgrVolume)
-       {
+       {\r
+               //slf021104b Begin\r
+               // Get some space for the volume name.
+        vol->volName = malloc( MAX_PATH * sizeof(WCHAR));\r
+        if (vol->volName) \r
+               {\r
+#if WINCEOSVER >= 400\r
+                       // Get the name we were really mounted under.\r
+            FSDMGR_GetVolumeName(vol->mgrVolume, vol->volName, MAX_PATH);\r
+\r
+                       // If we got mounted as root then throw away the backslash\r
+                       // so we won't get a double backslash when volName is\r
+                       // prepended to the path in the full path name calculation\r
+                       // that is used for shell callbacks.\r
+                       if (0 == wcscmp(vol->volName,L"\\"))\r
+                               vol->volName[0] = 0;\r
+#else\r
+                       // Use the name we asked to be mounted under for\r
+                       // our root.  \r
+                       wcscpy(vol->volName,L"\\");\r
+                       wcscat(vol->volName, szName);\r
+#endif\r
+               }\r
+               //slf021104b end\r
                return TRUE;
        }
        else
@@ -629,6 +727,14 @@ BOOL YFSD_InitVolume(HDSK hdsk, yfsd_Volume *vol, int startBlock, int endBlock,
 
 BOOL YFSD_MountDisk(HDSK hdsk)
 {
+//slf021105a begin\r
+#ifdef DO_PARTITION_TABLE\r
+       ynandif_partition PartTable[MAXPARTITIONS];\r
+       DWORD dwAvail;\r
+       int i;\r
+       BOOL rval = FALSE;\r
+#endif\r
+//slf021105a end\r
        int deadBlox=0,emptyBlox=0,fullBlox=0,allocatingBlox=0,dirtyBlox=0;
        //int i;
        // Called to mount a disk.
@@ -646,29 +752,124 @@ BOOL YFSD_MountDisk(HDSK hdsk)
                yfsd_InitialiseWinFiles();
                yaffsLockInited = 1;
        }
-
-#ifdef DISABLE_BOOT_PARTITION
-       // Only want disk volume
-       YFSD_InitVolume(hdsk, &disk_volume, 1, -1, YFSD_DISK_NAME);
-
-       
-       if(disk_volume.isMounted)
-       {
-               return TRUE;
-       }
+\r
+       //slf021105a begin\r
+       memset(disk_volumes,0,sizeof(disk_volumes));\r
+#ifdef DO_PARTITION_TABLE\r
+       memset(&PartTable,0,sizeof(PartTable));\r
+       // Call the block driver to get the partition table from it.\r
+    if (FSDMGR_DiskIoControl(hdsk, YNANDIF_GETPARTITIONS, NULL, 0, (LPVOID)&PartTable, sizeof(PartTable), &dwAvail, NULL)) \r
+       {\r
+               // Scan throught the table it return.\r
+               for (i=0; i<MAXPARTITIONS; i++)\r
+               {\r
+                       // At the very lease check that the end is later than the beginning\r
+                       // and don't let it start at 0.  \r
+                       // Probably could do more thorough checking but I trust the block\r
+                       // driver.\r
+                       if (PartTable[i].startBlock && (PartTable[i].endBlock > PartTable[i].startBlock))\r
+                       {\r
+                               // Found a partion.  Get a volume structure to hold it.\r
+                               disk_volumes[i] = malloc(sizeof(yfsd_Volume));\r
+                               if (disk_volumes[i])\r
+                               {\r
+                                       memset(disk_volumes[i],0,sizeof(yfsd_Volume));\r
+                                       // Go init the volume.  Note that if the block driver wants the\r
+                                       // name to come from the registry it will have returned an\r
+                                       // empty name string.\r
+                                       YFSD_InitVolume(hdsk,disk_volumes[i],PartTable[i].startBlock,PartTable[i].endBlock,PartTable[i].volName);\r
+                                       if (disk_volumes[i]->isMounted)\r
+                                               rval = TRUE; //Hey, we found at least on partition.\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       return rval;\r
+\r
 #else
-       // Want both boot and disk
-       YFSD_InitVolume(hdsk, &disk_volume, PARTITION_START_NUMBER+1, -1, YFSD_DISK_NAME);
-       YFSD_InitVolume(hdsk, &boot_volume, 1, PARTITION_START_NUMBER, YFSD_BOOT_NAME);
-
-       
-       if(disk_volume.isMounted && boot_volume.isMounted)
-       {
-               return TRUE;
-       }
-#endif
-
-       return FALSE;
+#ifdef DISABLE_BOOT_PARTITION
+       // Only want disk volume\r
+       disk_volumes[0] = malloc(sizeof(yfsd_Volume));\r
+       if (disk_volumes[0])\r
+       {\r
+               memset(disk_volumes[0],0,sizeof(yfsd_Volume));\r
+               YFSD_InitVolume(hdsk, disk_volumes[0], 1, -1, YFSD_DISK_NAME);\r
+\r
+               if(disk_volumes[0].isMounted)\r
+               {\r
+                       return TRUE;\r
+               }\r
+       }\r
+       if (disk_volumes[0])\r
+       {\r
+               free(disk_volumes[0];\r
+               disk_volumes[0] = NULL;\r
+       }\r
+#else\r
+       // Want both boot and disk\r
+       disk_volumes[0] = malloc(sizeof(yfsd_Volume));\r
+       disk_volumes[1] = malloc(sizeof(yfsd_Volume));\r
+       if (disk_volumes[0] && disk_volumes[1])\r
+       {\r
+               memset(disk_volumes[0],0,sizeof(yfsd_Volume));\r
+               memset(disk_volumes[1],0,sizeof(yfsd_Volume));\r
+               YFSD_InitVolume(hdsk, disk_volumes[0], PARTITION_START_NUMBER+1, -1, YFSD_DISK_NAME);\r
+               YFSD_InitVolume(hdsk, disk_volumes[1], 1, PARTITION_START_NUMBER, YFSD_BOOT_NAME);\r
+\r
+               if(disk_volumes[0]->isMounted && disk_volumes[1]->isMounted)\r
+               {\r
+                       return TRUE;\r
+               }\r
+       }\r
+\r
+       // If we got this far something went wrong.  Make sure to \r
+       // free any memory we allocated.\r
+       if (disk_volumes[0])\r
+       {\r
+               if (disk_volumes[0]->volName)\r
+               {\r
+                       free(disk_volumes[0]->volName);\r
+               }\r
+               free(disk_volumes[0]);\r
+               disk_volumes[0] = NULL;\r
+       }\r
+       if (disk_volumes[1])\r
+       {\r
+               if (disk_volumes[1]->volName)\r
+               {\r
+                       free(disk_volumes[1]->volName);\r
+               }\r
+               free(disk_volumes[1]);\r
+               disk_volumes[1] = NULL;\r
+       }\r
+#endif\r
+\r
+       return FALSE;\r
+\r
+       // Only want disk volume\r
+//     YFSD_InitVolume(hdsk, &disk_volume, 1, -1, YFSD_DISK_NAME);
+//
+//     
+//     if(disk_volume.isMounted)
+//     {
+//             return TRUE;
+//     }
+//#else
+//     // Want both boot and disk
+//     YFSD_InitVolume(hdsk, &disk_volume, PARTITION_START_NUMBER+1, -1, YFSD_DISK_NAME);
+//     YFSD_InitVolume(hdsk, &boot_volume, 1, PARTITION_START_NUMBER, YFSD_BOOT_NAME);
+//
+//     
+//     if(disk_volume.isMounted && boot_volume.isMounted)
+//     {
+//             return TRUE;
+//     }
+//#endif\r
+//
+//     return FALSE;
+#endif\r
+//slf021105a end\r
 
 //     yfsd_SetGuards();
 
@@ -679,17 +880,47 @@ BOOL YFSD_MountDisk(HDSK hdsk)
 
 BOOL YFSD_UnmountDisk(HDSK hdsk)
 {
+//slf021105a begin\r
+       int i;\r
+//slf021105a end\r
        RETAILMSG (MSGSTATE, (L"YAFFS::UnmountDisk\r\n"));
        
-       yfsd_FlushAllFiles();
-
-       yfsd_LockYAFFS();
-       yaffs_Deinitialise(&disk_volume.dev);
-       yaffs_Deinitialise(&boot_volume.dev);
-       yfsd_UnlockYAFFS();
-
-       FSDMGR_DeregisterVolume(disk_volume.mgrVolume);
-       FSDMGR_DeregisterVolume(boot_volume.mgrVolume);
+       //slf021104d begin\r
+       // If there are any files open don't let them dismount\r
+       // it or the system will get very confused.  \r
+       if (yfsd_FilesOpen())\r
+               return FALSE;\r
+\r
+       //yfsd_FlushAllFiles();\r
+       //slf021104d end\r
+\r
+       yfsd_LockYAFFS();\r
+//slf021105a begin\r
+//     yaffs_Deinitialise(&disk_volume.dev);\r
+//     yaffs_Deinitialise(&boot_volume.dev);\r
+//     yfsd_UnlockYAFFS();
+//
+//     FSDMGR_DeregisterVolume(disk_volume.mgrVolume);\r
+//     FSDMGR_DeregisterVolume(boot_volume.mgrVolume);\r
+\r
+       // Walk through the partions deinitializing, deregistering\r
+       // and freeing them.\r
+       for (i=0; i<MAXPARTITIONS; i++)\r
+       {\r
+               if (disk_volumes[i])\r
+               {\r
+                       yaffs_Deinitialise(&(disk_volumes[i]->dev));\r
+                       FSDMGR_DeregisterVolume(disk_volumes[i]->mgrVolume);\r
+                       if (disk_volumes[i]->volName)\r
+                       {\r
+                               free(disk_volumes[i]->volName);\r
+                       }\r
+                       free(disk_volumes[i]);\r
+                       disk_volumes[i] = NULL;\r
+               }\r
+       }\r
+       yfsd_UnlockYAFFS();\r
+//slf021105a end
        return TRUE;
 }
 
@@ -711,22 +942,35 @@ BOOL YFSD_CreateDirectoryW(PVOLUME pVolume, PCWSTR pathName, PSECURITY_ATTRIBUTE
 
        parent = yfsd_FindDirectoryByWinPath(&pVolume->dev,pathName,name,YFSD_NAME_LENGTH);
 
-       if(parent && yfsd_NameIsValid(name))
-       {
-               newDir = yaffs_MknodDirectory(parent,name,0,0,0);
-       }
-       
-       if(newDir)
+       //slf021101b begin 
+       if (parent)
        {
-               objSize = yaffs_GetObjectFileLength(newDir);
-               attribs = yfsd_GetObjectWinAttributes(newDir);
-               modifiedTime[0] = newDir->win_mtime[0];\r
-               modifiedTime[1] = newDir->win_mtime[1];\r
+               if(yfsd_NameIsValid(name))
+               {
+                       newDir = yaffs_MknodDirectory(parent,name,0,0,0);
+                       if(newDir)
+                       {
+                               objSize = yaffs_GetObjectFileLength(newDir);
+                               attribs = yfsd_GetObjectWinAttributes(newDir);
+                               modifiedTime[0] = newDir->win_mtime[0];
+                                modifiedTime[1] = newDir->win_mtime[1];
+                       }
+                       else
+                       {
+                               if(yaffs_FindObjectByName(parent,name))
+                                       SetLastError(ERROR_ALREADY_EXISTS);
+                               else
+                                       SetLastError(ERROR_DISK_FULL);
+                       }
+               }
+               else
+                       SetLastError(ERROR_INVALID_NAME);
        }
        else
        {
                SetLastError(ERROR_PATH_NOT_FOUND);
        }
+    //slf021101b end
 
        yfsd_UnlockYAFFS();
 
@@ -752,10 +996,12 @@ BOOL YFSD_CreateDirectoryW(PVOLUME pVolume, PCWSTR pathName, PSECURITY_ATTRIBUTE
 
        }
 
-       if(parent && !newDir)
-       {
-                       SetLastError(ERROR_DISK_FULL);
-       }
+//slf021101b begin 
+//     if(parent && !newDir)
+//     {
+//                     SetLastError(ERROR_DISK_FULL);
+//     }
+//slf021101b end
 
        return newDir ? TRUE : FALSE;
 }
@@ -871,19 +1117,19 @@ DWORD YFSD_GetFileAttributesW(PVOLUME pVolume, PCWSTR pwsFileName )
 
 BOOL YFSD_SetFileAttributesW( PVOLUME pVolume,PCWSTR pwsFileName, DWORD dwFileAttributes )
 {
-       yaffs_Object *obj = NULL;\r
-       DWORD mtime[2];\r
-       DWORD attribs;\r
+       yaffs_Object *obj = NULL;
+       DWORD mtime[2];
+       DWORD attribs;
        DWORD objSize;
 
        int result = 0;
 
-       RETAILMSG (MSGSTATE, (L"YAFFS::SetFileAttributes %X\r\n",dwFileAttributes));\r
-\r
-       if(!yfsd_CheckValidAttributes(dwFileAttributes))\r
-       {\r
-                       SetLastError(ERROR_INVALID_PARAMETER);\r
-                       return FALSE;\r
+       RETAILMSG (MSGSTATE, (L"YAFFS::SetFileAttributes %X\r\n",dwFileAttributes));
+
+       if(!yfsd_CheckValidAttributes(dwFileAttributes))
+       {
+                       SetLastError(ERROR_INVALID_PARAMETER);
+                       return FALSE;
        }
 
        yfsd_LockYAFFS();
@@ -894,11 +1140,11 @@ BOOL YFSD_SetFileAttributesW( PVOLUME pVolume,PCWSTR pwsFileName, DWORD dwFileAt
        {
                obj->st_mode = dwFileAttributes;
                obj->dirty = 1;
-               result = yaffs_FlushFile(obj);\r
-               attribs = yfsd_GetObjectWinAttributes(obj);\r
-               objSize = yaffs_GetObjectFileLength(obj);\r
-               mtime[0] = obj->win_mtime[0];\r
-               mtime[1] = obj->win_mtime[1];\r
+               result = yaffs_FlushFile(obj,0);
+               attribs = yfsd_GetObjectWinAttributes(obj);
+               objSize = yaffs_GetObjectFileLength(obj);
+               mtime[0] = obj->win_mtime[0];
+               mtime[1] = obj->win_mtime[1];
        }
        else
        {
@@ -971,7 +1217,7 @@ BOOL YFSD_MoveFileW(PVOLUME pVolume,PCWSTR pwsOldFileName, PCWSTR pwsNewFileName
        int result = 0;
        int objIsDir = 0;
        DWORD attribs;
-       DWORD objSize;\r
+       DWORD objSize;
        DWORD mtime[2];
 
        RETAILMSG (MSGSTATE, (L"YAFFS::MoveFile\r\n"));
@@ -994,9 +1240,9 @@ BOOL YFSD_MoveFileW(PVOLUME pVolume,PCWSTR pwsOldFileName, PCWSTR pwsNewFileName
                {
                        objIsDir = (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY);
                        attribs = yfsd_GetObjectWinAttributes(obj);
-                       objSize = yaffs_GetObjectFileLength(obj);\r
-                       mtime[0] = obj->win_mtime[0];\r
-                       mtime[1] = obj->win_mtime[1];\r
+                       objSize = yaffs_GetObjectFileLength(obj);
+                       mtime[0] = obj->win_mtime[0];
+                       mtime[1] = obj->win_mtime[1];
                }
        }
        else
@@ -1036,8 +1282,18 @@ BOOL YFSD_MoveFileW(PVOLUME pVolume,PCWSTR pwsOldFileName, PCWSTR pwsNewFileName
 
 BOOL YFSD_DeleteAndRenameFileW(PVOLUME pVolume, PCWSTR pwsOldFileName, PCWSTR pwsNewFileName )
 {
-       RETAILMSG (MSGSTATE, (L"YAFFS::DeleteAndRename\r\n"));
-       return FALSE;
+       //slf021104c begin\r
+    BOOL fSuccess;\r
+       //slf021104c end\r
+\r
+       RETAILMSG (MSGSTATE, (L"YAFFS::DeleteAndRename\r\n"));\r
+\r
+       //slf021104c begin
+    if (fSuccess = YFSD_DeleteFileW(pVolume, pwsOldFileName))\r
+        fSuccess = YFSD_MoveFileW(pVolume, pwsNewFileName, pwsOldFileName);\r
+       return fSuccess;\r
+       //return FALSE;
+       //slf021104c end\r
 }
 
 BOOL YFSD_GetDiskFreeSpaceW( PVOLUME pVolume, PCWSTR pwsPathName, PDWORD pSectorsPerCluster,PDWORD pBytesPerSector, PDWORD pFreeClusters, PDWORD pClusters )
@@ -1232,8 +1488,8 @@ BOOL yfsd_ObjectAlreadyFound(PSEARCH pSearch, yaffs_Object *l)
 
   return found;
 }
-\r
-#if 0\r
+
+#if 0
 // slower one
 BOOL yfsd_DoFindFile(PSEARCH pSearch, PWIN32_FIND_DATAW pfd)
 {
@@ -1309,77 +1565,77 @@ out_of_here:
        return found;
        
 }
-\r
-#else\r
-// faster one\r
-BOOL yfsd_DoFindFile(PSEARCH pSearch, PWIN32_FIND_DATAW pfd)\r
-{\r
-\r
-       struct list_head *i;\r
-       yaffs_Object *l;\r
-       BOOL found = 0;\r
-\r
-       char name[YAFFS_MAX_NAME_LENGTH+1];\r
-\r
-  if(!pSearch->foundObjects)\r
-  {\r
-    pSearch->foundObjects = malloc(sizeof(yaffs_FoundObject));\r
-    pSearch->foundObjects->next = NULL;\r
-    pSearch->foundObjects->obj = 0;\r
-  }\r
-\r
-\r
-       yfsd_LockYAFFS();\r
-\r
-       list_for_each(i,&pSearch->dir->variant.directoryVariant.children)\r
-       {\r
-\r
-               l = list_entry(i, yaffs_Object,siblings);\r
-               if(!yfsd_ObjectAlreadyFound(pSearch,l))\r
-               {\r
-                       // Only look at things we have not looked at already\r
-                       yaffs_GetObjectName(l,name,YAFFS_MAX_NAME_LENGTH+1);\r
-\r
-                       if(regularMatch(pSearch->pattern,name))\r
-                       {\r
-                               found = 1;\r
-                               // fill out find data\r
-\r
-                               pfd->dwFileAttributes = yfsd_GetObjectWinAttributes(l);\r
-\r
-                               yfsd_U32sToWinFileTime(l->win_ctime,&pfd->ftCreationTime);\r
-                               yfsd_U32sToWinFileTime(l->win_atime,&pfd->ftLastAccessTime);\r
-                               yfsd_U32sToWinFileTime(l->win_mtime,&pfd->ftLastWriteTime);\r
-\r
-                               pfd->nFileSizeHigh = 0;\r
-                               pfd->nFileSizeLow = yaffs_GetObjectFileLength(l);\r
-                               pfd->dwOID = 0; // wtf is this???\r
-\r
-                               MultiByteToWideChar(CP_ACP,0,name,-1,pfd->cFileName,YFSD_NAME_LENGTH);\r
-\r
-                               RETAILMSG(MSGSTATE,(L"File %s id %d header %d nDataChunks %d scannedLength %d\r\n",\r
-                                                       pfd->cFileName,l->objectId, l->chunkId, l->nDataChunks,\r
-                                                       l->variant.fileVariant.scannedFileSize));\r
-                               goto out_of_here;\r
-                       }\r
-\r
-               }\r
-\r
-\r
-       }\r
-\r
-out_of_here:\r
-       yfsd_UnlockYAFFS();\r
-\r
-\r
-       if(!found)\r
-       {\r
-               SetLastError(ERROR_NO_MORE_FILES);\r
-       }\r
-       return found;\r
-       \r
-}\r
-#endif\r
+
+#else
+// faster one
+BOOL yfsd_DoFindFile(PSEARCH pSearch, PWIN32_FIND_DATAW pfd)
+{
+
+       struct list_head *i;
+       yaffs_Object *l;
+       BOOL found = 0;
+
+       char name[YAFFS_MAX_NAME_LENGTH+1];
+
+  if(!pSearch->foundObjects)
+  {
+    pSearch->foundObjects = malloc(sizeof(yaffs_FoundObject));
+    pSearch->foundObjects->next = NULL;
+    pSearch->foundObjects->obj = 0;
+  }
+
+
+       yfsd_LockYAFFS();
+
+       list_for_each(i,&pSearch->dir->variant.directoryVariant.children)
+       {
+
+               l = list_entry(i, yaffs_Object,siblings);
+               if(!yfsd_ObjectAlreadyFound(pSearch,l))
+               {
+                       // Only look at things we have not looked at already
+                       yaffs_GetObjectName(l,name,YAFFS_MAX_NAME_LENGTH+1);
+
+                       if(regularMatch(pSearch->pattern,name))
+                       {
+                               found = 1;
+                               // fill out find data
+
+                               pfd->dwFileAttributes = yfsd_GetObjectWinAttributes(l);
+
+                               yfsd_U32sToWinFileTime(l->win_ctime,&pfd->ftCreationTime);
+                               yfsd_U32sToWinFileTime(l->win_atime,&pfd->ftLastAccessTime);
+                               yfsd_U32sToWinFileTime(l->win_mtime,&pfd->ftLastWriteTime);
+
+                               pfd->nFileSizeHigh = 0;
+                               pfd->nFileSizeLow = yaffs_GetObjectFileLength(l);
+                               pfd->dwOID = 0; // wtf is this???
+
+                               MultiByteToWideChar(CP_ACP,0,name,-1,pfd->cFileName,YFSD_NAME_LENGTH);
+
+                               RETAILMSG(MSGSTATE,(L"File %s id %d header %d nDataChunks %d scannedLength %d\r\n",
+                                                       pfd->cFileName,l->objectId, l->chunkId, l->nDataChunks,
+                                                       l->variant.fileVariant.scannedFileSize));
+                               goto out_of_here;
+                       }
+
+               }
+
+
+       }
+
+out_of_here:
+       yfsd_UnlockYAFFS();
+
+
+       if(!found)
+       {
+               SetLastError(ERROR_NO_MORE_FILES);
+       }
+       return found;
+       
+}
+#endif
 
 HANDLE YFSD_FindFirstFileW(PVOLUME pVolume, HANDLE hProc,PCWSTR pwsFileSpec, PWIN32_FIND_DATAW pfd )
 {
@@ -1484,7 +1740,12 @@ HANDLE YFSD_CreateFileW(
        unsigned modifiedTime[2];
        unsigned objSize;
 
-       BOOL writePermitted = (dwAccess & GENERIC_WRITE) ? TRUE : FALSE;
+       BOOL writePermitted = (dwAccess & GENERIC_WRITE) ? TRUE : FALSE;\r
+       BOOL readPermitted = (dwAccess & GENERIC_READ) ? TRUE : FALSE;\r
+       BOOL shareRead = (dwShareMode & FILE_SHARE_READ) ? TRUE : FALSE;\r
+       BOOL shareWrite = (dwShareMode & FILE_SHARE_WRITE) ? TRUE : FALSE;\r
+\r
+       BOOL openRead, openWrite, openReadAllowed, openWriteAllowed;\r
 
        BOOL fileCreated = FALSE;
 
@@ -1502,11 +1763,11 @@ HANDLE YFSD_CreateFileW(
                RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile write not permitted\r\n"));
        }
 
-       if(!yfsd_CheckValidAttributes(mode))\r
-       {\r
-                       SetLastError(ERROR_INVALID_PARAMETER);\r
-                       return FALSE;\r
-       }\r
+       if(!yfsd_CheckValidAttributes(mode))
+       {
+                       SetLastError(ERROR_INVALID_PARAMETER);
+                       return FALSE;
+       }
 
        yfsd_LockYAFFS();
 
@@ -1516,24 +1777,26 @@ HANDLE YFSD_CreateFileW(
 
        if(parent && yfsd_NameIsValid(name))
        {
-\r
 
-               obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);\r
-               if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)\r
-               {\r
-                       // Naughty, naughty. Don't do file ops on directories\r
-                       SetLastError(ERROR_ACCESS_DENIED);\r
-                       fileCreated = FALSE;\r
-                       obj = NULL;\r
-               }\r
-               else if(dwCreate == CREATE_NEW)
+               if(dwCreate == CREATE_NEW)
                {
                        RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile creating file in CREATE_NEW\r\n"));
 
-                       obj = yaffs_MknodFile(parent,name,mode,0,0);
+                       //slf021101c begin
+                       obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
                        if(!obj)
-                               SetLastError(ERROR_DISK_FULL);
-                       fileCreated = TRUE;
+                       {
+                               obj = yaffs_MknodFile(parent,name,mode,0,0);
+                               if(!obj)
+                                       SetLastError(ERROR_DISK_FULL);
+                               fileCreated = TRUE;
+                       }
+                       else
+                       {
+                               obj = NULL;
+                               SetLastError(ERROR_ALREADY_EXISTS);
+                       }\r
+                       //slf021101c end
                }
                else if( dwCreate == OPEN_ALWAYS)
                {
@@ -1558,6 +1821,14 @@ HANDLE YFSD_CreateFileW(
                        obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
                        if(!obj)
                                SetLastError(ERROR_FILE_NOT_FOUND);
+            //slf021101c begin
+                       else
+                               if (yfsd_GetObjectWinAttributes(obj) & FILE_ATTRIBUTE_DIRECTORY)
+                               {
+                                       SetLastError(ERROR_ACCESS_DENIED);
+                                       obj = NULL;
+                               }
+            //slf021101c end
                }
                else if(dwCreate == TRUNCATE_EXISTING)
                {
@@ -1590,7 +1861,7 @@ HANDLE YFSD_CreateFileW(
                                obj->st_mode = mode;
                                obj->dirty = 1;
                                yaffs_ResizeFile(obj,0);
-                               yaffs_FlushFile(obj);
+                               yaffs_FlushFile(obj,1);
                        }
                }
                else
@@ -1604,7 +1875,41 @@ HANDLE YFSD_CreateFileW(
                RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile unable to get parent node\r\n"));
                SetLastError(ERROR_PATH_NOT_FOUND);
        }
-
+\r
+       if(obj)\r
+       {\r
+                       int i;\r
+                       yfsd_WinFile *p;\r
+                       openRead = openWrite =0;\r
+                       openReadAllowed = openWriteAllowed = 1;\r
+\r
+                       for(i = 0; i < MAX_WIN_FILE; i++)\r
+                       {\r
+                                       p = &yfsd_winFile[i];\r
+\r
+                                       if(p->obj == obj)\r
+                                       {\r
+                                               if (p->readPermitted) openRead = 1;\r
+                                               if (p->writePermitted) openWrite = 1;\r
+                                               if (!p->shareRead) openReadAllowed = 0;\r
+                                               if (!p->shareWrite) openWriteAllowed = 0;\r
+                                       }\r
+\r
+                       }\r
+\r
+                       // Now we test if the share works out.\r
+\r
+                       if((openRead && !shareRead) ||   // already open for read, but we are not prepared to share it for read\r
+                          (openWrite && !shareWrite) || // already open for write, but we are not prepared to share it for write\r
+                          (!openReadAllowed && readPermitted) || // already open with read sharing not permitted\r
+                          (!openWriteAllowed && writePermitted)) // same... write\r
+                       {\r
+                               SetLastError(ERROR_ACCESS_DENIED);\r
+                               obj = NULL;\r
+                       }\r
+\r
+\r
+       }
        if(obj)
        {
                RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - we have an object\r\n"));
@@ -1625,12 +1930,15 @@ HANDLE YFSD_CreateFileW(
                        RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - we have an fsdmgr handle\r\n"));
                        f->obj = obj;
                        f->offset = 0;
-                       f->writePermitted = writePermitted;
+                       f->writePermitted = writePermitted;\r
+                       f->readPermitted = writePermitted;\r
+                       f->shareRead= shareRead;\r
+                       f->shareWrite = shareWrite;\r
                        f->myVolume = pVolume;
                        obj->inUse++;
 
-                       modifiedTime[0] = obj->win_mtime[0];\r
-                       modifiedTime[1] = obj->win_mtime[1];\r
+                       modifiedTime[0] = obj->win_mtime[0];
+                       modifiedTime[1] = obj->win_mtime[1];
                        objSize = yaffs_GetObjectFileLength(obj);
                        RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - file size %d\r\n",objSize));
                }
@@ -1737,8 +2045,8 @@ BOOL yfsd_DoReadFile(
        {
                nread = yaffs_ReadDataFromFile(obj,pBuffer,pFile->offset,cbRead);
                if(nread > 0)
-               {\r
-                       pFile->offset += nread;\r
+               {
+                       pFile->offset += nread;
 
                        if(pcbRead)
                        {
@@ -1748,9 +2056,9 @@ BOOL yfsd_DoReadFile(
        }
        else
        {
-               if(pcbRead) \r
-               {\r
-                       *pcbRead = maxRead;\r
+               if(pcbRead) 
+               {
+                       *pcbRead = maxRead;
                }
        }
 
@@ -1794,7 +2102,7 @@ BOOL YFSD_ReadFileWithSeek(
        DWORD dwLowOffset, 
        DWORD dwHighOffset )
 {
-       BOOL result;\r
+       BOOL result;
        DWORD rememberedOffset;
 
        RETAILMSG (MSGSTATE, (L"YAFFS::ReadFileWithSeek %d bytes at %d high %d pcbRead %X\r\n",cbRead,dwLowOffset,dwHighOffset,pcbRead));
@@ -1813,16 +2121,16 @@ BOOL YFSD_ReadFileWithSeek(
                return FALSE;
        }
 
-       yfsd_LockYAFFS();\r
-\r
+       yfsd_LockYAFFS();
+
        rememberedOffset = pFile->offset;
 
        pFile->offset = dwLowOffset;
        // ignore high offset for now
 
        result = yfsd_DoReadFile(pFile,pBuffer,cbRead,pcbRead);
-\r
-       //pFile->offset = rememberedOffset;\r
+
+       //pFile->offset = rememberedOffset;
 
        yfsd_UnlockYAFFS();
 
@@ -1909,7 +2217,7 @@ BOOL YFSD_WriteFileWithSeek(
        DWORD rememberedOffset;
        RETAILMSG (MSGSTATE, (L"YAFFS::WriteFileWithSeek %d bytes at %d,%d pcbWritten %X\r\n",cbWrite,dwHighOffset,dwLowOffset,pcbWritten));
 
-       \r
+       
 
        if(!pFile || !pFile->obj)
        {
@@ -1918,15 +2226,15 @@ BOOL YFSD_WriteFileWithSeek(
        }
 
        yfsd_LockYAFFS();
-\r
-       rememberedOffset = pFile->offset;\r
+
+       rememberedOffset = pFile->offset;
 
        pFile->offset = dwLowOffset;
        // ignore high offset for now
 
        result = yfsd_DoWriteFile(pFile,pBuffer,cbWrite,pcbWritten);
-\r
-       //pFile->offset = rememberedOffset;\r
+
+       //pFile->offset = rememberedOffset;
 
        yfsd_UnlockYAFFS();
 
@@ -1953,8 +2261,8 @@ DWORD YFSD_SetFilePointer(
                return offset;
        }
 
-       yfsd_LockYAFFS();\r
-\r
+       yfsd_LockYAFFS();
+
 
        oldPos = pFile->offset;
 
@@ -2028,8 +2336,8 @@ DWORD YFSD_GetFileSize(
 
        fileSize = yaffs_GetObjectFileLength(pFile->obj);
 
-       yfsd_UnlockYAFFS();\r
-       if(pFileSizeHigh)\r
+       yfsd_UnlockYAFFS();
+       if(pFileSizeHigh)
                 *pFileSizeHigh = 0;
 
        return fileSize;
@@ -2047,35 +2355,40 @@ BOOL YFSD_GetFileInformationByHandle(
        {
                SetLastError(ERROR_INVALID_HANDLE);
                return FALSE;
-       }\r
-\r
-       yfsd_LockYAFFS();\r
-\r
-       pFileInfo->dwFileAttributes = yfsd_GetObjectWinAttributes(pFile->obj);\r
-       yfsd_U32sToWinFileTime(pFile->obj->win_ctime,&pFileInfo->ftCreationTime);\r
-       yfsd_U32sToWinFileTime(pFile->obj->win_atime,&pFileInfo->ftLastAccessTime);\r
-       yfsd_U32sToWinFileTime(pFile->obj->win_mtime,&pFileInfo->ftLastWriteTime);\r
-       pFileInfo->dwVolumeSerialNumber = 0; //todo is this OK? \r
-       pFileInfo->nFileSizeHigh = 0;\r
-       pFileInfo->nFileSizeLow = yaffs_GetObjectFileLength(pFile->obj); \r
-       pFileInfo->nNumberOfLinks = 1; // only primary link supported like FAT\r
-       pFileInfo->nFileIndexHigh = 0; \r
-       pFileInfo->nFileIndexLow = pFile->obj->objectId; \r
-\r
+       }
+
+       yfsd_LockYAFFS();
+
+       pFileInfo->dwFileAttributes = yfsd_GetObjectWinAttributes(pFile->obj);
+       yfsd_U32sToWinFileTime(pFile->obj->win_ctime,&pFileInfo->ftCreationTime);
+       yfsd_U32sToWinFileTime(pFile->obj->win_atime,&pFileInfo->ftLastAccessTime);
+       yfsd_U32sToWinFileTime(pFile->obj->win_mtime,&pFileInfo->ftLastWriteTime);
+       pFileInfo->dwVolumeSerialNumber = 0; //todo is this OK? 
+       pFileInfo->nFileSizeHigh = 0;
+       pFileInfo->nFileSizeLow = yaffs_GetObjectFileLength(pFile->obj); 
+       pFileInfo->nNumberOfLinks = 1; // only primary link supported like FAT
+       pFileInfo->nFileIndexHigh = 0; 
+       pFileInfo->nFileIndexLow = pFile->obj->objectId;\r
+//slf021104a Begin Window CE 4.0 added an additional field.\r
+#if _WINCEOSVER >= 400
+       pFileInfo->dwOID = (CEOID)(INVALID_HANDLE_VALUE);\r
+#endif\r
+//slf021104a end\r
+
        yfsd_UnlockYAFFS();
 
        return TRUE;
 }
 
 BOOL YFSD_FlushFileBuffers(PFILE pFile )
-{\r
-       WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];\r
-       int nameExists = 0;\r
-       yfsd_Volume *vol = NULL;\r
-       DWORD attribs = 0;\r
-       DWORD objSize = 0;\r
-       DWORD mtime[2];\r
-\r
+{
+       WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
+       int nameExists = 0;
+       yfsd_Volume *vol = NULL;
+       DWORD attribs = 0;
+       DWORD objSize = 0;
+       DWORD mtime[2];
+
 
        RETAILMSG (MSGSTATE, (L"YAFFS::FlushFileBuffers\r\n"));
 
@@ -2085,40 +2398,40 @@ BOOL YFSD_FlushFileBuffers(PFILE pFile )
                return FALSE;
        }
 
-       yfsd_LockYAFFS();\r
+       yfsd_LockYAFFS();
+
+       yaffs_FlushFile(pFile->obj,1);
+       attribs = yfsd_GetObjectWinAttributes(pFile->obj);
+       objSize = yaffs_GetObjectFileLength(pFile->obj);
+       mtime[0] = pFile->obj->win_mtime[0];
+       mtime[1] = pFile->obj->win_mtime[1];
+       if(pFile->fullName)
+       {
+               wcscpy(fpn,pFile->fullName);
+               nameExists = 1;
+       }
+       vol = pFile->myVolume;
 
-       yaffs_FlushFile(pFile->obj);\r
-       attribs = yfsd_GetObjectWinAttributes(pFile->obj);\r
-       objSize = yaffs_GetObjectFileLength(pFile->obj);\r
-       mtime[0] = pFile->obj->win_mtime[0];\r
-       mtime[1] = pFile->obj->win_mtime[1];\r
-       if(pFile->fullName)\r
-       {\r
-               wcscpy(fpn,pFile->fullName);\r
-               nameExists = 1;\r
-       }\r
-       vol = pFile->myVolume;\r
-\r
        yfsd_UnlockYAFFS();
-       \r
-       if(vol && vol->shellFunction && nameExists)\r
-       {\r
-                       FILECHANGEINFO fc;\r
-               \r
-                       fc.cbSize = sizeof(FILECHANGEINFO);\r
-                       fc.wEventId = SHCNE_UPDATEITEM;\r
-                       fc.uFlags = SHCNF_PATH;\r
-                       fc.dwItem1 = (DWORD)fpn;\r
-                       fc.dwItem2 = 0;\r
-                       fc.dwAttributes = attribs;\r
-                       yfsd_U32sToWinFileTime(mtime,&fc.ftModified);\r
-                       fc.nFileSize = objSize;\r
-\r
-                       vol->shellFunction(&fc);\r
-                       RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));\r
-                       //yfsd_ShellDirectoryChanged(vol,fpn);\r
-       }\r
-\r
+       
+       if(vol && vol->shellFunction && nameExists)
+       {
+                       FILECHANGEINFO fc;
+               
+                       fc.cbSize = sizeof(FILECHANGEINFO);
+                       fc.wEventId = SHCNE_UPDATEITEM;
+                       fc.uFlags = SHCNF_PATH;
+                       fc.dwItem1 = (DWORD)fpn;
+                       fc.dwItem2 = 0;
+                       fc.dwAttributes = attribs;
+                       yfsd_U32sToWinFileTime(mtime,&fc.ftModified);
+                       fc.nFileSize = objSize;
+
+                       vol->shellFunction(&fc);
+                       RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
+                       //yfsd_ShellDirectoryChanged(vol,fpn);
+       }
+
        
        return TRUE;
 }
@@ -2154,15 +2467,15 @@ BOOL YFSD_SetFileTime(
        CONST FILETIME *pLastAccess, 
        CONST FILETIME *pLastWrite )
 {
-       WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];\r
-       int nameExists = 0;\r
+       WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
+       int nameExists = 0;
        int result = FALSE;
-       yfsd_Volume *vol = NULL;\r
-       DWORD attribs = 0;\r
-       DWORD objSize = 0;\r
-       DWORD mtime[2];\r
-\r
-       \r
+       yfsd_Volume *vol = NULL;
+       DWORD attribs = 0;
+       DWORD objSize = 0;
+       DWORD mtime[2];
+
+       
        RETAILMSG (MSGSTATE, (L"YAFFS::SetFileTime\r\n"));
 
        if(!pFile || !pFile->obj)
@@ -2174,60 +2487,60 @@ BOOL YFSD_SetFileTime(
        
        yfsd_LockYAFFS();
 
-       if(pCreation) \r
-       {\r
-                yfsd_WinFileTimeToU32s(pCreation,pFile->obj->win_ctime);\r
-               pFile->obj->dirty = 1;\r
+       if(pCreation) 
+       {
+                yfsd_WinFileTimeToU32s(pCreation,pFile->obj->win_ctime);
+               pFile->obj->dirty = 1;
        }
-       if(pLastAccess)\r
-       {\r
-               yfsd_WinFileTimeToU32s(pLastAccess,pFile->obj->win_atime);\r
-               pFile->obj->dirty = 1;\r
+       if(pLastAccess)
+       {
+               yfsd_WinFileTimeToU32s(pLastAccess,pFile->obj->win_atime);
+               pFile->obj->dirty = 1;
        }
-       if(pLastWrite)\r
-       {\r
-               yfsd_WinFileTimeToU32s(pLastWrite,pFile->obj->win_mtime);\r
+       if(pLastWrite)
+       {
+               yfsd_WinFileTimeToU32s(pLastWrite,pFile->obj->win_mtime);
                pFile->obj->dirty = 1;
        }
        if(pCreation || pLastAccess || pLastWrite)
        {
-               result = yaffs_FlushFile(pFile->obj);
+               result = yaffs_FlushFile(pFile->obj,0);
        }
-\r
-       if(result)\r
+
+       if(result)
        {
-               attribs = yfsd_GetObjectWinAttributes(pFile->obj);\r
-               objSize = yaffs_GetObjectFileLength(pFile->obj);\r
-               mtime[0] = pFile->obj->win_mtime[0];\r
-               mtime[1] = pFile->obj->win_mtime[1];\r
-               if(pFile->fullName)\r
-               {\r
-                       wcscpy(fpn,pFile->fullName);\r
-                       nameExists = 1;\r
-               }\r
-               vol = pFile->myVolume;\r
-       }\r
-\r
+               attribs = yfsd_GetObjectWinAttributes(pFile->obj);
+               objSize = yaffs_GetObjectFileLength(pFile->obj);
+               mtime[0] = pFile->obj->win_mtime[0];
+               mtime[1] = pFile->obj->win_mtime[1];
+               if(pFile->fullName)
+               {
+                       wcscpy(fpn,pFile->fullName);
+                       nameExists = 1;
+               }
+               vol = pFile->myVolume;
+       }
+
        yfsd_UnlockYAFFS();
 
        // Call shell function
-       if(nameExists && result && vol && vol->shellFunction)\r
-       {\r
-                       FILECHANGEINFO fc;\r
-               \r
-                       fc.cbSize = sizeof(FILECHANGEINFO);\r
-                       fc.wEventId = SHCNE_UPDATEITEM;\r
-                       fc.uFlags = SHCNF_PATH;\r
-                       fc.dwItem1 = (DWORD)fpn;\r
-                       fc.dwItem2 = 0;\r
-                       fc.dwAttributes = attribs;\r
-                       yfsd_U32sToWinFileTime(mtime,&fc.ftModified);\r
-                       fc.nFileSize = objSize;\r
-\r
-                       vol->shellFunction(&fc);\r
-                       RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));\r
-                       //yfsd_ShellDirectoryChanged(vol,fpn);\r
-       }\r
+       if(nameExists && result && vol && vol->shellFunction)
+       {
+                       FILECHANGEINFO fc;
+               
+                       fc.cbSize = sizeof(FILECHANGEINFO);
+                       fc.wEventId = SHCNE_UPDATEITEM;
+                       fc.uFlags = SHCNF_PATH;
+                       fc.dwItem1 = (DWORD)fpn;
+                       fc.dwItem2 = 0;
+                       fc.dwAttributes = attribs;
+                       yfsd_U32sToWinFileTime(mtime,&fc.ftModified);
+                       fc.nFileSize = objSize;
+
+                       vol->shellFunction(&fc);
+                       RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
+                       //yfsd_ShellDirectoryChanged(vol,fpn);
+       }
 
        return TRUE;
 }
@@ -2236,12 +2549,12 @@ BOOL YFSD_SetEndOfFile(
 PFILE pFile )
 {
 
-       WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];\r
-       int nameExists = 0;\r
-       yfsd_Volume *vol = NULL;\r
-       DWORD attribs = 0;\r
-       DWORD objSize = 0;\r
-       DWORD mtime[2];\r
+       WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
+       int nameExists = 0;
+       yfsd_Volume *vol = NULL;
+       DWORD attribs = 0;
+       DWORD objSize = 0;
+       DWORD mtime[2];
        static unsigned char zeros[512];
 
        int result;
@@ -2303,40 +2616,40 @@ PFILE pFile )
        {
                retVal = TRUE;
        }
-       if(retVal)\r
-       {\r
-               attribs = yfsd_GetObjectWinAttributes(pFile->obj);\r
-               objSize = yaffs_GetObjectFileLength(pFile->obj);\r
-               mtime[0] = pFile->obj->win_mtime[0];\r
-               mtime[1] = pFile->obj->win_mtime[1];\r
-               if(pFile->fullName)\r
-               {\r
-                       wcscpy(fpn,pFile->fullName);\r
-                       nameExists = 1;\r
-               }\r
-               vol = pFile->myVolume;\r
-       }\r
-\r
-\r
-       yfsd_UnlockYAFFS();\r
-\r
-       if(nameExists && retVal && vol && vol->shellFunction)\r
-       {\r
-                       FILECHANGEINFO fc;\r
-               \r
-                       fc.cbSize = sizeof(FILECHANGEINFO);\r
-                       fc.wEventId = SHCNE_UPDATEITEM;\r
-                       fc.uFlags = SHCNF_PATH;\r
-                       fc.dwItem1 = (DWORD)fpn;\r
-                       fc.dwItem2 = 0;\r
-                       fc.dwAttributes = attribs;\r
-                       yfsd_U32sToWinFileTime(mtime,&fc.ftModified);\r
-                       fc.nFileSize = objSize;\r
-\r
-                       vol->shellFunction(&fc);\r
-                       RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));\r
-                       //yfsd_ShellDirectoryChanged(vol,fpn);\r
-       }\r
+       if(retVal)
+       {
+               attribs = yfsd_GetObjectWinAttributes(pFile->obj);
+               objSize = yaffs_GetObjectFileLength(pFile->obj);
+               mtime[0] = pFile->obj->win_mtime[0];
+               mtime[1] = pFile->obj->win_mtime[1];
+               if(pFile->fullName)
+               {
+                       wcscpy(fpn,pFile->fullName);
+                       nameExists = 1;
+               }
+               vol = pFile->myVolume;
+       }
+
+
+       yfsd_UnlockYAFFS();
+
+       if(nameExists && retVal && vol && vol->shellFunction)
+       {
+                       FILECHANGEINFO fc;
+               
+                       fc.cbSize = sizeof(FILECHANGEINFO);
+                       fc.wEventId = SHCNE_UPDATEITEM;
+                       fc.uFlags = SHCNF_PATH;
+                       fc.dwItem1 = (DWORD)fpn;
+                       fc.dwItem2 = 0;
+                       fc.dwAttributes = attribs;
+                       yfsd_U32sToWinFileTime(mtime,&fc.ftModified);
+                       fc.nFileSize = objSize;
+
+                       vol->shellFunction(&fc);
+                       RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
+                       //yfsd_ShellDirectoryChanged(vol,fpn);
+       }
 
        RETAILMSG (MSGSTATE, (L"YAFFS::SetEOF file size %d\r\n",yaffs_GetObjectFileLength(pFile->obj)));
 
@@ -2367,7 +2680,7 @@ BOOL YFSD_CloseFile( PFILE pFile )
        yfsd_Volume *vol = NULL;
        DWORD attribs = 0;
        DWORD objSize = 0;
-       DWORD mtime[2];\r
+       DWORD mtime[2];
 
        RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile %X\r\n",pFile));
 
@@ -2383,11 +2696,11 @@ BOOL YFSD_CloseFile( PFILE pFile )
                {
                        pFile->obj->inUse--;
                        RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile on obj\r\n"));
-                       yaffs_FlushFile(pFile->obj);
+                       yaffs_FlushFile(pFile->obj,1);
                        attribs = yfsd_GetObjectWinAttributes(pFile->obj);
                        objSize = yaffs_GetObjectFileLength(pFile->obj);
-                       mtime[0] = pFile->obj->win_mtime[0];\r
-                       mtime[1] = pFile->obj->win_mtime[1];\r
+                       mtime[0] = pFile->obj->win_mtime[0];
+                       mtime[1] = pFile->obj->win_mtime[1];
                        RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile on obj done, size is %d\r\n",objSize));
                        if(pFile->fullName)
                        {
index f4a324e113e33b2e590d7f73fd01009c04524648..3ee50eb739ab6a39f32bff4259b985a0ec331c14 100644 (file)
@@ -26,7 +26,7 @@
 #include <fcntl.h>
 #include <string.h>
 
-#define FILE_SIZE_IN_MEG 4
+#define FILE_SIZE_IN_MEG 2
 
 // #define YAFFS_ERROR_TESTING 
 
index 81b8ccf068fe7c9f4dd3556b407c437f8536a586..1f4f5b866fda28e3de6619506d721be107ee5795 100644 (file)
@@ -27,7 +27,7 @@
  */
 
 
-const char *yaffs_fs_c_version = "$Id: yaffs_fs.c,v 1.21 2002-11-26 01:39:53 charles Exp $";
+const char *yaffs_fs_c_version = "$Id: yaffs_fs.c,v 1.22 2003-01-14 23:15:29 charles Exp $";
 extern const char *yaffs_guts_c_version;
 
 
@@ -352,7 +352,7 @@ static int yaffs_file_flush(struct file* file)
 
        yaffs_GrossLock(dev);
        
-    yaffs_FlushFile(obj);
+    yaffs_FlushFile(obj,1);
 
        yaffs_GrossUnlock(dev);
 
@@ -853,8 +853,11 @@ static int yaffs_link(struct dentry *old_dentry, struct inode * dir, struct dent
        dev = obj->myDev;
        
        yaffs_GrossLock(dev);
-       
-       link = yaffs_Link(yaffs_InodeToObject(dir),dentry->d_name.name,obj);
+
+       if (!S_ISDIR(inode->i_mode))    // Don't link directories
+       {
+               link = yaffs_Link(yaffs_InodeToObject(dir),dentry->d_name.name,obj);
+       }
        
 
        if(link)
@@ -926,7 +929,7 @@ static int yaffs_sync_object(struct file * file, struct dentry *dentry, int data
        
        T(YAFFS_TRACE_OS,(KERN_DEBUG"yaffs_sync_object\n"));
        yaffs_GrossLock(dev);
-       yaffs_FlushFile(obj);
+       yaffs_FlushFile(obj,1);
        yaffs_GrossUnlock(dev);
        return 0;
 }
@@ -939,22 +942,44 @@ static int yaffs_sync_object(struct file * file, struct dentry *dentry, int data
 static int yaffs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry)
 {
        yaffs_Device *dev;
-       int retVal;
+       int retVal = YAFFS_FAIL;
+       int removed = 0;
+       yaffs_Object *target;
        
        dev = yaffs_InodeToObject(old_dir)->myDev;
 
        yaffs_GrossLock(dev);
        
-       // Unlink the target if it exists
-       yaffs_Unlink(yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
+       // Check if the target is an existing directory that is not empty.
+       target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
+       
+       if(target &&
+          target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+          !list_empty(&target->variant.directoryVariant.children))
+       {
+               retVal = YAFFS_FAIL;
+       }
+       else
+       {
+          
+               // Unlink the target if it exists
+               removed = yaffs_Unlink(yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
 
        
-       retVal =  yaffs_RenameObject(yaffs_InodeToObject(old_dir),old_dentry->d_name.name,
-                                        yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
+               retVal =  yaffs_RenameObject(yaffs_InodeToObject(old_dir),old_dentry->d_name.name,
+                                                                       yaffs_InodeToObject(new_dir),new_dentry->d_name.name);
+                                                                       
+       }
        yaffs_GrossUnlock(dev);
        
        if(retVal == YAFFS_OK)
        {
+               if(removed == YAFFS_OK)
+               {
+                       new_dentry->d_inode->i_nlink--;
+                       mark_inode_dirty(new_dentry->d_inode);
+               }
+               
                return 0;
        }
        else
@@ -1222,6 +1247,10 @@ static struct super_block *yaffs_internal_read_super(int useRam, struct super_bl
                dev->initialiseNAND = nandmtd_InitialiseNAND;
                                
                dev->putSuperFunc = yaffs_MTDPutSuper;
+               
+#ifdef CONFIG_YAFFS_USE_NANDECC
+               dev->useNANDECC = 1;
+#endif
 
                yaffs_dev = dev;
                
@@ -1312,6 +1341,8 @@ static char * yaffs_dump_dev(char *buf,yaffs_Device *dev,char *name)
        buf +=sprintf(buf,"nDeletedFiles...... %d\n",dev->nDeletedFiles);
        buf +=sprintf(buf,"nUnlinkedFiles..... %d\n",dev->nUnlinkedFiles);
        buf +=sprintf(buf,"nBackgroudDeletions %d\n",dev->nBackgroundDeletions);
+       buf +=sprintf(buf,"useNANDECC......... %d\n",dev->useNANDECC);
+
        
        return buf;     
 }
index 9ddabf687170d561ea5a87fbed323b82527540c9..bb714e01bcc79b6bc5df98f490545b8556a7fbcb 100644 (file)
@@ -14,7 +14,7 @@
  */
  //yaffs_guts.c
 
-const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.15 2002-12-13 00:13:06 charles Exp $";
+const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.16 2003-01-14 23:15:29 charles Exp $";
 
 #include "yportenv.h"
 
@@ -72,7 +72,7 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn
 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
 static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force);
-static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId);
+static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND);
 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
 static int yaffs_CheckStructures(void);
 static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);
@@ -90,7 +90,7 @@ static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaf
 static int  yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND);
 
 static int yaffs_UnlinkWorker(yaffs_Object *obj);
-
+static void yaffs_AbortHalfCreatedObject(yaffs_Object *obj);
 
 static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1);
 
@@ -113,12 +113,63 @@ static int yaffs_CheckFileSanity(yaffs_Object *in);
 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
 
+// Chunk bitmap manipulations
 
+static __inline __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
+{
+       if(blk < dev->startBlock || blk > dev->endBlock)
+       {
+               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),blk));
+               YBUG();
+       }
+       return dev->chunkBits + (dev->chunkBitmapStride * (blk - dev->startBlock));
+}
+
+static __inline__ void yaffs_ClearChunkBits(yaffs_Device *dev,int blk)
+{
+       __u8 *blkBits = yaffs_BlockBits(dev,blk);
+
+        memset(blkBits,0,dev->chunkBitmapStride);
+}
+
+static __inline__ void yaffs_ClearChunkBit(yaffs_Device *dev,int blk,int chunk)
+{
+       __u8 *blkBits = yaffs_BlockBits(dev,blk);
+       
+       blkBits[chunk/8] &=  ~ (1<<(chunk & 7));
+}
+
+static __inline__ void yaffs_SetChunkBit(yaffs_Device *dev,int blk,int chunk)
+{
+       __u8 *blkBits = yaffs_BlockBits(dev,blk);
+
+       blkBits[chunk/8] |=   (1<<(chunk & 7));
+}
+
+static __inline__ int yaffs_CheckChunkBit(yaffs_Device *dev,int blk,int chunk)
+{
+       __u8 *blkBits = yaffs_BlockBits(dev,blk);
+       return (blkBits[chunk/8] &  (1<<(chunk & 7))) ? 1 :0;
+}
+
+static __inline__ int yaffs_StillSomeChunkBits(yaffs_Device *dev,int blk)
+{
+       __u8 *blkBits = yaffs_BlockBits(dev,blk);
+       int i;
+       for(i = 0; i < dev->chunkBitmapStride; i++)
+       {
+               if(*blkBits) return 1;
+               blkBits++;
+       }
+       return 0;
+}
+
+// Function to manipulate block info
 static  __inline__ yaffs_BlockInfo* yaffs_GetBlockInfo(yaffs_Device *dev, int blk)
 {
        if(blk < dev->startBlock || blk > dev->endBlock)
        {
-               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: block %d is not valid" TENDSTR),blk));
+               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),blk));
                YBUG();
        }
        return &dev->blockInfo[blk - dev->startBlock];
@@ -154,11 +205,7 @@ static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND
        return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);
 }
 
-struct nandspare {
-       yaffs_Spare     spare;
-       int             eccres1;
-       int             eccres2;
-};
+
 
 int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
                                                        int chunkInNAND, 
@@ -169,12 +216,9 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
        int retVal;
        yaffs_Spare localSpare;
 
-#ifndef CONFIG_YAFFS_USE_NANDECC
        __u8 calcEcc[3];
        int eccResult1,eccResult2;
-#else
-       struct nandspare nspare;
-#endif 
+       struct yaffs_NANDSpare nspare;
 
        dev->nPageReads++;
        
@@ -189,7 +233,8 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
        }
        
 
-#ifndef CONFIG_YAFFS_USE_NANDECC
+       if(!dev->useNANDECC)
+       {
                retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
                if(data && doErrorCorrection)
                {
@@ -228,37 +273,39 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
                                yaffs_HandleReadDataError(dev,chunkInNAND);
                        }
                }
-#else
-       retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare);
-       memcpy (spare, &nspare, sizeof(yaffs_Spare));
-       if(data && doErrorCorrection)
-       {
-                if(nspare.eccres1>0)
-                {
-                       T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
-                }
-                else if(nspare.eccres1<0)
-                {
-                       T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
-                }
-
-                if(nspare.eccres2>0)
-                {
-                       T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
-                }
-                else if(nspare.eccres2<0)
-                {
-                       T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
-                }
-
-                if(nspare.eccres2 || nspare.eccres2)
-                {
-                       // Hoosterman, we had a data problem on this page
-                       yaffs_HandleReadDataError(dev,chunkInNAND);
-                }
+       }
+       else
+       {
+               retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare);
+               memcpy (spare, &nspare, sizeof(yaffs_Spare));
+               if(data && doErrorCorrection)
+               {
+                       if(nspare.eccres1>0)
+                       {
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
+                       }
+                       else if(nspare.eccres1<0)
+                       {
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
+                       }
 
+                       if(nspare.eccres2>0)
+                       {
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
+                       }
+                       else if(nspare.eccres2<0)
+                       {
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
+                       }
+
+                       if(nspare.eccres2 || nspare.eccres2)
+                       {
+                               // Hoosterman, we had a data problem on this page
+                               yaffs_HandleReadDataError(dev,chunkInNAND);
+                       }
+
+               }
        }
-#endif
        return retVal;
 }
 
@@ -448,7 +495,7 @@ static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
        // Mark the block for retirement
        yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
        // Delete the chunk
-       yaffs_DeleteChunk(dev,chunkInNAND);
+       yaffs_DeleteChunk(dev,chunkInNAND,1);
 }
 
 
@@ -505,7 +552,8 @@ static __u16 yaffs_CalcNameSum(const char *name)
        {
                while ((*bname) && (i <=YAFFS_MAX_NAME_LENGTH))
                {
-#ifdef CONFIG_YAFFS_WINCE
+
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
                        sum += toupper(*bname) * i;
 #else
                        sum += (*bname) * i;
@@ -639,9 +687,15 @@ static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
     for(i = 0; i < nTnodes - 1; i++)
     {
        newTnodes[i].internal[0] = &newTnodes[i+1];
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+       newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = 1;
+#endif
     }
        
        newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+       newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = 1;
+#endif
        dev->freeTnodes = newTnodes;
        dev->nFreeTnodes+= nTnodes;
        dev->nTnodesCreated += nTnodes;
@@ -684,6 +738,13 @@ static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
        if(dev->freeTnodes)
        {
                tn = dev->freeTnodes;
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+       if(tn->internal[YAFFS_NTNODES_INTERNAL] != 1)
+               {
+                       // Hoosterman, this thing looks like it isn't in the list
+                               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR)));
+               }
+#endif
                dev->freeTnodes = dev->freeTnodes->internal[0];
                dev->nFreeTnodes--;
                // zero out
@@ -698,9 +759,20 @@ static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
 // FreeTnode frees up a tnode and puts it back on the free list
 static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
 {
-       tn->internal[0] = dev->freeTnodes;
-       dev->freeTnodes = tn;
-       dev->nFreeTnodes++;
+       if(tn)
+       {
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+       if(tn->internal[YAFFS_NTNODES_INTERNAL] != 0)
+               {
+                       // Hoosterman, this thing looks like it is already in the list
+                               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR)));
+               }
+               tn->internal[YAFFS_NTNODES_INTERNAL] = 1;
+#endif
+               tn->internal[0] = dev->freeTnodes;
+               dev->freeTnodes = tn;
+               dev->nFreeTnodes++;
+       }
 }
 
 
@@ -970,7 +1042,9 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, in
                }
                else if(level == 0)
                {
-                       for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0; i--) //NB Don't apply the limit here, always delete a whole level0
+                       int hitLimit = 0;
+                       
+                       for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0 && !hitLimit; i--)
                        {
                            if(tn->level0[i])
                        {
@@ -998,11 +1072,15 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, in
                                        
                                        if(found)
                                        {
-                                               yaffs_DeleteChunk(in->myDev,theChunk);
+                                               yaffs_DeleteChunk(in->myDev,theChunk,1);
                                                in->nDataChunks--;
                                                if(limit)
                                                { 
                                                        *limit = *limit-1;
+                                                       if(limit <= 0) 
+                                                       { 
+                                                               hitLimit = 1;
+                                                       }
                                                }
                                        
                                        }
@@ -1011,7 +1089,7 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, in
                            }
                    
                        }
-                       return 1;
+                       return (i < 0) ? 1 : 0;
 
                        
                }
@@ -1022,6 +1100,100 @@ static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, in
        
 }
 
+// SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
+// All soft deleting does is increment the block's softdelete count and pulls the chunk out
+// of the tnode.
+// THus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
+//
+static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset)
+{
+       int i;
+       int chunkInInode;
+       int theChunk;
+       yaffs_BlockInfo *theBlock;
+       yaffs_Tags tags;
+       int found;
+       int chunkDeleted;
+       int allDone = 1;
+       
+       
+       if(tn)
+       {
+               if(level > 0)
+               {
+               
+                       for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
+                       {
+                           if(tn->internal[i])
+                       {
+                                               allDone = yaffs_SoftDeleteWorker(in,tn->internal[i],level - 1,
+                                                                               (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i);
+                                       if(allDone)
+                                       {
+                                               yaffs_FreeTnode(in->myDev,tn->internal[i]);
+                                       tn->internal[i] = NULL;
+                                       }
+                                       else
+                                       {
+                                               //Hoosterman... how could this happen.
+                                       }                           
+                               }                   
+                       }
+                       return (allDone) ? 1 : 0;
+               }
+               else if(level == 0)
+               {
+                       
+                       for(i = YAFFS_NTNODES_LEVEL0 -1; i >=0; i--)
+                       {
+                           if(tn->level0[i])
+                       {
+                                       
+                                       theChunk =  (tn->level0[i] << in->myDev->chunkGroupBits);
+                                       theBlock =      yaffs_GetBlockInfo(in->myDev,  theChunk/ YAFFS_CHUNKS_PER_BLOCK);
+                                       if(theBlock)
+                                       {
+                                               theBlock->softDeletions++;
+                                       }
+                               tn->level0[i] = 0;
+                           }
+                   
+                       }
+                       return 1;
+                       
+               }
+               
+       }
+       
+       return 1;
+               
+}
+
+
+
+static void yaffs_SoftDeleteFile(yaffs_Object *obj)
+{
+       if(obj->deleted &&
+          obj->variantType == YAFFS_OBJECT_TYPE_FILE &&
+          !obj->softDeleted)
+       {
+               if(obj->nDataChunks <= 0)
+               {
+                               // Empty file, just delete it immediately
+                               yaffs_FreeTnode(obj->myDev,obj->variant.fileVariant.top);
+                               obj->variant.fileVariant.top = NULL;
+                               T(YAFFS_TRACE_TRACING,(TSTR("yaffs: Deleting empty file %d" TENDSTR),obj->objectId));
+                               yaffs_DoGenericObjectDeletion(obj);     
+               }
+               else
+               {
+                       yaffs_SoftDeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0);
+                       obj->softDeleted = 1;
+               }
+       }
+}
+
+
 
 
 
@@ -1148,7 +1320,7 @@ static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
     // Hook them into the free list
     for(i = 0; i < nObjects - 1; i++)
     {
-       (yaffs_Object *)newObjects[i].siblings.next = &newObjects[i+1];
+       newObjects[i].siblings.next = (struct list_head *)(&newObjects[i+1]);
     }
        
        newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
@@ -1263,7 +1435,7 @@ static void yaffs_FreeObject(yaffs_Object *tn)
        yaffs_UnhashObject(tn);
        
        // Link into the free list.
-       (yaffs_Object *)(tn->siblings.next) = dev->freeObjects;
+       tn->siblings.next = (struct list_head *)(dev->freeObjects);
        dev->freeObjects = tn;
        dev->nFreeObjects++;
 }
@@ -1581,11 +1753,11 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
                                break;
                }
 
-               if(yaffs_GetNumberOfFreeChunks(dev) <= 0 ||
+               if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */
                   yaffs_UpdateObjectHeader(in,name,0) < 0)
                {
                        // Could not create the object header, fail the creation
-                       yaffs_UnlinkWorker(in);
+                       yaffs_AbortHalfCreatedObject(in);
                        in = NULL;
                }
 
@@ -1675,7 +1847,7 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const char *oldName, yaffs_Object *
        yaffs_Object *obj;
        int force = 0;
        
-#ifdef CONFIG_YAFFS_WINCE
+#ifdef YAFFS_CASE_INSENSITIVE
        // Special case for WinCE.
        // While look-up is case insensitive, the name isn't.
        // THerefore we might want to change x.txt to X.txt
@@ -1790,11 +1962,16 @@ static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)
        dev->allocationBlock = -1; // force it to get a new one
        //Todo we're assuming the malloc will pass.
        dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
-       if(dev->blockInfo)
+       // Set up dynamic blockinfo stuff.
+       dev->chunkBitmapStride = (dev->nChunksPerBlock+7)/8;
+       dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
+       if(dev->blockInfo && dev->chunkBits)
        {
                memset(dev->blockInfo,0,nBlocks * sizeof(yaffs_BlockInfo));
+               memset(dev->chunkBits,0,dev->chunkBitmapStride * nBlocks);
                return YAFFS_OK;
        }
+       
        return YAFFS_FAIL;
        
 }
@@ -1802,6 +1979,9 @@ static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)
 static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
 {
        YFREE(dev->blockInfo);
+       dev->blockInfo = NULL;
+       YFREE(dev->chunkBits);
+       dev->chunkBits = NULL;
 }
 
 // FindDiretiestBlock is used to select the dirtiest block (or close enough)
@@ -1814,7 +1994,7 @@ static int yaffs_FindDirtiestBlock(yaffs_Device *dev)
        
        int i;
        int dirtiest = -1;
-       int pagesInUse = 100; // silly big number
+       int pagesInUse = dev->nChunksPerBlock; 
        yaffs_BlockInfo *bi;
        
        for(i = dev->startBlock; i <= dev->endBlock && pagesInUse > 2 ; i++)
@@ -1834,10 +2014,10 @@ static int yaffs_FindDirtiestBlock(yaffs_Device *dev)
                bi = yaffs_GetBlockInfo(dev,b);
                
                if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
-                  bi->pagesInUse < pagesInUse)
+                  (bi->pagesInUse - bi->softDeletions )< pagesInUse)
                {
                        dirtiest = b;
-                       pagesInUse = bi->pagesInUse;
+                       pagesInUse = (bi->pagesInUse - bi->softDeletions);
                }
        }
        
@@ -1868,10 +2048,12 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
        
        if( erasedOk )
        {
+               // Clean it up...
                bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
                dev->nErasedBlocks++;
                bi->pagesInUse = 0;
-               bi->pageBits = 0;
+               bi->softDeletions = 0;
+               yaffs_ClearChunkBits(dev,blockNo);
        
                T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo));
        }
@@ -1886,13 +2068,14 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
 static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
 {
        int i;
+       
        yaffs_BlockInfo *bi;
        
        if(dev->nErasedBlocks < 1)
        {
                // Hoosterman we've got a problem.
                // Can't get space to gc
-               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: no space during gc" TENDSTR)));
+               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during gc" TENDSTR)));
 
                return -1;
        }
@@ -1902,13 +2085,13 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
        for(i = dev->startBlock; i <= dev->endBlock; i++)
        {
                dev->allocationBlockFinder++;
-               if(dev->allocationBlockFinder < dev->startBlock || 
-                  dev->allocationBlockFinder > dev->endBlock)
+               if(dev->allocationBlockFinder <dev->startBlock || dev->allocationBlockFinder> dev->endBlock) 
                {
-                  dev->allocationBlockFinder = dev->startBlock;
+                       dev->allocationBlockFinder = dev->startBlock;
                }
                
                bi = yaffs_GetBlockInfo(dev,dev->allocationBlockFinder);
+
                if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
                {
                        bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
@@ -1948,7 +2131,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
                retVal = (dev->allocationBlock * YAFFS_CHUNKS_PER_BLOCK) + 
                                  dev->allocationPage;
                bi->pagesInUse++;
-               bi->pageBits |= (1 << (dev->allocationPage));
+               yaffs_SetChunkBit(dev,dev->allocationBlock,dev->allocationPage);
 
                dev->allocationPage++;
                
@@ -1984,29 +2167,30 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
 {
        int oldChunk;
        int newChunk;
-       __u32 mask;
+       int chunkInBlock;
+       int markNAND;
        
        
        yaffs_Spare spare;
        yaffs_Tags  tags;
                __u8  buffer[YAFFS_BYTES_PER_CHUNK];
        
-       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
+//     yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
        
        yaffs_Object *object;
 
        //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));        
        
-       for(mask = 1,oldChunk = block * YAFFS_CHUNKS_PER_BLOCK; 
-           mask && bi->pageBits;
-           mask <<= 1, oldChunk++ )
+       for(chunkInBlock = 0,oldChunk = block * YAFFS_CHUNKS_PER_BLOCK; 
+           chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
+           chunkInBlock++, oldChunk++ )
        {
-               if(bi->pageBits & mask)
+               if(yaffs_CheckChunkBit(dev,block,chunkInBlock))
                {
                        
-                       // This page is in use and needs to be copied off
+                       // This page is in use and might need to be copied off
                        
-                       dev->nGCCopies++;
+                       markNAND = 1;
                        
                        //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
                        
@@ -2023,15 +2207,27 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
                                // No need to copy this, just forget about it and fix up the
                                // object.
                                
-                               yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0); 
+                               //yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0); 
                                object->nDataChunks--;
+                               
+                               if(object->nDataChunks <= 0)
+                               {
+                                       // Time to delete the file too
+                                       yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top);
+                                       object->variant.fileVariant.top = NULL;
+                                       T(YAFFS_TRACE_TRACING,(TSTR("yaffs: About to finally delete object %d" TENDSTR),object->objectId));
+                                       yaffs_DoGenericObjectDeletion(object);                                  
+                               }
+                               markNAND = 0;
                        }
                        else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */)
                        {
                                // Deleted object header with no data chunks.
-                               // Can be discarded
+                               // Can be discarded and the file deleted.
                                object->chunkId = 0;
-                               //Todo some clean up
+                               yaffs_FreeTnode(object->myDev,object->variant.fileVariant.top);
+                               object->variant.fileVariant.top = NULL;
+                               yaffs_DoGenericObjectDeletion(object);
                                
                        }
                        else if(object)
@@ -2043,6 +2239,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
                                tags.serialNumber++;
                                yaffs_LoadTagsIntoSpare(&spare,&tags);
 
+                               dev->nGCCopies++;
 
                                newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1);
                        
@@ -2065,7 +2262,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
                                }
                        }
                        
-                       yaffs_DeleteChunk(dev,oldChunk);                        
+                       yaffs_DeleteChunk(dev,oldChunk,markNAND);                       
                        
                }
        }
@@ -2076,12 +2273,12 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
 
 static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)
 {
-       // todo find a file to delete
+       // find a file to delete
        struct list_head *i;    
        yaffs_Object *l;
 
 
-       // To the free chunks add the chunks that are in the deleted unlinked files.
+       //Scan the unlinked files looking for one to delete
        list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
        {
                l = list_entry(i, yaffs_Object,siblings);
@@ -2093,6 +2290,7 @@ static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)
        return NULL;
 }
 
+
 static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
 {
        // This does background deletion on unlinked files.. only deleted ones.
@@ -2110,18 +2308,8 @@ static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
                int limit; // Number of chunks to delete in a file.
                                   // NB this can be exceeded, but not by much.
                                   
-               limit = 5;
-#if 0                             
-               if(dev->nErasedBlocks <= (YAFFS_RESERVED_BLOCKS + YAFFS_GARBAGE_COLLECT_LOW_WATER))
-               {
-                       limit = 50; // Doing GC soon, so dig deeper     
-               }
-               else
-               {
-                       limit = 5;
-               }
-#endif
-       
+               limit = -1;
+
                delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
                
                if(obj->nDataChunks == 0)
@@ -2129,6 +2317,7 @@ static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
                        // Done all the deleting of data chunks.
                        // Now dump the header and clean up
                        yaffs_FreeTnode(dev,obj->variant.fileVariant.top);
+                       obj->variant.fileVariant.top = NULL;
                        yaffs_DoGenericObjectDeletion(obj);
                        dev->nDeletedFiles--;
                        dev->nUnlinkedFiles--;
@@ -2144,7 +2333,7 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
 {
        int block;
        
-       yaffs_DoUnlinkedFileDeletion(dev);
+       //yaffs_DoUnlinkedFileDeletion(dev);
        
        if(dev->nErasedBlocks <= (YAFFS_RESERVED_BLOCKS + YAFFS_GARBAGE_COLLECT_LOW_WATER))
        {
@@ -2261,12 +2450,10 @@ static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, con
        
        yaffs_SpareInitialise(&spare);
        
-#ifndef CONFIG_YAFFS_USE_NANDECC
-       if(buffer)
+       if(!dev->useNANDECC && buffer)
        {
                yaffs_CalcECC(buffer,&spare);
        }
-#endif
        
        yaffs_LoadTagsIntoSpare(&spare,tags);
        
@@ -2290,13 +2477,10 @@ static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buff
        
        yaffs_SpareInitialise(&spare);
        
-#ifndef CONFIG_YAFFS_USE_NANDECC
-
-       if(buffer)
+       if(!dev->useNANDECC && buffer)
        {
                yaffs_CalcECC(buffer,&spare);
        }
-#endif
        
        yaffs_LoadTagsIntoSpare(&spare,tags);
        
@@ -2523,7 +2707,7 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn
                        {
                                //Hoosterman - how did this happen?
                                
-                               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: existing chunk < 0 in scan" TENDSTR)));
+                               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: existing chunk < 0 in scan" TENDSTR)));
 
                        }
 
@@ -2539,13 +2723,13 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn
                        {
                                // Use new
                                // Delete the old one and drop through to update the tnode
-                               yaffs_DeleteChunk(dev,existingChunk);
+                               yaffs_DeleteChunk(dev,existingChunk,1);
                        }
                        else
                        {
                                // Use existing.
                                // Delete the new one and return early so that the tnode isn't changed
-                               yaffs_DeleteChunk(dev,chunkInNAND);
+                               yaffs_DeleteChunk(dev,chunkInNAND,1);
                                return YAFFS_OK;
                        }
                }
@@ -2580,7 +2764,7 @@ int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffe
 }
 
 
-static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)
+static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND)
 {
        int block;
        int page;
@@ -2588,16 +2772,26 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)
        yaffs_BlockInfo *bi;
        
        if(chunkId <= 0) return;        
-               
+       
+       dev->nDeletions++;
        block = chunkId / YAFFS_CHUNKS_PER_BLOCK;
        page = chunkId % YAFFS_CHUNKS_PER_BLOCK;
-       yaffs_SpareInitialise(&spare);
        
-       spare.pageStatus = 0; // To mark it as deleted.
+       if(markNAND)
+       {
+               yaffs_SpareInitialise(&spare);
+       
+               spare.pageStatus = 0; // To mark it as deleted.
 
        
-       yaffs_WriteChunkToNAND(dev,chunkId,NULL,&spare);
-       yaffs_HandleUpdateChunk(dev,chunkId,&spare);
+               yaffs_WriteChunkToNAND(dev,chunkId,NULL,&spare);
+               yaffs_HandleUpdateChunk(dev,chunkId,&spare);
+       }
+       else
+       {
+                       dev->nUnmarkedDeletions++;
+       }       
+       
        bi = yaffs_GetBlockInfo(dev,block);
                        
        
@@ -2608,7 +2802,7 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)
        {
                dev->nFreeChunks++;
 
-               bi->pageBits &= ~(1 << page);
+               yaffs_ClearChunkBit(dev,block,page);
                bi->pagesInUse--;
                
                if(bi->pagesInUse == 0 &&
@@ -2664,7 +2858,7 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *
                
                if(prevChunkId >= 0)
                {
-                       yaffs_DeleteChunk(dev,prevChunkId);
+                       yaffs_DeleteChunk(dev,prevChunkId,1);
        
                }
                
@@ -2791,7 +2985,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force)
        
 
                // Create new chunk in NAND
-               newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,bufferNew,&newTags,1);
+               newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,bufferNew,&newTags, (prevChunkId >= 0) ? 1 : 0 );
     
                if(newChunkId >= 0)
                {
@@ -2800,7 +2994,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force)
                
                        if(prevChunkId >= 0)
                        {
-                               yaffs_DeleteChunk(dev,prevChunkId);
+                               yaffs_DeleteChunk(dev,prevChunkId,1);
                        }
                
                        in->dirty = 0;
@@ -2823,7 +3017,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force)
 //  need a very intelligent search.
 
 
-#ifdef CONFIG_YAFFS_SHORT_OP_CACHE
+
 
 
 static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
@@ -2834,50 +3028,55 @@ static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
        yaffs_ChunkCache *cache;
        int chunkWritten;
        int nBytes;
+       int nCaches = obj->myDev->nShortOpCaches;
        
-       do{
-               cache = NULL;
+       if  (nCaches > 0)
+       {
+               do{
+                       cache = NULL;
                
-               // Find the dirty cache for this object with the lowest chunk id.
-               for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)
-               {
-                       if(dev->srCache[i].object == obj &&
-                          dev->srCache[i].dirty)
+                       // Find the dirty cache for this object with the lowest chunk id.
+                       for(i = 0; i < nCaches; i++)
                        {
-                               if(!cache ||  dev->srCache[i].chunkId < lowest)
+                               if(dev->srCache[i].object == obj &&
+                               dev->srCache[i].dirty)
                                {
-                                       cache = &dev->srCache[i];
-                                       lowest = cache->chunkId;
+                                       if(!cache ||  dev->srCache[i].chunkId < lowest)
+                                       {
+                                               cache = &dev->srCache[i];
+                                               lowest = cache->chunkId;
+                                       }
                                }
                        }
-               }
                
-               if(cache)
-               {
-                       //Write it out
-
-                       nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK);
-                       
-                       if(nBytes > YAFFS_BYTES_PER_CHUNK)
+                       if(cache)
                        {
-                               nBytes= YAFFS_BYTES_PER_CHUNK;
-                       }
+                               //Write it out
+
+#if 0
+                               nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK);
                        
-                       chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
-                                                                                                               cache->chunkId,
-                                                                                                               cache->data,
-                                                                                                               nBytes,1);
+                               if(nBytes > YAFFS_BYTES_PER_CHUNK)
+                               {
+                                       nBytes= YAFFS_BYTES_PER_CHUNK;
+                               }
+#endif                 
+                               chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
+                                                                                                                       cache->chunkId,
+                                                                                                                       cache->data,
+                                                                                                                       cache->nBytes,1);
 
-                       cache->dirty = 0;
-               }
+                               cache->dirty = 0;
+                       }
                
-       } while(cache && chunkWritten > 0);
+               } while(cache && chunkWritten > 0);
        
-       if(cache)
-       {
-               //Hoosterman, disk full while writing cache out.
-               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: no space during caceh write" TENDSTR)));
+               if(cache)
+               {
+                       //Hoosterman, disk full while writing cache out.
+                       T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
 
+               }
        }       
                
 }
@@ -2893,32 +3092,39 @@ static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
        int usage;
        int theOne;
        
-       for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)
+       if(dev->nShortOpCaches > 0)
        {
-               if(!dev->srCache[i].object)
+               for(i = 0; i < dev->nShortOpCaches; i++)
                {
-                       //T(("Grabbing empty %d\n",i));
+                       if(!dev->srCache[i].object)
+                       {
+                               //T(("Grabbing empty %d\n",i));
                        
-                       return &dev->srCache[i];
+                               return &dev->srCache[i];
+                       }
                }
-       }
        
-       theOne = -1; 
-       usage = 0; // just to stop the compiler grizzling
+               theOne = -1; 
+               usage = 0; // just to stop the compiler grizzling
        
-       for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)
-       {
-               if(!dev->srCache[i].dirty &&
-                  ((dev->srCache[i].lastUse < usage  && theOne >= 0)|| 
-                    theOne < 0))
+               for(i = 0; i < dev->nShortOpCaches; i++)
                {
-                       usage = dev->srCache[i].lastUse;
-                       theOne = i;
+                       if(!dev->srCache[i].dirty &&
+                       ((dev->srCache[i].lastUse < usage  && theOne >= 0)|| 
+                               theOne < 0))
+                       {
+                               usage = dev->srCache[i].lastUse;
+                               theOne = i;
+                       }
                }
-       }
        
-       //T(("Grabbing non-empty %d\n",theOne));
-       return  theOne >= 0 ?  &dev->srCache[theOne] : NULL;
+               //T(("Grabbing non-empty %d\n",theOne));
+               return  theOne >= 0 ?  &dev->srCache[theOne] : NULL;
+       }
+       else
+       {
+               return NULL;
+       }
        
 }
 
@@ -2930,37 +3136,42 @@ static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
        int usage;
        int i;
        
-       // Try find a non-dirty one...
+       if(dev->nShortOpCaches > 0)
+       {
+               // Try find a non-dirty one...
        
-       cache = yaffs_GrabChunkCacheWorker(dev);
+               cache = yaffs_GrabChunkCacheWorker(dev);
        
-       if(!cache)
-       {
-               // They were all dirty, find the last recently used object and flush
-               // its cache, then  find again.
-               // NB what's here is not very accurate, we actually flush the object
-               // the last recently used page.
+               if(!cache)
+               {
+                       // They were all dirty, find the last recently used object and flush
+                       // its cache, then  find again.
+                       // NB what's here is not very accurate, we actually flush the object
+                       // the last recently used page.
                
-               theObj = dev->srCache[0].object;
-               usage = dev->srCache[0].lastUse;
+                       theObj = dev->srCache[0].object;
+                       usage = dev->srCache[0].lastUse;
        
-               for(i = 1; i < YAFFS_N_CACHE_CHUNKS; i++)
-               {
-                       if( dev->srCache[i].object && 
-                           dev->srCache[i].lastUse < usage)
+                       for(i = 1; i < dev->nShortOpCaches; i++)
                        {
-                               usage  = dev->srCache[i].lastUse;
-                               theObj = dev->srCache[i].object;
+                               if( dev->srCache[i].object && 
+                                       dev->srCache[i].lastUse < usage)
+                               {
+                                       usage  = dev->srCache[i].lastUse;
+                                       theObj = dev->srCache[i].object;
+                               }
                        }
-               }
                
-               yaffs_FlushFilesChunkCache(theObj);
+                       yaffs_FlushFilesChunkCache(theObj);
                
-               // Try again
-               cache = yaffs_GrabChunkCacheWorker(dev);
-       }
+                       // Try again
+                       cache = yaffs_GrabChunkCacheWorker(dev);
+               }
        
-       return cache;
+               return cache;
+       }
+       else
+               return NULL;
 
 }
 
@@ -2970,43 +3181,48 @@ static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, int chunk
 {
        yaffs_Device *dev = obj->myDev;
        int i;
-       
-       for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)
+       if(dev->nShortOpCaches > 0)
        {
-               if(dev->srCache[i].object == obj && 
-                  dev->srCache[i].chunkId == chunkId)
+               for(i = 0; i < dev->nShortOpCaches; i++)
                {
-                       dev->cacheHits++;
+                       if(dev->srCache[i].object == obj && 
+                       dev->srCache[i].chunkId == chunkId)
+                       {
+                               dev->cacheHits++;
                        
-                       return &dev->srCache[i];
+                               return &dev->srCache[i];
+                       }
                }
        }
-       
        return NULL;
 }
 
 // Mark the chunk for the least recently used algorithym
 static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite)
 {
-       if( dev->srLastUse < 0 || 
-               dev->srLastUse > 100000000)
+
+       if(dev->nShortOpCaches > 0)
        {
-               // Reset the cache usages
-               int i;
-               for(i = 1; i < YAFFS_N_CACHE_CHUNKS; i++)
+               if( dev->srLastUse < 0 || 
+                       dev->srLastUse > 100000000)
                {
-                       dev->srCache[i].lastUse = 0;
+                       // Reset the cache usages
+                       int i;
+                       for(i = 1; i < dev->nShortOpCaches; i++)
+                       {
+                               dev->srCache[i].lastUse = 0;
+                       }
+                       dev->srLastUse = 0;
                }
-               dev->srLastUse = 0;
-       }
 
-       dev->srLastUse++;
+               dev->srLastUse++;
        
-       cache->lastUse = dev->srLastUse;
+               cache->lastUse = dev->srLastUse;
 
-       if(isAWrite)
-       {
-               cache->dirty = 1;
+               if(isAWrite)
+               {
+                       cache->dirty = 1;
+               }
        }
 }
 
@@ -3015,11 +3231,14 @@ static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int
 // ie the short cache for this page is no longer valid.
 static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
 {
-       yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId);
-
-       if(cache)
+       if(object->myDev->nShortOpCaches > 0)
        {
-               cache->object = NULL;
+               yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId);
+
+               if(cache)
+               {
+                       cache->object = NULL;
+               }
        }
 }
 
@@ -3031,49 +3250,20 @@ static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
        int i;
        yaffs_Device *dev = in->myDev;
        
-       // Now invalidate it.
-       for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)
-       {
-               if(dev->srCache[i].object == in)
+       if(dev->nShortOpCaches > 0)
+       { 
+               // Now invalidate it.
+               for(i = 0; i < dev->nShortOpCaches; i++)
                {
-                       dev->srCache[i].object = NULL;
+                       if(dev->srCache[i].object == in)
+                       {
+                               dev->srCache[i].object = NULL;
+                       }
                }
        }
 }
 
 
-#else
-// Stubs for disabling short op caching
-
-static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
-{}
-
-static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
-{
-       return NULL;    
-}
-
-
-static yaffs_ChunkCache *yaffs_FindChunkCache(yaffs_Device *dev, int objectId, int chunkId)
-{
-       return NULL;
-}
-
-static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache)
-{
-}
-
-static void yaffs_InvalidateChunkCache(yaffs_Object *obj, int chunkId)
-{
-}
-
-static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
-{
-}
-
-
-
-#endif
 
 
 
@@ -3119,27 +3309,32 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nB
                if(nToCopy != YAFFS_BYTES_PER_CHUNK)
                {
                        // An incomplete start or end chunk (or maybe both start and end chunk)
-#ifdef CONFIG_YAFFS_SHORT_OP_CACHE
-                       yaffs_ChunkCache *cache;
-                       // If we can't find the data in the cache, then load it up.
-                       cache = yaffs_FindChunkCache(in,chunk);
-                       if(!cache)
+                       if(dev->nShortOpCaches > 0)
                        {
-                               cache = yaffs_GrabChunkCache(in->myDev);
-                               cache->object = in;
-                               cache->chunkId = chunk;
-                               cache->dirty = 0;
-                               yaffs_ReadChunkDataFromObject(in,chunk,cache->data);            
-                       }
+                               yaffs_ChunkCache *cache;
+                               // If we can't find the data in the cache, then load it up.
+                               cache = yaffs_FindChunkCache(in,chunk);
+                               if(!cache)
+                               {
+                                       cache = yaffs_GrabChunkCache(in->myDev);
+                                       cache->object = in;
+                                       cache->chunkId = chunk;
+                                       cache->dirty = 0;
+                                       yaffs_ReadChunkDataFromObject(in,chunk,cache->data);
+                                       cache->nBytes = 0;      
+                               }
                        
-                       yaffs_UseChunkCache(dev,cache,0);
+                               yaffs_UseChunkCache(dev,cache,0);
+
+                               memcpy(buffer,&cache->data[start],nToCopy);
+                       }
+                       else
+                       {
+                               // Read into the local buffer then copy...
+                               yaffs_ReadChunkDataFromObject(in,chunk,dev->localBuffer);               
+                               memcpy(buffer,&dev->localBuffer[start],nToCopy);
+                       }
 
-                       memcpy(buffer,&cache->data[start],nToCopy);
-#else
-                       // Read into the local buffer then copy...
-                       yaffs_ReadChunkDataFromObject(in,chunk,dev->localBuffer);               
-                       memcpy(buffer,&dev->localBuffer[start],nToCopy);
-#endif
                }
                else
                {
@@ -3221,42 +3416,44 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in
                if(nToCopy != YAFFS_BYTES_PER_CHUNK)
                {
                        // An incomplete start or end chunk (or maybe both start and end chunk)
-#ifdef CONFIG_YAFFS_SHORT_OP_CACHE
-                       yaffs_ChunkCache *cache;
-                       // If we can't find the data in the cache, then load it up.
-                       cache = yaffs_FindChunkCache(in,chunk);
-                       if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev))
+                       if(dev->nShortOpCaches > 0)
                        {
-                               cache = yaffs_GrabChunkCache(in->myDev);
-                               cache->object = in;
-                               cache->chunkId = chunk;
-                               cache->dirty = 0;
-                               yaffs_ReadChunkDataFromObject(in,chunk,cache->data);            
-                       }
+                               yaffs_ChunkCache *cache;
+                               // If we can't find the data in the cache, then load it up.
+                               cache = yaffs_FindChunkCache(in,chunk);
+                               if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev))
+                               {
+                                       cache = yaffs_GrabChunkCache(in->myDev);
+                                       cache->object = in;
+                                       cache->chunkId = chunk;
+                                       cache->dirty = 0;
+                                       yaffs_ReadChunkDataFromObject(in,chunk,cache->data);            
+                               }
                        
-                       if(cache)
-                       {       
-                               yaffs_UseChunkCache(dev,cache,1);
-                               memcpy(&cache->data[start],buffer,nToCopy);
+                               if(cache)
+                               {       
+                                       yaffs_UseChunkCache(dev,cache,1);
+                                       memcpy(&cache->data[start],buffer,nToCopy);
+                                       cache->nBytes = nToWriteBack;
+                               }
+                               else
+                               {
+                                       chunkWritten = -1; // fail the write
+                               }
                        }
                        else
                        {
-                               chunkWritten = -1; // fail the write
-                       }
-#else
-               
-
-                       // An incomplete start or end chunk (or maybe both start and end chunk)
-                       // Read into the local buffer then copy, then copy over and write back.
+                               // An incomplete start or end chunk (or maybe both start and end chunk)
+                               // Read into the local buffer then copy, then copy over and write back.
                
-                       yaffs_ReadChunkDataFromObject(in,chunk,dev->localBuffer);
+                               yaffs_ReadChunkDataFromObject(in,chunk,dev->localBuffer);
                                
-                       memcpy(&dev->localBuffer[start],buffer,nToCopy);
+                               memcpy(&dev->localBuffer[start],buffer,nToCopy);
                        
-                       chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,dev->localBuffer,nToWriteBack,0);
+                               chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,dev->localBuffer,nToWriteBack,0);
                        
-                       //T(("Write with readback to chunk %d %d  start %d  copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack));
-#endif
+                               //T(("Write with readback to chunk %d %d  start %d  copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack));
+                       }
                        
                }
                else
@@ -3341,7 +3538,7 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize)
                        else
                        {
                                in->nDataChunks--;
-                               yaffs_DeleteChunk(dev,chunkId);
+                               yaffs_DeleteChunk(dev,chunkId,1);
                        }
                }
                
@@ -3391,7 +3588,7 @@ loff_t yaffs_GetFileSize(yaffs_Object *obj)
 // yaffs_FlushFile() updates the file's
 // objectId in NAND
 
-int yaffs_FlushFile(yaffs_Object *in)
+int yaffs_FlushFile(yaffs_Object *in, int updateTime)
 {
        int retVal;
        if(in->dirty)
@@ -3399,12 +3596,14 @@ int yaffs_FlushFile(yaffs_Object *in)
                //T(("flushing object header\n"));
                
                yaffs_FlushFilesChunkCache(in);
-       
+               if(updateTime)
+               {
 #ifdef CONFIG_YAFFS_WINCE
-               yfsd_WinFileTimeNow(in->win_mtime);
+                       yfsd_WinFileTimeNow(in->win_mtime);
 #else
-               in->st_mtime = CURRENT_TIME;
+                       in->st_mtime = CURRENT_TIME;
 #endif
+               }
 
                retVal = yaffs_UpdateObjectHeader(in,NULL,0);
        }
@@ -3425,7 +3624,7 @@ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
        yaffs_InvalidateWholeChunkCache(in);
        
        yaffs_RemoveObjectFromDirectory(in);
-       yaffs_DeleteChunk(in->myDev,in->chunkId);
+       yaffs_DeleteChunk(in->myDev,in->chunkId,1);
 #ifdef __KERNEL__
        if(in->myInode)
        {
@@ -3445,6 +3644,7 @@ static int yaffs_UnlinkFile(yaffs_Object *in)
 {
 
 #ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION
+
        // Delete the file data & tnodes
 
         yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL);
@@ -3457,7 +3657,10 @@ static int yaffs_UnlinkFile(yaffs_Object *in)
        int retVal;
        int immediateDeletion=0;
        retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0);
-       if(retVal == YAFFS_OK)
+       if(1 || // Ignore the result of the change name. This will only fail
+                       // if the disk was completely full (an error condition)
+                       // We ignore the error so we can delete files to recover the disk
+          retVal == YAFFS_OK)
        {
                //in->unlinked = 1;
                //in->myDev->nUnlinkedFiles++;
@@ -3468,8 +3671,7 @@ static int yaffs_UnlinkFile(yaffs_Object *in)
                        immediateDeletion = 1;
 
                }
-#endif
-#ifdef CONFIG_YAFFS_WINCE
+#else
                if(in->inUse <= 0)
                {
                        immediateDeletion = 1;
@@ -3482,6 +3684,7 @@ static int yaffs_UnlinkFile(yaffs_Object *in)
                        T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
                        in->deleted=1;
                        in->myDev->nDeletedFiles++;
+                       yaffs_SoftDeleteFile(in);
                }
        
        }
@@ -3494,18 +3697,33 @@ static int yaffs_UnlinkFile(yaffs_Object *in)
 int yaffs_DeleteFile(yaffs_Object *in)
 {
        int retVal = YAFFS_OK;
-       if(!in->unlinked)
+       
+       if(in->nDataChunks > 0)
        {
-               retVal = yaffs_UnlinkFile(in);
+               // Use soft deletion
+               if(!in->unlinked)
+               {
+                       retVal = yaffs_UnlinkFile(in);
+               }
+               if(retVal == YAFFS_OK && 
+               in->unlinked &&
+               !in->deleted)
+               {
+                       in->deleted = 1;
+                       in->myDev->nDeletedFiles++;
+                       yaffs_SoftDeleteFile(in);
+               }
+               return in->deleted ? YAFFS_OK : YAFFS_FAIL;     
        }
-       if(retVal == YAFFS_OK && 
-          in->unlinked &&
-          !in->deleted)
+       else
        {
-               in->deleted = 1;
-               in->myDev->nDeletedFiles++;
+               // The file has no data chunks so we toss it immediately
+               yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
+               in->variant.fileVariant.top = NULL;
+               yaffs_DoGenericObjectDeletion(in);      
+               
+               return YAFFS_OK;        
        }
-       return in->deleted ? YAFFS_OK : YAFFS_FAIL;     
 }
 
 static int yaffs_DeleteDirectory(yaffs_Object *in)
@@ -3536,6 +3754,20 @@ static int yaffs_DeleteHardLink(yaffs_Object *in)
 }
 
 
+static void yaffs_AbortHalfCreatedObject(yaffs_Object *obj)
+{
+       switch(obj->variantType)
+       {
+               case YAFFS_OBJECT_TYPE_FILE: yaffs_DeleteFile(obj); break;
+               case YAFFS_OBJECT_TYPE_DIRECTORY: yaffs_DeleteDirectory(obj); break;
+               case YAFFS_OBJECT_TYPE_SYMLINK: yaffs_DeleteSymLink(obj); break;
+               case YAFFS_OBJECT_TYPE_HARDLINK: yaffs_DeleteHardLink(obj); break;
+               case YAFFS_OBJECT_TYPE_SPECIAL: yaffs_DoGenericObjectDeletion(obj); break;
+               case YAFFS_OBJECT_TYPE_UNKNOWN: break; // should not happen.
+       }
+}
+
+
 static int yaffs_UnlinkWorker(yaffs_Object *obj)
 {
 
@@ -3687,8 +3919,9 @@ static int yaffs_Scan(yaffs_Device *dev)
        {
                deleted = 0;
                bi = yaffs_GetBlockInfo(dev,blk);
-               bi->pageBits = 0;
+               yaffs_ClearChunkBits(dev,blk);
                bi->pagesInUse = 0;
+               bi->softDeletions = 0;
                state = YAFFS_BLOCK_STATE_SCANNING;
                
                
@@ -3746,7 +3979,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                        {
                                int endpos;
                                // A data chunk.
-                               bi->pageBits |= (1 << c);
+                               yaffs_SetChunkBit(dev,blk,c);
                                bi->pagesInUse++;
                                                                
                                in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
@@ -3769,7 +4002,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                        {
                                // chunkId == 0, so it is an ObjectHeader.
                                // Thus, we read in the object header and make the object
-                               bi->pageBits |= (1 << c);
+                               yaffs_SetChunkBit(dev,blk,c);
                                bi->pagesInUse++;
                                                        
                                yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL,1);
@@ -3788,13 +4021,13 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        if(((existingSerial+1) & 3) == newSerial)
                                        {
                                                // Use new one - destroy the exisiting one
-                                               yaffs_DeleteChunk(dev,in->chunkId);
+                                               yaffs_DeleteChunk(dev,in->chunkId,1);
                                                in->valid = 0;
                                        }
                                        else
                                        {
                                                // Use existing - destroy this one.
-                                               yaffs_DeleteChunk(dev,chunk);
+                                               yaffs_DeleteChunk(dev,chunk,1);
                                        }
                                }
                                
@@ -3868,7 +4101,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                                                // Hoosterman, another problem....
                                                // We're trying to use a non-directory as a directory
                                                // Todo ... handle
-                                               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: attempting to use non-directory as a directory in scan" TENDSTR)));
+                                               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tragedy: attempting to use non-directory as a directory in scan" TENDSTR)));
 
                                        }
                                
@@ -3896,7 +4129,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                                                        break;
                                                case YAFFS_OBJECT_TYPE_HARDLINK:
                                                        in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
-                                                       (yaffs_Object *)(in->hardLinks.next) = hardList;
+                                                       in->hardLinks.next = (struct list_head *)hardList;
                                                        hardList = in;
                                                        break;
                                                case YAFFS_OBJECT_TYPE_DIRECTORY:       // Do nothing
@@ -3956,6 +4189,19 @@ static int yaffs_Scan(yaffs_Device *dev)
                
        }
        
+       {
+               struct list_head *i;    
+               yaffs_Object *l;
+               // Soft delete all the unlinked files
+               list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
+               {
+                       l = list_entry(i, yaffs_Object,siblings);
+                       if(l->deleted)
+                       {
+                               yaffs_SoftDeleteFile(l);                
+                       }
+               }       
+       }
        
        
        return YAFFS_OK;
@@ -4291,6 +4537,14 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
                T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
                return YAFFS_FAIL;
        }
+
+       if(dev->isMounted)
+       {
+               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: device already mounted\n" TENDSTR)));
+               return YAFFS_FAIL;
+       }
+
+       dev->isMounted = 1;
        
        if(dev->startBlock <= 0 ||
           (dev->endBlock - dev->startBlock) < 10)
@@ -4332,6 +4586,10 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        }
        dev->chunkGroupSize = 1 << dev->chunkGroupBits;
        
+       // Stuff to be taken out later
+       dev->nBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
+       dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
+       
        
        // More device initialisation
        dev->garbageCollectionRequired  = 0;
@@ -4348,7 +4606,10 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        dev->tagsEccFixed=0;
        dev->tagsEccUnfixed=0;
        
-       dev->localBuffer = YMALLOC(YAFFS_BYTES_PER_CHUNK);
+       dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
+       
+
+       
        
        yaffs_InitialiseBlocks(dev,nBlocks);
        
@@ -4356,10 +4617,18 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
 
        yaffs_InitialiseObjects(dev);
        
-#ifdef CONFIG_YAFFS_SHORT_OP_CACHE
+       if(dev->nShortOpCaches > 0)
        { 
                int i;
-               for(i=0; i < YAFFS_N_CACHE_CHUNKS; i++)
+               
+               if(dev->nShortOpCaches >  YAFFS_MAX_SHORT_OP_CACHES)
+               {
+                       dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
+               }
+               
+               dev->srCache = YMALLOC( dev->nShortOpCaches * sizeof(yaffs_ChunkCache));
+               
+               for(i=0; i < dev->nShortOpCaches; i++)
                {
                        dev->srCache[i].object = NULL;
                        dev->srCache[i].lastUse = 0;
@@ -4367,7 +4636,6 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
                }
                dev->srLastUse = 0;
        }
-#endif
 
        dev->cacheHits = 0;
        
@@ -4400,12 +4668,18 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
 
 void yaffs_Deinitialise(yaffs_Device *dev)
 {
-       yaffs_DeinitialiseBlocks(dev);
-       yaffs_DeinitialiseTnodes(dev);
-       yaffs_DeinitialiseObjects(dev);
+       if(dev->isMounted)
+       {
+       
+               yaffs_DeinitialiseBlocks(dev);
+               yaffs_DeinitialiseTnodes(dev);
+               yaffs_DeinitialiseObjects(dev);
+       }
        
 }
 
+#if 0
+
 int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
 {
        int nFree = dev->nFreeChunks - (YAFFS_CHUNKS_PER_BLOCK * YAFFS_RESERVED_BLOCKS);
@@ -4424,13 +4698,75 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
                        nFree += l->nDataChunks;
                }
        }
+       
+       
+       printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);   
+
+       if(nFree < 0) nFree = 0;
+
+       return nFree;   
+       
+}
+
+#endif
+
+int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
+{
+       int nFree;
+       int pending;
+       int b;
+       
+       yaffs_BlockInfo *blk;
+       
+       struct list_head *i;    
+       yaffs_Object *l;
+       
+       for(nFree = 0, b = dev->startBlock; b <= dev->endBlock; b++)
+       {
+               blk = yaffs_GetBlockInfo(dev,b);
+               
+               switch(blk->blockState)
+               {
+                       case YAFFS_BLOCK_STATE_EMPTY:
+                       case YAFFS_BLOCK_STATE_ALLOCATING: 
+                       case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse); break;
+                       default: break;
+               }
+       }
+       
+       
+       pending = 0;
+       
+       // To the free chunks add the chunks that are in the deleted unlinked files.
+       list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
+       {
+               l = list_entry(i, yaffs_Object,siblings);
+               if(l->deleted)
+               {
+                       pending++;
+                       pending += l->nDataChunks;
+               }
+       }
+       
+       
+       
+       //printf("___________ really free is %d, pending %d, nFree is %d\n",nFree,pending, nFree+pending);
+       
+       if(nFree != dev->nFreeChunks) 
+       {
+       //      printf("___________Different! really free is %d, nFreeChunks %d\n",nFree dev->nFreeChunks);
+       }
 
+       nFree += pending;
+       
+       if(nFree < 0) nFree = 0;
 
-       return (nFree < 0) ? 0 : nFree; 
+       return nFree;   
        
 }
 
 
+
 /////////////////// YAFFS test code //////////////////////////////////
 
 #define yaffs_CheckStruct(structure,syze, name) \
@@ -4446,7 +4782,9 @@ static int yaffs_CheckStructures(void)
        yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags")
        yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion")
        yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare")
+#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
        yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode")
+#endif
        yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader")
        
        
index 3ab41f70b29349db3dae36751b5113c6ca56c69b..0fe8f74557b7ca942ad0d1c9b5591102606cc0e8 100644 (file)
@@ -14,7 +14,7 @@
  *
  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
  *
- * $Id: yaffs_guts.h,v 1.13 2002-12-13 00:13:06 charles Exp $
+ * $Id: yaffs_guts.h,v 1.14 2003-01-14 23:15:32 charles Exp $
  */
 
 #ifndef __YAFFS_GUTS_H__
 #define YAFFS_TNODES_INTERNAL_MASK     0x7
 #define YAFFS_TNODES_MAX_LEVEL         6
                
+#define YAFFS_BYTES_PER_SPARE          16
+
 #define YAFFS_BYTES_PER_CHUNK          512
-#define YAFFS_CHUNK_SIZE_SHIFT         9
+//#define YAFFS_CHUNK_SIZE_SHIFT               9
 
-#define YAFFS_BYTES_PER_SPARE          16
 
 #define YAFFS_CHUNKS_PER_BLOCK         32
 #define YAFFS_BYTES_PER_BLOCK          (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
 #define YAFFS_OBJECTID_LOSTNFOUND      2
 #define YAFFS_OBJECTID_UNLINKED                3
 
-#define YAFFS_N_CACHE_CHUNKS           10
-
-#ifdef CONFIG_YAFFS_WINCE
-
-// Force the short operation cache on for WinCE
-
-#define CONFIG_YAFFS_SHORT_OP_CACHE
-#endif
+#define YAFFS_MAX_SHORT_OP_CACHES      20
 
 
 // ChunkCache is used for short read/write operations.
@@ -90,11 +84,12 @@ typedef struct
        int chunkId;
        int lastUse;
        int dirty;      
+       int nBytes;     // Only valid if the cache is dirty
        __u8 data[YAFFS_BYTES_PER_CHUNK];
 } yaffs_ChunkCache;
 
 // Tags structures in RAM
-// NB This uses bitfield. Bitfields should not stradle a u32 boundary otherwise
+// NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
 // the structure size will get blown out.
 
 typedef struct
@@ -131,10 +126,17 @@ typedef struct
     __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_UddNKNOWN     = 0,
+       YAFFS_BLOCK_STATE_UNKNOWN       = 0,
        YAFFS_BLOCK_STATE_SCANNING,             // Used while the block is being scanned.
                                                                        // NB Don't erase blocks while they're being scanned
        
@@ -151,7 +153,7 @@ typedef enum {
        YAFFS_BLOCK_STATE_DIRTY,                // All pages have been allocated and deleted. 
                                                                        // Erase me, reuse me.
                                                        
-       YAFFS_BLOCK_STATE_DEAD = 0x77   // This block has failed and is not in use
+       YAFFS_BLOCK_STATE_DEAD                  // This block has failed and is not in use
 
 } yaffs_BlockState;
 
@@ -160,10 +162,13 @@ typedef enum {
 
 typedef struct
 {
-       __u32 pageBits;   // bitmap of pages in use
-    __u8  blockState; // One of the above block states
-    __u8  pagesInUse; // number of pages in use
-    __u8  needsRetiring:1;     // Data has failed on this block, need to get valid data off
+#ifndef CONFIG_YAFFS_NO_YAFFS2
+       __u32 sequenceNumber;   // block sequence number for yaffs2
+#endif
+       int   softDeletions:8;  // number of soft deleted pages
+    int   pagesInUse:8;                // number of pages in use
+    __u32 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.
 } yaffs_BlockInfo;
 
@@ -231,7 +236,11 @@ typedef struct
 
 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];
        
 };
@@ -292,6 +301,7 @@ typedef union
 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 pseudo directory.
        __u8 fake:1;                    // A fake object has no presence on NAND.
        __u8 renameAllowed:1;
@@ -331,9 +341,11 @@ struct  yaffs_ObjectStruct
        char shortName[YAFFS_SHORT_NAME_LENGTH+1];
 #endif
 
-#ifdef CONFIG_YAFFS_WINCE
+#ifndef __KERNEL__
        __u32 inUse;
+#endif
 
+#ifdef CONFIG_YAFFS_WINCE
        __u32 win_ctime[2];
        __u32 win_mtime[2];
        __u32 win_atime[2];
@@ -343,9 +355,9 @@ struct  yaffs_ObjectStruct
        __u32 st_atime;         // time of last access
        __u32 st_mtime;         // time of last modification
        __u32 st_ctime;         // time of last change
-       __u32 st_rdev;      // device stuff for block and char devices
 #endif
 
+       __u32 st_rdev;      // device stuff for block and char devices
 
 
 
@@ -386,23 +398,19 @@ typedef struct
 struct yaffs_DeviceStruct
 {
        // Entry parameters set up way early. Yaffs sets up the rest.
+       int   nBytesPerChunk;    // Should be a power of 2 >= 512
+       int       nChunksPerBlock;
        int   startBlock;       // Start block we're allowed to use
        int   endBlock;         // End block we're allowed to use
-       __u16 chunkGroupBits; // 0 for devices <= 32MB. else log2(nchunks) - 16
-       __u16 chunkGroupSize; // == 2^^chunkGroupBits
+       
+       int   useNANDECC;               // Flag to decide whether or not to use NANDECC
+       int   nShortOpCaches;   // If <= 0, then short op caching is disabled, else
+                                                       // the number of short op caches (don't use too many).
        
        
        void *genericDevice; // Pointer to device context
                                                 // On an mtd this holds the mtd pointer.
-       
-#ifdef __KERNEL__
-
-       struct semaphore sem;// Semaphore for waiting on erasure.
-       struct semaphore grossLock; // Gross locking semaphore
 
-#endif
-       
-       
        // NAND access functions (Must be set before calling YAFFS)
        
        int (*writeChunkToNAND)(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare);
@@ -410,16 +418,34 @@ struct yaffs_DeviceStruct
        int (*eraseBlockInNAND)(struct yaffs_DeviceStruct *dev,int blockInNAND);        
        int (*initialiseNAND)(struct yaffs_DeviceStruct *dev);
 
+       // Runtime parameters. Set up by YAFFS.
+       
+       __u16 chunkGroupBits; // 0 for devices <= 32MB. else log2(nchunks) - 16
+       __u16 chunkGroupSize; // == 2^^chunkGroupBits
+       
+#ifdef __KERNEL__
+
+       struct semaphore sem;// Semaphore for waiting on erasure.
+       struct semaphore grossLock; // Gross locking semaphore
+
+#endif 
 #ifdef __KERNEL__
        void (*putSuperFunc)(struct super_block *sb);
 #endif
 
-       // Runtime parameters.
+       int isMounted;
+       
+       // Block Info
        yaffs_BlockInfo *blockInfo;
+       __u8 *chunkBits;   // bitmap of chunks in use
+       int   chunkBitmapStride; // Number of bytes of chunkBits per block. 
+                                                        //     Must be consistent with nChunksPerBlock.
+
+
        int   nErasedBlocks;
-       int   allocationBlock;
+       int   allocationBlock;                  // Current block being allocated off
        __u32 allocationPage;
-       int   allocationBlockFinder;
+       int   allocationBlockFinder;    // Used to search for next allocation block
        
        // Runtime state
        int   nTnodesCreated;   
@@ -454,22 +480,23 @@ struct yaffs_DeviceStruct
        int eccUnfixed;
        int tagsEccFixed;
        int tagsEccUnfixed;
+       int nDeletions;
+       int nUnmarkedDeletions;
        
        yaffs_Object *rootDir;
        yaffs_Object *lostNFoundDir;
        
        // Buffer areas for storing data to recover from write failures
-       __u8            bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
-       yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
+//     __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;
        
        int blockSelectedForGC;
 
-#ifdef CONFIG_YAFFS_SHORT_OP_CACHE
-       yaffs_ChunkCache srCache[YAFFS_N_CACHE_CHUNKS];
+       yaffs_ChunkCache *srCache;
        int srLastUse;
-#endif
+
        int cacheHits;
 
        // Stuff for background deletion and unlinked files.
@@ -519,7 +546,7 @@ int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, __u32 offset, i
 int yaffs_ResizeFile(yaffs_Object *obj, int newSize);
 
 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid);
-int yaffs_FlushFile(yaffs_Object *obj);
+int yaffs_FlushFile(yaffs_Object *obj,int updateTime);
 
 
 // Directory operations
@@ -560,3 +587,4 @@ void yaffs_GutsTest(yaffs_Device *dev);
 
 
 #endif
+
index 5505d55f9a5aae82c98d8208daf89d0a25ea2141..14876c84206a3b3468544ebf7f543e0dfffc8982 100644 (file)
@@ -13,7 +13,7 @@
  *
  */
 
-const char *yaffs_mtdif_c_version = "$Id: yaffs_mtdif.c,v 1.5 2002-12-13 00:13:06 charles Exp $";
+const char *yaffs_mtdif_c_version = "$Id: yaffs_mtdif.c,v 1.6 2003-01-14 23:15:32 charles Exp $";
 
 #ifdef CONFIG_YAFFS_MTD_ENABLED
  
@@ -42,11 +42,10 @@ int nandmtd_WriteChunkToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data,
 #ifndef        CONFIG_YAFFS_USE_OLD_MTD
        if(data && spare)
        {
-#ifdef CONFIG_YAFFS_USE_NANDECC
-               retval = mtd->write_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_YAFFS_OOB);
-#else
-               retval = mtd->write_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_NONE_OOB);
-#endif
+               if(dev->useNANDECC)
+                       mtd->write_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_YAFFS_OOB);
+               else
+                       mtd->write_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_NONE_OOB);
        }
        else
        {
@@ -78,13 +77,16 @@ int nandmtd_ReadChunkFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaf
 #ifndef        CONFIG_YAFFS_USE_OLD_MTD
        if(data && spare)
        {
-#ifdef CONFIG_YAFFS_USE_NANDECC
-        u8 tmpSpare[ YAFFS_BYTES_PER_SPARE + (2*sizeof(int)) ];
-               retval = mtd->read_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,tmpSpare,NAND_YAFFS_OOB);
-        memcpy(spareAsBytes, tmpSpare, YAFFS_BYTES_PER_SPARE);
-#else
-               retval = mtd->read_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_NONE_OOB);
-#endif 
+               if(dev->useNANDECC)
+               {
+                       u8 tmpSpare[ YAFFS_BYTES_PER_SPARE + (2*sizeof(int)) ];
+                       retval = mtd->read_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,tmpSpare,NAND_YAFFS_OOB);
+                       memcpy(spareAsBytes, tmpSpare, YAFFS_BYTES_PER_SPARE);
+               }
+               else
+               {
+                       retval = mtd->read_ecc(mtd,addr,YAFFS_BYTES_PER_CHUNK,&dummy,data,spareAsBytes,NAND_NONE_OOB);
+               }
        }
        else
        {
index c44715b32f9d062b2bf69578ef37a0c8666d0a10..f325b78c1099972b23056c2b2c13429499b268d0 100644 (file)
@@ -111,7 +111,7 @@ void TestTimeasasas(yaffs_Device *dev)
        
        printf("Flush\n");
        
-       yaffs_FlushFile(f);
+       yaffs_FlushFile(f,1);
 
        yaffs_ApplyToDirectoryChildren(yaffs_Root(dev),yaffs_DumpObject);
        
@@ -129,7 +129,7 @@ void TestTimeasasas(yaffs_Device *dev)
        
        yaffs_DumpObject(f);
 
-       yaffs_FlushFile(f);
+       yaffs_FlushFile(f,1);
        
        
                
@@ -187,7 +187,7 @@ void TestTimeBigDeletes(yaffs_Device *dev)
                        written = yaffs_WriteDataToFile(f,testStr2,i,strlen(testStr2));
        }
        
-       yaffs_FlushFile(f);
+       yaffs_FlushFile(f,1);
        yaffs_DeleteFile(f);
 
        f = yaffs_FindObjectByName(yaffs_Root(dev),"Name1");
@@ -211,7 +211,7 @@ void TestTimeBigDeletes(yaffs_Device *dev)
                        written = yaffs_WriteDataToFile(f,testStr2,i,strlen(testStr2));
        }
        
-       yaffs_FlushFile(f);
+       yaffs_FlushFile(f,1);
        yaffs_DeleteFile(f);
 
        f = yaffs_FindObjectByName(yaffs_Root(dev),"Name1");
@@ -235,7 +235,7 @@ void TestTimeBigDeletes(yaffs_Device *dev)
                        written = yaffs_WriteDataToFile(f,testStr2,i,strlen(testStr2));
        }
        
-       yaffs_FlushFile(f);
+       yaffs_FlushFile(f,1);
        yaffs_DeleteFile(f);
        
 }
@@ -392,7 +392,7 @@ void TestTime(yaffs_Device *dev)
        
        printf("Flush\n");
        
-       yaffs_FlushFile(f);
+       yaffs_FlushFile(f,1);
        yaffs_ReadDataFromFile(f,data,1000,50);
        data[50] = 0;
        
@@ -443,7 +443,7 @@ void TestTime(yaffs_Device *dev)
        
        
 
-       yaffs_FlushFile(f);
+       yaffs_FlushFile(f,1);
                
 
        printf("Unlink file: %d\n",yaffs_Unlink(yaffs_Root(dev),"Rename"));
@@ -573,7 +573,7 @@ void TestTimeDeleteFocussed(yaffs_Device *dev)
        
        
 
-       yaffs_FlushFile(f);
+       yaffs_FlushFile(f,1);
                
 
        printf("Unlink file: %d\n",yaffs_Unlink(yaffs_Root(dev),"Rename"));
@@ -629,6 +629,56 @@ void TestTimeTnodeFocussed(yaffs_Device *dev)
                        written = yaffs_WriteDataToFile(f,testStr2,0,strlen(testStr2));
        }
        
+}
+void TestTimeBackgroundDeleteFocussed(yaffs_Device *dev)
+{
+       yaffs_Object *f;
+       yaffs_Object *lnf;
+       
+       
+       int x;
+       int i,j;
+       int b;
+       int written;
+       
+       
+       printf("Exisiting objects\n");
+       yaffs_ApplyToDirectoryChildren(yaffs_Root(dev),yaffs_DumpObject);
+       printf("Exisiting objects in lost+found\n");
+       lnf = yaffs_FindObjectByName(yaffs_Root(dev),YAFFS_LOSTNFOUND_NAME);
+       yaffs_ApplyToDirectoryChildren(lnf,yaffs_DumpObject);
+
+       printf("Start\n");
+       
+       
+       for(j = 0; j < 20; j++)
+       {
+               printf("Run %d\n",j);
+
+               f = yaffs_FindObjectByName(yaffs_Root(dev),"Name1");
+               if(f)
+               {
+                       printf("Found\n");
+               }
+               else
+               {
+                       f = yaffs_MknodFile(yaffs_Root(dev),"Name1",0,0,0);
+                       printf("Created\n");
+               }
+       
+               printf("@@@@@@@ Run %d, object %d\n",j,f->objectId);
+       
+               for(i = 0; i < 1000000; i+=20)
+               {
+       
+                       written = yaffs_WriteDataToFile(f,testStr,i,100);
+               }
+               
+               yaffs_FlushFile(f,1);
+               
+               yaffs_DeleteFile(f);
+       }
+       
 }
 
 int main(int argc,char *argv[])
@@ -637,7 +687,7 @@ int main(int argc,char *argv[])
        int nBlocks;
        
 #if YAFFS_FILEEM       
-       nBlocks =(4 * 1024 * 1024) / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK) ;
+       nBlocks =(2 * 1024 * 1024) / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK) ;
        device.writeChunkToNAND = yaffs_FEWriteChunkToNAND;
        device.readChunkFromNAND = yaffs_FEReadChunkFromNAND;
        device.eraseBlockInNAND = yaffs_FEEraseBlockInNAND;
@@ -662,14 +712,20 @@ int main(int argc,char *argv[])
        device.endBlock = nBlocks;
 #endif
 
+       device.nShortOpCaches = 10;
+
+
        yaffs_GutsInitialise(&device);
        
        // yaffs_GutsTest();
        
-       TestTime(&device);
+       TestTimeBackgroundDeleteFocussed(&device);
        
        printf("Cache hits %d\n",device.cacheHits);
        printf("Retired blocks %d\n",device.nRetiredBlocks);
        
+       printf("Deletions %d\n",device.nDeletions);
+       printf("Unmarked deletions %d\n",device.nUnmarkedDeletions);
+       
        exit(0);
 }
index 770d67c5c763dffc2423e8bee0a725bda635b61e..fa40e294daa7c7730fda1cf8e35ce49bf0e8c1f3 100644 (file)
Binary files a/yaffsdev.proj and b/yaffsdev.proj differ
index 943cffe5071b90a35636ec45779dd248faca3648..b330375888f19595e60604183f8a35ab5b20f3be 100644 (file)
@@ -15,7 +15,7 @@
  *
  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
  *
- * $Id: yportenv.h,v 1.7 2002-11-26 01:15:37 charles Exp $
+ * $Id: yportenv.h,v 1.8 2003-01-14 23:15:41 charles Exp $
  *
  */
  
@@ -30,6 +30,8 @@
 #include "stdio.h"
 #include "string.h"
 
+#define CONFIG_YAFFS_CASE_INSENSITIVE
+
 #define YMALLOC(x) malloc(x)
 #define YFREE(x)   free(x)
 
@@ -100,9 +102,44 @@ extern unsigned yfsd_U32FileTimeNow(void);
 #define TOUT(p) printk p
 
 
-#else
+#elif defined CONFIG_YAFFS_DIRECT
+
+// Directct interface
+
+#include "stdlib.h"
+#include "stdio.h"
+#include "string.h"
+
+#define YMALLOC(x) malloc(x)
+#define YFREE(x)   free(x)
+
+
+//#define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s))
+//#define YALERT(s) YINFO(s)
+
+
+#define TENDSTR "\n"
+#define TSTR(x) x
+#define TOUT(p) printf p
+
+
+#define YAFFS_LOSTNFOUND_NAME          "lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX                "obj"
+//#define YPRINTF(x) printf x
+
+#include "yaffscfg.h"
+
+#define CURRENT_TIME yaffsfs_CurrentTime()
+#define YAFFS_ROOT_MODE                                0666
+#define YAFFS_LOSTNFOUND_MODE          0666
+
+#define yaffs_SumCompare(x,y) ((x) == (y))
+#define yaffs_strcmp(a,b) strcmp(a,b)
+
+#elif defined CONFIG_YAFFS_UTIL
+
+// Stuff for YAFFS utilities
 
-// Linux application
 #include "stdlib.h"
 #include "stdio.h"
 #include "string.h"
@@ -124,6 +161,7 @@ extern unsigned yfsd_U32FileTimeNow(void);
 #define YAFFS_LOSTNFOUND_PREFIX                "obj"
 //#define YPRINTF(x) printf x
 
+
 #define CURRENT_TIME 0
 #define YAFFS_ROOT_MODE                                0666
 #define YAFFS_LOSTNFOUND_MODE          0666
@@ -131,6 +169,10 @@ extern unsigned yfsd_U32FileTimeNow(void);
 #define yaffs_SumCompare(x,y) ((x) == (y))
 #define yaffs_strcmp(a,b) strcmp(a,b)
 
+#else
+// Should have specified a configuration type
+#error Unknown configuration
+
 #endif