--- /dev/null
+/*\r
+ * YAFFS: Yet another FFS. A NAND-flash specific file system.\r
+ * yaffsfsd.c: The FSD layer for the WinCE version of YAFFS.\r
+ *\r
+ * Copyright (C) 2002 Trimble Navigation Ltd.\r
+ *\r
+ * Created by Charles Manning <charles.manning@trimble.co.nz>\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License version 2 as\r
+ * published by the Free Software Foundation.\r
+ *\r
+ * This program is distributed in the hope that it will be useful, \r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of \r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU \r
+ * General Public License for more details. You should have received a \r
+ * copy of the GNU General Public License along with this program; \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
+ */
+#include <windows.h>
+#include <extfile.h>
+#include <yaffs_guts.h>
+#include <ynandif.h>
+
+#define MAX_WIN_FILE 200
+#define YFSD_NAME_LENGTH 128
+#define YFSD_FULL_PATH_NAME_SIZE 500
+
+
+#define YFSD_DISK_NAME L"Disk"
+#define YFSD_BOOT_NAME L"Boot"
+
+#define PARTITION_START_NUMBER (1280)
+
+#define MSGSTATE 1
+//#define DISABLE_BOOT_PARTITION\r
+\r
+unsigned yaffs_traceMask=0xffffffff;
+
+
+typedef struct
+{
+ yaffs_Device dev;
+ DWORD hdsk;
+ DWORD mgrVolume; // The volume id from the manager issed when we registered it - it is an HVOL
+ BOOL isMounted;
+ BOOL configured;
+// DWORD guard0[100];
+// DWORD guard1[100];
+ SHELLFILECHANGEFUNC_t shellFunction;
+ PWSTR volName;
+} yfsd_Volume;
+
+typedef struct
+{
+ yaffs_Object *obj;
+ DWORD offset;
+ BOOL isopen;
+ BOOL writePermitted;
+ BOOL dirty;
+ WCHAR *fullName;
+ yfsd_Volume *myVolume;
+
+} yfsd_WinFile;
+
+struct yfsd_FoundObjectStruct
+{
+ yaffs_Object *obj;
+ struct yfsd_FoundObjectStruct *next;
+};
+
+typedef struct yfsd_FoundObjectStruct yaffs_FoundObject;
+
+typedef struct
+{
+ yaffs_Object *dir;
+ char pattern[YFSD_NAME_LENGTH+1];
+ yaffs_FoundObject *foundObjects;
+} yfsd_WinFind;
+
+
+
+#define PSEARCH yfsd_WinFind*
+
+#define PVOLUME yfsd_Volume*
+#define PFILE yfsd_WinFile*
+
+#define FSD_API YFSD
+
+#include <fsdmgr.h>
+
+
+static yfsd_Volume disk_volume;
+static yfsd_Volume boot_volume;
+
+static CRITICAL_SECTION yaffsLock;
+static CRITICAL_SECTION winFileLock;
+
+static int yaffsLockInited = 0;
+
+static yfsd_WinFile yfsd_winFile[MAX_WIN_FILE];
+
+#if 0
+static yfsd_SetGuards(void)
+{
+ int i;
+ for(i = 0; i < 100; i++)
+ {
+ yfsd_volume.guard0[i] = yfsd_volume.guard1[i] = i;
+ }
+}
+
+static void yfsd_CheckGuards(void)
+{
+ int i;
+ int found;
+ for(i = found = 0; i < 100 && !found; i++)
+ {
+ if(yfsd_volume.guard0[i] != i)
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS:: guard 0 %d brocken\r\n",i));
+ found = 1;
+ }
+ if(yfsd_volume.guard1[i] != i)
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS:: guard 0 %d brocken\r\n",i));
+ found = 1;
+ }
+ }
+}
+#endif
+
+void yfsd_LockWinFiles(void)
+{
+ //RETAILMSG (MSGSTATE, (L"YAFFS::LockWinfiles\r\n"));
+ EnterCriticalSection(&winFileLock);
+}
+void yfsd_UnlockWinFiles(void)
+{
+ //RETAILMSG (MSGSTATE, (L"YAFFS::UnlockWinFiles\r\n"));
+ LeaveCriticalSection(&winFileLock);
+}
+
+int lockwaits;
+
+void yfsd_LockYAFFS(void)
+{
+ //yfsd_CheckGuards();
+ //RETAILMSG (MSGSTATE, (L"YAFFS::LockYAFFS %d ",lockwaits));
+ lockwaits++;
+ EnterCriticalSection(&yaffsLock);
+ //RETAILMSG (MSGSTATE, (L" locked\r\n"));
+}
+void yfsd_UnlockYAFFS(void)
+{
+ //yfsd_CheckGuards();
+ //RETAILMSG (MSGSTATE, (L"YAFFS::UnLockYAFFS "));
+ LeaveCriticalSection(&yaffsLock);
+ lockwaits--;
+ //RETAILMSG (MSGSTATE, (L" unlocked\r\n"));
+}
+
+
+void yfsd_InitialiseWinFiles(void)
+{
+ int i;
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::InitWinFiles\r\n"));
+
+ InitializeCriticalSection(&winFileLock);
+
+ yfsd_LockWinFiles();
+ for(i = 0; i < MAX_WIN_FILE; i++)
+ {
+ yfsd_winFile[i].isopen = 0;
+ }
+ yfsd_UnlockWinFiles();
+}
+
+yfsd_WinFile * yfsd_GetWinFile(void)
+{
+ int i;
+ RETAILMSG (MSGSTATE, (L"YAFFS::GetWinFiles\r\n"));
+
+ yfsd_LockWinFiles();
+
+ for(i = 0; i < MAX_WIN_FILE; i++)
+ {
+ if(!yfsd_winFile[i].isopen)
+ {
+ yfsd_winFile[i].isopen = 1;
+ yfsd_winFile[i].writePermitted = 0;
+ yfsd_winFile[i].dirty = 0;
+ yfsd_winFile[i].fullName = NULL;
+ yfsd_winFile[i].obj = NULL;
+
+ yfsd_UnlockWinFiles();
+ return &yfsd_winFile[i];
+ }
+ }
+
+ yfsd_UnlockWinFiles();
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::GetWinFiles did not find a handle. Too many open.\r\n"));
+
+ return NULL;
+}
+
+void yfsd_PutWinFile(yfsd_WinFile *f)
+{
+ RETAILMSG (MSGSTATE, (L"YAFFS::PutWinFile\r\n"));
+ yfsd_LockWinFiles();
+ f->isopen = 0;
+ f->obj = NULL;
+ if(f->fullName)
+ {
+ free(f->fullName);
+ f->fullName = NULL;
+ }
+
+ yfsd_UnlockWinFiles();
+}
+
+
+
+void yfsd_FlushAllFiles(void)
+{
+ int i;
+ RETAILMSG (MSGSTATE, (L"YAFFS::FlushAllFiles\r\n"));
+
+ yfsd_LockYAFFS();
+ yfsd_LockWinFiles();
+ for(i = 0; i < MAX_WIN_FILE; i++)
+ {
+ if(yfsd_winFile[i].isopen &&
+ yfsd_winFile[i].obj)
+ {
+ yaffs_FlushFile(yfsd_winFile[i].obj);
+ }
+ }
+ yfsd_UnlockWinFiles();
+ yfsd_UnlockYAFFS();
+}
+
+PWSTR yfsd_FullPathName(PVOLUME vol, PWSTR fpn,int slength,PCWSTR pathName)
+{
+
+ // todo check for bounds
+ wcscpy(fpn,L"\\");
+ wcscat(fpn,vol->volName);
+ if(pathName[0] != '\\')
+ {
+ wcscat(fpn,L"\\");
+ }
+ wcscat(fpn,pathName);
+
+ return fpn;
+
+}
+
+
+// FILETIME is a 64-bit value as 100-nanosecond intervals since January 1, 1601.
+\r
+void yfsd_U32sToWinFileTime(__u32 target[2], FILETIME *wft)
+{
+
+ wft->dwLowDateTime = target[0];
+ wft->dwHighDateTime = target[1];
+
+}
+
+void yfsd_NullWinFileTime(FILETIME *wft)
+{
+ wft->dwLowDateTime = 0;
+ wft->dwHighDateTime = 0;
+}
+
+void yfsd_WinFileTimeToU32s(const FILETIME *wft, __u32 target[2])
+{
+ target[0] = wft->dwLowDateTime;
+ target[1] = wft->dwHighDateTime;
+}
+
+void yfsd_WinFileTimeNow(__u32 target[2])
+{
+ SYSTEMTIME st;
+ FILETIME ft;
+
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st,&ft);
+ yfsd_WinFileTimeToU32s(&ft,target);
+}
+
+// Cut down the name to the parent directory, then inform the shell of
+// a change to the directory.
+void yfsd_ShellDirectoryChanged(PVOLUME pVolume, PWSTR fullPathName)
+{
+ WCHAR str[500];
+ int i;
+ wcscpy(str,fullPathName);
+
+ i = wcslen(str) - 1;
+
+ if(i > 0)
+ {
+ str[i] = 0;
+ i--;
+ }
+
+ // Curveball if the name is a directory (ie. we're doing an update of
+ // a directory because we added a directory item). , then it might end in a \
+ // which we must toss first
+ if(i >= 0 && (str[i] == '\\' || str[i] == '/'))
+ {
+ str[i] = 0;
+ i--;
+ }
+
+ // Ok, now strip back...
+
+ while(i >= 0 && str[i] != '\\' && str[i] != '/')
+ {
+ str[i] = 0;
+ i--;
+ }
+
+ if(pVolume->shellFunction)
+ {
+ FILECHANGEINFO fc;
+
+ fc.cbSize = sizeof(FILECHANGEINFO);
+ fc.wEventId = SHCNE_UPDATEDIR;
+ fc.uFlags = SHCNF_PATH;
+ fc.dwItem1 = (DWORD)str;
+ fc.dwItem2 = 0;
+ fc.dwAttributes = 0;
+ yfsd_NullWinFileTime(&fc.ftModified);
+ fc.nFileSize = 0;
+
+ pVolume->shellFunction(&fc);
+ RETAILMSG (MSGSTATE, (L"YAFFS:: directory changed %s\r\n",str));
+
+ }
+
+
+}
+\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
+}
+
+// File attributes:
+// Wince understands the following attributes of any use to YAFFS:
+//
+// ARCHIVE
+// HIDDEN
+// READONLY
+// SYSTEM
+// TEMPORARY
+//
+// Also, FILE_ATTRIBUTE_DIRECTORY is used to mark directories.
+//
+// It also understands NORMAL. If no other flag is set, then set NORMAL.
+// If any of the above are set, then NORMAL must **not** be set.
+// Ignore this and the WinCE Explorer barfs the file.
+//
+//
+// 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
+}
+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
+ FILE_ATTRIBUTE_SYSTEM);
+\r
+ if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) result |= FILE_ATTRIBUTE_DIRECTORY;\r
+
+ if(result & ~FILE_ATTRIBUTE_NORMAL)
+ {
+ result &= ~FILE_ATTRIBUTE_NORMAL;
+ }
+ else
+ {
+ result = FILE_ATTRIBUTE_NORMAL;
+ }
+\r
+
+ return result;
+}
+
+
+
+/*
+* Runs over input until a '\' is found, or '\0' is found, or outSize - 1 is
+* reached. Characters are copied from input into output until the above stop
+* condition is reached - output is then given a '\0'. output must be at least
+* as large as outSize
+*/
+static int parseToNextSlash(const unsigned short *input, char *output, int outSize)
+{
+ int counter = 0;
+ char *t = output;
+ /* strip any starting \'s */
+ //RETAILMSG(1, (L"\r\nParsing.. "));
+ while (*input == '\\' || *input == '/') input++, counter++;
+
+ for (; counter < outSize - 1; counter++)
+ {
+ if (*input == '\0' ||
+ ((*input == '\\' || *input == '/') && input[1] == '\0')) // special case: if the string ends in a '\', then toss the '\'
+ {
+ counter = -1; // break & tell people we've run to the end
+ break;
+ }
+ if (*input == '\\' || *input == '/')
+ break;
+ //RETAILMSG(1, (L"%c", *input));
+ *output = (char) (*input);
+ input++;
+ output++;
+ }
+ *output++ = '\0';
+ *output = '\0';
+// RETAILMSG(1, (L"\r\nOut %a\r\n", t));
+
+ return counter;
+}
+
+/*
+* Since the notion of paths as WinCE sees them and as YAFFS sees them
+* is different, we needed a helper function to search from the root of
+* device along the string in path. The processed pointer is set to where
+* abouts in the string the function was able to search up to.
+*/
+yaffs_Object *yfsd_FindDirectoryByWinPath(yaffs_Device *device, const wchar_t *path, char *processed, int length)
+{
+ // a buffer to keep the current chunk of path we're talking about it
+ char pathChunk[255];
+ int chunkSize;
+ int counter;
+ // the current object we are at
+ yaffs_Object *current;
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::FindByWinPath (%s) : ", path));
+ // start at the root of this device
+ current = yaffs_Root(device);\r
+ *processed = '\0';
+
+ do
+ {
+ // parse chunks until we run out
+ chunkSize = parseToNextSlash(path, pathChunk, 255);
+// RETAILMSG(1, (L"Chunk %a\r\n", pathChunk));
+ if (chunkSize == -1)
+ break;
+ // move the path pointer along
+ path += chunkSize;
+ // try and find the next yaffs object by chunkname
+ current = yaffs_FindObjectByName(current, pathChunk);
+ if (current == 0)
+ {
+ processed[0] = '\0';
+ return 0;
+ }
+ } while (1);
+
+ for (counter = 0; counter < length; counter++)
+ {
+ // Get the rest of the string
+ processed[counter] = pathChunk[counter];
+ if (pathChunk[counter] == '\0')
+ break;
+ }
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::FindDirectoryByWinPath parent:%X name:%a\r\n", current,processed));
+
+ return current;
+}
+
+
+yaffs_Object *yfsd_FindObjectByWinPath(yaffs_Device *dev, PCWSTR pwsFileName )
+{
+ yaffs_Object *obj = NULL;
+ yaffs_Object *parent = NULL;
+ char name[YFSD_NAME_LENGTH+1];
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::FindObjByWinPath\r\n"));
+
+ parent = yfsd_FindDirectoryByWinPath(dev,pwsFileName,name,YFSD_NAME_LENGTH);
+
+ if(parent && yfsd_NameIsValid(name))
+ {
+ obj = yaffs_FindObjectByName(parent,name);
+ }
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::FindObjectByWinPath parent:%X obj:%X\r\n", parent,obj));
+
+ return obj;
+}
+
+BOOL YFSD_InitVolume(HDSK hdsk, yfsd_Volume *vol, int startBlock, int endBlock, PWSTR volName)
+{
+ RETAILMSG (MSGSTATE, (L"YAFFS::InitVolume\r\n"));
+ vol->volName = volName;
+
+
+ yfsd_LockYAFFS();
+
+ //Mount/initialise YAFFs here
+ ynandif_InitialiseNAND(&vol->dev);
+
+ vol->dev.writeChunkToNAND = ynandif_WriteChunkToNAND;
+ vol->dev.readChunkFromNAND = ynandif_ReadChunkFromNAND;
+ vol->dev.eraseBlockInNAND = ynandif_EraseBlockInNAND;
+ vol->dev.initialiseNAND = ynandif_InitialiseNAND;
+ vol->dev.startBlock = startBlock;
+ if (endBlock != -1)
+ vol->dev.endBlock = endBlock;
+
+ // nBlocks is set the total size of the disk, not the partition
+// vol->dev.nBlocks = endBlock - startBlock + 1;
+
+// qnand_EraseAllBlocks(&vol->dev);
+
+ yaffs_GutsInitialise(&vol->dev);
+ RETAILMSG(1, (L"YAFFS::Done yaffs_GutsInitialise\r\n"));
+
+ RETAILMSG(1, (L"Blocks start %d end %d Group size %d bits %d\r\n",
+ vol->dev.startBlock,vol->dev.endBlock,
+ vol->dev.chunkGroupSize,vol->dev.chunkGroupBits));
+
+
+#if 0
+ for(i = vol->dev.startBlock; i <= vol->dev.endBlock; i++)
+ {
+ switch(vol->dev.blockInfo[i].blockState)
+ {
+ case YAFFS_BLOCK_STATE_DEAD:
+
+ RETAILMSG(1, (L"YAFFS::Dead block %d\r\n",i));
+ deadBlox++;
+ break;
+ case YAFFS_BLOCK_STATE_EMPTY: emptyBlox++; break;
+ case YAFFS_BLOCK_STATE_FULL: fullBlox++; break;
+ case YAFFS_BLOCK_STATE_ALLOCATING: allocatingBlox++; break;
+ case YAFFS_BLOCK_STATE_DIRTY: dirtyBlox++; break;
+ default:
+ RETAILMSG(1, (L"YAFFS::Block %d has goofus state %d\r\n",i,vol->dev.blockInfo[i].blockState));
+ break;
+ }
+ }
+
+ RETAILMSG(1, (L"Blocks dead %d empty %d full %d allocating %d dirty %d\r\n",
+ deadBlox,emptyBlox,fullBlox,allocatingBlox,dirtyBlox));
+
+#endif
+
+ yfsd_UnlockYAFFS();
+
+ vol->isMounted = 1;
+
+ vol->mgrVolume = FSDMGR_RegisterVolume(hdsk,vol->volName,vol);
+
+ if(vol->mgrVolume)
+ {
+ return TRUE;
+ }
+ else
+ {
+ vol->isMounted = 0;
+ SetLastError(ERROR_OUTOFMEMORY);
+ return FALSE;
+ }
+}
+
+
+BOOL YFSD_MountDisk(HDSK hdsk)
+{
+ int deadBlox=0,emptyBlox=0,fullBlox=0,allocatingBlox=0,dirtyBlox=0;
+ //int i;
+ // Called to mount a disk.
+ // NB THis call might happen redundantly.
+ //
+ //
+ // If yaffs is not initialised, then call the
+ // initialisation function
+ //
+ RETAILMSG (MSGSTATE, (L"YAFFS::MountDisk\r\n"));
+
+ if (!yaffsLockInited)
+ {
+ InitializeCriticalSection(&yaffsLock);
+ 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;
+ }
+#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;
+
+// yfsd_SetGuards();
+
+ // todo - get name from registry
+
+}
+
+
+BOOL YFSD_UnmountDisk(HDSK hdsk)
+{
+ 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);
+ return TRUE;
+}
+
+
+BOOL YFSD_CreateDirectoryW(PVOLUME pVolume, PCWSTR pathName, PSECURITY_ATTRIBUTES pSecurityAttributes)
+{
+ // security attributes are ignored (should be NULL)
+
+ yaffs_Object *newDir = NULL;
+ yaffs_Object *parent = NULL;
+ char name[YFSD_NAME_LENGTH+1];
+ ULONG objSize;
+ DWORD attribs;
+ unsigned modifiedTime[2];
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateDirectory (%s)\r\n", pathName));
+
+ yfsd_LockYAFFS();
+
+ 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)
+ {
+ objSize = yaffs_GetObjectFileLength(newDir);
+ attribs = yfsd_GetObjectWinAttributes(newDir);
+ modifiedTime[0] = newDir->win_mtime[0];\r
+ modifiedTime[1] = newDir->win_mtime[1];\r
+ }
+ else
+ {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ }
+
+ yfsd_UnlockYAFFS();
+
+ // Call shell function to tell of new directory
+ if(newDir && pVolume->shellFunction)
+ {
+ FILECHANGEINFO fc;
+ WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
+
+ fc.cbSize = sizeof(FILECHANGEINFO);
+ fc.wEventId = SHCNE_MKDIR;
+ fc.uFlags = SHCNF_PATH;
+ fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume, fpn,YFSD_FULL_PATH_NAME_SIZE,pathName);
+ fc.dwItem2 = 0;
+ fc.dwAttributes = attribs;
+ yfsd_U32sToWinFileTime(modifiedTime,&fc.ftModified);
+ fc.nFileSize = objSize;
+
+ pVolume->shellFunction(&fc);
+ RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
+
+ //yfsd_ShellDirectoryChanged(pVolume,fpn);
+
+ }
+
+ if(parent && !newDir)
+ {
+ SetLastError(ERROR_DISK_FULL);
+ }
+
+ return newDir ? TRUE : FALSE;
+}
+
+
+BOOL yfsd_RemoveObjectW(PVOLUME pVolume, PCWSTR pathName)
+{
+ // Fails if directory is not empty
+ int result = FALSE;
+ yaffs_Object *parent = NULL;
+ yaffs_Object *obj;
+ char name[YFSD_NAME_LENGTH+1];
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::RemoveObjectW (%s)\r\n", pathName));
+
+ yfsd_LockYAFFS();
+
+ obj = yfsd_FindObjectByWinPath(&pVolume->dev,pathName);
+ if(!obj)
+ {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ result = FALSE;
+ }
+ else if(obj->st_mode & FILE_ATTRIBUTE_READONLY)
+ {
+ SetLastError(ERROR_ACCESS_DENIED);
+ result = FALSE;
+ }
+ else if(obj->inUse)
+ {
+ SetLastError(ERROR_ACCESS_DENIED);
+ result = FALSE;
+ }
+ else
+ {
+
+ parent = yfsd_FindDirectoryByWinPath(&pVolume->dev,pathName,name,YFSD_NAME_LENGTH);
+
+ if(parent && yfsd_NameIsValid(name))
+ {
+ result = yaffs_Unlink(parent,name);
+ if(!result)
+ SetLastError(ERROR_ACCESS_DENIED);
+ }
+ }
+
+ yfsd_UnlockYAFFS();
+
+ return result ? TRUE : FALSE;
+}
+
+
+BOOL YFSD_RemoveDirectoryW(PVOLUME pVolume, PCWSTR pathName)
+{
+ BOOL result;
+ RETAILMSG (MSGSTATE, (L"YAFFS::RemoveDirectory\r\n"));
+
+ result = yfsd_RemoveObjectW(pVolume, pathName);
+
+ if(result && pVolume->shellFunction)
+ {
+ FILECHANGEINFO fc;
+ WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
+
+ fc.cbSize = sizeof(FILECHANGEINFO);
+ fc.wEventId = SHCNE_RMDIR;
+ fc.uFlags = SHCNF_PATH;
+ fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume,fpn,YFSD_FULL_PATH_NAME_SIZE,pathName);
+ fc.dwItem2 = 0;
+ fc.dwAttributes = 0;
+ yfsd_NullWinFileTime(&fc.ftModified);
+ fc.nFileSize = 0;
+
+ pVolume->shellFunction(&fc);
+ RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
+
+ yfsd_ShellDirectoryChanged(pVolume,fpn);
+ }
+
+ return result;
+
+}
+
+
+DWORD YFSD_GetFileAttributesW(PVOLUME pVolume, PCWSTR pwsFileName )
+{
+ yaffs_Object *obj = NULL;
+
+ DWORD result = 0xFFFFFFFF;
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::GetFileAttributes\r\n"));
+
+ yfsd_LockYAFFS();
+
+ obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
+
+ if(obj)
+ {
+ result = yfsd_GetObjectWinAttributes(obj);
+ }
+ else
+ {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+
+ yfsd_UnlockYAFFS();
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::GetFileAttributes for %s returning %X\r\n",pwsFileName,result));
+ return result;
+
+
+}
+
+BOOL YFSD_SetFileAttributesW( PVOLUME pVolume,PCWSTR pwsFileName, DWORD dwFileAttributes )
+{
+ yaffs_Object *obj = NULL;\r
+ DWORD mtime[2];\r
+ DWORD attribs;\r
+ 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
+ }
+
+ yfsd_LockYAFFS();
+
+ obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
+
+ if(obj)
+ {
+ 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
+ }
+ else
+ {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+
+ yfsd_UnlockYAFFS();
+
+ if(result && pVolume->shellFunction)
+ {
+ FILECHANGEINFO fc;
+ WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
+
+ fc.cbSize = sizeof(FILECHANGEINFO);
+ fc.wEventId = SHCNE_ATTRIBUTES;
+ fc.uFlags = SHCNF_PATH;
+ fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume,fpn,YFSD_FULL_PATH_NAME_SIZE,pwsFileName);
+ fc.dwItem2 = 0;
+ fc.dwAttributes = attribs;
+ yfsd_U32sToWinFileTime(mtime,&fc.ftModified);
+ fc.nFileSize = objSize;
+
+ pVolume->shellFunction(&fc);
+ RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
+
+ //yfsd_ShellDirectoryChanged(pVolume,fpn);
+ }
+
+
+ return result;
+
+}
+
+BOOL YFSD_DeleteFileW( PVOLUME pVolume, PCWSTR pwsFileName )
+{
+ BOOL result;
+ RETAILMSG (MSGSTATE, (L"YAFFS::DeleteFileW (%s)\r\n", pwsFileName));
+
+ result = yfsd_RemoveObjectW(pVolume, pwsFileName);
+ if(result && pVolume->shellFunction)
+ {
+ FILECHANGEINFO fc;
+ WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
+
+ fc.cbSize = sizeof(FILECHANGEINFO);
+ fc.wEventId = SHCNE_DELETE;
+ fc.uFlags = SHCNF_PATH;
+ fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume,fpn,YFSD_FULL_PATH_NAME_SIZE,pwsFileName);
+ fc.dwItem2 = 0;
+ fc.dwAttributes = -1;
+ yfsd_NullWinFileTime(&fc.ftModified);
+ fc.nFileSize = 0;
+
+ pVolume->shellFunction(&fc);
+ RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
+
+ yfsd_ShellDirectoryChanged(pVolume,fpn);
+ }
+
+ return result;
+}
+
+BOOL YFSD_MoveFileW(PVOLUME pVolume,PCWSTR pwsOldFileName, PCWSTR pwsNewFileName )
+{
+ yaffs_Object *newParent = NULL;
+ yaffs_Object *oldParent = NULL;
+ yaffs_Object *obj = NULL;
+ char oldName[YFSD_NAME_LENGTH+1];
+ char newName[YFSD_NAME_LENGTH+1];
+ int result = 0;
+ int objIsDir = 0;
+ DWORD attribs;
+ DWORD objSize;\r
+ DWORD mtime[2];
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::MoveFile\r\n"));
+
+ yfsd_LockYAFFS();
+
+ oldParent = yfsd_FindDirectoryByWinPath(&pVolume->dev,pwsOldFileName,oldName,YFSD_NAME_LENGTH);
+ newParent = yfsd_FindDirectoryByWinPath(&pVolume->dev,pwsNewFileName,newName,YFSD_NAME_LENGTH);
+
+ if(oldParent && yfsd_NameIsValid(oldName) && newParent && yfsd_NameIsValid(newName))
+ {
+ result = yaffs_RenameObject(oldParent,oldName,newParent,newName);
+ if(!result)
+ {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+
+ obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsNewFileName);
+ if(obj)
+ {
+ 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
+ }
+ }
+ else
+ {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ }
+
+ yfsd_UnlockYAFFS();
+
+
+ if(result && pVolume->shellFunction)
+ {
+ FILECHANGEINFO fc;
+ WCHAR fpn1[YFSD_FULL_PATH_NAME_SIZE];
+ WCHAR fpn2[YFSD_FULL_PATH_NAME_SIZE];
+
+ fc.cbSize = sizeof(FILECHANGEINFO);
+ fc.wEventId = objIsDir ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM;
+ fc.uFlags = SHCNF_PATH;
+ fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume,fpn1,YFSD_FULL_PATH_NAME_SIZE,pwsOldFileName);
+ fc.dwItem2 = (DWORD)yfsd_FullPathName(pVolume,fpn2,YFSD_FULL_PATH_NAME_SIZE,pwsNewFileName);
+ fc.dwAttributes = attribs;
+ yfsd_U32sToWinFileTime(mtime,&fc.ftModified);
+ fc.nFileSize = objSize;
+
+ pVolume->shellFunction(&fc);
+ RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
+
+ yfsd_ShellDirectoryChanged(pVolume,fpn1);
+ yfsd_ShellDirectoryChanged(pVolume,fpn2);
+ }
+
+
+ return result ? TRUE : FALSE;
+
+}
+
+BOOL YFSD_DeleteAndRenameFileW(PVOLUME pVolume, PCWSTR pwsOldFileName, PCWSTR pwsNewFileName )
+{
+ RETAILMSG (MSGSTATE, (L"YAFFS::DeleteAndRename\r\n"));
+ return FALSE;
+}
+
+BOOL YFSD_GetDiskFreeSpaceW( PVOLUME pVolume, PCWSTR pwsPathName, PDWORD pSectorsPerCluster,PDWORD pBytesPerSector, PDWORD pFreeClusters, PDWORD pClusters )
+{
+
+ int nChunks;
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::GetFreeSpace\r\n"));
+
+ yfsd_LockYAFFS();
+ nChunks = yaffs_GetNumberOfFreeChunks(&pVolume->dev);
+ yfsd_UnlockYAFFS();
+
+ if(nChunks >= 0)
+ {
+ // Let's pretentd our clusters are the same size as eraseable blocks...
+ *pBytesPerSector = 512;
+ *pSectorsPerCluster =32;
+ *pFreeClusters = nChunks/32;
+ *pClusters = pVolume->dev.endBlock - pVolume->dev.startBlock + 1;
+ }
+
+ return (nChunks >= 0)? TRUE : FALSE;
+
+
+
+}
+
+void YFSD_Notify(PVOLUME pVolume, DWORD dwFlags )
+{
+ // Flags can be one of:
+ // FSNOTIFY_POWER_ON: no action required
+ // FSNOTIFY_POWER_OFF: flush all files
+ // FSNOTIFY_DEVICE_ON: no action required
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::Notify\r\n"));
+ if(dwFlags == FSNOTIFY_POWER_OFF)
+ {
+ yfsd_FlushAllFiles();
+ }
+
+}
+
+
+BOOL YFSD_RegisterFileSystemFunction(PVOLUME pVolume,SHELLFILECHANGEFUNC_t pfn )
+{
+ RETAILMSG (MSGSTATE, (L"YAFFS::RegisterFileSysFunction\r\n"));
+
+ pVolume->shellFunction = pfn;
+
+ return TRUE;
+}
+
+
+
+
+
+int iMatch(const char a, const char b)
+{
+ if (a == '?' || b == '?')
+ return 1;
+ return (toupper(a) == toupper(b));
+}
+
+void pString(const char *inp)
+{
+ while (*inp) RETAILMSG(1, (L"%c", *inp++));
+}
+
+int regularMatch(const char *regexp, const char *str)
+{
+// pString(regexp);
+// RETAILMSG(1, (L" "));
+// pString(str);
+// RETAILMSG(1, (L"\r\n"));
+
+ if (*regexp == 0 && *str == 0)
+ {
+ //RETAILMSG(1, (L"Match!\r\n"));
+ return 1;
+ }
+ if (*regexp == '*')
+ {
+ regexp++;
+ if (*regexp == 0) // end of the expression is a *, we must match
+ {
+ //RETAILMSG(1, (L"Match!\r\n"));
+ return 1;
+ }
+ while (!iMatch(*regexp, *str)) // throw away chars from str until we match
+ {
+ if (*str == 0) // if we're not at the end
+ {
+ // if we have .* left to match, but the str is finished then match it OK
+ if (regexp[0] == '.' && regexp[1] == '*')
+ {
+ //RETAILMSG(1, (L"Match!\r\n"));
+ return 1;
+ }
+ else
+ {
+ // the extension failed the match
+ //RETAILMSG(1, (L"No Match!\r\n"));
+ return 0;
+ }
+ }
+ str++;
+ }
+ // right now we should either eat more characters, or try to match
+ return (regularMatch(regexp, str) || regularMatch(--regexp, ++str));
+ }
+// compare chars until we hit another *, or we fail
+ while (iMatch(*regexp, *str))
+ {
+ if (*regexp == 0 && *str == 0)
+ {
+ //RETAILMSG(1, (L"Match!\r\n"));
+ return 1;
+ }
+ regexp++;
+ str++;
+ }
+
+ if (*regexp == 0 && *str == 0)
+ {
+ //RETAILMSG(1, (L"Match!\r\n"));
+ return 1;
+ }
+
+ if (*regexp == '*')
+ return regularMatch(regexp, str);
+
+ //RETAILMSG(1, (L"No Match!\r\n"));
+ return 0;
+}
+
+
+void yfsd_DeleteFinder(PSEARCH pSearch)
+{
+ if(pSearch->foundObjects) //If we found some objects we must clean up the cached linked list.
+ {
+ yaffs_FoundObject *it;
+ yaffs_FoundObject *temp;
+
+ it = pSearch->foundObjects;
+
+ while(it != NULL)
+ {
+ temp = it;
+ it = it->next;
+
+ free(temp);
+ }
+
+ pSearch->foundObjects = NULL;
+ }
+
+ pSearch->dir->inUse--;
+ free(pSearch);
+}
+
+BOOL yfsd_ObjectAlreadyFound(PSEARCH pSearch, yaffs_Object *l)
+{
+ //Iterate through the current list of objs already found and return true if already exists.
+ //If the object hasn't already been found then add it to the list (SIDE-EFFECT alert) and return false.
+ BOOL found = FALSE;
+
+ yaffs_FoundObject *it;
+ it = pSearch->foundObjects;
+
+
+ while(it->next != NULL) //iterate through singly linked list.
+ {
+ if(it->obj == l)
+ {
+ found = TRUE;
+ break;
+ }
+ it = it->next;
+ }
+
+ if(!found)
+ {
+ //Add the item to the list.
+ //'it' will currently be pointing to the last of the list nodes. i.e node->next == NULL
+ it->next = malloc(sizeof(yaffs_FoundObject));
+ it->next->next = NULL;
+ it->next->obj = 0;
+
+ it->obj = l;
+ }
+
+ return found;
+}
+\r
+#if 0\r
+// slower one
+BOOL yfsd_DoFindFile(PSEARCH pSearch, PWIN32_FIND_DATAW pfd)
+{
+
+ struct list_head *i;
+ int pos;
+ 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();
+
+ pos = 0;
+ list_for_each(i,&pSearch->dir->variant.directoryVariant.children)
+ {
+
+ l = list_entry(i, yaffs_Object,siblings);
+
+ yaffs_GetObjectName(l,name,YAFFS_MAX_NAME_LENGTH+1);
+
+ if(regularMatch(pSearch->pattern,name))
+ {
+ if(!yfsd_ObjectAlreadyFound(pSearch, l))//pos == pSearch->currentPos)
+ {
+
+
+ found = 1;
+ //pSearch->currentPos++;
+
+ // 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;
+ }
+ else
+ {
+ pos++;
+ }
+ }
+ }
+
+out_of_here:
+ yfsd_UnlockYAFFS();
+
+
+ if(!found)
+ {
+ SetLastError(ERROR_NO_MORE_FILES);
+ }
+ 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
+
+HANDLE YFSD_FindFirstFileW(PVOLUME pVolume, HANDLE hProc,PCWSTR pwsFileSpec, PWIN32_FIND_DATAW pfd )
+{
+
+ // Create a search context, register it, and do the first search
+
+ PSEARCH pSearch;
+ HANDLE h = INVALID_HANDLE_VALUE;
+ BOOL found = 0;
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::FindFirst\r\n"));
+
+ pSearch = malloc(sizeof(yfsd_WinFind));
+ if(!pSearch)
+ {
+ SetLastError(ERROR_OUTOFMEMORY);
+ }
+
+ yfsd_LockYAFFS();
+
+ if(pSearch)
+ {
+ pSearch->foundObjects = NULL; //pSearch->currentPos = 0;
+ pSearch->dir = yfsd_FindDirectoryByWinPath(&pVolume->dev,pwsFileSpec,pSearch->pattern,YFSD_NAME_LENGTH);
+ if(pSearch->dir)
+ {
+ pSearch->dir->inUse++;
+ }
+ else
+ {
+ free(pSearch);
+ pSearch = NULL;
+ }
+ }
+
+ yfsd_UnlockYAFFS();
+
+
+
+ if(pSearch)
+ {
+ found = yfsd_DoFindFile(pSearch,pfd);
+ }
+
+ if(found)
+ {
+ h = FSDMGR_CreateSearchHandle(pVolume->mgrVolume,hProc,pSearch);
+ }
+
+ if(h == INVALID_HANDLE_VALUE && pSearch)
+ {
+ yfsd_DeleteFinder(pSearch);
+ SetLastError(ERROR_NO_MORE_SEARCH_HANDLES);
+ }
+
+
+
+ return h;
+}
+
+BOOL YFSD_FindNextFileW(PSEARCH pSearch, PWIN32_FIND_DATAW pfd )
+{
+ RETAILMSG (MSGSTATE, (L"YAFFS::FindNext\r\n"));
+ if(!pSearch)
+ {
+ return FALSE;
+ }
+ return yfsd_DoFindFile(pSearch,pfd);
+}
+
+BOOL YFSD_FindClose( PSEARCH pSearch )
+{
+ RETAILMSG (MSGSTATE, (L"YAFFS::FindClose\r\n"));
+ if(!pSearch)
+ {
+ return FALSE;
+ }
+ yfsd_DeleteFinder(pSearch);
+ return TRUE;
+}
+
+
+HANDLE YFSD_CreateFileW(
+ PVOLUME pVolume,
+ HANDLE hProc,
+ PCWSTR pwsFileName,
+ DWORD dwAccess,
+ DWORD dwShareMode,
+ PSECURITY_ATTRIBUTES pSecurityAttributes, // ignore
+ DWORD dwCreate,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile ) // ignore
+{
+
+
+ yaffs_Object *parent = NULL;
+ yaffs_Object *obj = NULL;
+ char name[YFSD_NAME_LENGTH+1];
+ int mode;
+ yfsd_WinFile *f = NULL;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ unsigned modifiedTime[2];
+ unsigned objSize;
+
+ BOOL writePermitted = (dwAccess & GENERIC_WRITE) ? TRUE : FALSE;
+
+ BOOL fileCreated = FALSE;
+
+
+ mode = dwFlagsAndAttributes & 0x00FFFFFF; // ding off the flags
+
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile (%s) flags %X mode %X\r\n", pwsFileName,dwFlagsAndAttributes,mode));
+ if(writePermitted)
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile write permitted\r\n"));
+ }
+ else
+ {
+ 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
+
+ yfsd_LockYAFFS();
+
+
+ parent = yfsd_FindDirectoryByWinPath(&pVolume->dev,pwsFileName,name,YFSD_NAME_LENGTH);
+
+
+ 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)
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile creating file in CREATE_NEW\r\n"));
+
+ obj = yaffs_MknodFile(parent,name,mode,0,0);
+ if(!obj)
+ SetLastError(ERROR_DISK_FULL);
+ fileCreated = TRUE;
+ }
+ else if( dwCreate == OPEN_ALWAYS)
+ {
+ obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
+ if(!obj)
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile creating file in OPEN_ALWAYS\r\n"));
+ obj = yaffs_MknodFile(parent,name,mode,0,0);
+ if(!obj)
+ SetLastError(ERROR_DISK_FULL);
+ fileCreated = TRUE;
+
+ }
+ else
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile opening existing file in OPEN_ALWAYS\r\n"));
+ }
+ }
+ else if(dwCreate == OPEN_EXISTING)
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile opening file in OPEN_EXISTING\r\n"));
+ obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
+ if(!obj)
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+ else if(dwCreate == TRUNCATE_EXISTING)
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile opening file in TRUNCATE_EXISTING\r\n"));
+ obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
+ if(obj)
+ {
+ yaffs_ResizeFile(obj,0);
+ }
+ else
+ {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+ }
+ else if(dwCreate == CREATE_ALWAYS)
+ {
+ obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
+
+ if(!obj)
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile creating file parent %X, name %a in CREATE_ALWAYS\r\n",parent,name));
+ obj = yaffs_MknodFile(parent,name,mode,0,0);
+ if(!obj)
+ SetLastError(ERROR_DISK_FULL);
+ fileCreated = TRUE;
+ }
+ else
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile in CREATE_ALWAYS (already exists)\r\n"));
+ obj->st_mode = mode;
+ obj->dirty = 1;
+ yaffs_ResizeFile(obj,0);
+ yaffs_FlushFile(obj);
+ }
+ }
+ else
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile called with unknown flags %x\r\n", dwCreate));
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ }
+ else
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile unable to get parent node\r\n"));
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ }
+
+ if(obj)
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - we have an object\r\n"));
+ f = yfsd_GetWinFile();
+ }
+ else
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::Creatfile - no object\r\n"));
+ }
+
+ if(f)
+ {
+
+ handle = FSDMGR_CreateFileHandle(pVolume->mgrVolume,hProc,f);
+
+ if(handle != INVALID_HANDLE_VALUE)
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - we have an fsdmgr handle\r\n"));
+ f->obj = obj;
+ f->offset = 0;
+ f->writePermitted = writePermitted;
+ f->myVolume = pVolume;
+ obj->inUse++;
+
+ modifiedTime[0] = obj->win_mtime[0];\r
+ modifiedTime[1] = obj->win_mtime[1];\r
+ objSize = yaffs_GetObjectFileLength(obj);
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - file size %d\r\n",objSize));
+ }
+ else
+ {
+ yfsd_PutWinFile(f);
+ RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - we have no fsdmgr handle\r\n"));
+ }
+
+ }
+
+ yfsd_UnlockYAFFS();
+
+ if(handle != INVALID_HANDLE_VALUE &&
+ fileCreated &&
+ pVolume->shellFunction)
+ {
+ FILECHANGEINFO fc;
+ WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
+
+ fc.cbSize = sizeof(FILECHANGEINFO);
+ fc.wEventId = SHCNE_CREATE;
+ fc.uFlags = SHCNF_PATH;
+ fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume,fpn,YFSD_FULL_PATH_NAME_SIZE,pwsFileName);
+ fc.dwItem2 = 0;
+ fc.dwAttributes = mode;
+ yfsd_U32sToWinFileTime(modifiedTime,&fc.ftModified);
+ fc.nFileSize = objSize;
+
+ pVolume->shellFunction(&fc);
+ RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
+
+ yfsd_ShellDirectoryChanged(pVolume,fpn);
+ }
+
+ if(handle != INVALID_HANDLE_VALUE && (fileCreated || writePermitted))
+ {
+ // Remember the name
+
+ WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
+ int slen;
+
+ yfsd_FullPathName(pVolume,fpn,YFSD_FULL_PATH_NAME_SIZE,pwsFileName);
+ slen = wcslen(fpn);
+ f->fullName = malloc((slen+1)* sizeof(WCHAR));
+ if(f->fullName)
+ {
+ wcscpy(f->fullName,fpn);
+ }
+
+ }
+
+
+ return handle;
+
+}
+
+BOOL yfsd_DoReadFile(
+ PFILE pFile,
+ PVOID pBuffer,
+ DWORD cbRead,
+ PDWORD pcbRead)
+{
+
+ DWORD maxRead;
+ int nread = 0;
+ yaffs_Object *obj = NULL;
+
+
+ if(pcbRead)
+ {
+ *pcbRead = 0;
+ }
+ else
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::DoReadFile pcbRead was NULL. naughty.\r\n"));
+ }
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::DoReadFile %d bytes\r\n",cbRead));
+
+ if(!pFile || !pFile->obj)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ obj = pFile->obj;
+
+ if(yaffs_GetObjectFileLength(obj) > pFile->offset)
+ {
+ maxRead = yaffs_GetObjectFileLength(obj) - pFile->offset;
+ }
+ else
+ {
+ maxRead = 0;
+ }
+
+ if(cbRead > maxRead)
+ {
+ cbRead = maxRead;
+ }
+
+ if(maxRead > 0)
+ {
+ nread = yaffs_ReadDataFromFile(obj,pBuffer,pFile->offset,cbRead);
+ if(nread > 0)
+ {\r
+ pFile->offset += nread;\r
+
+ if(pcbRead)
+ {
+ *pcbRead = nread;
+ }
+ }
+ }
+ else
+ {
+ if(pcbRead) \r
+ {\r
+ *pcbRead = maxRead;\r
+ }
+ }
+
+
+ return nread < 0? FALSE : TRUE;
+
+}
+
+BOOL YFSD_ReadFile(
+ PFILE pFile,
+ PVOID pBuffer,
+ DWORD cbRead,
+ PDWORD pcbRead,
+ OVERLAPPED *pOverlapped ) //ignore
+{
+ BOOL result;
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::ReadFile\r\n"));
+
+ if(!pFile || !pFile->obj)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ yfsd_LockYAFFS();
+
+ result = yfsd_DoReadFile(pFile,pBuffer,cbRead,pcbRead);
+
+ yfsd_UnlockYAFFS();
+
+ return result;
+}
+
+BOOL YFSD_ReadFileWithSeek(
+ PFILE pFile,
+ PVOID pBuffer,
+ DWORD cbRead,
+ PDWORD pcbRead,
+ OVERLAPPED *pOverlapped,
+ DWORD dwLowOffset,
+ DWORD dwHighOffset )
+{
+ BOOL result;\r
+ DWORD rememberedOffset;
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::ReadFileWithSeek %d bytes at %d high %d pcbRead %X\r\n",cbRead,dwLowOffset,dwHighOffset,pcbRead));
+
+ // To determine if paging is supported, the kernel calls this with all parameters except pFile
+ // being zero.
+ if(!pBuffer && !cbRead && !pcbRead && !pOverlapped && !dwLowOffset && !dwHighOffset)
+ {
+ return TRUE; // paging suppported
+ //return FALSE; // paging not supported
+ }
+
+ if(!pFile || !pFile->obj)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ yfsd_LockYAFFS();\r
+\r
+ rememberedOffset = pFile->offset;
+
+ pFile->offset = dwLowOffset;
+ // ignore high offset for now
+
+ result = yfsd_DoReadFile(pFile,pBuffer,cbRead,pcbRead);
+\r
+ //pFile->offset = rememberedOffset;\r
+
+ yfsd_UnlockYAFFS();
+
+ return result;
+
+
+}
+
+
+BOOL yfsd_DoWriteFile(
+ PFILE pFile,
+ PCVOID pBuffer,
+ DWORD cbWrite,
+ PDWORD pcbWritten)
+{
+ int nwritten = 0;
+ yaffs_Object *obj = NULL;
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::DoWriteFile size %d\r\n",cbWrite));
+
+ if(!pFile || !pFile->obj)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ if(!pFile->writePermitted)
+ {
+ *pcbWritten = 0;
+ SetLastError(ERROR_ACCESS_DENIED);
+ return FALSE;
+ }
+
+ obj = pFile->obj;
+
+ *pcbWritten = 0;
+
+
+ nwritten = yaffs_WriteDataToFile(obj,pBuffer,pFile->offset,cbWrite);
+ if(nwritten >= 0)
+ {
+ pFile->offset += nwritten;
+ *pcbWritten = nwritten;
+ }
+ if(nwritten != cbWrite)
+ {
+ SetLastError(ERROR_DISK_FULL);
+ }
+
+
+ return nwritten != cbWrite? FALSE : TRUE;
+}
+
+
+BOOL YFSD_WriteFile(
+ PFILE pFile,
+ PCVOID pBuffer,
+ DWORD cbWrite,
+ PDWORD pcbWritten,
+ OVERLAPPED *pOverlapped )
+{
+ BOOL result;
+
+ yfsd_LockYAFFS();
+ RETAILMSG (MSGSTATE, (L"YAFFS::WriteFile\r\n"));
+
+ result = yfsd_DoWriteFile(pFile,pBuffer,cbWrite,pcbWritten);
+
+ yfsd_UnlockYAFFS();
+
+ return result;
+}
+
+BOOL YFSD_WriteFileWithSeek(
+ PFILE pFile,
+ PCVOID pBuffer,
+ DWORD cbWrite,
+ PDWORD pcbWritten,
+ OVERLAPPED *pOverlapped,
+ DWORD dwLowOffset,
+ DWORD dwHighOffset )
+{
+ BOOL result;
+ 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)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ yfsd_LockYAFFS();
+\r
+ rememberedOffset = pFile->offset;\r
+
+ pFile->offset = dwLowOffset;
+ // ignore high offset for now
+
+ result = yfsd_DoWriteFile(pFile,pBuffer,cbWrite,pcbWritten);
+\r
+ //pFile->offset = rememberedOffset;\r
+
+ yfsd_UnlockYAFFS();
+
+ return result;
+}
+
+DWORD YFSD_SetFilePointer(
+ PFILE pFile,
+ LONG lDistanceToMove,
+ PLONG pDistanceToMoveHigh,
+ DWORD dwMoveMethod )
+{
+ // ignore high offset for now
+
+ DWORD offset = 0xFFFFFFFF;
+ DWORD oldPos;
+ int fileSize;
+ int seekNegative = 0;
+
+
+ if(!pFile || !pFile->obj)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return offset;
+ }
+
+ yfsd_LockYAFFS();\r
+\r
+
+ oldPos = pFile->offset;
+
+ if(dwMoveMethod == FILE_BEGIN)
+ {
+ if(lDistanceToMove >= 0)
+ {
+ offset = pFile->offset = lDistanceToMove;
+ }
+ else
+ {
+ seekNegative = 1;
+ }
+ }
+ else if(dwMoveMethod == FILE_END)
+ {
+ fileSize = yaffs_GetObjectFileLength(pFile->obj);
+ if(fileSize >= 0 &&
+ (fileSize + lDistanceToMove) >= 0)
+ {
+ offset = pFile->offset = fileSize + lDistanceToMove;
+ }
+ else
+ {
+ seekNegative = 1;
+ }
+ }
+ else if(dwMoveMethod == FILE_CURRENT)
+ {
+ if(pFile->offset + lDistanceToMove >= 0)
+ {
+ offset = pFile->offset = pFile->offset + lDistanceToMove;
+ }
+ else
+ {
+ seekNegative = 1;
+ }
+ }
+
+ if(seekNegative)
+ {
+ SetLastError(ERROR_NEGATIVE_SEEK);
+
+ }
+
+ yfsd_UnlockYAFFS();
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::SetFilePtr method %d distance %d high %X oldpos %d newpos %d\r\n",
+ dwMoveMethod,lDistanceToMove,pDistanceToMoveHigh,oldPos,offset));
+
+ return offset;
+
+}
+
+DWORD YFSD_GetFileSize(
+ PFILE pFile,
+ PDWORD pFileSizeHigh )
+{
+ int fileSize;
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::GetFileSize high %X\r\n",pFileSizeHigh));
+
+
+ if(!pFile || !pFile->obj)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return -1;
+ }
+
+ yfsd_LockYAFFS();
+
+ fileSize = yaffs_GetObjectFileLength(pFile->obj);
+
+ yfsd_UnlockYAFFS();\r
+ if(pFileSizeHigh)\r
+ *pFileSizeHigh = 0;
+
+ return fileSize;
+
+}
+
+
+BOOL YFSD_GetFileInformationByHandle(
+ PFILE pFile,
+ PBY_HANDLE_FILE_INFORMATION pFileInfo )
+{
+ RETAILMSG (MSGSTATE, (L"YAFFS::GetFileInfoByHandle\r\n"));
+
+ if(!pFile || !pFile->obj || !pFileInfo)
+ {
+ 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_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
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::FlushFileBuffers\r\n"));
+
+ if(!pFile || !pFile->obj)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ yfsd_LockYAFFS();\r
+
+ 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
+
+ return TRUE;
+}
+
+BOOL YFSD_GetFileTime(
+ PFILE pFile,
+ FILETIME *pCreation,
+ FILETIME *pLastAccess,
+ FILETIME *pLastWrite )
+{
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::GetFileTime\r\n"));
+ if(!pFile || !pFile->obj)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ yfsd_LockYAFFS();
+
+ if(pCreation) yfsd_U32sToWinFileTime(pFile->obj->win_ctime,pCreation);
+ if(pLastAccess) yfsd_U32sToWinFileTime(pFile->obj->win_atime,pLastAccess);
+ if(pLastWrite) yfsd_U32sToWinFileTime(pFile->obj->win_mtime,pLastWrite);
+
+ yfsd_UnlockYAFFS();
+
+ return TRUE;
+}
+
+BOOL YFSD_SetFileTime(
+ PFILE pFile,
+ CONST FILETIME *pCreation,
+ CONST FILETIME *pLastAccess,
+ CONST FILETIME *pLastWrite )
+{
+ WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];\r
+ int nameExists = 0;\r
+ int result = FALSE;
+ yfsd_Volume *vol = NULL;\r
+ DWORD attribs = 0;\r
+ DWORD objSize = 0;\r
+ DWORD mtime[2];\r
+\r
+ \r
+ RETAILMSG (MSGSTATE, (L"YAFFS::SetFileTime\r\n"));
+
+ if(!pFile || !pFile->obj)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+
+ yfsd_LockYAFFS();
+
+ if(pCreation) \r
+ {\r
+ yfsd_WinFileTimeToU32s(pCreation,pFile->obj->win_ctime);\r
+ pFile->obj->dirty = 1;\r
+ }
+ if(pLastAccess)\r
+ {\r
+ yfsd_WinFileTimeToU32s(pLastAccess,pFile->obj->win_atime);\r
+ pFile->obj->dirty = 1;\r
+ }
+ if(pLastWrite)\r
+ {\r
+ yfsd_WinFileTimeToU32s(pLastWrite,pFile->obj->win_mtime);\r
+ pFile->obj->dirty = 1;
+ }
+ if(pCreation || pLastAccess || pLastWrite)
+ {
+ result = yaffs_FlushFile(pFile->obj);
+ }
+\r
+ if(result)\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
+ 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
+
+ return TRUE;
+}
+
+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
+ static unsigned char zeros[512];
+
+ int result;
+ BOOL retVal = FALSE;
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::SetEOF\r\n"));
+
+ if(!pFile || !pFile->obj)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ yfsd_LockYAFFS();
+ result = yaffs_ResizeFile(pFile->obj,pFile->offset);
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::SetEOF resizing to %d, result %d\r\n",pFile->offset,result));
+
+ // Resize only works if we're shortening the file.
+ // If the result is shorter than the offset, then we need to write zeros....
+ //
+ if(result != pFile->offset)
+ {
+ if(result < pFile->offset)
+ {
+
+ int nBytes = pFile->offset - result;
+ int thisWriteSize;
+ int written;
+ BOOL ok = TRUE;
+
+ memset(zeros,0,512);
+
+ pFile->offset = result;
+ RETAILMSG (MSGSTATE, (L"YAFFS::SetEOF expanding file by %d bytes\r\n",nBytes));
+ while(nBytes > 0 && ok)
+ {
+ thisWriteSize = (nBytes > 512) ? 512 : nBytes;
+
+ ok = yfsd_DoWriteFile(pFile,zeros,thisWriteSize,&written);
+ if(written != thisWriteSize)
+ {
+ ok = FALSE;
+ }
+
+ nBytes -= thisWriteSize;
+ }
+
+ retVal = ok;
+ }
+ else
+ {
+
+ SetLastError(ERROR_ACCESS_DENIED);
+ retVal = FALSE;
+ }
+ }
+ else
+ {
+ 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
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::SetEOF file size %d\r\n",yaffs_GetObjectFileLength(pFile->obj)));
+
+
+
+ return retVal;
+}
+
+BOOL YFSD_DeviceIoControl(
+ PFILE pFile,
+ DWORD dwIoControlCode,
+ PVOID pInBuf,
+ DWORD nInBufSize,
+ PVOID pOutBuf,
+ DWORD nOutBufSize,
+ PDWORD pBytesReturned,
+ OVERLAPPED *pOverlapped )
+{
+ RETAILMSG (MSGSTATE, (L"YAFFS::DeviceIoControl\r\n"));
+
+ return FALSE;
+}
+
+BOOL YFSD_CloseFile( PFILE pFile )
+{
+ WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
+ int nameExists = 0;
+ yfsd_Volume *vol = NULL;
+ DWORD attribs = 0;
+ DWORD objSize = 0;
+ DWORD mtime[2];\r
+
+ RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile %X\r\n",pFile));
+
+ yfsd_LockYAFFS();
+
+ if(!pFile)
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile null pFile\r\n"));
+ }
+ else
+ {
+ if(pFile->obj)
+ {
+ pFile->obj->inUse--;
+ RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile on obj\r\n"));
+ yaffs_FlushFile(pFile->obj);
+ 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
+ RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile on obj done, size is %d\r\n",objSize));
+ if(pFile->fullName)
+ {
+ wcscpy(fpn,pFile->fullName);
+ nameExists = 1;
+ }
+ vol = pFile->myVolume;
+ yfsd_PutWinFile(pFile);
+ }
+ else
+ {
+ RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile null obj\r\n"));
+ }
+
+ }
+ yfsd_UnlockYAFFS();
+
+
+ if(nameExists && 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::CloseFile done\r\n"));
+
+ return TRUE;
+
+}
+
+
+BOOL YFSD_CloseVolume(PVOLUME pVolume )
+{
+ RETAILMSG (MSGSTATE, (L"YAFFS::CloseVolume\r\n"));
+ yfsd_FlushAllFiles();
+ return TRUE;
+}
+