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