*** empty log message ***
[yaffs/.git] / wince / yaffsfsd.c
1 /*\r
2  * YAFFS: Yet another FFS. A NAND-flash specific file system.\r
3  * yaffsfsd.c: The FSD layer for the WinCE version of YAFFS.\r
4  *\r
5  * Copyright (C) 2002 Trimble Navigation Ltd.\r
6  *\r
7  * Created by Charles Manning <charles.manning@trimble.co.nz>\r
8  *\r
9  * This program is free software; you can redistribute it and/or modify\r
10  * it under the terms of the GNU General Public License version 2 as\r
11  * published by the Free Software Foundation.\r
12  *\r
13  * This program is distributed in the hope that it will be useful, \r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of \r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU \r
16  * General Public License for more details. You should have received a \r
17  * copy of the GNU General Public License along with this program; \r
18  * if not, write to the Free Software Foundation, Inc., \r
19  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. \r
20  *\r
21  * $Id: yaffsfsd.c,v 1.1 2002-11-08 07:30:00 charles Exp $\r
22  */
23 #include <windows.h>
24 #include <extfile.h>
25 #include <yaffs_guts.h>
26 #include <ynandif.h>
27
28 #define MAX_WIN_FILE    200
29 #define YFSD_NAME_LENGTH 128
30 #define YFSD_FULL_PATH_NAME_SIZE 500
31
32
33 #define YFSD_DISK_NAME L"Disk"
34 #define YFSD_BOOT_NAME L"Boot"
35
36 #define PARTITION_START_NUMBER (1280)           
37
38 #define MSGSTATE 1
39 //#define DISABLE_BOOT_PARTITION\r
40 \r
41 unsigned yaffs_traceMask=0xffffffff;
42
43
44 typedef struct
45 {
46         yaffs_Device dev;
47         DWORD   hdsk;
48         DWORD    mgrVolume; // The volume id from the manager issed when we registered it - it is an HVOL
49         BOOL    isMounted;
50         BOOL    configured;
51 //      DWORD   guard0[100];
52 //      DWORD   guard1[100];
53         SHELLFILECHANGEFUNC_t shellFunction;
54         PWSTR volName;
55 } yfsd_Volume;
56
57 typedef struct 
58 {
59         yaffs_Object *obj;
60         DWORD offset;
61         BOOL isopen;
62         BOOL writePermitted;
63         BOOL dirty;
64         WCHAR *fullName;
65         yfsd_Volume *myVolume;
66
67 }       yfsd_WinFile;
68
69 struct yfsd_FoundObjectStruct
70 {
71   yaffs_Object *obj;
72   struct yfsd_FoundObjectStruct *next;
73 };
74
75 typedef struct yfsd_FoundObjectStruct yaffs_FoundObject;
76
77 typedef struct 
78 {
79         yaffs_Object *dir;
80         char pattern[YFSD_NAME_LENGTH+1];
81         yaffs_FoundObject *foundObjects;
82 }       yfsd_WinFind;
83
84
85
86 #define PSEARCH yfsd_WinFind*
87
88 #define PVOLUME yfsd_Volume*
89 #define PFILE   yfsd_WinFile*
90
91 #define FSD_API YFSD
92
93 #include <fsdmgr.h>
94
95
96 static yfsd_Volume disk_volume;
97 static yfsd_Volume boot_volume;
98
99 static CRITICAL_SECTION yaffsLock;
100 static CRITICAL_SECTION winFileLock;
101
102 static int yaffsLockInited = 0;
103
104 static yfsd_WinFile yfsd_winFile[MAX_WIN_FILE];
105
106 #if 0
107 static yfsd_SetGuards(void)
108 {
109         int i;
110         for(i = 0; i < 100; i++)
111         {
112                 yfsd_volume.guard0[i] = yfsd_volume.guard1[i] = i;
113         }
114 }
115
116 static void yfsd_CheckGuards(void)
117 {
118         int i;
119         int found;
120         for(i = found = 0; i < 100 && !found; i++)
121         {
122                         if(yfsd_volume.guard0[i] != i)
123                         {
124                                         RETAILMSG (MSGSTATE, (L"YAFFS:: guard 0 %d brocken\r\n",i));
125                                         found = 1;
126                         }
127                         if(yfsd_volume.guard1[i] != i)
128                         {
129                                         RETAILMSG (MSGSTATE, (L"YAFFS:: guard 0 %d brocken\r\n",i));
130                                         found = 1;
131                         }
132         }
133 }
134 #endif
135
136 void yfsd_LockWinFiles(void)
137 {
138         //RETAILMSG (MSGSTATE, (L"YAFFS::LockWinfiles\r\n"));
139         EnterCriticalSection(&winFileLock);
140 }
141 void yfsd_UnlockWinFiles(void)
142 {
143         //RETAILMSG (MSGSTATE, (L"YAFFS::UnlockWinFiles\r\n"));
144         LeaveCriticalSection(&winFileLock);
145 }
146
147 int lockwaits;
148
149 void yfsd_LockYAFFS(void)
150 {
151         //yfsd_CheckGuards();
152         //RETAILMSG (MSGSTATE, (L"YAFFS::LockYAFFS %d ",lockwaits));
153         lockwaits++;
154         EnterCriticalSection(&yaffsLock);
155         //RETAILMSG (MSGSTATE, (L" locked\r\n"));
156 }
157 void yfsd_UnlockYAFFS(void)
158 {
159         //yfsd_CheckGuards();
160         //RETAILMSG (MSGSTATE, (L"YAFFS::UnLockYAFFS "));
161         LeaveCriticalSection(&yaffsLock);
162         lockwaits--;
163         //RETAILMSG (MSGSTATE, (L" unlocked\r\n"));
164 }
165
166
167 void yfsd_InitialiseWinFiles(void)
168 {
169         int i;
170         
171         RETAILMSG (MSGSTATE, (L"YAFFS::InitWinFiles\r\n"));
172
173         InitializeCriticalSection(&winFileLock);
174
175         yfsd_LockWinFiles();
176         for(i = 0; i < MAX_WIN_FILE; i++)
177         {
178                         yfsd_winFile[i].isopen = 0;
179         }
180         yfsd_UnlockWinFiles();
181 }
182
183 yfsd_WinFile * yfsd_GetWinFile(void)
184 {
185         int i;
186         RETAILMSG (MSGSTATE, (L"YAFFS::GetWinFiles\r\n"));
187
188         yfsd_LockWinFiles();
189
190         for(i = 0; i < MAX_WIN_FILE; i++)
191         {
192                 if(!yfsd_winFile[i].isopen)
193                 {
194                         yfsd_winFile[i].isopen = 1;
195                         yfsd_winFile[i].writePermitted = 0;
196                         yfsd_winFile[i].dirty = 0;
197                         yfsd_winFile[i].fullName = NULL;
198                         yfsd_winFile[i].obj = NULL;
199
200                         yfsd_UnlockWinFiles();
201                         return &yfsd_winFile[i];
202                 }
203         }
204
205         yfsd_UnlockWinFiles();
206
207         RETAILMSG (MSGSTATE, (L"YAFFS::GetWinFiles did not find a handle. Too many open.\r\n"));
208
209         return NULL;
210 }
211
212 void yfsd_PutWinFile(yfsd_WinFile *f)
213 {
214         RETAILMSG (MSGSTATE, (L"YAFFS::PutWinFile\r\n"));
215         yfsd_LockWinFiles();
216         f->isopen = 0;
217         f->obj = NULL;
218         if(f->fullName)
219         {
220                 free(f->fullName);
221                 f->fullName = NULL;
222         }
223
224         yfsd_UnlockWinFiles();
225 }
226
227
228
229 void yfsd_FlushAllFiles(void)
230 {
231         int i;
232         RETAILMSG (MSGSTATE, (L"YAFFS::FlushAllFiles\r\n"));
233
234         yfsd_LockYAFFS();
235         yfsd_LockWinFiles();
236         for(i = 0; i < MAX_WIN_FILE; i++)
237         {
238                 if(yfsd_winFile[i].isopen &&
239                    yfsd_winFile[i].obj)
240                 {
241                         yaffs_FlushFile(yfsd_winFile[i].obj);
242                 }
243         }
244         yfsd_UnlockWinFiles();
245         yfsd_UnlockYAFFS();
246 }
247
248 PWSTR yfsd_FullPathName(PVOLUME vol, PWSTR fpn,int slength,PCWSTR pathName)
249 {
250
251         // todo check for bounds
252         wcscpy(fpn,L"\\");
253         wcscat(fpn,vol->volName);
254         if(pathName[0] != '\\')
255         {
256                 wcscat(fpn,L"\\");
257         }
258         wcscat(fpn,pathName);
259
260         return fpn;
261
262 }
263
264
265 // FILETIME is a 64-bit value as 100-nanosecond intervals since January 1, 1601.
266 \r
267 void yfsd_U32sToWinFileTime(__u32 target[2], FILETIME *wft)
268 {
269         
270         wft->dwLowDateTime = target[0];
271         wft->dwHighDateTime = target[1];
272
273 }
274
275 void yfsd_NullWinFileTime(FILETIME *wft)
276 {
277         wft->dwLowDateTime = 0;
278         wft->dwHighDateTime = 0;
279 }
280
281 void yfsd_WinFileTimeToU32s(const FILETIME *wft, __u32 target[2])
282 {
283         target[0] = wft->dwLowDateTime;
284         target[1] = wft->dwHighDateTime;
285 }
286
287 void  yfsd_WinFileTimeNow(__u32 target[2])
288 {
289         SYSTEMTIME st;
290         FILETIME ft;
291
292         GetSystemTime(&st);
293         SystemTimeToFileTime(&st,&ft);
294         yfsd_WinFileTimeToU32s(&ft,target);
295 }
296
297 // Cut down the name to the parent directory, then inform the shell of
298 // a change to the directory.
299 void yfsd_ShellDirectoryChanged(PVOLUME pVolume, PWSTR fullPathName)
300 {
301         WCHAR str[500];
302         int i;
303         wcscpy(str,fullPathName);
304
305         i = wcslen(str) - 1;
306         
307         if(i > 0)
308         {
309                 str[i] = 0;
310                 i--;
311         }
312
313         // Curveball if the name is a directory (ie. we're doing an update of
314         // a directory because we added a directory item). , then it might end in a \
315         // which we must toss first
316         if(i >= 0 && (str[i] == '\\' || str[i] == '/'))
317         {
318                 str[i] = 0;
319                 i--;
320         }
321
322         // Ok, now strip back...
323
324         while(i >= 0 && str[i] != '\\' && str[i] != '/')
325         {
326                 str[i] = 0;
327                 i--;
328         }
329
330         if(pVolume->shellFunction)
331         {
332                         FILECHANGEINFO fc;
333                         
334                         fc.cbSize = sizeof(FILECHANGEINFO);
335                         fc.wEventId = SHCNE_UPDATEDIR;
336                         fc.uFlags = SHCNF_PATH;
337                         fc.dwItem1 = (DWORD)str;
338                         fc.dwItem2 = 0;
339                         fc.dwAttributes = 0;
340                         yfsd_NullWinFileTime(&fc.ftModified);
341                         fc.nFileSize = 0;
342
343                         pVolume->shellFunction(&fc);
344                         RETAILMSG (MSGSTATE, (L"YAFFS:: directory changed %s\r\n",str));
345
346         }
347
348
349 }
350 \r
351 \r
352 // Minimal name test for now\r
353 BOOL yfsd_NameIsValid (const char *name)\r
354 {\r
355         int length = strlen(name);\r
356 \r
357         return (length > 0 && length <= YFSD_NAME_LENGTH);\r
358 \r
359 }
360
361 // File attributes:
362 // Wince understands the following attributes of any use to YAFFS:
363 //  
364 //   ARCHIVE
365 //   HIDDEN
366 //   READONLY
367 //   SYSTEM
368 //   TEMPORARY
369 //
370 //       Also, FILE_ATTRIBUTE_DIRECTORY is used to mark directories.
371 //
372 //   It also understands NORMAL. If no other flag is set, then set NORMAL.
373 //   If any of the above are set, then NORMAL must **not** be set.
374 //       Ignore this and the WinCE Explorer barfs the file.
375 //
376 //
377 // in addition, GetAttributes also returns FILE_ATTRIBUTE_DIRECTORY
378 \r
379 // The following are valid ones we get presented with,\r
380 // but must filter out the stuff we don't unserstand\r
381 //#define FILE_ATTRIBUTE_READONLY             0x00000001  \r
382 //#define FILE_ATTRIBUTE_HIDDEN               0x00000002  \r
383 //#define FILE_ATTRIBUTE_SYSTEM               0x00000004  \r
384 //#define FILE_ATTRIBUTE_DIRECTORY            0x00000010  \r
385 //#define FILE_ATTRIBUTE_ARCHIVE              0x00000020  \r
386 //#define FILE_ATTRIBUTE_INROM                            0x00000040\r
387 //#define FILE_ATTRIBUTE_ENCRYPTED            0x00000040  \r
388 //#define FILE_ATTRIBUTE_NORMAL               0x00000080  \r
389 //#define FILE_ATTRIBUTE_TEMPORARY            0x00000100  \r
390 //#define FILE_ATTRIBUTE_SPARSE_FILE          0x00000200  \r
391 //#define FILE_ATTRIBUTE_REPARSE_POINT        0x00000400  \r
392 //#define FILE_ATTRIBUTE_COMPRESSED           0x00000800  \r
393 //#define FILE_ATTRIBUTE_OFFLINE              0x00001000  \r
394 //#define FILE_ATTRIBUTE_ROMSTATICREF             0x00001000\r
395 //#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED  0x00002000  \r
396 //#define FILE_ATTRIBUTE_ROMMODULE                        0x00002000\r
397 \r
398 \r
399 BOOL yfsd_CheckValidAttributes(DWORD attribs)\r
400 {\r
401 \r
402         RETAILMSG (MSGSTATE, (L"Attributes:%X\r\n", attribs));\r
403 \r
404 #if 0\r
405                 // If NORMAL, then nothing else\r
406                 if(attribs & FILE_ATTRIBUTE_NORMAL && attribs != FILE_ATTRIBUTE_NORMAL)\r
407                         return FALSE;\r
408                 if(attribs == FILE_ATTRIBUTE_NORMAL) \r
409                         return TRUE;\r
410 #endif\r
411                 // Check that the bits are in the valid set\r
412                 if(attribs & ~(0x3FE7))\r
413                         return FALSE;\r
414 \r
415                 return TRUE;\r
416 \r
417 }
418 DWORD yfsd_GetObjectWinAttributes(yaffs_Object *obj)
419 {
420
421                 DWORD result;
422                 
423                 result = obj->st_mode & \r
424                                         (FILE_ATTRIBUTE_READONLY | \r
425                                          FILE_ATTRIBUTE_ARCHIVE | \r
426                                          FILE_ATTRIBUTE_HIDDEN |\r
427                                          FILE_ATTRIBUTE_SYSTEM);
428 \r
429                 if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) result |= FILE_ATTRIBUTE_DIRECTORY;\r
430
431                 if(result & ~FILE_ATTRIBUTE_NORMAL)
432                 { 
433                         result &= ~FILE_ATTRIBUTE_NORMAL;
434                 }
435                 else 
436                 {
437                         result = FILE_ATTRIBUTE_NORMAL;
438                 }
439 \r
440
441                 return result;
442 }
443
444
445
446 /*
447 *       Runs over input until a '\' is found, or '\0' is found, or outSize - 1 is
448 *       reached.  Characters are copied from input into output until the above stop
449 *       condition is reached - output is then given a '\0'.  output must be at least
450 *       as large as outSize
451 */
452 static int parseToNextSlash(const unsigned short *input, char *output, int outSize)
453 {
454         int counter = 0;
455         char *t = output;
456         /* strip any starting \'s */
457         //RETAILMSG(1, (L"\r\nParsing.. "));
458         while (*input == '\\' || *input == '/') input++, counter++;
459
460         for (; counter < outSize - 1; counter++)
461         {
462                 if (*input == '\0' ||
463                         ((*input == '\\' || *input == '/') && input[1] == '\0'))   // special case: if the string ends in a '\', then toss the '\'
464                 {
465                         counter = -1;   // break & tell people we've run to the end
466                         break;
467                 }
468                 if (*input == '\\' || *input == '/')
469                         break;
470                 //RETAILMSG(1, (L"%c", *input));
471                 *output = (char) (*input);
472                 input++;
473                 output++;
474         }
475         *output++ = '\0';
476         *output  = '\0';
477 //      RETAILMSG(1, (L"\r\nOut %a\r\n", t));
478         
479         return counter;
480 }
481
482 /*
483 *       Since the notion of paths as WinCE sees them and as YAFFS sees them
484 *       is different, we needed a helper function to search from the root of
485 *       device along the string in path.  The processed pointer is set to where
486 *       abouts in the string the function was able to search up to.
487 */
488 yaffs_Object *yfsd_FindDirectoryByWinPath(yaffs_Device *device, const wchar_t *path, char *processed, int length)
489 {
490         // a buffer to keep the current chunk of path we're talking about it
491         char pathChunk[255];
492         int chunkSize;
493         int counter;
494         // the current object we are at
495         yaffs_Object *current;
496
497         RETAILMSG (MSGSTATE, (L"YAFFS::FindByWinPath (%s) : ", path));
498         // start at the root of this device
499         current = yaffs_Root(device);\r
500         *processed = '\0';
501
502         do
503         {
504         //      parse chunks until we run out
505                 chunkSize = parseToNextSlash(path, pathChunk, 255);
506 //              RETAILMSG(1, (L"Chunk %a\r\n", pathChunk));
507                 if (chunkSize == -1)
508                         break;
509         //      move the path pointer along
510                 path += chunkSize;
511         //      try and find the next yaffs object by chunkname 
512                 current = yaffs_FindObjectByName(current, pathChunk);
513                 if (current == 0)
514                 {
515                         processed[0] = '\0';
516                         return 0;
517                 }
518         } while (1);
519
520         for (counter = 0; counter < length; counter++)
521         {
522                 // Get the rest of the string
523                 processed[counter] = pathChunk[counter];
524                 if (pathChunk[counter] == '\0')
525                         break;
526         }
527
528         RETAILMSG (MSGSTATE, (L"YAFFS::FindDirectoryByWinPath parent:%X name:%a\r\n", current,processed));
529
530         return current;
531 }
532
533
534 yaffs_Object *yfsd_FindObjectByWinPath(yaffs_Device *dev, PCWSTR pwsFileName )
535 {
536         yaffs_Object *obj = NULL;
537         yaffs_Object *parent = NULL;
538         char name[YFSD_NAME_LENGTH+1];
539
540         RETAILMSG (MSGSTATE, (L"YAFFS::FindObjByWinPath\r\n"));
541
542         parent = yfsd_FindDirectoryByWinPath(dev,pwsFileName,name,YFSD_NAME_LENGTH);
543
544         if(parent && yfsd_NameIsValid(name))
545         {
546                 obj = yaffs_FindObjectByName(parent,name);
547         }
548
549         RETAILMSG (MSGSTATE, (L"YAFFS::FindObjectByWinPath parent:%X obj:%X\r\n", parent,obj));
550
551         return obj;
552 }
553
554 BOOL YFSD_InitVolume(HDSK hdsk, yfsd_Volume *vol, int startBlock, int endBlock, PWSTR volName)
555 {
556         RETAILMSG (MSGSTATE, (L"YAFFS::InitVolume\r\n"));
557         vol->volName = volName;
558
559
560         yfsd_LockYAFFS();
561         
562         //Mount/initialise YAFFs here
563         ynandif_InitialiseNAND(&vol->dev);
564         
565         vol->dev.writeChunkToNAND = ynandif_WriteChunkToNAND;
566         vol->dev.readChunkFromNAND = ynandif_ReadChunkFromNAND;
567         vol->dev.eraseBlockInNAND = ynandif_EraseBlockInNAND;
568         vol->dev.initialiseNAND = ynandif_InitialiseNAND;
569         vol->dev.startBlock = startBlock;
570         if (endBlock != -1)
571                 vol->dev.endBlock = endBlock;
572
573         // nBlocks is set the total size of the disk, not the partition
574 //      vol->dev.nBlocks = endBlock - startBlock + 1;
575
576 //      qnand_EraseAllBlocks(&vol->dev);
577
578         yaffs_GutsInitialise(&vol->dev);
579         RETAILMSG(1, (L"YAFFS::Done yaffs_GutsInitialise\r\n"));
580
581         RETAILMSG(1, (L"Blocks start %d end %d Group size %d bits %d\r\n",
582                             vol->dev.startBlock,vol->dev.endBlock,
583                                         vol->dev.chunkGroupSize,vol->dev.chunkGroupBits));
584
585
586 #if 0
587         for(i = vol->dev.startBlock; i <= vol->dev.endBlock; i++)
588         {
589                         switch(vol->dev.blockInfo[i].blockState)
590                         {
591                                 case YAFFS_BLOCK_STATE_DEAD:
592                 
593                                         RETAILMSG(1, (L"YAFFS::Dead block %d\r\n",i));
594                                         deadBlox++;
595                                         break;
596                                 case YAFFS_BLOCK_STATE_EMPTY: emptyBlox++; break;
597                                 case YAFFS_BLOCK_STATE_FULL: fullBlox++; break;
598                                 case YAFFS_BLOCK_STATE_ALLOCATING: allocatingBlox++; break;
599                                 case YAFFS_BLOCK_STATE_DIRTY: dirtyBlox++; break;
600                                 default:
601                                         RETAILMSG(1, (L"YAFFS::Block %d has goofus state %d\r\n",i,vol->dev.blockInfo[i].blockState));
602                                         break;
603                         }
604         }
605
606         RETAILMSG(1, (L"Blocks dead  %d empty %d full %d allocating %d dirty %d\r\n",
607                             deadBlox,emptyBlox,fullBlox,allocatingBlox,dirtyBlox));
608
609 #endif
610
611         yfsd_UnlockYAFFS();
612
613         vol->isMounted = 1;
614         
615         vol->mgrVolume = FSDMGR_RegisterVolume(hdsk,vol->volName,vol);
616
617         if(vol->mgrVolume)
618         {
619                 return TRUE;
620         }
621         else
622         {
623                 vol->isMounted = 0;
624                 SetLastError(ERROR_OUTOFMEMORY);
625                 return FALSE;
626         }       
627 }
628
629
630 BOOL YFSD_MountDisk(HDSK hdsk)
631 {
632         int deadBlox=0,emptyBlox=0,fullBlox=0,allocatingBlox=0,dirtyBlox=0;
633         //int i;
634         // Called to mount a disk.
635         // NB THis call might happen redundantly.
636         //
637         //
638         // If yaffs is not initialised, then call the 
639         // initialisation function
640         //
641         RETAILMSG (MSGSTATE, (L"YAFFS::MountDisk\r\n"));
642
643         if (!yaffsLockInited)
644         {
645                 InitializeCriticalSection(&yaffsLock);
646                 yfsd_InitialiseWinFiles();
647                 yaffsLockInited = 1;
648         }
649
650 #ifdef DISABLE_BOOT_PARTITION
651         // Only want disk volume
652         YFSD_InitVolume(hdsk, &disk_volume, 1, -1, YFSD_DISK_NAME);
653
654         
655         if(disk_volume.isMounted)
656         {
657                 return TRUE;
658         }
659 #else
660         // Want both boot and disk
661         YFSD_InitVolume(hdsk, &disk_volume, PARTITION_START_NUMBER+1, -1, YFSD_DISK_NAME);
662         YFSD_InitVolume(hdsk, &boot_volume, 1, PARTITION_START_NUMBER, YFSD_BOOT_NAME);
663
664         
665         if(disk_volume.isMounted && boot_volume.isMounted)
666         {
667                 return TRUE;
668         }
669 #endif
670
671         return FALSE;
672
673 //      yfsd_SetGuards();
674
675         // todo - get name from registry
676
677 }
678
679
680 BOOL YFSD_UnmountDisk(HDSK hdsk)
681 {
682         RETAILMSG (MSGSTATE, (L"YAFFS::UnmountDisk\r\n"));
683         
684         yfsd_FlushAllFiles();
685
686         yfsd_LockYAFFS();
687         yaffs_Deinitialise(&disk_volume.dev);
688         yaffs_Deinitialise(&boot_volume.dev);
689         yfsd_UnlockYAFFS();
690
691         FSDMGR_DeregisterVolume(disk_volume.mgrVolume);
692         FSDMGR_DeregisterVolume(boot_volume.mgrVolume);
693         return TRUE;
694 }
695
696
697 BOOL YFSD_CreateDirectoryW(PVOLUME pVolume, PCWSTR pathName, PSECURITY_ATTRIBUTES pSecurityAttributes)
698 {
699         // security attributes are ignored (should be NULL)
700
701         yaffs_Object *newDir = NULL;
702         yaffs_Object *parent = NULL;
703         char name[YFSD_NAME_LENGTH+1];
704         ULONG objSize;
705         DWORD attribs;
706         unsigned modifiedTime[2];
707
708         RETAILMSG (MSGSTATE, (L"YAFFS::CreateDirectory (%s)\r\n", pathName));
709
710         yfsd_LockYAFFS();
711
712         parent = yfsd_FindDirectoryByWinPath(&pVolume->dev,pathName,name,YFSD_NAME_LENGTH);
713
714         if(parent && yfsd_NameIsValid(name))
715         {
716                 newDir = yaffs_MknodDirectory(parent,name,0,0,0);
717         }
718         
719         if(newDir)
720         {
721                 objSize = yaffs_GetObjectFileLength(newDir);
722                 attribs = yfsd_GetObjectWinAttributes(newDir);
723                 modifiedTime[0] = newDir->win_mtime[0];\r
724                 modifiedTime[1] = newDir->win_mtime[1];\r
725         }
726         else
727         {
728                 SetLastError(ERROR_PATH_NOT_FOUND);
729         }
730
731         yfsd_UnlockYAFFS();
732
733         // Call shell function to tell of new directory
734         if(newDir && pVolume->shellFunction)
735         {
736                         FILECHANGEINFO fc;
737                         WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
738
739                         fc.cbSize = sizeof(FILECHANGEINFO);
740                         fc.wEventId = SHCNE_MKDIR;
741                         fc.uFlags = SHCNF_PATH;
742                         fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume, fpn,YFSD_FULL_PATH_NAME_SIZE,pathName);
743                         fc.dwItem2 = 0;
744                         fc.dwAttributes = attribs; 
745                         yfsd_U32sToWinFileTime(modifiedTime,&fc.ftModified);
746                         fc.nFileSize = objSize;
747
748                         pVolume->shellFunction(&fc);
749                         RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
750
751                         //yfsd_ShellDirectoryChanged(pVolume,fpn);
752
753         }
754
755         if(parent && !newDir)
756         {
757                         SetLastError(ERROR_DISK_FULL);
758         }
759
760         return newDir ? TRUE : FALSE;
761 }
762
763
764 BOOL yfsd_RemoveObjectW(PVOLUME pVolume, PCWSTR pathName)
765 {
766         // Fails if directory is not empty
767         int result = FALSE;
768         yaffs_Object *parent = NULL;
769         yaffs_Object *obj;
770         char name[YFSD_NAME_LENGTH+1];
771
772         RETAILMSG (MSGSTATE, (L"YAFFS::RemoveObjectW (%s)\r\n", pathName));
773
774         yfsd_LockYAFFS();
775
776         obj = yfsd_FindObjectByWinPath(&pVolume->dev,pathName);
777         if(!obj)
778         {
779                 SetLastError(ERROR_FILE_NOT_FOUND);
780                 result = FALSE;
781         }
782         else if(obj->st_mode & FILE_ATTRIBUTE_READONLY)
783         {
784                 SetLastError(ERROR_ACCESS_DENIED);
785                 result = FALSE;
786         }
787         else if(obj->inUse)
788         {
789                 SetLastError(ERROR_ACCESS_DENIED);
790                 result = FALSE;
791         }
792         else
793         {
794
795                 parent = yfsd_FindDirectoryByWinPath(&pVolume->dev,pathName,name,YFSD_NAME_LENGTH);
796
797                 if(parent && yfsd_NameIsValid(name))
798                 {
799                         result = yaffs_Unlink(parent,name);
800                         if(!result)
801                                 SetLastError(ERROR_ACCESS_DENIED);
802                 }
803         }
804
805         yfsd_UnlockYAFFS();
806
807         return result ? TRUE : FALSE;
808 }
809
810
811 BOOL YFSD_RemoveDirectoryW(PVOLUME pVolume, PCWSTR pathName)
812 {
813         BOOL result;
814         RETAILMSG (MSGSTATE, (L"YAFFS::RemoveDirectory\r\n"));
815         
816         result =  yfsd_RemoveObjectW(pVolume, pathName);
817
818         if(result && pVolume->shellFunction)
819         {
820                         FILECHANGEINFO fc;
821                         WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
822
823                         fc.cbSize = sizeof(FILECHANGEINFO);
824                         fc.wEventId = SHCNE_RMDIR;
825                         fc.uFlags = SHCNF_PATH;
826                         fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume,fpn,YFSD_FULL_PATH_NAME_SIZE,pathName);
827                         fc.dwItem2 = 0;
828                         fc.dwAttributes = 0;
829                         yfsd_NullWinFileTime(&fc.ftModified);
830                         fc.nFileSize = 0;
831
832                         pVolume->shellFunction(&fc);
833                         RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
834
835                         yfsd_ShellDirectoryChanged(pVolume,fpn);
836         }
837         
838         return result;
839
840 }
841
842
843 DWORD YFSD_GetFileAttributesW(PVOLUME pVolume, PCWSTR pwsFileName )
844 {
845         yaffs_Object *obj = NULL;
846
847         DWORD result = 0xFFFFFFFF;
848
849         RETAILMSG (MSGSTATE, (L"YAFFS::GetFileAttributes\r\n"));
850
851         yfsd_LockYAFFS();
852
853         obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
854
855         if(obj)
856         {
857                 result = yfsd_GetObjectWinAttributes(obj);
858         }
859         else
860         {
861                 SetLastError(ERROR_FILE_NOT_FOUND);
862         }
863
864         yfsd_UnlockYAFFS();
865         
866         RETAILMSG (MSGSTATE, (L"YAFFS::GetFileAttributes for %s returning %X\r\n",pwsFileName,result));
867         return result;
868
869         
870 }
871
872 BOOL YFSD_SetFileAttributesW( PVOLUME pVolume,PCWSTR pwsFileName, DWORD dwFileAttributes )
873 {
874         yaffs_Object *obj = NULL;\r
875         DWORD mtime[2];\r
876         DWORD attribs;\r
877         DWORD objSize;
878
879         int result = 0;
880
881         RETAILMSG (MSGSTATE, (L"YAFFS::SetFileAttributes %X\r\n",dwFileAttributes));\r
882 \r
883         if(!yfsd_CheckValidAttributes(dwFileAttributes))\r
884         {\r
885                         SetLastError(ERROR_INVALID_PARAMETER);\r
886                         return FALSE;\r
887         }
888
889         yfsd_LockYAFFS();
890
891         obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
892
893         if(obj)
894         {
895                 obj->st_mode = dwFileAttributes;
896                 obj->dirty = 1;
897                 result = yaffs_FlushFile(obj);\r
898                 attribs = yfsd_GetObjectWinAttributes(obj);\r
899                 objSize = yaffs_GetObjectFileLength(obj);\r
900                 mtime[0] = obj->win_mtime[0];\r
901                 mtime[1] = obj->win_mtime[1];\r
902         }
903         else
904         {
905                 SetLastError(ERROR_FILE_NOT_FOUND);
906         }
907
908         yfsd_UnlockYAFFS();
909
910         if(result && pVolume->shellFunction)
911         {
912                         FILECHANGEINFO fc;
913                         WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
914
915                         fc.cbSize = sizeof(FILECHANGEINFO);
916                         fc.wEventId = SHCNE_ATTRIBUTES;
917                         fc.uFlags = SHCNF_PATH;
918                         fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume,fpn,YFSD_FULL_PATH_NAME_SIZE,pwsFileName);
919                         fc.dwItem2 = 0;
920                         fc.dwAttributes =  attribs;
921                         yfsd_U32sToWinFileTime(mtime,&fc.ftModified);
922                         fc.nFileSize = objSize;
923
924                         pVolume->shellFunction(&fc);
925                         RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
926
927                         //yfsd_ShellDirectoryChanged(pVolume,fpn);
928         }
929         
930
931         return result;
932
933 }
934
935 BOOL YFSD_DeleteFileW( PVOLUME pVolume, PCWSTR pwsFileName )
936 {
937         BOOL result;
938         RETAILMSG (MSGSTATE, (L"YAFFS::DeleteFileW (%s)\r\n", pwsFileName));
939
940         result =  yfsd_RemoveObjectW(pVolume, pwsFileName);
941         if(result && pVolume->shellFunction)
942         {
943                         FILECHANGEINFO fc;
944                         WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
945
946                         fc.cbSize = sizeof(FILECHANGEINFO);
947                         fc.wEventId = SHCNE_DELETE;
948                         fc.uFlags = SHCNF_PATH;
949                         fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume,fpn,YFSD_FULL_PATH_NAME_SIZE,pwsFileName);
950                         fc.dwItem2 = 0;
951                         fc.dwAttributes = -1;
952                         yfsd_NullWinFileTime(&fc.ftModified);
953                         fc.nFileSize = 0;
954
955                         pVolume->shellFunction(&fc);
956                         RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
957
958                         yfsd_ShellDirectoryChanged(pVolume,fpn);
959         }
960
961         return result;
962 }
963
964 BOOL YFSD_MoveFileW(PVOLUME pVolume,PCWSTR pwsOldFileName, PCWSTR pwsNewFileName )
965 {
966         yaffs_Object *newParent = NULL;
967         yaffs_Object *oldParent = NULL;
968         yaffs_Object *obj = NULL;
969         char oldName[YFSD_NAME_LENGTH+1];
970         char newName[YFSD_NAME_LENGTH+1];
971         int result = 0;
972         int objIsDir = 0;
973         DWORD attribs;
974         DWORD objSize;\r
975         DWORD mtime[2];
976
977         RETAILMSG (MSGSTATE, (L"YAFFS::MoveFile\r\n"));
978
979         yfsd_LockYAFFS();
980
981         oldParent = yfsd_FindDirectoryByWinPath(&pVolume->dev,pwsOldFileName,oldName,YFSD_NAME_LENGTH);
982         newParent = yfsd_FindDirectoryByWinPath(&pVolume->dev,pwsNewFileName,newName,YFSD_NAME_LENGTH);
983
984         if(oldParent  && yfsd_NameIsValid(oldName) && newParent && yfsd_NameIsValid(newName))
985         {
986                 result = yaffs_RenameObject(oldParent,oldName,newParent,newName);
987                 if(!result)
988                 {
989                         SetLastError(ERROR_FILE_NOT_FOUND);
990                 }
991
992                 obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsNewFileName);
993                 if(obj)
994                 {
995                         objIsDir = (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY);
996                         attribs = yfsd_GetObjectWinAttributes(obj);
997                         objSize = yaffs_GetObjectFileLength(obj);\r
998                         mtime[0] = obj->win_mtime[0];\r
999                         mtime[1] = obj->win_mtime[1];\r
1000                 }
1001         }
1002         else
1003         {
1004                 SetLastError(ERROR_PATH_NOT_FOUND);
1005         }
1006
1007         yfsd_UnlockYAFFS();
1008
1009
1010         if(result && pVolume->shellFunction)
1011         {
1012                         FILECHANGEINFO fc;
1013                         WCHAR fpn1[YFSD_FULL_PATH_NAME_SIZE];
1014                         WCHAR fpn2[YFSD_FULL_PATH_NAME_SIZE];
1015
1016                         fc.cbSize = sizeof(FILECHANGEINFO);
1017                         fc.wEventId = objIsDir ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM;
1018                         fc.uFlags = SHCNF_PATH;
1019                         fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume,fpn1,YFSD_FULL_PATH_NAME_SIZE,pwsOldFileName);
1020                         fc.dwItem2 = (DWORD)yfsd_FullPathName(pVolume,fpn2,YFSD_FULL_PATH_NAME_SIZE,pwsNewFileName);
1021                         fc.dwAttributes = attribs;
1022                         yfsd_U32sToWinFileTime(mtime,&fc.ftModified);
1023                         fc.nFileSize = objSize;
1024
1025                         pVolume->shellFunction(&fc);
1026                         RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
1027
1028                         yfsd_ShellDirectoryChanged(pVolume,fpn1);
1029                         yfsd_ShellDirectoryChanged(pVolume,fpn2);
1030         }
1031
1032
1033         return result ? TRUE : FALSE;
1034
1035 }
1036
1037 BOOL YFSD_DeleteAndRenameFileW(PVOLUME pVolume, PCWSTR pwsOldFileName, PCWSTR pwsNewFileName )
1038 {
1039         RETAILMSG (MSGSTATE, (L"YAFFS::DeleteAndRename\r\n"));
1040         return FALSE;
1041 }
1042
1043 BOOL YFSD_GetDiskFreeSpaceW( PVOLUME pVolume, PCWSTR pwsPathName, PDWORD pSectorsPerCluster,PDWORD pBytesPerSector, PDWORD pFreeClusters, PDWORD pClusters )
1044 {
1045
1046         int nChunks;
1047
1048         RETAILMSG (MSGSTATE, (L"YAFFS::GetFreeSpace\r\n"));
1049
1050         yfsd_LockYAFFS();
1051         nChunks = yaffs_GetNumberOfFreeChunks(&pVolume->dev);
1052         yfsd_UnlockYAFFS();
1053
1054         if(nChunks >= 0)
1055         {
1056                 // Let's pretentd our clusters are the same size as eraseable blocks...
1057                 *pBytesPerSector = 512;
1058                 *pSectorsPerCluster  =32;
1059                 *pFreeClusters = nChunks/32;
1060                 *pClusters = pVolume->dev.endBlock - pVolume->dev.startBlock + 1;
1061         }
1062
1063         return (nChunks >= 0)? TRUE : FALSE;
1064
1065
1066
1067 }
1068
1069 void YFSD_Notify(PVOLUME pVolume, DWORD dwFlags )
1070 {
1071         // Flags can be one of:
1072         // FSNOTIFY_POWER_ON: no action required
1073         // FSNOTIFY_POWER_OFF: flush all files
1074         // FSNOTIFY_DEVICE_ON: no action required
1075
1076         RETAILMSG (MSGSTATE, (L"YAFFS::Notify\r\n"));
1077         if(dwFlags == FSNOTIFY_POWER_OFF)
1078         {
1079                 yfsd_FlushAllFiles();
1080         }
1081
1082 }
1083
1084
1085 BOOL YFSD_RegisterFileSystemFunction(PVOLUME pVolume,SHELLFILECHANGEFUNC_t pfn )
1086 {
1087         RETAILMSG (MSGSTATE, (L"YAFFS::RegisterFileSysFunction\r\n"));
1088         
1089         pVolume->shellFunction = pfn;
1090
1091         return TRUE;
1092 }
1093
1094
1095
1096
1097
1098 int iMatch(const char a, const char b)
1099 {
1100         if (a == '?' || b == '?')
1101                 return 1;
1102         return (toupper(a) == toupper(b));
1103 }
1104
1105 void pString(const char *inp)
1106 {
1107         while (*inp) RETAILMSG(1, (L"%c", *inp++));
1108 }
1109
1110 int regularMatch(const char *regexp, const char *str)
1111 {
1112 //      pString(regexp);
1113 //      RETAILMSG(1, (L" "));
1114 //      pString(str);
1115 //      RETAILMSG(1, (L"\r\n"));
1116
1117         if (*regexp == 0 && *str == 0)
1118         {
1119                 //RETAILMSG(1, (L"Match!\r\n"));
1120                 return 1;
1121         }
1122         if (*regexp == '*')                     
1123         {
1124                 regexp++;
1125                 if (*regexp == 0)   // end of the expression is a *, we must match
1126                 {
1127                         //RETAILMSG(1, (L"Match!\r\n"));
1128                         return 1;
1129                 }
1130                 while (!iMatch(*regexp, *str)) // throw away chars from str until we match
1131                 {
1132                         if (*str == 0)  // if we're not at the end
1133                         {
1134                                 // if we have .* left to match, but the str is finished then match it OK
1135                                 if (regexp[0] == '.' && regexp[1] == '*')
1136                                 {
1137                                         //RETAILMSG(1, (L"Match!\r\n"));
1138                                         return 1;
1139                                 }
1140                                 else
1141                                 {
1142                                 // the extension failed the match
1143                                         //RETAILMSG(1, (L"No Match!\r\n"));
1144                                         return 0;
1145                                 }
1146                         }
1147                         str++;
1148                 } 
1149                 // right now we should either eat more characters, or try to match
1150                 return (regularMatch(regexp, str) || regularMatch(--regexp, ++str));
1151         }
1152 //  compare chars until we hit another *, or we fail
1153         while (iMatch(*regexp, *str))
1154         {
1155                 if (*regexp == 0 && *str == 0)
1156                 {
1157                         //RETAILMSG(1, (L"Match!\r\n"));
1158                         return 1;
1159                 }
1160                 regexp++;
1161                 str++;
1162         }
1163
1164         if (*regexp == 0 && *str == 0)
1165         {
1166                 //RETAILMSG(1, (L"Match!\r\n"));
1167                 return 1;
1168         }
1169
1170         if (*regexp == '*')
1171                 return regularMatch(regexp, str);
1172
1173         //RETAILMSG(1, (L"No Match!\r\n"));
1174         return 0;
1175 }
1176
1177
1178 void yfsd_DeleteFinder(PSEARCH pSearch)
1179 {
1180   if(pSearch->foundObjects) //If we found some objects we must clean up the cached linked list.
1181   {
1182     yaffs_FoundObject *it;
1183     yaffs_FoundObject *temp;
1184
1185     it = pSearch->foundObjects;
1186
1187     while(it != NULL)
1188     {
1189       temp = it;
1190       it = it->next;
1191       
1192       free(temp);
1193     }
1194
1195     pSearch->foundObjects = NULL;
1196   }
1197
1198                 pSearch->dir->inUse--;
1199                 free(pSearch);
1200 }
1201
1202 BOOL yfsd_ObjectAlreadyFound(PSEARCH pSearch, yaffs_Object *l)
1203 {
1204   //Iterate through the current list of objs already found and return true if already exists.
1205   //If the object hasn't already been found then add it to the list (SIDE-EFFECT alert) and return false.
1206   BOOL found = FALSE;
1207
1208   yaffs_FoundObject *it;
1209   it = pSearch->foundObjects;
1210
1211   
1212   while(it->next != NULL) //iterate through singly linked list.
1213   {
1214     if(it->obj == l)
1215     {
1216       found = TRUE;
1217       break;
1218     }
1219     it = it->next;
1220   }
1221
1222   if(!found)
1223   {
1224     //Add the item to the list.
1225     //'it' will currently be pointing to the last of the list nodes. i.e node->next == NULL
1226     it->next = malloc(sizeof(yaffs_FoundObject));
1227     it->next->next = NULL;
1228     it->next->obj = 0;
1229
1230     it->obj = l;
1231   }
1232
1233   return found;
1234 }
1235 \r
1236 #if 0\r
1237 // slower one
1238 BOOL yfsd_DoFindFile(PSEARCH pSearch, PWIN32_FIND_DATAW pfd)
1239 {
1240
1241         struct list_head *i;
1242         int pos;
1243         yaffs_Object *l;
1244         BOOL found = 0;
1245
1246         char name[YAFFS_MAX_NAME_LENGTH+1];
1247
1248   if(!pSearch->foundObjects)
1249   {
1250     pSearch->foundObjects = malloc(sizeof(yaffs_FoundObject));
1251     pSearch->foundObjects->next = NULL;
1252     pSearch->foundObjects->obj = 0;
1253   }
1254
1255
1256         yfsd_LockYAFFS();
1257
1258         pos = 0;
1259         list_for_each(i,&pSearch->dir->variant.directoryVariant.children)
1260         {
1261
1262                 l = list_entry(i, yaffs_Object,siblings);
1263
1264                 yaffs_GetObjectName(l,name,YAFFS_MAX_NAME_LENGTH+1);
1265
1266                 if(regularMatch(pSearch->pattern,name))
1267                 {
1268                         if(!yfsd_ObjectAlreadyFound(pSearch, l))//pos == pSearch->currentPos)
1269                         {               
1270
1271                                 
1272                                 found = 1;
1273                                 //pSearch->currentPos++;
1274
1275                                 // fill out find data
1276
1277                                 pfd->dwFileAttributes = yfsd_GetObjectWinAttributes(l);
1278
1279                                 yfsd_U32sToWinFileTime(l->win_ctime,&pfd->ftCreationTime);
1280                                 yfsd_U32sToWinFileTime(l->win_atime,&pfd->ftLastAccessTime);
1281                                 yfsd_U32sToWinFileTime(l->win_mtime,&pfd->ftLastWriteTime);
1282
1283                                 pfd->nFileSizeHigh = 0;
1284                                 pfd->nFileSizeLow = yaffs_GetObjectFileLength(l);
1285                                 pfd->dwOID = 0; // wtf is this???
1286
1287                                 MultiByteToWideChar(CP_ACP,0,name,-1,pfd->cFileName,YFSD_NAME_LENGTH);
1288
1289                                 RETAILMSG(MSGSTATE,(L"File %s id %d header %d nDataChunks %d scannedLength %d\r\n",
1290                                                         pfd->cFileName,l->objectId, l->chunkId, l->nDataChunks,
1291                                                         l->variant.fileVariant.scannedFileSize));
1292                                 goto out_of_here;
1293                         }
1294                         else
1295                         {
1296                                 pos++;
1297                         }
1298                 }
1299         }
1300
1301 out_of_here:
1302         yfsd_UnlockYAFFS();
1303
1304
1305         if(!found)
1306         {
1307                 SetLastError(ERROR_NO_MORE_FILES);
1308         }
1309         return found;
1310         
1311 }
1312 \r
1313 #else\r
1314 // faster one\r
1315 BOOL yfsd_DoFindFile(PSEARCH pSearch, PWIN32_FIND_DATAW pfd)\r
1316 {\r
1317 \r
1318         struct list_head *i;\r
1319         yaffs_Object *l;\r
1320         BOOL found = 0;\r
1321 \r
1322         char name[YAFFS_MAX_NAME_LENGTH+1];\r
1323 \r
1324   if(!pSearch->foundObjects)\r
1325   {\r
1326     pSearch->foundObjects = malloc(sizeof(yaffs_FoundObject));\r
1327     pSearch->foundObjects->next = NULL;\r
1328     pSearch->foundObjects->obj = 0;\r
1329   }\r
1330 \r
1331 \r
1332         yfsd_LockYAFFS();\r
1333 \r
1334         list_for_each(i,&pSearch->dir->variant.directoryVariant.children)\r
1335         {\r
1336 \r
1337                 l = list_entry(i, yaffs_Object,siblings);\r
1338                 if(!yfsd_ObjectAlreadyFound(pSearch,l))\r
1339                 {\r
1340                         // Only look at things we have not looked at already\r
1341                         yaffs_GetObjectName(l,name,YAFFS_MAX_NAME_LENGTH+1);\r
1342 \r
1343                         if(regularMatch(pSearch->pattern,name))\r
1344                         {\r
1345                                 found = 1;\r
1346                                 // fill out find data\r
1347 \r
1348                                 pfd->dwFileAttributes = yfsd_GetObjectWinAttributes(l);\r
1349 \r
1350                                 yfsd_U32sToWinFileTime(l->win_ctime,&pfd->ftCreationTime);\r
1351                                 yfsd_U32sToWinFileTime(l->win_atime,&pfd->ftLastAccessTime);\r
1352                                 yfsd_U32sToWinFileTime(l->win_mtime,&pfd->ftLastWriteTime);\r
1353 \r
1354                                 pfd->nFileSizeHigh = 0;\r
1355                                 pfd->nFileSizeLow = yaffs_GetObjectFileLength(l);\r
1356                                 pfd->dwOID = 0; // wtf is this???\r
1357 \r
1358                                 MultiByteToWideChar(CP_ACP,0,name,-1,pfd->cFileName,YFSD_NAME_LENGTH);\r
1359 \r
1360                                 RETAILMSG(MSGSTATE,(L"File %s id %d header %d nDataChunks %d scannedLength %d\r\n",\r
1361                                                         pfd->cFileName,l->objectId, l->chunkId, l->nDataChunks,\r
1362                                                         l->variant.fileVariant.scannedFileSize));\r
1363                                 goto out_of_here;\r
1364                         }\r
1365 \r
1366                 }\r
1367 \r
1368 \r
1369         }\r
1370 \r
1371 out_of_here:\r
1372         yfsd_UnlockYAFFS();\r
1373 \r
1374 \r
1375         if(!found)\r
1376         {\r
1377                 SetLastError(ERROR_NO_MORE_FILES);\r
1378         }\r
1379         return found;\r
1380         \r
1381 }\r
1382 #endif\r
1383
1384 HANDLE YFSD_FindFirstFileW(PVOLUME pVolume, HANDLE hProc,PCWSTR pwsFileSpec, PWIN32_FIND_DATAW pfd )
1385 {
1386
1387         // Create a search context, register it, and do the first search
1388
1389         PSEARCH pSearch;
1390         HANDLE h = INVALID_HANDLE_VALUE;
1391         BOOL found = 0;
1392
1393         RETAILMSG (MSGSTATE, (L"YAFFS::FindFirst\r\n"));
1394
1395         pSearch = malloc(sizeof(yfsd_WinFind));
1396         if(!pSearch)
1397         {
1398                 SetLastError(ERROR_OUTOFMEMORY);
1399         }
1400
1401         yfsd_LockYAFFS();
1402
1403         if(pSearch)
1404         {
1405                 pSearch->foundObjects = NULL; //pSearch->currentPos = 0;
1406                 pSearch->dir = yfsd_FindDirectoryByWinPath(&pVolume->dev,pwsFileSpec,pSearch->pattern,YFSD_NAME_LENGTH);
1407                 if(pSearch->dir)
1408                 {
1409                                 pSearch->dir->inUse++;
1410                 }
1411                 else
1412                 {
1413                         free(pSearch);
1414                         pSearch = NULL;
1415                 }
1416         }
1417
1418         yfsd_UnlockYAFFS();
1419
1420
1421
1422         if(pSearch)
1423         {
1424                 found = yfsd_DoFindFile(pSearch,pfd);
1425         }
1426
1427         if(found)
1428         {
1429                 h = FSDMGR_CreateSearchHandle(pVolume->mgrVolume,hProc,pSearch);
1430         }
1431
1432         if(h == INVALID_HANDLE_VALUE && pSearch)
1433         {
1434                 yfsd_DeleteFinder(pSearch);
1435                 SetLastError(ERROR_NO_MORE_SEARCH_HANDLES);
1436         }
1437
1438
1439
1440         return h;
1441 }
1442
1443 BOOL YFSD_FindNextFileW(PSEARCH pSearch, PWIN32_FIND_DATAW pfd )
1444 {
1445         RETAILMSG (MSGSTATE, (L"YAFFS::FindNext\r\n"));
1446         if(!pSearch)
1447         {
1448                 return FALSE;
1449         }
1450         return yfsd_DoFindFile(pSearch,pfd);
1451 }
1452
1453 BOOL YFSD_FindClose( PSEARCH pSearch )
1454 {       
1455         RETAILMSG (MSGSTATE, (L"YAFFS::FindClose\r\n"));
1456         if(!pSearch)
1457         {
1458                 return FALSE;
1459         }
1460         yfsd_DeleteFinder(pSearch);
1461         return TRUE;
1462 }
1463
1464
1465 HANDLE YFSD_CreateFileW( 
1466         PVOLUME pVolume, 
1467         HANDLE hProc, 
1468         PCWSTR pwsFileName, 
1469         DWORD dwAccess, 
1470         DWORD dwShareMode,
1471         PSECURITY_ATTRIBUTES pSecurityAttributes, // ignore
1472         DWORD dwCreate,
1473         DWORD dwFlagsAndAttributes, 
1474         HANDLE hTemplateFile ) // ignore
1475 {
1476
1477
1478         yaffs_Object *parent = NULL;
1479         yaffs_Object *obj = NULL;
1480         char name[YFSD_NAME_LENGTH+1];
1481         int mode;
1482         yfsd_WinFile *f = NULL;
1483         HANDLE handle = INVALID_HANDLE_VALUE;
1484         unsigned modifiedTime[2];
1485         unsigned objSize;
1486
1487         BOOL writePermitted = (dwAccess & GENERIC_WRITE) ? TRUE : FALSE;
1488
1489         BOOL fileCreated = FALSE;
1490
1491
1492         mode = dwFlagsAndAttributes & 0x00FFFFFF;  // ding off the flags
1493
1494
1495         RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile (%s) flags %X mode %X\r\n", pwsFileName,dwFlagsAndAttributes,mode));
1496         if(writePermitted)
1497         {
1498                 RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile write permitted\r\n"));
1499         }
1500         else
1501         {
1502                 RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile write not permitted\r\n"));
1503         }
1504
1505         if(!yfsd_CheckValidAttributes(mode))\r
1506         {\r
1507                         SetLastError(ERROR_INVALID_PARAMETER);\r
1508                         return FALSE;\r
1509         }\r
1510
1511         yfsd_LockYAFFS();
1512
1513
1514         parent = yfsd_FindDirectoryByWinPath(&pVolume->dev,pwsFileName,name,YFSD_NAME_LENGTH);
1515
1516
1517         if(parent && yfsd_NameIsValid(name))
1518         {
1519 \r
1520
1521                 obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);\r
1522                 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)\r
1523                 {\r
1524                         // Naughty, naughty. Don't do file ops on directories\r
1525                         SetLastError(ERROR_ACCESS_DENIED);\r
1526                         fileCreated = FALSE;\r
1527                         obj = NULL;\r
1528                 }\r
1529                 else if(dwCreate == CREATE_NEW)
1530                 {
1531                         RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile creating file in CREATE_NEW\r\n"));
1532
1533                         obj = yaffs_MknodFile(parent,name,mode,0,0);
1534                         if(!obj)
1535                                 SetLastError(ERROR_DISK_FULL);
1536                         fileCreated = TRUE;
1537                 }
1538                 else if( dwCreate == OPEN_ALWAYS)
1539                 {
1540                         obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
1541                         if(!obj)
1542                         {
1543                                 RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile creating file in OPEN_ALWAYS\r\n"));
1544                                 obj = yaffs_MknodFile(parent,name,mode,0,0);
1545                                 if(!obj)
1546                                         SetLastError(ERROR_DISK_FULL);
1547                                 fileCreated = TRUE;
1548
1549                         }
1550                         else
1551                         {
1552                                 RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile opening existing file in OPEN_ALWAYS\r\n"));
1553                         }
1554                 }
1555                 else if(dwCreate == OPEN_EXISTING)
1556                 {
1557                         RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile opening file in OPEN_EXISTING\r\n"));
1558                         obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
1559                         if(!obj)
1560                                 SetLastError(ERROR_FILE_NOT_FOUND);
1561                 }
1562                 else if(dwCreate == TRUNCATE_EXISTING)
1563                 {
1564                         RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile opening file in TRUNCATE_EXISTING\r\n"));
1565                         obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
1566                         if(obj)
1567                         {
1568                                 yaffs_ResizeFile(obj,0);
1569                         }
1570                         else
1571                         {
1572                                 SetLastError(ERROR_FILE_NOT_FOUND);
1573                         }
1574                 }
1575                 else if(dwCreate == CREATE_ALWAYS)
1576                 {
1577                         obj = yfsd_FindObjectByWinPath(&pVolume->dev,pwsFileName);
1578
1579                         if(!obj)
1580                         {
1581                                 RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile creating file parent %X, name %a in CREATE_ALWAYS\r\n",parent,name));
1582                                 obj = yaffs_MknodFile(parent,name,mode,0,0);
1583                                 if(!obj)
1584                                         SetLastError(ERROR_DISK_FULL);
1585                                 fileCreated = TRUE;
1586                         }
1587                         else
1588                         {
1589                                 RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile in CREATE_ALWAYS (already exists)\r\n"));
1590                                 obj->st_mode = mode;
1591                                 obj->dirty = 1;
1592                                 yaffs_ResizeFile(obj,0);
1593                                 yaffs_FlushFile(obj);
1594                         }
1595                 }
1596                 else
1597                 {
1598                                 RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile called with unknown flags %x\r\n", dwCreate));
1599                                 SetLastError(ERROR_INVALID_PARAMETER);
1600                 }
1601         }
1602         else
1603         {
1604                 RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile unable to get parent node\r\n"));
1605                 SetLastError(ERROR_PATH_NOT_FOUND);
1606         }
1607
1608         if(obj)
1609         {
1610                 RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - we have an object\r\n"));
1611                 f = yfsd_GetWinFile();
1612         }
1613         else
1614         {
1615                 RETAILMSG (MSGSTATE, (L"YAFFS::Creatfile - no object\r\n"));
1616         }
1617
1618         if(f)
1619         {
1620
1621                 handle = FSDMGR_CreateFileHandle(pVolume->mgrVolume,hProc,f);
1622
1623                 if(handle != INVALID_HANDLE_VALUE)
1624                 {
1625                         RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - we have an fsdmgr handle\r\n"));
1626                         f->obj = obj;
1627                         f->offset = 0;
1628                         f->writePermitted = writePermitted;
1629                         f->myVolume = pVolume;
1630                         obj->inUse++;
1631
1632                         modifiedTime[0] = obj->win_mtime[0];\r
1633                         modifiedTime[1] = obj->win_mtime[1];\r
1634                         objSize = yaffs_GetObjectFileLength(obj);
1635                         RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - file size %d\r\n",objSize));
1636                 }
1637                 else
1638                 {
1639                         yfsd_PutWinFile(f);
1640                         RETAILMSG (MSGSTATE, (L"YAFFS::CreateFile - we have no fsdmgr handle\r\n"));
1641                 }
1642
1643         }
1644
1645         yfsd_UnlockYAFFS();
1646
1647         if(handle != INVALID_HANDLE_VALUE && 
1648            fileCreated &&
1649            pVolume->shellFunction)
1650         {
1651                         FILECHANGEINFO fc;
1652                         WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
1653
1654                         fc.cbSize = sizeof(FILECHANGEINFO);
1655                         fc.wEventId = SHCNE_CREATE;
1656                         fc.uFlags = SHCNF_PATH;
1657                         fc.dwItem1 = (DWORD)yfsd_FullPathName(pVolume,fpn,YFSD_FULL_PATH_NAME_SIZE,pwsFileName);
1658                         fc.dwItem2 = 0;
1659                         fc.dwAttributes = mode;
1660                         yfsd_U32sToWinFileTime(modifiedTime,&fc.ftModified);
1661                         fc.nFileSize = objSize;
1662
1663                         pVolume->shellFunction(&fc);
1664                         RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
1665
1666                         yfsd_ShellDirectoryChanged(pVolume,fpn);
1667         }
1668
1669         if(handle != INVALID_HANDLE_VALUE && (fileCreated || writePermitted))
1670         {
1671                         // Remember the name
1672
1673                         WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
1674                         int slen;
1675
1676                         yfsd_FullPathName(pVolume,fpn,YFSD_FULL_PATH_NAME_SIZE,pwsFileName);
1677                         slen = wcslen(fpn);
1678                         f->fullName = malloc((slen+1)* sizeof(WCHAR));
1679                         if(f->fullName)
1680                         {
1681                                 wcscpy(f->fullName,fpn);
1682                         }
1683
1684         }
1685
1686
1687         return handle;
1688
1689 }
1690
1691 BOOL yfsd_DoReadFile( 
1692         PFILE pFile, 
1693         PVOID pBuffer, 
1694         DWORD cbRead, 
1695         PDWORD pcbRead)
1696 {
1697         
1698         DWORD maxRead;
1699         int nread = 0;
1700         yaffs_Object *obj = NULL;
1701
1702
1703         if(pcbRead)
1704         {
1705                 *pcbRead = 0;
1706         }
1707         else
1708         {
1709                 RETAILMSG (MSGSTATE, (L"YAFFS::DoReadFile pcbRead was NULL. naughty.\r\n"));
1710         }
1711
1712         RETAILMSG (MSGSTATE, (L"YAFFS::DoReadFile %d bytes\r\n",cbRead));
1713
1714         if(!pFile || !pFile->obj)
1715         {
1716                 SetLastError(ERROR_INVALID_HANDLE);
1717                 return FALSE;
1718         }
1719         
1720         obj = pFile->obj;
1721
1722         if(yaffs_GetObjectFileLength(obj) > pFile->offset)
1723         {
1724                 maxRead = yaffs_GetObjectFileLength(obj) - pFile->offset;
1725         }
1726         else
1727         {
1728                 maxRead = 0;
1729         }
1730
1731         if(cbRead > maxRead)
1732         {
1733                 cbRead = maxRead;
1734         }
1735         
1736         if(maxRead > 0)
1737         {
1738                 nread = yaffs_ReadDataFromFile(obj,pBuffer,pFile->offset,cbRead);
1739                 if(nread > 0)
1740                 {\r
1741                         pFile->offset += nread;\r
1742
1743                         if(pcbRead)
1744                         {
1745                                 *pcbRead = nread;
1746                         }
1747                 }
1748         }
1749         else
1750         {
1751                 if(pcbRead) \r
1752                 {\r
1753                         *pcbRead = maxRead;\r
1754                 }
1755         }
1756
1757
1758         return nread < 0? FALSE : TRUE; 
1759
1760 }
1761
1762 BOOL YFSD_ReadFile( 
1763         PFILE pFile, 
1764         PVOID pBuffer, 
1765         DWORD cbRead, 
1766         PDWORD pcbRead, 
1767         OVERLAPPED *pOverlapped ) //ignore
1768 {
1769         BOOL result;
1770
1771         RETAILMSG (MSGSTATE, (L"YAFFS::ReadFile\r\n"));
1772
1773         if(!pFile || !pFile->obj)
1774         {
1775                 SetLastError(ERROR_INVALID_HANDLE);
1776                 return FALSE;
1777         }
1778
1779         yfsd_LockYAFFS();
1780
1781         result = yfsd_DoReadFile(pFile,pBuffer,cbRead,pcbRead);
1782
1783         yfsd_UnlockYAFFS();
1784
1785         return result;
1786 }
1787
1788 BOOL YFSD_ReadFileWithSeek( 
1789         PFILE pFile, 
1790         PVOID pBuffer, 
1791         DWORD cbRead, 
1792         PDWORD pcbRead, 
1793         OVERLAPPED *pOverlapped, 
1794         DWORD dwLowOffset, 
1795         DWORD dwHighOffset )
1796 {
1797         BOOL result;\r
1798         DWORD rememberedOffset;
1799
1800         RETAILMSG (MSGSTATE, (L"YAFFS::ReadFileWithSeek %d bytes at %d high %d pcbRead %X\r\n",cbRead,dwLowOffset,dwHighOffset,pcbRead));
1801
1802         // To determine if paging is supported, the kernel calls this with all parameters except pFile
1803         // being zero.
1804         if(!pBuffer && !cbRead && !pcbRead && !pOverlapped && !dwLowOffset && !dwHighOffset)
1805         {
1806                 return TRUE; // paging suppported
1807                 //return FALSE; // paging not supported
1808         }
1809
1810         if(!pFile || !pFile->obj)
1811         {
1812                 SetLastError(ERROR_INVALID_HANDLE);
1813                 return FALSE;
1814         }
1815
1816         yfsd_LockYAFFS();\r
1817 \r
1818         rememberedOffset = pFile->offset;
1819
1820         pFile->offset = dwLowOffset;
1821         // ignore high offset for now
1822
1823         result = yfsd_DoReadFile(pFile,pBuffer,cbRead,pcbRead);
1824 \r
1825         //pFile->offset = rememberedOffset;\r
1826
1827         yfsd_UnlockYAFFS();
1828
1829         return result;
1830
1831
1832 }
1833
1834
1835 BOOL yfsd_DoWriteFile( 
1836         PFILE pFile, 
1837         PCVOID pBuffer, 
1838         DWORD cbWrite, 
1839         PDWORD pcbWritten)
1840 {
1841         int nwritten = 0;
1842         yaffs_Object *obj = NULL;
1843         
1844         RETAILMSG (MSGSTATE, (L"YAFFS::DoWriteFile size %d\r\n",cbWrite));
1845         
1846         if(!pFile || !pFile->obj)
1847         {
1848                 SetLastError(ERROR_INVALID_HANDLE);
1849                 return FALSE;
1850         }
1851
1852         if(!pFile->writePermitted)
1853         {
1854                         *pcbWritten = 0;
1855                         SetLastError(ERROR_ACCESS_DENIED);
1856                         return FALSE;
1857         }
1858
1859         obj = pFile->obj;
1860
1861         *pcbWritten = 0;
1862
1863
1864                 nwritten = yaffs_WriteDataToFile(obj,pBuffer,pFile->offset,cbWrite);
1865                 if(nwritten >= 0)
1866                 {
1867                         pFile->offset += nwritten;
1868                         *pcbWritten = nwritten;
1869                 }
1870                 if(nwritten != cbWrite)
1871                 {
1872                         SetLastError(ERROR_DISK_FULL);
1873                 }
1874
1875
1876         return nwritten != cbWrite? FALSE : TRUE; 
1877 }
1878
1879
1880 BOOL YFSD_WriteFile( 
1881         PFILE pFile, 
1882         PCVOID pBuffer, 
1883         DWORD cbWrite, 
1884         PDWORD pcbWritten, 
1885         OVERLAPPED *pOverlapped )
1886 {
1887         BOOL result;
1888
1889         yfsd_LockYAFFS();
1890         RETAILMSG (MSGSTATE, (L"YAFFS::WriteFile\r\n"));
1891
1892         result = yfsd_DoWriteFile(pFile,pBuffer,cbWrite,pcbWritten);
1893
1894         yfsd_UnlockYAFFS();
1895
1896         return result;
1897 }
1898
1899 BOOL YFSD_WriteFileWithSeek( 
1900         PFILE pFile, 
1901         PCVOID pBuffer, 
1902         DWORD cbWrite, 
1903         PDWORD pcbWritten, 
1904         OVERLAPPED *pOverlapped,
1905         DWORD dwLowOffset, 
1906         DWORD dwHighOffset )
1907 {
1908         BOOL result;
1909         DWORD rememberedOffset;
1910         RETAILMSG (MSGSTATE, (L"YAFFS::WriteFileWithSeek %d bytes at %d,%d pcbWritten %X\r\n",cbWrite,dwHighOffset,dwLowOffset,pcbWritten));
1911
1912         \r
1913
1914         if(!pFile || !pFile->obj)
1915         {
1916                 SetLastError(ERROR_INVALID_HANDLE);
1917                 return FALSE;
1918         }
1919
1920         yfsd_LockYAFFS();
1921 \r
1922         rememberedOffset = pFile->offset;\r
1923
1924         pFile->offset = dwLowOffset;
1925         // ignore high offset for now
1926
1927         result = yfsd_DoWriteFile(pFile,pBuffer,cbWrite,pcbWritten);
1928 \r
1929         //pFile->offset = rememberedOffset;\r
1930
1931         yfsd_UnlockYAFFS();
1932
1933         return result;
1934 }
1935
1936 DWORD YFSD_SetFilePointer( 
1937         PFILE pFile, 
1938         LONG lDistanceToMove, 
1939         PLONG pDistanceToMoveHigh, 
1940         DWORD dwMoveMethod )
1941 {
1942         // ignore high offset for now
1943
1944         DWORD offset = 0xFFFFFFFF;
1945         DWORD oldPos;
1946         int fileSize;
1947         int seekNegative = 0;
1948
1949
1950         if(!pFile || !pFile->obj)
1951         {
1952                 SetLastError(ERROR_INVALID_HANDLE);
1953                 return offset;
1954         }
1955
1956         yfsd_LockYAFFS();\r
1957 \r
1958
1959         oldPos = pFile->offset;
1960
1961         if(dwMoveMethod == FILE_BEGIN)
1962         {
1963                 if(lDistanceToMove >= 0)
1964                 {       
1965                         offset = pFile->offset = lDistanceToMove;
1966                 }
1967                 else
1968                 {
1969                         seekNegative = 1;
1970                 }
1971         }
1972         else if(dwMoveMethod == FILE_END)
1973         {
1974                 fileSize = yaffs_GetObjectFileLength(pFile->obj);
1975                 if(fileSize >= 0 &&
1976                    (fileSize + lDistanceToMove) >= 0)
1977                 {
1978                         offset = pFile->offset = fileSize + lDistanceToMove;
1979                 }
1980                 else
1981                 {
1982                         seekNegative = 1;
1983                 }
1984         }
1985         else if(dwMoveMethod == FILE_CURRENT)
1986         {
1987                 if(pFile->offset + lDistanceToMove >= 0)
1988                 {
1989                         offset = pFile->offset = pFile->offset + lDistanceToMove;               
1990                 }
1991                 else
1992                 {
1993                                 seekNegative = 1;
1994                 }
1995         }
1996
1997         if(seekNegative)
1998         {
1999                         SetLastError(ERROR_NEGATIVE_SEEK);
2000                         
2001         }
2002
2003         yfsd_UnlockYAFFS();
2004
2005         RETAILMSG (MSGSTATE, (L"YAFFS::SetFilePtr method %d distance %d high %X oldpos %d newpos %d\r\n",
2006                                   dwMoveMethod,lDistanceToMove,pDistanceToMoveHigh,oldPos,offset));
2007
2008         return offset;
2009
2010 }
2011
2012 DWORD YFSD_GetFileSize( 
2013         PFILE pFile, 
2014         PDWORD pFileSizeHigh )
2015 {
2016         int fileSize;
2017         
2018         RETAILMSG (MSGSTATE, (L"YAFFS::GetFileSize high %X\r\n",pFileSizeHigh));
2019         
2020
2021         if(!pFile || !pFile->obj)
2022         {
2023                 SetLastError(ERROR_INVALID_HANDLE);
2024                 return -1;
2025         }
2026
2027         yfsd_LockYAFFS();
2028
2029         fileSize = yaffs_GetObjectFileLength(pFile->obj);
2030
2031         yfsd_UnlockYAFFS();\r
2032         if(pFileSizeHigh)\r
2033                  *pFileSizeHigh = 0;
2034
2035         return fileSize;
2036
2037 }
2038
2039
2040 BOOL YFSD_GetFileInformationByHandle( 
2041         PFILE pFile,
2042         PBY_HANDLE_FILE_INFORMATION pFileInfo )
2043 {
2044         RETAILMSG (MSGSTATE, (L"YAFFS::GetFileInfoByHandle\r\n"));
2045
2046         if(!pFile || !pFile->obj || !pFileInfo)
2047         {
2048                 SetLastError(ERROR_INVALID_HANDLE);
2049                 return FALSE;
2050         }\r
2051 \r
2052         yfsd_LockYAFFS();\r
2053 \r
2054         pFileInfo->dwFileAttributes = yfsd_GetObjectWinAttributes(pFile->obj);\r
2055         yfsd_U32sToWinFileTime(pFile->obj->win_ctime,&pFileInfo->ftCreationTime);\r
2056         yfsd_U32sToWinFileTime(pFile->obj->win_atime,&pFileInfo->ftLastAccessTime);\r
2057         yfsd_U32sToWinFileTime(pFile->obj->win_mtime,&pFileInfo->ftLastWriteTime);\r
2058         pFileInfo->dwVolumeSerialNumber = 0; //todo is this OK? \r
2059         pFileInfo->nFileSizeHigh = 0;\r
2060         pFileInfo->nFileSizeLow = yaffs_GetObjectFileLength(pFile->obj); \r
2061         pFileInfo->nNumberOfLinks = 1; // only primary link supported like FAT\r
2062         pFileInfo->nFileIndexHigh = 0; \r
2063         pFileInfo->nFileIndexLow = pFile->obj->objectId; \r
2064 \r
2065         yfsd_UnlockYAFFS();
2066
2067         return TRUE;
2068 }
2069
2070 BOOL YFSD_FlushFileBuffers(PFILE pFile )
2071 {\r
2072         WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];\r
2073         int nameExists = 0;\r
2074         yfsd_Volume *vol = NULL;\r
2075         DWORD attribs = 0;\r
2076         DWORD objSize = 0;\r
2077         DWORD mtime[2];\r
2078 \r
2079
2080         RETAILMSG (MSGSTATE, (L"YAFFS::FlushFileBuffers\r\n"));
2081
2082         if(!pFile || !pFile->obj)
2083         {
2084                 SetLastError(ERROR_INVALID_HANDLE);
2085                 return FALSE;
2086         }
2087
2088         yfsd_LockYAFFS();\r
2089
2090         yaffs_FlushFile(pFile->obj);\r
2091         attribs = yfsd_GetObjectWinAttributes(pFile->obj);\r
2092         objSize = yaffs_GetObjectFileLength(pFile->obj);\r
2093         mtime[0] = pFile->obj->win_mtime[0];\r
2094         mtime[1] = pFile->obj->win_mtime[1];\r
2095         if(pFile->fullName)\r
2096         {\r
2097                 wcscpy(fpn,pFile->fullName);\r
2098                 nameExists = 1;\r
2099         }\r
2100         vol = pFile->myVolume;\r
2101 \r
2102         yfsd_UnlockYAFFS();
2103         \r
2104         if(vol && vol->shellFunction && nameExists)\r
2105         {\r
2106                         FILECHANGEINFO fc;\r
2107                 \r
2108                         fc.cbSize = sizeof(FILECHANGEINFO);\r
2109                         fc.wEventId = SHCNE_UPDATEITEM;\r
2110                         fc.uFlags = SHCNF_PATH;\r
2111                         fc.dwItem1 = (DWORD)fpn;\r
2112                         fc.dwItem2 = 0;\r
2113                         fc.dwAttributes = attribs;\r
2114                         yfsd_U32sToWinFileTime(mtime,&fc.ftModified);\r
2115                         fc.nFileSize = objSize;\r
2116 \r
2117                         vol->shellFunction(&fc);\r
2118                         RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));\r
2119                         //yfsd_ShellDirectoryChanged(vol,fpn);\r
2120         }\r
2121 \r
2122         
2123         return TRUE;
2124 }
2125
2126 BOOL YFSD_GetFileTime( 
2127         PFILE pFile, 
2128         FILETIME *pCreation, 
2129         FILETIME *pLastAccess, 
2130         FILETIME *pLastWrite )
2131 {
2132
2133         RETAILMSG (MSGSTATE, (L"YAFFS::GetFileTime\r\n"));
2134         if(!pFile || !pFile->obj)
2135         {
2136                 SetLastError(ERROR_INVALID_HANDLE);
2137                 return FALSE;
2138         }
2139
2140         yfsd_LockYAFFS();
2141
2142         if(pCreation) yfsd_U32sToWinFileTime(pFile->obj->win_ctime,pCreation);
2143         if(pLastAccess) yfsd_U32sToWinFileTime(pFile->obj->win_atime,pLastAccess);
2144         if(pLastWrite) yfsd_U32sToWinFileTime(pFile->obj->win_mtime,pLastWrite);
2145
2146         yfsd_UnlockYAFFS();
2147
2148         return TRUE;
2149 }
2150
2151 BOOL YFSD_SetFileTime( 
2152         PFILE pFile, 
2153         CONST FILETIME *pCreation, 
2154         CONST FILETIME *pLastAccess, 
2155         CONST FILETIME *pLastWrite )
2156 {
2157         WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];\r
2158         int nameExists = 0;\r
2159         int result = FALSE;
2160         yfsd_Volume *vol = NULL;\r
2161         DWORD attribs = 0;\r
2162         DWORD objSize = 0;\r
2163         DWORD mtime[2];\r
2164 \r
2165         \r
2166         RETAILMSG (MSGSTATE, (L"YAFFS::SetFileTime\r\n"));
2167
2168         if(!pFile || !pFile->obj)
2169         {
2170                 SetLastError(ERROR_INVALID_HANDLE);
2171                 return FALSE;
2172         }
2173         
2174         
2175         yfsd_LockYAFFS();
2176
2177         if(pCreation) \r
2178         {\r
2179                  yfsd_WinFileTimeToU32s(pCreation,pFile->obj->win_ctime);\r
2180                 pFile->obj->dirty = 1;\r
2181         }
2182         if(pLastAccess)\r
2183         {\r
2184                 yfsd_WinFileTimeToU32s(pLastAccess,pFile->obj->win_atime);\r
2185                 pFile->obj->dirty = 1;\r
2186         }
2187         if(pLastWrite)\r
2188         {\r
2189                 yfsd_WinFileTimeToU32s(pLastWrite,pFile->obj->win_mtime);\r
2190                 pFile->obj->dirty = 1;
2191         }
2192         if(pCreation || pLastAccess || pLastWrite)
2193         {
2194                 result = yaffs_FlushFile(pFile->obj);
2195         }
2196 \r
2197         if(result)\r
2198         {
2199                 attribs = yfsd_GetObjectWinAttributes(pFile->obj);\r
2200                 objSize = yaffs_GetObjectFileLength(pFile->obj);\r
2201                 mtime[0] = pFile->obj->win_mtime[0];\r
2202                 mtime[1] = pFile->obj->win_mtime[1];\r
2203                 if(pFile->fullName)\r
2204                 {\r
2205                         wcscpy(fpn,pFile->fullName);\r
2206                         nameExists = 1;\r
2207                 }\r
2208                 vol = pFile->myVolume;\r
2209         }\r
2210 \r
2211         yfsd_UnlockYAFFS();
2212
2213         // Call shell function
2214         if(nameExists && result && vol && vol->shellFunction)\r
2215         {\r
2216                         FILECHANGEINFO fc;\r
2217                 \r
2218                         fc.cbSize = sizeof(FILECHANGEINFO);\r
2219                         fc.wEventId = SHCNE_UPDATEITEM;\r
2220                         fc.uFlags = SHCNF_PATH;\r
2221                         fc.dwItem1 = (DWORD)fpn;\r
2222                         fc.dwItem2 = 0;\r
2223                         fc.dwAttributes = attribs;\r
2224                         yfsd_U32sToWinFileTime(mtime,&fc.ftModified);\r
2225                         fc.nFileSize = objSize;\r
2226 \r
2227                         vol->shellFunction(&fc);\r
2228                         RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));\r
2229                         //yfsd_ShellDirectoryChanged(vol,fpn);\r
2230         }\r
2231
2232         return TRUE;
2233 }
2234    
2235 BOOL YFSD_SetEndOfFile( 
2236 PFILE pFile )
2237 {
2238
2239         WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];\r
2240         int nameExists = 0;\r
2241         yfsd_Volume *vol = NULL;\r
2242         DWORD attribs = 0;\r
2243         DWORD objSize = 0;\r
2244         DWORD mtime[2];\r
2245         static unsigned char zeros[512];
2246
2247         int result;
2248         BOOL retVal = FALSE;
2249
2250         RETAILMSG (MSGSTATE, (L"YAFFS::SetEOF\r\n"));
2251
2252         if(!pFile || !pFile->obj)
2253         {
2254                 SetLastError(ERROR_INVALID_HANDLE);
2255                 return FALSE;
2256         }
2257
2258         yfsd_LockYAFFS();
2259         result = yaffs_ResizeFile(pFile->obj,pFile->offset);
2260
2261         RETAILMSG (MSGSTATE, (L"YAFFS::SetEOF resizing to %d, result %d\r\n",pFile->offset,result));
2262
2263         // Resize only works if we're shortening the file.
2264         // If the result is shorter than the offset, then we need to write zeros....
2265         // 
2266         if(result != pFile->offset)
2267         {
2268                 if(result < pFile->offset)
2269                 {
2270
2271                         int nBytes = pFile->offset - result;
2272                         int thisWriteSize;
2273                         int written;
2274                         BOOL ok = TRUE;
2275
2276                         memset(zeros,0,512);
2277
2278                         pFile->offset = result;
2279                         RETAILMSG (MSGSTATE, (L"YAFFS::SetEOF expanding file by %d bytes\r\n",nBytes));
2280                         while(nBytes > 0 && ok)
2281                         {
2282                                 thisWriteSize = (nBytes > 512) ? 512  : nBytes;
2283
2284                                 ok = yfsd_DoWriteFile(pFile,zeros,thisWriteSize,&written);      
2285                                 if(written != thisWriteSize)
2286                                 {
2287                                         ok = FALSE;
2288                                 }
2289
2290                                 nBytes -= thisWriteSize;
2291                         }
2292
2293                         retVal = ok;
2294                 }
2295                 else
2296                 {
2297
2298                         SetLastError(ERROR_ACCESS_DENIED);
2299                         retVal = FALSE;
2300                 }
2301         }
2302         else
2303         {
2304                 retVal = TRUE;
2305         }
2306         if(retVal)\r
2307         {\r
2308                 attribs = yfsd_GetObjectWinAttributes(pFile->obj);\r
2309                 objSize = yaffs_GetObjectFileLength(pFile->obj);\r
2310                 mtime[0] = pFile->obj->win_mtime[0];\r
2311                 mtime[1] = pFile->obj->win_mtime[1];\r
2312                 if(pFile->fullName)\r
2313                 {\r
2314                         wcscpy(fpn,pFile->fullName);\r
2315                         nameExists = 1;\r
2316                 }\r
2317                 vol = pFile->myVolume;\r
2318         }\r
2319 \r
2320 \r
2321         yfsd_UnlockYAFFS();\r
2322 \r
2323         if(nameExists && retVal && vol && vol->shellFunction)\r
2324         {\r
2325                         FILECHANGEINFO fc;\r
2326                 \r
2327                         fc.cbSize = sizeof(FILECHANGEINFO);\r
2328                         fc.wEventId = SHCNE_UPDATEITEM;\r
2329                         fc.uFlags = SHCNF_PATH;\r
2330                         fc.dwItem1 = (DWORD)fpn;\r
2331                         fc.dwItem2 = 0;\r
2332                         fc.dwAttributes = attribs;\r
2333                         yfsd_U32sToWinFileTime(mtime,&fc.ftModified);\r
2334                         fc.nFileSize = objSize;\r
2335 \r
2336                         vol->shellFunction(&fc);\r
2337                         RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));\r
2338                         //yfsd_ShellDirectoryChanged(vol,fpn);\r
2339         }\r
2340
2341         RETAILMSG (MSGSTATE, (L"YAFFS::SetEOF file size %d\r\n",yaffs_GetObjectFileLength(pFile->obj)));
2342
2343
2344         
2345         return retVal;
2346 }
2347
2348 BOOL YFSD_DeviceIoControl( 
2349         PFILE pFile, 
2350         DWORD dwIoControlCode, 
2351         PVOID pInBuf, 
2352         DWORD nInBufSize, 
2353         PVOID pOutBuf, 
2354         DWORD nOutBufSize, 
2355         PDWORD pBytesReturned, 
2356         OVERLAPPED *pOverlapped )
2357 {
2358         RETAILMSG (MSGSTATE, (L"YAFFS::DeviceIoControl\r\n"));
2359
2360         return FALSE;
2361 }
2362
2363 BOOL YFSD_CloseFile( PFILE pFile )
2364 {
2365         WCHAR fpn[YFSD_FULL_PATH_NAME_SIZE];
2366         int nameExists = 0;
2367         yfsd_Volume *vol = NULL;
2368         DWORD attribs = 0;
2369         DWORD objSize = 0;
2370         DWORD mtime[2];\r
2371
2372         RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile %X\r\n",pFile));
2373
2374         yfsd_LockYAFFS();
2375
2376         if(!pFile)
2377         {
2378                 RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile null pFile\r\n"));
2379         }
2380         else
2381         {
2382                 if(pFile->obj)
2383                 {
2384                         pFile->obj->inUse--;
2385                         RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile on obj\r\n"));
2386                         yaffs_FlushFile(pFile->obj);
2387                         attribs = yfsd_GetObjectWinAttributes(pFile->obj);
2388                         objSize = yaffs_GetObjectFileLength(pFile->obj);
2389                         mtime[0] = pFile->obj->win_mtime[0];\r
2390                         mtime[1] = pFile->obj->win_mtime[1];\r
2391                         RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile on obj done, size is %d\r\n",objSize));
2392                         if(pFile->fullName)
2393                         {
2394                                 wcscpy(fpn,pFile->fullName);
2395                                 nameExists = 1;
2396                         }
2397                         vol = pFile->myVolume;
2398                         yfsd_PutWinFile(pFile);
2399                 }
2400                 else
2401                 {
2402                         RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile null obj\r\n"));
2403                 }
2404
2405         }
2406         yfsd_UnlockYAFFS();
2407
2408
2409         if(nameExists && vol && vol->shellFunction)
2410         {
2411                         FILECHANGEINFO fc;
2412                 
2413                         fc.cbSize = sizeof(FILECHANGEINFO);
2414                         fc.wEventId = SHCNE_UPDATEITEM;
2415                         fc.uFlags = SHCNF_PATH;
2416                         fc.dwItem1 = (DWORD)fpn;
2417                         fc.dwItem2 = 0;
2418                         fc.dwAttributes = attribs;
2419                         yfsd_U32sToWinFileTime(mtime,&fc.ftModified);
2420                         fc.nFileSize = objSize;
2421
2422                         vol->shellFunction(&fc);
2423                         RETAILMSG (MSGSTATE, (L"YAFFS::shell function called\r\n"));
2424                         //yfsd_ShellDirectoryChanged(vol,fpn);
2425         }
2426
2427         
2428
2429         RETAILMSG (MSGSTATE, (L"YAFFS::CloseFile done\r\n"));
2430
2431         return TRUE;
2432
2433 }
2434
2435
2436 BOOL YFSD_CloseVolume(PVOLUME pVolume )
2437 {
2438         RETAILMSG (MSGSTATE, (L"YAFFS::CloseVolume\r\n"));
2439         yfsd_FlushAllFiles();
2440         return TRUE;
2441 }
2442