Change a few tests
[yaffs2.git] / direct / yaffsfs.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2007 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 #include "yaffsfs.h"
15 #include "yaffs_guts.h"
16 #include "yaffscfg.h"
17 #include <string.h> // for memset
18 #include "yportenv.h"
19
20 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
21
22 #ifndef NULL
23 #define NULL ((void *)0)
24 #endif
25
26
27 const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.22 2008-08-19 23:14:22 charles Exp $";
28
29 // configurationList is the list of devices that are supported
30 static yaffsfs_DeviceConfiguration *yaffsfs_configurationList;
31
32
33 /* Some forward references */
34 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const YCHAR *path, int symDepth);
35 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj);
36
37
38 // Handle management.
39 //
40
41
42 unsigned int yaffs_wr_attempts;
43
44 typedef struct
45 {
46         __u8  inUse:1;          // this handle is in use
47         __u8  readOnly:1;       // this handle is read only
48         __u8  append:1;         // append only
49         __u8  exclusive:1;      // exclusive
50         __u32 position;         // current position in file
51         yaffs_Object *obj;      // the object
52 }yaffsfs_Handle;
53
54
55 static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
56
57 // yaffsfs_InitHandle
58 /// Inilitalise handles on start-up.
59 //
60 static int yaffsfs_InitHandles(void)
61 {
62         int i;
63         for(i = 0; i < YAFFSFS_N_HANDLES; i++)
64         {
65                 yaffsfs_handle[i].inUse = 0;
66                 yaffsfs_handle[i].obj = NULL;
67         }
68         return 0;
69 }
70
71 yaffsfs_Handle *yaffsfs_GetHandlePointer(int h)
72 {
73         if(h < 0 || h >= YAFFSFS_N_HANDLES)
74         {
75                 return NULL;
76         }
77
78         return &yaffsfs_handle[h];
79 }
80
81 yaffs_Object *yaffsfs_GetHandleObject(int handle)
82 {
83         yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
84
85         if(h && h->inUse)
86         {
87                 return h->obj;
88         }
89
90         return NULL;
91 }
92
93
94 //yaffsfs_GetHandle
95 // Grab a handle (when opening a file)
96 //
97
98 static int yaffsfs_GetHandle(void)
99 {
100         int i;
101         yaffsfs_Handle *h;
102
103         for(i = 0; i < YAFFSFS_N_HANDLES; i++)
104         {
105                 h = yaffsfs_GetHandlePointer(i);
106                 if(!h)
107                 {
108                         // todo bug: should never happen
109                 }
110                 if(!h->inUse)
111                 {
112                         memset(h,0,sizeof(yaffsfs_Handle));
113                         h->inUse=1;
114                         return i;
115                 }
116         }
117         return -1;
118 }
119
120 // yaffs_PutHandle
121 // Let go of a handle (when closing a file)
122 //
123 static int yaffsfs_PutHandle(int handle)
124 {
125         yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
126
127         if(h)
128         {
129                 h->inUse = 0;
130                 h->obj = NULL;
131         }
132         return 0;
133 }
134
135
136
137 // Stuff to search for a directory from a path
138
139
140 int yaffsfs_Match(YCHAR a, YCHAR b)
141 {
142         // case sensitive
143         return (a == b);
144 }
145
146 int yaffsfs_IsPathDivider(YCHAR ch)
147 {
148         YCHAR *str = YAFFS_PATH_DIVIDERS;
149
150         while(*str){
151                 if(*str == ch)
152                         return 1;
153                 str++;
154         }
155
156         return 0;
157 }
158
159 // yaffsfs_FindDevice
160 // yaffsfs_FindRoot
161 // Scan the configuration list to find the root.
162 // Curveballs: Should match paths that end in '/' too
163 // Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
164 static yaffs_Device *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
165 {
166         yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
167         const YCHAR *leftOver;
168         const YCHAR *p;
169         yaffs_Device *retval = NULL;
170         int thisMatchLength;
171         int longestMatch = -1;
172         int matching;
173
174         // Check all configs, choose the one that:
175         // 1) Actually matches a prefix (ie /a amd /abc will not match
176         // 2) Matches the longest.
177         while(cfg && cfg->prefix && cfg->dev)
178         {
179                 leftOver = path;
180                 p = cfg->prefix;
181                 thisMatchLength = 0;
182                 matching = 1;
183
184
185                 while(matching && *p && *leftOver){
186                         // Skip over any /s
187                         while(yaffsfs_IsPathDivider(*p))
188                               p++;
189
190                         // Skip over any /s
191                         while(yaffsfs_IsPathDivider(*leftOver))
192                               leftOver++;
193
194                         // Now match the text part
195                         while(matching &&
196                               *p && !yaffsfs_IsPathDivider(*p) &&
197                               *leftOver && !yaffsfs_IsPathDivider(*leftOver)){
198                                 if(yaffsfs_Match(*p,*leftOver)){
199                                         p++;
200                                         leftOver++;
201                                         thisMatchLength++;
202                                 } else {
203                                         matching = 0;
204                                 }
205                         }
206                 }
207
208                 // Skip over any /s in leftOver
209                 while(yaffsfs_IsPathDivider(*leftOver))
210                       leftOver++;
211                 
212
213                 if( matching && (thisMatchLength > longestMatch))
214                 {
215                         // Matched prefix
216                         *restOfPath = (YCHAR *)leftOver;
217                         retval = cfg->dev;
218                         longestMatch = thisMatchLength;
219                 }
220
221                 cfg++;
222         }
223         return retval;
224 }
225
226 #if 0
227 static yaffs_Device *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
228 {
229         yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
230         const YCHAR *leftOver;
231         const YCHAR *p;
232         yaffs_Device *retval = NULL;
233         int thisMatchLength;
234         int longestMatch = -1;
235
236         // Check all configs, choose the one that:
237         // 1) Actually matches a prefix (ie /a amd /abc will not match
238         // 2) Matches the longest.
239         while(cfg && cfg->prefix && cfg->dev)
240         {
241                 leftOver = path;
242                 p = cfg->prefix;
243                 thisMatchLength = 0;
244
245                 while(*p &&  //unmatched part of prefix
246                       !(yaffsfs_IsPathDivider(*p) && (p[1] == 0)) && // the rest of the prefix is not / (to catch / at end)
247                       *leftOver &&
248                       yaffsfs_Match(*p,*leftOver))
249                 {
250                         p++;
251                         leftOver++;
252                         thisMatchLength++;
253                 }
254
255
256                 if((!*p || (yaffsfs_IsPathDivider(*p) && (p[1] == 0))) &&      // end of prefix
257                    (!*leftOver || yaffsfs_IsPathDivider(*leftOver)) && // no more in this path name part
258                    (thisMatchLength > longestMatch))
259                 {
260                         // Matched prefix
261                         *restOfPath = (YCHAR *)leftOver;
262                         retval = cfg->dev;
263                         longestMatch = thisMatchLength;
264                 }
265                 cfg++;
266         }
267         return retval;
268 }
269 #endif
270
271 static yaffs_Object *yaffsfs_FindRoot(const YCHAR *path, YCHAR **restOfPath)
272 {
273
274         yaffs_Device *dev;
275
276         dev= yaffsfs_FindDevice(path,restOfPath);
277         if(dev && dev->isMounted)
278         {
279                 return dev->rootDir;
280         }
281         return NULL;
282 }
283
284 static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth)
285 {
286
287         while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
288         {
289                 YCHAR *alias = obj->variant.symLinkVariant.alias;
290
291                 if(yaffsfs_IsPathDivider(*alias))
292                 {
293                         // Starts with a /, need to scan from root up
294                         obj = yaffsfs_FindObject(NULL,alias,symDepth++);
295                 }
296                 else
297                 {
298                         // Relative to here, so use the parent of the symlink as a start
299                         obj = yaffsfs_FindObject(obj->parent,alias,symDepth++);
300                 }
301         }
302         return obj;
303 }
304
305
306 // yaffsfs_FindDirectory
307 // Parse a path to determine the directory and the name within the directory.
308 //
309 // eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
310 static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,const YCHAR *path,YCHAR **name,int symDepth)
311 {
312         yaffs_Object *dir;
313         YCHAR *restOfPath;
314         YCHAR str[YAFFS_MAX_NAME_LENGTH+1];
315         int i;
316
317         if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES)
318         {
319                 return NULL;
320         }
321
322         if(startDir)
323         {
324                 dir = startDir;
325                 restOfPath = (YCHAR *)path;
326         }
327         else
328         {
329                 dir = yaffsfs_FindRoot(path,&restOfPath);
330         }
331
332         while(dir)
333         {
334                 // parse off /.
335                 // curve ball: also throw away surplus '/'
336                 // eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
337                 while(yaffsfs_IsPathDivider(*restOfPath))
338                 {
339                         restOfPath++; // get rid of '/'
340                 }
341
342                 *name = restOfPath;
343                 i = 0;
344
345                 while(*restOfPath && !yaffsfs_IsPathDivider(*restOfPath))
346                 {
347                         if (i < YAFFS_MAX_NAME_LENGTH)
348                         {
349                                 str[i] = *restOfPath;
350                                 str[i+1] = '\0';
351                                 i++;
352                         }
353                         restOfPath++;
354                 }
355
356                 if(!*restOfPath)
357                 {
358                         // got to the end of the string
359                         return dir;
360                 }
361                 else
362                 {
363                         if(yaffs_strcmp(str,_Y(".")) == 0)
364                         {
365                                 // Do nothing
366                         }
367                         else if(yaffs_strcmp(str,_Y("..")) == 0)
368                         {
369                                 dir = dir->parent;
370                         }
371                         else
372                         {
373                                 dir = yaffs_FindObjectByName(dir,str);
374
375                                 while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
376                                 {
377
378                                         dir = yaffsfs_FollowLink(dir,symDepth);
379
380                                 }
381
382                                 if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
383                                 {
384                                         dir = NULL;
385                                 }
386                         }
387                 }
388         }
389         // directory did not exist.
390         return NULL;
391 }
392
393 static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,const YCHAR *path,YCHAR **name,int symDepth)
394 {
395         return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);
396 }
397
398 // yaffsfs_FindObject turns a path for an existing object into the object
399 //
400 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const YCHAR *path,int symDepth)
401 {
402         yaffs_Object *dir;
403         YCHAR *name;
404
405         dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth);
406
407         if(dir && *name)
408         {
409                 return yaffs_FindObjectByName(dir,name);
410         }
411
412         return dir;
413 }
414
415
416 int yaffs_dup(int fd)
417 {
418         int newHandle = -1;
419         yaffsfs_Handle *oldPtr = NULL;
420         yaffsfs_Handle *newPtr = NULL;
421
422         yaffsfs_Lock();
423
424         oldPtr = yaffsfs_GetHandlePointer(fd);
425         if(oldPtr && oldPtr->inUse)
426                 newHandle = yaffsfs_GetHandle();
427         if(newHandle >= 0)
428                 newPtr = yaffsfs_GetHandlePointer(newHandle);
429
430         if(newPtr){
431                 *newPtr = *oldPtr;
432                 return newHandle;
433         }
434
435         if(!oldPtr)
436                 yaffsfs_SetError(-EBADF);
437         else
438                 yaffsfs_SetError(-ENOMEM);
439
440         return -1;
441
442 }
443
444 int yaffs_open(const YCHAR *path, int oflag, int mode)
445 {
446         yaffs_Object *obj = NULL;
447         yaffs_Object *dir = NULL;
448         YCHAR *name;
449         int handle = -1;
450         yaffsfs_Handle *h = NULL;
451         int alreadyOpen = 0;
452         int alreadyExclusive = 0;
453         int openDenied = 0;
454         int symDepth = 0;
455         int errorReported = 0;
456
457         int i;
458
459
460         // todo sanity check oflag (eg. can't have O_TRUNC without WRONLY or RDWR
461
462
463         yaffsfs_Lock();
464
465         handle = yaffsfs_GetHandle();
466
467         if(handle >= 0)
468         {
469
470                 h = yaffsfs_GetHandlePointer(handle);
471
472
473                 // try to find the exisiting object
474                 obj = yaffsfs_FindObject(NULL,path,0);
475
476                 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
477                 {
478
479                         obj = yaffsfs_FollowLink(obj,symDepth++);
480                 }
481
482                 if(obj && obj->variantType != YAFFS_OBJECT_TYPE_FILE)
483                 {
484                         obj = NULL;
485                 }
486
487                 if(obj)
488                 {
489                         // Check if the object is already in use
490                         alreadyOpen = alreadyExclusive = 0;
491
492                         for(i = 0; i <= YAFFSFS_N_HANDLES; i++)
493                         {
494
495                                 if(i != handle &&
496                                    yaffsfs_handle[i].inUse &&
497                                     obj == yaffsfs_handle[i].obj)
498                                  {
499                                         alreadyOpen = 1;
500                                         if(yaffsfs_handle[i].exclusive)
501                                         {
502                                                 alreadyExclusive = 1;
503                                         }
504                                  }
505                         }
506
507                         if(((oflag & O_EXCL) && alreadyOpen) || alreadyExclusive)
508                         {
509                                 openDenied = 1;
510                         }
511
512                         // Open should fail if O_CREAT and O_EXCL are specified
513                         if((oflag & O_EXCL) && (oflag & O_CREAT))
514                         {
515                                 openDenied = 1;
516                                 yaffsfs_SetError(-EEXIST);
517                                 errorReported = 1;
518                         }
519
520                         // Check file permissions
521                         if( (oflag & (O_RDWR | O_WRONLY)) == 0 &&     // ie O_RDONLY
522                            !(obj->yst_mode & S_IREAD))
523                         {
524                                 openDenied = 1;
525                         }
526
527                         if( (oflag & O_RDWR) &&
528                            !(obj->yst_mode & S_IREAD))
529                         {
530                                 openDenied = 1;
531                         }
532
533                         if( (oflag & (O_RDWR | O_WRONLY)) &&
534                            !(obj->yst_mode & S_IWRITE))
535                         {
536                                 openDenied = 1;
537                         }
538
539                 }
540
541                 else if((oflag & O_CREAT))
542                 {
543                         // Let's see if we can create this file
544                         dir = yaffsfs_FindDirectory(NULL,path,&name,0);
545                         if(dir)
546                         {
547                                 obj = yaffs_MknodFile(dir,name,mode,0,0);
548                         }
549                         else
550                         {
551                                 yaffsfs_SetError(-ENOTDIR);
552                                 errorReported = 1;
553                         }
554                 }
555
556                 if(obj && !openDenied)
557                 {
558                         h->obj = obj;
559                         h->inUse = 1;
560                 h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1;
561                         h->append =  (oflag & O_APPEND) ? 1 : 0;
562                         h->exclusive = (oflag & O_EXCL) ? 1 : 0;
563                         h->position = 0;
564
565                         obj->inUse++;
566                         if((oflag & O_TRUNC) && !h->readOnly)
567                         {
568                                 yaffs_ResizeFile(obj,0);
569                         }
570
571                 }
572                 else
573                 {
574                         yaffsfs_PutHandle(handle);
575                         if(!errorReported)
576                         {
577                                 yaffsfs_SetError(-EACCES);
578                                 errorReported = 1;
579                         }
580                         handle = -1;
581                 }
582
583         }
584
585         yaffsfs_Unlock();
586
587         return handle;
588 }
589
590 int yaffs_flush(int fd)
591 {
592         yaffsfs_Handle *h = NULL;
593         int retVal = 0;
594
595         yaffsfs_Lock();
596
597         h = yaffsfs_GetHandlePointer(fd);
598
599         if(h && h->inUse)
600         {
601                 // flush the file
602                 yaffs_FlushFile(h->obj,1);
603         }
604         else
605         {
606                 // bad handle
607                 yaffsfs_SetError(-EBADF);
608                 retVal = -1;
609         }
610
611         yaffsfs_Unlock();
612
613         return retVal;
614 }
615
616
617 int yaffs_close(int fd)
618 {
619         yaffsfs_Handle *h = NULL;
620         int retVal = 0;
621
622         yaffsfs_Lock();
623
624         h = yaffsfs_GetHandlePointer(fd);
625
626         if(h && h->inUse)
627         {
628                 // clean up
629                 yaffs_FlushFile(h->obj,1);
630                 h->obj->inUse--;
631                 if(h->obj->inUse <= 0 && h->obj->unlinked)
632                 {
633                         yaffs_DeleteFile(h->obj);
634                 }
635                 yaffsfs_PutHandle(fd);
636                 retVal = 0;
637         }
638         else
639         {
640                 // bad handle
641                 yaffsfs_SetError(-EBADF);
642                 retVal = -1;
643         }
644
645         yaffsfs_Unlock();
646
647         return retVal;
648 }
649
650 int yaffs_read(int fd, void *buf, unsigned int nbyte)
651 {
652         yaffsfs_Handle *h = NULL;
653         yaffs_Object *obj = NULL;
654         int pos = 0;
655         int nRead = -1;
656         unsigned int maxRead;
657
658         yaffsfs_Lock();
659         h = yaffsfs_GetHandlePointer(fd);
660         obj = yaffsfs_GetHandleObject(fd);
661
662         if(!h || !obj)
663         {
664                 // bad handle
665                 yaffsfs_SetError(-EBADF);
666         }
667         else if( h && obj)
668         {
669                 pos=  h->position;
670                 if(yaffs_GetObjectFileLength(obj) > pos)
671                 {
672                         maxRead = yaffs_GetObjectFileLength(obj) - pos;
673                 }
674                 else
675                 {
676                         maxRead = 0;
677                 }
678
679                 if(nbyte > maxRead)
680                 {
681                         nbyte = maxRead;
682                 }
683
684
685                 if(nbyte > 0)
686                 {
687                         nRead = yaffs_ReadDataFromFile(obj,buf,pos,nbyte);
688                         if(nRead >= 0)
689                         {
690                                 h->position = pos + nRead;
691                         }
692                         else
693                         {
694                                 //todo error
695                         }
696                 }
697                 else
698                 {
699                         nRead = 0;
700                 }
701
702         }
703
704         yaffsfs_Unlock();
705
706
707         return (nRead >= 0) ? nRead : -1;
708
709 }
710
711 int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset)
712 {
713         yaffsfs_Handle *h = NULL;
714         yaffs_Object *obj = NULL;
715         int pos = 0;
716         int nRead = -1;
717         unsigned int maxRead;
718
719         yaffsfs_Lock();
720         h = yaffsfs_GetHandlePointer(fd);
721         obj = yaffsfs_GetHandleObject(fd);
722
723         if(!h || !obj)
724         {
725                 // bad handle
726                 yaffsfs_SetError(-EBADF);
727         }
728         else if( h && obj)
729         {
730                 pos= offset;
731                 if(yaffs_GetObjectFileLength(obj) > pos)
732                 {
733                         maxRead = yaffs_GetObjectFileLength(obj) - pos;
734                 }
735                 else
736                 {
737                         maxRead = 0;
738                 }
739
740                 if(nbyte > maxRead)
741                 {
742                         nbyte = maxRead;
743                 }
744
745
746                 if(nbyte > 0)
747                 {
748                         nRead = yaffs_ReadDataFromFile(obj,buf,pos,nbyte);
749                 }
750                 else
751                 {
752                         nRead = 0;
753                 }
754
755         }
756
757         yaffsfs_Unlock();
758
759
760         return (nRead >= 0) ? nRead : -1;
761
762 }
763
764 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
765 {
766         yaffsfs_Handle *h = NULL;
767         yaffs_Object *obj = NULL;
768         int pos = 0;
769         int nWritten = -1;
770         int writeThrough = 0;
771
772         yaffsfs_Lock();
773         h = yaffsfs_GetHandlePointer(fd);
774         obj = yaffsfs_GetHandleObject(fd);
775
776         if(!h || !obj)
777         {
778                 // bad handle
779                 yaffsfs_SetError(-EBADF);
780         }
781         else if( h && obj && h->readOnly)
782         {
783                 // todo error
784         }
785         else if( h && obj)
786         {
787                 if(h->append)
788                 {
789                         pos =  yaffs_GetObjectFileLength(obj);
790                 }
791                 else
792                 {
793                         pos = h->position;
794                 }
795
796                 nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte,writeThrough);
797
798                 if(nWritten >= 0)
799                 {
800                         h->position = pos + nWritten;
801                 }
802                 else
803                 {
804                         //todo error
805                 }
806
807         }
808
809         yaffsfs_Unlock();
810
811
812         return (nWritten >= 0) ? nWritten : -1;
813
814 }
815
816 int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset)
817 {
818         yaffsfs_Handle *h = NULL;
819         yaffs_Object *obj = NULL;
820         int pos = 0;
821         int nWritten = -1;
822         int writeThrough = 0;
823
824         yaffsfs_Lock();
825         h = yaffsfs_GetHandlePointer(fd);
826         obj = yaffsfs_GetHandleObject(fd);
827
828         if(!h || !obj)
829         {
830                 // bad handle
831                 yaffsfs_SetError(-EBADF);
832         }
833         else if( h && obj && h->readOnly)
834         {
835                 // todo error
836         }
837         else if( h && obj)
838         {
839                 pos = offset;
840
841                 nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte,writeThrough);
842
843                 if(nWritten < 0 || ((unsigned int)nWritten) < nbyte)
844                         yaffsfs_SetError(-ENOSPC);
845
846         }
847
848         yaffsfs_Unlock();
849
850
851         return (nWritten >= 0) ? nWritten : -1;
852
853 }
854
855
856 int yaffs_truncate(const YCHAR *path,off_t newSize)
857 {
858         yaffs_Object *obj = NULL;
859         int result = YAFFS_FAIL;
860
861         yaffsfs_Lock();
862
863         obj = yaffsfs_FindObject(NULL,path,0);
864         if(obj)
865                 obj = yaffs_GetEquivalentObject(obj);
866
867         if(!obj)
868         {
869                 yaffsfs_SetError(-ENOENT);
870         }
871         else if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
872         {
873                 yaffsfs_SetError(-EISDIR);
874         }
875         else
876         {
877                 result = yaffs_ResizeFile(obj,newSize);
878         }
879
880         yaffsfs_Unlock();
881
882
883         return (result) ? 0 : -1;
884 }
885
886 int yaffs_ftruncate(int fd, off_t newSize)
887 {
888         yaffsfs_Handle *h = NULL;
889         yaffs_Object *obj = NULL;
890         int result = 0;
891
892         yaffsfs_Lock();
893         h = yaffsfs_GetHandlePointer(fd);
894         obj = yaffsfs_GetHandleObject(fd);
895
896         if(!h || !obj)
897         {
898                 // bad handle
899                 yaffsfs_SetError(-EBADF);
900         }
901         else
902         {
903                 // resize the file
904                 result = yaffs_ResizeFile(obj,newSize);
905         }
906         yaffsfs_Unlock();
907
908
909         return (result) ? 0 : -1;
910
911 }
912
913 off_t yaffs_lseek(int fd, off_t offset, int whence)
914 {
915         yaffsfs_Handle *h = NULL;
916         yaffs_Object *obj = NULL;
917         int pos = -1;
918         int fSize = -1;
919
920         yaffsfs_Lock();
921         h = yaffsfs_GetHandlePointer(fd);
922         obj = yaffsfs_GetHandleObject(fd);
923
924         if(!h || !obj)
925         {
926                 // bad handle
927                 yaffsfs_SetError(-EBADF);
928         }
929         else if(whence == SEEK_SET)
930         {
931                 if(offset >= 0)
932                 {
933                         pos = offset;
934                 }
935         }
936         else if(whence == SEEK_CUR)
937         {
938                 if( (h->position + offset) >= 0)
939                 {
940                         pos = (h->position + offset);
941                 }
942         }
943         else if(whence == SEEK_END)
944         {
945                 fSize = yaffs_GetObjectFileLength(obj);
946                 if(fSize >= 0 && (fSize + offset) >= 0)
947                 {
948                         pos = fSize + offset;
949                 }
950         }
951
952         if(pos >= 0)
953         {
954                 h->position = pos;
955         }
956         else
957         {
958                 // todo error
959         }
960
961
962         yaffsfs_Unlock();
963
964         return pos;
965 }
966
967
968 int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
969 {
970         yaffs_Object *dir = NULL;
971         yaffs_Object *obj = NULL;
972         YCHAR *name;
973         int result = YAFFS_FAIL;
974
975         yaffsfs_Lock();
976
977         obj = yaffsfs_FindObject(NULL,path,0);
978         dir = yaffsfs_FindDirectory(NULL,path,&name,0);
979         if(!dir)
980         {
981                 yaffsfs_SetError(-ENOTDIR);
982         }
983         else if(!obj)
984         {
985                 yaffsfs_SetError(-ENOENT);
986         }
987         else if(!isDirectory && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
988         {
989                 yaffsfs_SetError(-EISDIR);
990         }
991         else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
992         {
993                 yaffsfs_SetError(-ENOTDIR);
994         }
995         else
996         {
997                 result = yaffs_Unlink(dir,name);
998
999                 if(result == YAFFS_FAIL && isDirectory)
1000                 {
1001                         yaffsfs_SetError(-ENOTEMPTY);
1002                 }
1003         }
1004
1005         yaffsfs_Unlock();
1006
1007         // todo error
1008
1009         return (result == YAFFS_FAIL) ? -1 : 0;
1010 }
1011
1012
1013 int yaffs_rmdir(const YCHAR *path)
1014 {
1015         return yaffsfs_DoUnlink(path,1);
1016 }
1017
1018 int yaffs_unlink(const YCHAR *path)
1019 {
1020         return yaffsfs_DoUnlink(path,0);
1021 }
1022
1023 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1024 {
1025         yaffs_Object *olddir = NULL;
1026         yaffs_Object *newdir = NULL;
1027         yaffs_Object *obj = NULL;
1028         YCHAR *oldname;
1029         YCHAR *newname;
1030         int result= YAFFS_FAIL;
1031         int renameAllowed = 1;
1032
1033         yaffsfs_Lock();
1034
1035         olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
1036         newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
1037         obj = yaffsfs_FindObject(NULL,oldPath,0);
1038
1039         if(!olddir || !newdir || !obj)
1040         {
1041                 // bad file
1042                 yaffsfs_SetError(-EBADF);
1043                 renameAllowed = 0;
1044         }
1045         else if(olddir->myDev != newdir->myDev)
1046         {
1047                 // oops must be on same device
1048                 // todo error
1049                 yaffsfs_SetError(-EXDEV);
1050                 renameAllowed = 0;
1051         }
1052         else if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1053         {
1054                 // It is a directory, check that it is not being renamed to
1055                 // being its own decendent.
1056                 // Do this by tracing from the new directory back to the root, checking for obj
1057
1058                 yaffs_Object *xx = newdir;
1059
1060                 while( renameAllowed && xx)
1061                 {
1062                         if(xx == obj)
1063                         {
1064                                 renameAllowed = 0;
1065                         }
1066                         xx = xx->parent;
1067                 }
1068                 if(!renameAllowed) yaffsfs_SetError(-EACCES);
1069         }
1070
1071         if(renameAllowed)
1072         {
1073                 result = yaffs_RenameObject(olddir,oldname,newdir,newname);
1074         }
1075
1076         yaffsfs_Unlock();
1077
1078         return (result == YAFFS_FAIL) ? -1 : 0;
1079 }
1080
1081
1082 static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf)
1083 {
1084         int retVal = -1;
1085
1086         if(obj)
1087         {
1088                 obj = yaffs_GetEquivalentObject(obj);
1089         }
1090
1091         if(obj && buf)
1092         {
1093         buf->st_dev = (int)obj->myDev->genericDevice;
1094         buf->st_ino = obj->objectId;
1095         buf->st_mode = obj->yst_mode & ~S_IFMT; // clear out file type bits
1096
1097                 if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1098                 {
1099                         buf->st_mode |= S_IFDIR;
1100                 }
1101                 else if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
1102                 {
1103                         buf->st_mode |= S_IFLNK;
1104                 }
1105                 else if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
1106                 {
1107                         buf->st_mode |= S_IFREG;
1108                 }
1109
1110         buf->st_nlink = yaffs_GetObjectLinkCount(obj);
1111         buf->st_uid = 0;
1112         buf->st_gid = 0;;
1113         buf->st_rdev = obj->yst_rdev;
1114         buf->st_size = yaffs_GetObjectFileLength(obj);
1115                 buf->st_blksize = obj->myDev->nDataBytesPerChunk;
1116         buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
1117 #if CONFIG_YAFFS_WINCE
1118                 buf->yst_wince_atime[0] = obj->win_atime[0];
1119                 buf->yst_wince_atime[1] = obj->win_atime[1];
1120                 buf->yst_wince_ctime[0] = obj->win_ctime[0];
1121                 buf->yst_wince_ctime[1] = obj->win_ctime[1];
1122                 buf->yst_wince_mtime[0] = obj->win_mtime[0];
1123                 buf->yst_wince_mtime[1] = obj->win_mtime[1];
1124 #else
1125         buf->yst_atime = obj->yst_atime;
1126         buf->yst_ctime = obj->yst_ctime;
1127         buf->yst_mtime = obj->yst_mtime;
1128 #endif
1129                 retVal = 0;
1130         }
1131         return retVal;
1132 }
1133
1134 static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
1135 {
1136         yaffs_Object *obj;
1137
1138         int retVal = -1;
1139
1140         yaffsfs_Lock();
1141         obj = yaffsfs_FindObject(NULL,path,0);
1142
1143         if(!doLStat && obj)
1144         {
1145                 obj = yaffsfs_FollowLink(obj,0);
1146         }
1147
1148         if(obj)
1149         {
1150                 retVal = yaffsfs_DoStat(obj,buf);
1151         }
1152         else
1153         {
1154                 // todo error not found
1155                 yaffsfs_SetError(-ENOENT);
1156         }
1157
1158         yaffsfs_Unlock();
1159
1160         return retVal;
1161
1162 }
1163
1164 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1165 {
1166         return yaffsfs_DoStatOrLStat(path,buf,0);
1167 }
1168
1169 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1170 {
1171         return yaffsfs_DoStatOrLStat(path,buf,1);
1172 }
1173
1174 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1175 {
1176         yaffs_Object *obj;
1177
1178         int retVal = -1;
1179
1180         yaffsfs_Lock();
1181         obj = yaffsfs_GetHandleObject(fd);
1182
1183         if(obj)
1184         {
1185                 retVal = yaffsfs_DoStat(obj,buf);
1186         }
1187         else
1188         {
1189                 // bad handle
1190                 yaffsfs_SetError(-EBADF);
1191         }
1192
1193         yaffsfs_Unlock();
1194
1195         return retVal;
1196 }
1197
1198 #ifdef CONFIG_YAFFS_WINCE
1199 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1200 {
1201         yaffs_Object *obj;
1202
1203         int retVal = -1;
1204
1205         yaffsfs_Lock();
1206         obj = yaffsfs_GetHandleObject(fd);
1207
1208         if(obj)
1209         {
1210
1211                 if(wctime){
1212                         wctime[0] = obj->win_ctime[0];
1213                         wctime[1] = obj->win_ctime[1];
1214                 }
1215                 if(watime){
1216                         watime[0] = obj->win_atime[0];
1217                         watime[1] = obj->win_atime[1];
1218                 }
1219                 if(wmtime){
1220                         wmtime[0] = obj->win_mtime[0];
1221                         wmtime[1] = obj->win_mtime[1];
1222                 }
1223
1224
1225                 retVal = 0;
1226         }
1227         else
1228         {
1229                 // bad handle
1230                 yaffsfs_SetError(-EBADF);               
1231         }
1232         
1233         yaffsfs_Unlock();
1234         
1235         return retVal;
1236 }
1237
1238
1239 int yaffs_set_wince_times(int fd, 
1240                                                   const unsigned *wctime, 
1241                                                   const unsigned *watime, 
1242                                                   const unsigned *wmtime)
1243 {
1244         yaffs_Object *obj;
1245         int result;
1246         int retVal = -1;
1247
1248         yaffsfs_Lock();
1249         obj = yaffsfs_GetHandleObject(fd);
1250
1251         if(obj)
1252         {
1253
1254                 if(wctime){
1255                         obj->win_ctime[0] = wctime[0];
1256                         obj->win_ctime[1] = wctime[1];
1257                 }
1258                 if(watime){
1259                         obj->win_atime[0] = watime[0];
1260                         obj->win_atime[1] = watime[1];
1261                 }
1262                 if(wmtime){
1263                         obj->win_mtime[0] = wmtime[0];
1264                         obj->win_mtime[1] = wmtime[1];
1265                 }
1266
1267                 obj->dirty = 1;
1268                 result = yaffs_FlushFile(obj,0);
1269                 retVal = 0;
1270         }
1271         else
1272         {
1273                 // bad handle
1274                 yaffsfs_SetError(-EBADF);
1275         }
1276
1277         yaffsfs_Unlock();
1278
1279         return retVal;
1280 }
1281
1282 #endif
1283
1284
1285 static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode)
1286 {
1287         int result;
1288
1289         if(obj)
1290         {
1291                 obj = yaffs_GetEquivalentObject(obj);
1292         }
1293
1294         if(obj)
1295         {
1296                 obj->yst_mode = mode;
1297                 obj->dirty = 1;
1298                 result = yaffs_FlushFile(obj,0);
1299         }
1300
1301         return result == YAFFS_OK ? 0 : -1;
1302 }
1303
1304
1305 int yaffs_access(const YCHAR *path, int amode)
1306 {
1307         yaffs_Object *obj;
1308
1309         int retval = 0;
1310
1311         yaffsfs_Lock();
1312         obj = yaffsfs_FindObject(NULL,path,0);
1313
1314         if(obj)
1315         {
1316                 int access_ok = 1;
1317
1318                 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1319                         access_ok = 0;
1320                 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1321                         access_ok = 0;
1322                 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1323                         access_ok = 0;
1324
1325                 if(!access_ok) {
1326                         yaffsfs_SetError(-EACCES);
1327                         retval = -1;
1328                 }
1329         }
1330         else
1331         {
1332                 // todo error not found
1333                 yaffsfs_SetError(-ENOENT);
1334                 retval = -1;
1335         }
1336
1337         yaffsfs_Unlock();
1338
1339         return retval;
1340
1341 }
1342
1343
1344 int yaffs_chmod(const YCHAR *path, mode_t mode)
1345 {
1346         yaffs_Object *obj;
1347
1348         int retVal = -1;
1349
1350         yaffsfs_Lock();
1351         obj = yaffsfs_FindObject(NULL,path,0);
1352
1353         if(obj)
1354         {
1355                 retVal = yaffsfs_DoChMod(obj,mode);
1356         }
1357         else
1358         {
1359                 // todo error not found
1360                 yaffsfs_SetError(-ENOENT);
1361         }
1362
1363         yaffsfs_Unlock();
1364
1365         return retVal;
1366
1367 }
1368
1369
1370 int yaffs_fchmod(int fd, mode_t mode)
1371 {
1372         yaffs_Object *obj;
1373
1374         int retVal = -1;
1375
1376         yaffsfs_Lock();
1377         obj = yaffsfs_GetHandleObject(fd);
1378
1379         if(obj)
1380         {
1381                 retVal = yaffsfs_DoChMod(obj,mode);
1382         }
1383         else
1384         {
1385                 // bad handle
1386                 yaffsfs_SetError(-EBADF);
1387         }
1388
1389         yaffsfs_Unlock();
1390
1391         return retVal;
1392 }
1393
1394
1395 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1396 {
1397         yaffs_Object *parent = NULL;
1398         yaffs_Object *dir = NULL;
1399         YCHAR *name;
1400         int retVal= -1;
1401
1402         yaffsfs_Lock();
1403         parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1404         if(parent)
1405                 dir = yaffs_MknodDirectory(parent,name,mode,0,0);
1406         if(dir)
1407         {
1408                 retVal = 0;
1409         }
1410         else
1411         {
1412                 if(!parent){
1413                         yaffsfs_SetError(-ENOENT); // missing path
1414                 }
1415                 else if (yaffs_FindObjectByName(parent,name)){
1416                         yaffsfs_SetError(-EEXIST); // the name already exists
1417                 }
1418                 else
1419                         yaffsfs_SetError(-ENOSPC); // just assume no space
1420                 retVal = -1;
1421         }
1422
1423         yaffsfs_Unlock();
1424
1425         return retVal;
1426 }
1427
1428 int yaffs_mount(const YCHAR *path)
1429 {
1430         int retVal=-1;
1431         int result=YAFFS_FAIL;
1432         yaffs_Device *dev=NULL;
1433         YCHAR *dummy;
1434
1435         T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Mounting %s" TENDSTR),path));
1436
1437         yaffsfs_Lock();
1438         dev = yaffsfs_FindDevice(path,&dummy);
1439         if(dev)
1440         {
1441                 if(!dev->isMounted)
1442                 {
1443                         result = yaffs_GutsInitialise(dev);
1444                         if(result == YAFFS_FAIL)
1445                         {
1446                                 // todo error - mount failed
1447                                 yaffsfs_SetError(-ENOMEM);
1448                         }
1449                         retVal = result ? 0 : -1;
1450
1451                 }
1452                 else
1453                 {
1454                         //todo error - already mounted.
1455                         yaffsfs_SetError(-EBUSY);
1456                 }
1457         }
1458         else
1459         {
1460                 // todo error - no device
1461                 yaffsfs_SetError(-ENODEV);
1462         }
1463         yaffsfs_Unlock();
1464         return retVal;
1465
1466 }
1467
1468 int yaffs_sync(const YCHAR *path)
1469 {
1470         int retVal=-1;
1471         yaffs_Device *dev=NULL;
1472         YCHAR *dummy;
1473         
1474         yaffsfs_Lock();
1475         dev = yaffsfs_FindDevice(path,&dummy);
1476         if(dev)
1477         {
1478                 if(dev->isMounted)
1479                 {
1480                         
1481                         yaffs_FlushEntireDeviceCache(dev);
1482                         yaffs_CheckpointSave(dev);
1483                         
1484                         
1485                 }
1486                 else
1487                 {
1488                         //todo error - not mounted.
1489                         yaffsfs_SetError(-EINVAL);
1490                         
1491                 }
1492         }
1493         else
1494         {
1495                 // todo error - no device
1496                 yaffsfs_SetError(-ENODEV);
1497         }       
1498         yaffsfs_Unlock();
1499         return retVal;  
1500 }
1501
1502
1503 int yaffs_unmount(const YCHAR *path)
1504 {
1505         int retVal=-1;
1506         yaffs_Device *dev=NULL;
1507         YCHAR *dummy;
1508
1509         yaffsfs_Lock();
1510         dev = yaffsfs_FindDevice(path,&dummy);
1511         if(dev)
1512         {
1513                 if(dev->isMounted)
1514                 {
1515                         int i;
1516                         int inUse;
1517
1518                         yaffs_FlushEntireDeviceCache(dev);
1519                         yaffs_CheckpointSave(dev);
1520
1521                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++)
1522                         {
1523                                 if(yaffsfs_handle[i].inUse && yaffsfs_handle[i].obj->myDev == dev)
1524                                 {
1525                                         inUse = 1; // the device is in use, can't unmount
1526                                 }
1527                         }
1528
1529                         if(!inUse)
1530                         {
1531                                 yaffs_Deinitialise(dev);
1532
1533                                 retVal = 0;
1534                         }
1535                         else
1536                         {
1537                                 // todo error can't unmount as files are open
1538                                 yaffsfs_SetError(-EBUSY);
1539                         }
1540
1541                 }
1542                 else
1543                 {
1544                         //todo error - not mounted.
1545                         yaffsfs_SetError(-EINVAL);
1546
1547                 }
1548         }
1549         else
1550         {
1551                 // todo error - no device
1552                 yaffsfs_SetError(-ENODEV);
1553         }
1554         yaffsfs_Unlock();
1555         return retVal;
1556
1557 }
1558
1559 loff_t yaffs_freespace(const YCHAR *path)
1560 {
1561         loff_t retVal=-1;
1562         yaffs_Device *dev=NULL;
1563         YCHAR *dummy;
1564
1565         yaffsfs_Lock();
1566         dev = yaffsfs_FindDevice(path,&dummy);
1567         if(dev  && dev->isMounted)
1568         {
1569                 retVal = yaffs_GetNumberOfFreeChunks(dev);
1570                 retVal *= dev->nDataBytesPerChunk;
1571
1572         }
1573         else
1574         {
1575                 yaffsfs_SetError(-EINVAL);
1576         }
1577
1578         yaffsfs_Unlock();
1579         return retVal;
1580 }
1581
1582 loff_t yaffs_totalspace(const YCHAR *path)
1583 {
1584         loff_t retVal=-1;
1585         yaffs_Device *dev=NULL;
1586         YCHAR *dummy;
1587
1588         yaffsfs_Lock();
1589         dev = yaffsfs_FindDevice(path,&dummy);
1590         if(dev  && dev->isMounted)
1591         {
1592                 retVal = (dev->endBlock - dev->startBlock + 1) - dev->nReservedBlocks;
1593                 retVal *= dev->nChunksPerBlock;
1594                 retVal *= dev->nDataBytesPerChunk;
1595
1596         }
1597         else
1598         {
1599                 yaffsfs_SetError(-EINVAL);
1600         }
1601
1602         yaffsfs_Unlock();
1603         return retVal;
1604 }
1605
1606 int yaffs_inodecount(const YCHAR *path)
1607 {
1608         loff_t retVal= -1;
1609         yaffs_Device *dev=NULL;
1610         YCHAR *dummy;
1611
1612         yaffsfs_Lock();
1613         dev = yaffsfs_FindDevice(path,&dummy);
1614         if(dev  && dev->isMounted) {
1615            int nObjects = dev->nObjectsCreated - dev->nFreeObjects;
1616            if(nObjects > dev->nHardLinks)
1617                 retVal = nObjects - dev->nHardLinks;
1618         }
1619         
1620         if(retVal < 0){
1621                 yaffsfs_SetError(-EINVAL);
1622         }
1623         
1624         yaffsfs_Unlock();
1625         return retVal;  
1626 }
1627
1628
1629
1630 void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList)
1631 {
1632
1633         yaffsfs_DeviceConfiguration *cfg;
1634
1635         yaffsfs_configurationList = cfgList;
1636
1637         yaffsfs_InitHandles();
1638
1639         cfg = yaffsfs_configurationList;
1640
1641         while(cfg && cfg->prefix && cfg->dev)
1642         {
1643                 cfg->dev->isMounted = 0;
1644                 cfg->dev->removeObjectCallback = yaffsfs_RemoveObjectCallback;
1645                 cfg++;
1646         }
1647
1648
1649 }
1650
1651
1652 //
1653 // Directory search stuff.
1654
1655 //
1656 // Directory search context
1657 //
1658 // NB this is an opaque structure.
1659
1660
1661 typedef struct
1662 {
1663         __u32 magic;
1664         yaffs_dirent de;                /* directory entry being used by this dsc */
1665         YCHAR name[NAME_MAX+1];         /* name of directory being searched */
1666         yaffs_Object *dirObj;           /* ptr to directory being searched */
1667         yaffs_Object *nextReturn;       /* obj to be returned by next readddir */
1668         int offset;
1669         struct ylist_head others;       
1670 } yaffsfs_DirectorySearchContext;
1671
1672
1673
1674 static struct ylist_head search_contexts;
1675
1676
1677 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
1678 {
1679         if(dsc &&
1680            dsc->dirObj &&
1681            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1682
1683            dsc->offset = 0;
1684
1685            if( ylist_empty(&dsc->dirObj->variant.directoryVariant.children)){
1686                 dsc->nextReturn = NULL;
1687            } else {
1688                 dsc->nextReturn = ylist_entry(dsc->dirObj->variant.directoryVariant.children.next,
1689                                                 yaffs_Object,siblings);
1690            }
1691         } else {
1692                 /* Hey someone isn't playing nice! */
1693         }
1694 }
1695
1696 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
1697 {
1698         if(dsc &&
1699            dsc->dirObj &&
1700            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1701
1702            if( dsc->nextReturn == NULL ||
1703                ylist_empty(&dsc->dirObj->variant.directoryVariant.children)){
1704                 dsc->nextReturn = NULL;
1705            } else {
1706                    struct ylist_head *next = dsc->nextReturn->siblings.next;
1707
1708                    if( next == &dsc->dirObj->variant.directoryVariant.children)
1709                         dsc->nextReturn = NULL; /* end of list */
1710                    else
1711                         dsc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
1712            }
1713         } else {
1714                 /* Hey someone isn't playing nice! */
1715         }
1716 }
1717
1718 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj)
1719 {
1720
1721         struct ylist_head *i;
1722         yaffsfs_DirectorySearchContext *dsc;
1723
1724         /* if search contexts not initilised then skip */
1725         if(!search_contexts.next)
1726                 return;
1727
1728         /* Iterate through the directory search contexts.
1729          * If any are the one being removed, then advance the dsc to
1730          * the next one to prevent a hanging ptr.
1731          */
1732          ylist_for_each(i, &search_contexts) {
1733                 if (i) {
1734                         dsc = ylist_entry(i, yaffsfs_DirectorySearchContext,others);
1735                         if(dsc->nextReturn == obj)
1736                                 yaffsfs_DirAdvance(dsc);
1737                 }
1738         }
1739
1740 }
1741
1742 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
1743 {
1744         yaffs_DIR *dir = NULL;
1745         yaffs_Object *obj = NULL;
1746         yaffsfs_DirectorySearchContext *dsc = NULL;
1747
1748         yaffsfs_Lock();
1749
1750         obj = yaffsfs_FindObject(NULL,dirname,0);
1751
1752         if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1753         {
1754
1755                 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
1756                 dir = (yaffs_DIR *)dsc;
1757                 if(dsc)
1758                 {
1759                         memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
1760                         dsc->magic = YAFFS_MAGIC;
1761                         dsc->dirObj = obj;
1762                         yaffs_strncpy(dsc->name,dirname,NAME_MAX);
1763                         YINIT_LIST_HEAD(&dsc->others);
1764
1765                         if(!search_contexts.next)
1766                                 YINIT_LIST_HEAD(&search_contexts);
1767
1768                         ylist_add(&dsc->others,&search_contexts);       
1769                         yaffsfs_SetDirRewound(dsc);             }
1770
1771         }
1772
1773         yaffsfs_Unlock();
1774
1775         return dir;
1776 }
1777
1778 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
1779 {
1780         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1781         struct yaffs_dirent *retVal = NULL;
1782
1783         yaffsfs_Lock();
1784
1785         if(dsc && dsc->magic == YAFFS_MAGIC){
1786                 yaffsfs_SetError(0);
1787                 if(dsc->nextReturn){
1788                         dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId;
1789                         dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
1790                         dsc->de.d_off = dsc->offset++;
1791                         yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
1792                         if(yaffs_strlen(dsc->de.d_name) == 0)
1793                         {
1794                                 // this should not happen!
1795                                 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
1796                         }
1797                         dsc->de.d_reclen = sizeof(struct yaffs_dirent);
1798                         retVal = &dsc->de;
1799                         yaffsfs_DirAdvance(dsc);
1800                 } else
1801                         retVal = NULL;
1802         }
1803         else
1804         {
1805                 yaffsfs_SetError(-EBADF);
1806         }
1807
1808         yaffsfs_Unlock();
1809
1810         return retVal;
1811
1812 }
1813
1814
1815 void yaffs_rewinddir(yaffs_DIR *dirp)
1816 {
1817         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1818
1819         yaffsfs_Lock();
1820
1821         yaffsfs_SetDirRewound(dsc);
1822
1823         yaffsfs_Unlock();
1824 }
1825
1826
1827 int yaffs_closedir(yaffs_DIR *dirp)
1828 {
1829         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1830
1831         yaffsfs_Lock();
1832         dsc->magic = 0;
1833         ylist_del(&dsc->others); /* unhook from list */
1834         YFREE(dsc);
1835         yaffsfs_Unlock();
1836         return 0;
1837 }
1838
1839 // end of directory stuff
1840
1841
1842 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
1843 {
1844         yaffs_Object *parent = NULL;
1845         yaffs_Object *obj;
1846         YCHAR *name;
1847         int retVal= -1;
1848         int mode = 0; // ignore for now
1849
1850         yaffsfs_Lock();
1851         parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
1852         obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath);
1853         if(obj)
1854         {
1855                 retVal = 0;
1856         }
1857         else
1858         {
1859                 yaffsfs_SetError(-ENOSPC); // just assume no space for now
1860                 retVal = -1;
1861         }
1862
1863         yaffsfs_Unlock();
1864
1865         return retVal;
1866
1867 }
1868
1869 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
1870 {
1871         yaffs_Object *obj = NULL;
1872         int retVal;
1873
1874
1875         yaffsfs_Lock();
1876
1877         obj = yaffsfs_FindObject(NULL,path,0);
1878
1879         if(!obj)
1880         {
1881                 yaffsfs_SetError(-ENOENT);
1882                 retVal = -1;
1883         }
1884         else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK)
1885         {
1886                 yaffsfs_SetError(-EINVAL);
1887                 retVal = -1;
1888         }
1889         else
1890         {
1891                 YCHAR *alias = obj->variant.symLinkVariant.alias;
1892                 memset(buf,0,bufsiz);
1893                 yaffs_strncpy(buf,alias,bufsiz - 1);
1894                 retVal = 0;
1895         }
1896         yaffsfs_Unlock();
1897         return retVal;
1898 }
1899
1900 int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath)
1901 {
1902         // Creates a link called newpath to existing oldpath
1903         yaffs_Object *obj = NULL;
1904         yaffs_Object *target = NULL;
1905         int retVal = 0;
1906
1907
1908         yaffsfs_Lock();
1909
1910         obj = yaffsfs_FindObject(NULL,oldpath,0);
1911         target = yaffsfs_FindObject(NULL,newpath,0);
1912
1913         if(!obj)
1914         {
1915                 yaffsfs_SetError(-ENOENT);
1916                 retVal = -1;
1917         }
1918         else if(target)
1919         {
1920                 yaffsfs_SetError(-EEXIST);
1921                 retVal = -1;
1922         }
1923         else
1924         {
1925                 yaffs_Object *newdir = NULL;
1926                 yaffs_Object *link = NULL;
1927
1928                 YCHAR *newname;
1929
1930                 newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
1931
1932                 if(!newdir)
1933                 {
1934                         yaffsfs_SetError(-ENOTDIR);
1935                         retVal = -1;
1936                 }
1937                 else if(newdir->myDev != obj->myDev)
1938                 {
1939                         yaffsfs_SetError(-EXDEV);
1940                         retVal = -1;
1941                 }
1942                 if(newdir && yaffs_strlen(newname) > 0)
1943                 {
1944                         link = yaffs_Link(newdir,newname,obj);
1945                         if(link)
1946                                 retVal = 0;
1947                         else
1948                         {
1949                                 yaffsfs_SetError(-ENOSPC);
1950                                 retVal = -1;
1951                         }
1952
1953                 }
1954         }
1955         yaffsfs_Unlock();
1956
1957         return retVal;
1958 }
1959
1960 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev);
1961
1962 int yaffs_DumpDevStruct(const YCHAR *path)
1963 {
1964 #if 0
1965         YCHAR *rest;
1966
1967         yaffs_Object *obj = yaffsfs_FindRoot(path,&rest);
1968
1969         if(obj)
1970         {
1971                 yaffs_Device *dev = obj->myDev;
1972
1973                 printf("\n"
1974                            "nPageWrites.......... %d\n"
1975                            "nPageReads........... %d\n"
1976                            "nBlockErasures....... %d\n"
1977                            "nGCCopies............ %d\n"
1978                            "garbageCollections... %d\n"
1979                            "passiveGarbageColl'ns %d\n"
1980                            "\n",
1981                                 dev->nPageWrites,
1982                                 dev->nPageReads,
1983                                 dev->nBlockErasures,
1984                                 dev->nGCCopies,
1985                                 dev->garbageCollections,
1986                                 dev->passiveGarbageCollections
1987                 );
1988
1989         }
1990
1991 #endif
1992         return 0;
1993 }
1994