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