Merge branch 'master' of /home/stefan/git/u-boot/u-boot into next
[pandora-u-boot.git] / fs / yaffs2 / 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 /* XXX U-BOOT XXX */
15 #include <common.h>
16 #include <malloc.h>
17
18 #include "yaffsfs.h"
19 #include "yaffs_guts.h"
20 #include "yaffscfg.h"
21 #include "yportenv.h"
22
23 /* XXX U-BOOT XXX */
24 #if 0
25 #include <string.h> // for memset
26 #endif
27
28 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
29
30 #ifndef NULL
31 #define NULL ((void *)0)
32 #endif
33
34
35 const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.18 2007/07/18 19:40:38 charles Exp $";
36
37 // configurationList is the list of devices that are supported
38 static yaffsfs_DeviceConfiguration *yaffsfs_configurationList;
39
40
41 /* Some forward references */
42 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth);
43 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj);
44
45
46 // Handle management.
47 // 
48
49
50 unsigned int yaffs_wr_attempts;
51
52 typedef struct
53 {
54         __u8  inUse:1;          // this handle is in use
55         __u8  readOnly:1;       // this handle is read only
56         __u8  append:1;         // append only
57         __u8  exclusive:1;      // exclusive
58         __u32 position;         // current position in file
59         yaffs_Object *obj;      // the object
60 }yaffsfs_Handle;
61
62
63 static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
64
65 // yaffsfs_InitHandle
66 /// Inilitalise handles on start-up.
67 //
68 static int yaffsfs_InitHandles(void)
69 {
70         int i;
71         for(i = 0; i < YAFFSFS_N_HANDLES; i++)
72         {
73                 yaffsfs_handle[i].inUse = 0;
74                 yaffsfs_handle[i].obj = NULL;
75         }
76         return 0;
77 }
78
79 yaffsfs_Handle *yaffsfs_GetHandlePointer(int h)
80 {
81         if(h < 0 || h >= YAFFSFS_N_HANDLES)
82         {
83                 return NULL;
84         }
85         
86         return &yaffsfs_handle[h];
87 }
88
89 yaffs_Object *yaffsfs_GetHandleObject(int handle)
90 {
91         yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
92
93         if(h && h->inUse)
94         {
95                 return h->obj;
96         }
97         
98         return NULL;
99 }
100
101
102 //yaffsfs_GetHandle
103 // Grab a handle (when opening a file)
104 //
105
106 static int yaffsfs_GetHandle(void)
107 {
108         int i;
109         yaffsfs_Handle *h;
110         
111         for(i = 0; i < YAFFSFS_N_HANDLES; i++)
112         {
113                 h = yaffsfs_GetHandlePointer(i);
114                 if(!h)
115                 {
116                         // todo bug: should never happen
117                 }
118                 if(!h->inUse)
119                 {
120                         memset(h,0,sizeof(yaffsfs_Handle));
121                         h->inUse=1;
122                         return i;
123                 }
124         }
125         return -1;
126 }
127
128 // yaffs_PutHandle
129 // Let go of a handle (when closing a file)
130 //
131 static int yaffsfs_PutHandle(int handle)
132 {
133         yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
134         
135         if(h)
136         {
137                 h->inUse = 0;
138                 h->obj = NULL;
139         }
140         return 0;
141 }
142
143
144
145 // Stuff to search for a directory from a path
146
147
148 int yaffsfs_Match(char a, char b)
149 {
150         // case sensitive
151         return (a == b);
152 }
153
154 // yaffsfs_FindDevice
155 // yaffsfs_FindRoot
156 // Scan the configuration list to find the root.
157 // Curveballs: Should match paths that end in '/' too
158 // Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
159 static yaffs_Device *yaffsfs_FindDevice(const char *path, char **restOfPath)
160 {
161         yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
162         const char *leftOver;
163         const char *p;
164         yaffs_Device *retval = NULL;
165         int thisMatchLength;
166         int longestMatch = -1;
167         
168         // Check all configs, choose the one that:
169         // 1) Actually matches a prefix (ie /a amd /abc will not match
170         // 2) Matches the longest.
171         while(cfg && cfg->prefix && cfg->dev)
172         {
173                 leftOver = path;
174                 p = cfg->prefix;
175                 thisMatchLength = 0;
176                 
177                 while(*p &&  //unmatched part of prefix 
178                       strcmp(p,"/") && // the rest of the prefix is not / (to catch / at end)
179                       *leftOver && 
180                       yaffsfs_Match(*p,*leftOver))
181                 {
182                         p++;
183                         leftOver++;
184                         thisMatchLength++;
185                 }
186                 if((!*p || strcmp(p,"/") == 0) &&      // end of prefix
187                    (!*leftOver || *leftOver == '/') && // no more in this path name part
188                    (thisMatchLength > longestMatch))
189                 {
190                         // Matched prefix
191                         *restOfPath = (char *)leftOver;
192                         retval = cfg->dev;
193                         longestMatch = thisMatchLength;
194                 }
195                 cfg++;
196         }
197         return retval;
198 }
199
200 static yaffs_Object *yaffsfs_FindRoot(const char *path, char **restOfPath)
201 {
202
203         yaffs_Device *dev;
204         
205         dev= yaffsfs_FindDevice(path,restOfPath);
206         if(dev && dev->isMounted)
207         {
208                 return dev->rootDir;
209         }
210         return NULL;
211 }
212
213 static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth)
214 {
215
216         while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
217         {
218                 char *alias = obj->variant.symLinkVariant.alias;
219                                                 
220                 if(*alias == '/')
221                 {
222                         // Starts with a /, need to scan from root up
223                         obj = yaffsfs_FindObject(NULL,alias,symDepth++);
224                 }
225                 else
226                 {
227                         // Relative to here, so use the parent of the symlink as a start
228                         obj = yaffsfs_FindObject(obj->parent,alias,symDepth++);
229                 }
230         }
231         return obj;
232 }
233
234
235 // yaffsfs_FindDirectory
236 // Parse a path to determine the directory and the name within the directory.
237 //
238 // eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
239 static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,const char *path,char **name,int symDepth)
240 {
241         yaffs_Object *dir;
242         char *restOfPath;
243         char str[YAFFS_MAX_NAME_LENGTH+1];
244         int i;
245         
246         if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES)
247         {
248                 return NULL;
249         }
250         
251         if(startDir)
252         {
253                 dir = startDir;
254                 restOfPath = (char *)path;
255         }
256         else
257         {
258                 dir = yaffsfs_FindRoot(path,&restOfPath);
259         }
260         
261         while(dir)
262         {       
263                 // parse off /.
264                 // curve ball: also throw away surplus '/' 
265                 // eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
266                 while(*restOfPath == '/')
267                 {
268                         restOfPath++; // get rid of '/'
269                 }
270                 
271                 *name = restOfPath;
272                 i = 0;
273                 
274                 while(*restOfPath && *restOfPath != '/')
275                 {
276                         if (i < YAFFS_MAX_NAME_LENGTH)
277                         {
278                                 str[i] = *restOfPath;
279                                 str[i+1] = '\0';
280                                 i++;
281                         }
282                         restOfPath++;
283                 }
284                 
285                 if(!*restOfPath)
286                 {
287                         // got to the end of the string
288                         return dir;
289                 }
290                 else
291                 {
292                         if(strcmp(str,".") == 0)
293                         {
294                                 // Do nothing
295                         }
296                         else if(strcmp(str,"..") == 0)
297                         {
298                                 dir = dir->parent;
299                         }
300                         else
301                         {
302                                 dir = yaffs_FindObjectByName(dir,str);
303                                 
304                                 while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
305                                 {
306                                 
307                                         dir = yaffsfs_FollowLink(dir,symDepth);
308                 
309                                 }
310                                 
311                                 if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
312                                 {
313                                         dir = NULL;
314                                 }
315                         }
316                 }
317         }
318         // directory did not exist.
319         return NULL;
320 }
321
322 static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,const char *path,char **name,int symDepth)
323 {
324         return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);
325 }
326
327 // yaffsfs_FindObject turns a path for an existing object into the object
328 // 
329 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path,int symDepth)
330 {
331         yaffs_Object *dir;
332         char *name;
333         
334         dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth);
335         
336         if(dir && *name)
337         {
338                 return yaffs_FindObjectByName(dir,name);
339         }
340         
341         return dir;
342 }
343
344
345
346 int yaffs_open(const char *path, int oflag, int mode)
347 {
348         yaffs_Object *obj = NULL;
349         yaffs_Object *dir = NULL;
350         char *name;
351         int handle = -1;
352         yaffsfs_Handle *h = NULL;
353         int alreadyOpen = 0;
354         int alreadyExclusive = 0;
355         int openDenied = 0;
356         int symDepth = 0;
357         int errorReported = 0;
358         
359         int i;
360         
361         
362         // todo sanity check oflag (eg. can't have O_TRUNC without WRONLY or RDWR
363         
364         
365         yaffsfs_Lock();
366         
367         handle = yaffsfs_GetHandle();
368         
369         if(handle >= 0)
370         {
371
372                 h = yaffsfs_GetHandlePointer(handle);
373         
374         
375                 // try to find the exisiting object
376                 obj = yaffsfs_FindObject(NULL,path,0);
377                 
378                 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
379                 {
380                 
381                         obj = yaffsfs_FollowLink(obj,symDepth++);
382                 }
383
384                 if(obj)
385                 {
386                         // Check if the object is already in use
387                         alreadyOpen = alreadyExclusive = 0;
388                         
389                         for(i = 0; i <= YAFFSFS_N_HANDLES; i++)
390                         {
391                                 
392                                 if(i != handle &&
393                                    yaffsfs_handle[i].inUse &&
394                                     obj == yaffsfs_handle[i].obj)
395                                  {
396                                         alreadyOpen = 1;
397                                         if(yaffsfs_handle[i].exclusive)
398                                         {
399                                                 alreadyExclusive = 1;
400                                         }
401                                  }
402                         }
403
404                         if(((oflag & O_EXCL) && alreadyOpen) || alreadyExclusive)
405                         {
406                                 openDenied = 1;
407                         }
408                         
409                         // Open should fail if O_CREAT and O_EXCL are specified
410                         if((oflag & O_EXCL) && (oflag & O_CREAT))
411                         {
412                                 openDenied = 1;
413                                 yaffsfs_SetError(-EEXIST);
414                                 errorReported = 1;
415                         }
416                         
417                         // Check file permissions
418                         if( (oflag & (O_RDWR | O_WRONLY)) == 0 &&     // ie O_RDONLY
419                            !(obj->yst_mode & S_IREAD))
420                         {
421                                 openDenied = 1;
422                         }
423
424                         if( (oflag & O_RDWR) && 
425                            !(obj->yst_mode & S_IREAD))
426                         {
427                                 openDenied = 1;
428                         }
429
430                         if( (oflag & (O_RDWR | O_WRONLY)) && 
431                            !(obj->yst_mode & S_IWRITE))
432                         {
433                                 openDenied = 1;
434                         }
435                         
436                 }
437                 
438                 else if((oflag & O_CREAT))
439                 {
440                         // Let's see if we can create this file
441                         dir = yaffsfs_FindDirectory(NULL,path,&name,0);
442                         if(dir)
443                         {
444                                 obj = yaffs_MknodFile(dir,name,mode,0,0);       
445                         }
446                         else
447                         {
448                                 yaffsfs_SetError(-ENOTDIR);
449                         }
450                 }
451                 
452                 if(obj && !openDenied)
453                 {
454                         h->obj = obj;
455                         h->inUse = 1;
456                 h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1;
457                         h->append =  (oflag & O_APPEND) ? 1 : 0;
458                         h->exclusive = (oflag & O_EXCL) ? 1 : 0;
459                         h->position = 0;
460                         
461                         obj->inUse++;
462                         if((oflag & O_TRUNC) && !h->readOnly)
463                         {
464                                 //todo truncate
465                                 yaffs_ResizeFile(obj,0);
466                         }
467                         
468                 }
469                 else
470                 {
471                         yaffsfs_PutHandle(handle);
472                         if(!errorReported)
473                         {
474                                 yaffsfs_SetError(-EACCESS);
475                                 errorReported = 1;
476                         }
477                         handle = -1;
478                 }
479                 
480         }
481         
482         yaffsfs_Unlock();
483         
484         return handle;          
485 }
486
487 int yaffs_close(int fd)
488 {
489         yaffsfs_Handle *h = NULL;
490         int retVal = 0;
491         
492         yaffsfs_Lock();
493
494         h = yaffsfs_GetHandlePointer(fd);
495         
496         if(h && h->inUse)
497         {
498                 // clean up
499                 yaffs_FlushFile(h->obj,1);
500                 h->obj->inUse--;
501                 if(h->obj->inUse <= 0 && h->obj->unlinked)
502                 {
503                         yaffs_DeleteFile(h->obj);
504                 }
505                 yaffsfs_PutHandle(fd);
506                 retVal = 0;
507         }
508         else
509         {
510                 // bad handle
511                 yaffsfs_SetError(-EBADF);               
512                 retVal = -1;
513         }
514         
515         yaffsfs_Unlock();
516         
517         return retVal;
518 }
519
520 int yaffs_read(int fd, void *buf, unsigned int nbyte)
521 {
522         yaffsfs_Handle *h = NULL;
523         yaffs_Object *obj = NULL;
524         int pos = 0;
525         int nRead = -1;
526         int maxRead;
527         
528         yaffsfs_Lock();
529         h = yaffsfs_GetHandlePointer(fd);
530         obj = yaffsfs_GetHandleObject(fd);
531         
532         if(!h || !obj)
533         {
534                 // bad handle
535                 yaffsfs_SetError(-EBADF);               
536         }
537         else if( h && obj)
538         {
539                 pos=  h->position;
540                 if(yaffs_GetObjectFileLength(obj) > pos)
541                 {
542                         maxRead = yaffs_GetObjectFileLength(obj) - pos;
543                 }
544                 else
545                 {
546                         maxRead = 0;
547                 }
548
549                 if(nbyte > maxRead)
550                 {
551                         nbyte = maxRead;
552                 }
553
554                 
555                 if(nbyte > 0)
556                 {
557                         nRead = yaffs_ReadDataFromFile(obj,buf,pos,nbyte);
558                         if(nRead >= 0)
559                         {
560                                 h->position = pos + nRead;
561                         }
562                         else
563                         {
564                                 //todo error
565                         }
566                 }
567                 else
568                 {
569                         nRead = 0;
570                 }
571                 
572         }
573         
574         yaffsfs_Unlock();
575         
576         
577         return (nRead >= 0) ? nRead : -1;
578                 
579 }
580
581 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
582 {
583         yaffsfs_Handle *h = NULL;
584         yaffs_Object *obj = NULL;
585         int pos = 0;
586         int nWritten = -1;
587         int writeThrough = 0;
588         
589         yaffsfs_Lock();
590         h = yaffsfs_GetHandlePointer(fd);
591         obj = yaffsfs_GetHandleObject(fd);
592         
593         if(!h || !obj)
594         {
595                 // bad handle
596                 yaffsfs_SetError(-EBADF);               
597         }
598         else if( h && obj && h->readOnly)
599         {
600                 // todo error
601         }
602         else if( h && obj)
603         {
604                 if(h->append)
605                 {
606                         pos =  yaffs_GetObjectFileLength(obj);
607                 }
608                 else
609                 {
610                         pos = h->position;
611                 }
612                 
613                 nWritten = yaffs_WriteDataToFile(obj,buf,pos,nbyte,writeThrough);
614                 
615                 if(nWritten >= 0)
616                 {
617                         h->position = pos + nWritten;
618                 }
619                 else
620                 {
621                         //todo error
622                 }
623                 
624         }
625         
626         yaffsfs_Unlock();
627         
628         
629         return (nWritten >= 0) ? nWritten : -1;
630
631 }
632
633 int yaffs_truncate(int fd, off_t newSize)
634 {
635         yaffsfs_Handle *h = NULL;
636         yaffs_Object *obj = NULL;
637         int result = 0;
638         
639         yaffsfs_Lock();
640         h = yaffsfs_GetHandlePointer(fd);
641         obj = yaffsfs_GetHandleObject(fd);
642         
643         if(!h || !obj)
644         {
645                 // bad handle
646                 yaffsfs_SetError(-EBADF);               
647         }
648         else
649         {
650                 // resize the file
651                 result = yaffs_ResizeFile(obj,newSize);
652         }       
653         yaffsfs_Unlock();
654         
655         
656         return (result) ? 0 : -1;
657
658 }
659
660 off_t yaffs_lseek(int fd, off_t offset, int whence) 
661 {
662         yaffsfs_Handle *h = NULL;
663         yaffs_Object *obj = NULL;
664         int pos = -1;
665         int fSize = -1;
666         
667         yaffsfs_Lock();
668         h = yaffsfs_GetHandlePointer(fd);
669         obj = yaffsfs_GetHandleObject(fd);
670         
671         if(!h || !obj)
672         {
673                 // bad handle
674                 yaffsfs_SetError(-EBADF);               
675         }
676         else if(whence == SEEK_SET)
677         {
678                 if(offset >= 0)
679                 {
680                         pos = offset;
681                 }
682         }
683         else if(whence == SEEK_CUR)
684         {
685                 if( (h->position + offset) >= 0)
686                 {
687                         pos = (h->position + offset);
688                 }
689         }
690         else if(whence == SEEK_END)
691         {
692                 fSize = yaffs_GetObjectFileLength(obj);
693                 if(fSize >= 0 && (fSize + offset) >= 0)
694                 {
695                         pos = fSize + offset;
696                 }
697         }
698         
699         if(pos >= 0)
700         {
701                 h->position = pos;
702         }
703         else
704         {
705                 // todo error
706         }
707
708         
709         yaffsfs_Unlock();
710         
711         return pos;
712 }
713
714
715 int yaffsfs_DoUnlink(const char *path,int isDirectory) 
716 {
717         yaffs_Object *dir = NULL;
718         yaffs_Object *obj = NULL;
719         char *name;
720         int result = YAFFS_FAIL;
721         
722         yaffsfs_Lock();
723
724         obj = yaffsfs_FindObject(NULL,path,0);
725         dir = yaffsfs_FindDirectory(NULL,path,&name,0);
726         if(!dir)
727         {
728                 yaffsfs_SetError(-ENOTDIR);
729         }
730         else if(!obj)
731         {
732                 yaffsfs_SetError(-ENOENT);
733         }
734         else if(!isDirectory && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
735         {
736                 yaffsfs_SetError(-EISDIR);
737         }
738         else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
739         {
740                 yaffsfs_SetError(-ENOTDIR);
741         }
742         else
743         {
744                 result = yaffs_Unlink(dir,name);
745                 
746                 if(result == YAFFS_FAIL && isDirectory)
747                 {
748                         yaffsfs_SetError(-ENOTEMPTY);
749                 }
750         }
751         
752         yaffsfs_Unlock();
753         
754         // todo error
755         
756         return (result == YAFFS_FAIL) ? -1 : 0;
757 }
758 int yaffs_rmdir(const char *path) 
759 {
760         return yaffsfs_DoUnlink(path,1);
761 }
762
763 int yaffs_unlink(const char *path) 
764 {
765         return yaffsfs_DoUnlink(path,0);
766 }
767
768 int yaffs_rename(const char *oldPath, const char *newPath)
769 {
770         yaffs_Object *olddir = NULL;
771         yaffs_Object *newdir = NULL;
772         yaffs_Object *obj = NULL;
773         char *oldname;
774         char *newname;
775         int result= YAFFS_FAIL;
776         int renameAllowed = 1;
777         
778         yaffsfs_Lock();
779         
780         olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
781         newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
782         obj = yaffsfs_FindObject(NULL,oldPath,0);
783         
784         if(!olddir || !newdir || !obj)
785         {
786                 // bad file
787                 yaffsfs_SetError(-EBADF);       
788                 renameAllowed = 0;      
789         }
790         else if(olddir->myDev != newdir->myDev)
791         {
792                 // oops must be on same device
793                 // todo error
794                 yaffsfs_SetError(-EXDEV);
795                 renameAllowed = 0;      
796         }
797         else if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
798         {
799                 // It is a directory, check that it is not being renamed to 
800                 // being its own decendent.
801                 // Do this by tracing from the new directory back to the root, checking for obj
802                 
803                 yaffs_Object *xx = newdir;
804                 
805                 while( renameAllowed && xx)
806                 {
807                         if(xx == obj)
808                         {
809                                 renameAllowed = 0;
810                         }
811                         xx = xx->parent;
812                 }
813                 if(!renameAllowed) yaffsfs_SetError(-EACCESS);
814         }
815         
816         if(renameAllowed)
817         {
818                 result = yaffs_RenameObject(olddir,oldname,newdir,newname);
819         }
820         
821         yaffsfs_Unlock();
822         
823         return (result == YAFFS_FAIL) ? -1 : 0; 
824 }
825
826
827 static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf)
828 {
829         int retVal = -1;
830
831         if(obj)
832         {
833                 obj = yaffs_GetEquivalentObject(obj);
834         }
835
836         if(obj && buf)
837         {
838         buf->st_dev = (int)obj->myDev->genericDevice;
839         buf->st_ino = obj->objectId;
840         buf->st_mode = obj->yst_mode & ~S_IFMT; // clear out file type bits
841         
842                 if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) 
843                 {
844                         buf->st_mode |= S_IFDIR;
845                 }
846                 else if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK) 
847                 {
848                         buf->st_mode |= S_IFLNK;
849                 }
850                 else if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
851                 {
852                         buf->st_mode |= S_IFREG;
853                 }
854                 
855         buf->st_nlink = yaffs_GetObjectLinkCount(obj);
856         buf->st_uid = 0;    
857         buf->st_gid = 0;;     
858         buf->st_rdev = obj->yst_rdev;
859         buf->st_size = yaffs_GetObjectFileLength(obj);
860                 buf->st_blksize = obj->myDev->nDataBytesPerChunk;
861         buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
862         buf->yst_atime = obj->yst_atime; 
863         buf->yst_ctime = obj->yst_ctime; 
864         buf->yst_mtime = obj->yst_mtime; 
865                 retVal = 0;
866         }
867         return retVal;
868 }
869
870 static int yaffsfs_DoStatOrLStat(const char *path, struct yaffs_stat *buf,int doLStat)
871 {
872         yaffs_Object *obj;
873         
874         int retVal = -1;
875         
876         yaffsfs_Lock();
877         obj = yaffsfs_FindObject(NULL,path,0);
878         
879         if(!doLStat && obj)
880         {
881                 obj = yaffsfs_FollowLink(obj,0);
882         }
883         
884         if(obj)
885         {
886                 retVal = yaffsfs_DoStat(obj,buf);
887         }
888         else
889         {
890                 // todo error not found
891                 yaffsfs_SetError(-ENOENT);
892         }
893         
894         yaffsfs_Unlock();
895         
896         return retVal;
897         
898 }
899
900 int yaffs_stat(const char *path, struct yaffs_stat *buf)
901 {
902         return yaffsfs_DoStatOrLStat(path,buf,0);
903 }
904
905 int yaffs_lstat(const char *path, struct yaffs_stat *buf)
906 {
907         return yaffsfs_DoStatOrLStat(path,buf,1);
908 }
909
910 int yaffs_fstat(int fd, struct yaffs_stat *buf)
911 {
912         yaffs_Object *obj;
913         
914         int retVal = -1;
915         
916         yaffsfs_Lock();
917         obj = yaffsfs_GetHandleObject(fd);
918         
919         if(obj)
920         {
921                 retVal = yaffsfs_DoStat(obj,buf);
922         }
923         else
924         {
925                 // bad handle
926                 yaffsfs_SetError(-EBADF);               
927         }
928         
929         yaffsfs_Unlock();
930         
931         return retVal;
932 }
933
934 static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode)
935 {
936         int result = YAFFS_FAIL;
937
938         if(obj)
939         {
940                 obj = yaffs_GetEquivalentObject(obj);
941         }
942         
943         if(obj)
944         {
945                 obj->yst_mode = mode;
946                 obj->dirty = 1;
947                 result = yaffs_FlushFile(obj,0);
948         }
949         
950         return result == YAFFS_OK ? 0 : -1;
951 }
952
953
954 int yaffs_chmod(const char *path, mode_t mode)
955 {
956         yaffs_Object *obj;
957         
958         int retVal = -1;
959         
960         yaffsfs_Lock();
961         obj = yaffsfs_FindObject(NULL,path,0);
962         
963         if(obj)
964         {
965                 retVal = yaffsfs_DoChMod(obj,mode);
966         }
967         else
968         {
969                 // todo error not found
970                 yaffsfs_SetError(-ENOENT);
971         }
972         
973         yaffsfs_Unlock();
974         
975         return retVal;
976         
977 }
978
979
980 int yaffs_fchmod(int fd, mode_t mode)
981 {
982         yaffs_Object *obj;
983         
984         int retVal = -1;
985         
986         yaffsfs_Lock();
987         obj = yaffsfs_GetHandleObject(fd);
988         
989         if(obj)
990         {
991                 retVal = yaffsfs_DoChMod(obj,mode);
992         }
993         else
994         {
995                 // bad handle
996                 yaffsfs_SetError(-EBADF);               
997         }
998         
999         yaffsfs_Unlock();
1000         
1001         return retVal;
1002 }
1003
1004
1005 int yaffs_mkdir(const char *path, mode_t mode)
1006 {
1007         yaffs_Object *parent = NULL;
1008         yaffs_Object *dir = NULL;
1009         char *name;
1010         int retVal= -1;
1011         
1012         yaffsfs_Lock();
1013         parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1014         if(parent)
1015                 dir = yaffs_MknodDirectory(parent,name,mode,0,0);
1016         if(dir)
1017         {
1018                 retVal = 0;
1019         }
1020         else
1021         {
1022                 yaffsfs_SetError(-ENOSPC); // just assume no space for now
1023                 retVal = -1;
1024         }
1025         
1026         yaffsfs_Unlock();
1027         
1028         return retVal;
1029 }
1030
1031 int yaffs_mount(const char *path)
1032 {
1033         int retVal=-1;
1034         int result=YAFFS_FAIL;
1035         yaffs_Device *dev=NULL;
1036         char *dummy;
1037         
1038         T(YAFFS_TRACE_ALWAYS,("yaffs: Mounting %s\n",path));
1039         
1040         yaffsfs_Lock();
1041         dev = yaffsfs_FindDevice(path,&dummy);
1042         if(dev)
1043         {
1044                 if(!dev->isMounted)
1045                 {
1046                         result = yaffs_GutsInitialise(dev);
1047                         if(result == YAFFS_FAIL)
1048                         {
1049                                 // todo error - mount failed
1050                                 yaffsfs_SetError(-ENOMEM);
1051                         }
1052                         retVal = result ? 0 : -1;
1053                         
1054                 }
1055                 else
1056                 {
1057                         //todo error - already mounted.
1058                         yaffsfs_SetError(-EBUSY);
1059                 }
1060         }
1061         else
1062         {
1063                 // todo error - no device
1064                 yaffsfs_SetError(-ENODEV);
1065         }
1066         yaffsfs_Unlock();
1067         return retVal;
1068         
1069 }
1070
1071 int yaffs_unmount(const char *path)
1072 {
1073         int retVal=-1;
1074         yaffs_Device *dev=NULL;
1075         char *dummy;
1076         
1077         yaffsfs_Lock();
1078         dev = yaffsfs_FindDevice(path,&dummy);
1079         if(dev)
1080         {
1081                 if(dev->isMounted)
1082                 {
1083                         int i;
1084                         int inUse;
1085                         
1086                         yaffs_FlushEntireDeviceCache(dev);
1087                         yaffs_CheckpointSave(dev);
1088                         
1089                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++)
1090                         {
1091                                 if(yaffsfs_handle[i].inUse && yaffsfs_handle[i].obj->myDev == dev)
1092                                 {
1093                                         inUse = 1; // the device is in use, can't unmount
1094                                 }
1095                         }
1096                         
1097                         if(!inUse)
1098                         {
1099                                 yaffs_Deinitialise(dev);
1100                                         
1101                                 retVal = 0;
1102                         }
1103                         else
1104                         {
1105                                 // todo error can't unmount as files are open
1106                                 yaffsfs_SetError(-EBUSY);
1107                         }
1108                         
1109                 }
1110                 else
1111                 {
1112                         //todo error - not mounted.
1113                         yaffsfs_SetError(-EINVAL);
1114                         
1115                 }
1116         }
1117         else
1118         {
1119                 // todo error - no device
1120                 yaffsfs_SetError(-ENODEV);
1121         }       
1122         yaffsfs_Unlock();
1123         return retVal;
1124         
1125 }
1126
1127 loff_t yaffs_freespace(const char *path)
1128 {
1129         loff_t retVal=-1;
1130         yaffs_Device *dev=NULL;
1131         char *dummy;
1132         
1133         yaffsfs_Lock();
1134         dev = yaffsfs_FindDevice(path,&dummy);
1135         if(dev  && dev->isMounted)
1136         {
1137                 retVal = yaffs_GetNumberOfFreeChunks(dev);
1138                 retVal *= dev->nDataBytesPerChunk;
1139                 
1140         }
1141         else
1142         {
1143                 yaffsfs_SetError(-EINVAL);
1144         }
1145         
1146         yaffsfs_Unlock();
1147         return retVal;  
1148 }
1149
1150
1151
1152 void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList)
1153 {
1154         
1155         yaffsfs_DeviceConfiguration *cfg;
1156         
1157         yaffsfs_configurationList = cfgList;
1158         
1159         yaffsfs_InitHandles();
1160         
1161         cfg = yaffsfs_configurationList;
1162         
1163         while(cfg && cfg->prefix && cfg->dev)
1164         {
1165                 cfg->dev->isMounted = 0;
1166                 cfg->dev->removeObjectCallback = yaffsfs_RemoveObjectCallback;
1167                 cfg++;
1168         }
1169 }
1170
1171
1172 //
1173 // Directory search stuff.
1174
1175 //
1176 // Directory search context
1177 //
1178 // NB this is an opaque structure.
1179
1180
1181 typedef struct
1182 {
1183         __u32 magic;
1184         yaffs_dirent de;                /* directory entry being used by this dsc */
1185         char name[NAME_MAX+1];          /* name of directory being searched */
1186         yaffs_Object *dirObj;           /* ptr to directory being searched */
1187         yaffs_Object *nextReturn;       /* obj to be returned by next readddir */
1188         int offset;
1189         struct list_head others;        
1190 } yaffsfs_DirectorySearchContext;
1191
1192
1193
1194 static struct list_head search_contexts;
1195
1196
1197 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
1198 {
1199         if(dsc &&
1200            dsc->dirObj &&
1201            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1202            
1203            dsc->offset = 0;
1204            
1205            if( list_empty(&dsc->dirObj->variant.directoryVariant.children)){
1206                 dsc->nextReturn = NULL;
1207            } else {
1208                 dsc->nextReturn = list_entry(dsc->dirObj->variant.directoryVariant.children.next,
1209                                                 yaffs_Object,siblings);
1210            }
1211         } else {
1212                 /* Hey someone isn't playing nice! */
1213         }
1214 }
1215
1216 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
1217 {
1218         if(dsc &&
1219            dsc->dirObj &&
1220            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1221            
1222            if( dsc->nextReturn == NULL ||
1223                list_empty(&dsc->dirObj->variant.directoryVariant.children)){
1224                 dsc->nextReturn = NULL;
1225            } else {
1226                    struct list_head *next = dsc->nextReturn->siblings.next;
1227    
1228                    if( next == &dsc->dirObj->variant.directoryVariant.children)
1229                         dsc->nextReturn = NULL; /* end of list */
1230                    else 
1231                         dsc->nextReturn = list_entry(next,yaffs_Object,siblings);
1232            }
1233         } else {
1234                 /* Hey someone isn't playing nice! */
1235         }
1236 }
1237
1238 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj)
1239 {
1240
1241         struct list_head *i;
1242         yaffsfs_DirectorySearchContext *dsc;
1243         
1244         /* if search contexts not initilised then skip */
1245         if(!search_contexts.next)
1246                 return;
1247                 
1248         /* Iteratethrough the directory search contexts.
1249          * If any are the one being removed, then advance the dsc to
1250          * the next one to prevent a hanging ptr.
1251          */
1252          list_for_each(i, &search_contexts) {
1253                 if (i) {
1254                         dsc = list_entry(i, yaffsfs_DirectorySearchContext,others);
1255                         if(dsc->nextReturn == obj)
1256                                 yaffsfs_DirAdvance(dsc);
1257                 }
1258         }
1259                                 
1260 }
1261
1262 yaffs_DIR *yaffs_opendir(const char *dirname)
1263 {
1264         yaffs_DIR *dir = NULL;
1265         yaffs_Object *obj = NULL;
1266         yaffsfs_DirectorySearchContext *dsc = NULL;
1267         
1268         yaffsfs_Lock();
1269         
1270         obj = yaffsfs_FindObject(NULL,dirname,0);
1271         
1272         if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1273         {
1274                 
1275                 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
1276                 dir = (yaffs_DIR *)dsc;
1277                 if(dsc)
1278                 {
1279                         memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
1280                         dsc->magic = YAFFS_MAGIC;
1281                         dsc->dirObj = obj;
1282                         strncpy(dsc->name,dirname,NAME_MAX);
1283                         INIT_LIST_HEAD(&dsc->others);
1284                         
1285                         if(!search_contexts.next)
1286                                 INIT_LIST_HEAD(&search_contexts);
1287                                 
1288                         list_add(&dsc->others,&search_contexts);        
1289                         yaffsfs_SetDirRewound(dsc);             }
1290         
1291         }
1292         
1293         yaffsfs_Unlock();
1294         
1295         return dir;
1296 }
1297
1298 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
1299 {
1300         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1301         struct yaffs_dirent *retVal = NULL;
1302                 
1303         yaffsfs_Lock();
1304         
1305         if(dsc && dsc->magic == YAFFS_MAGIC){
1306                 yaffsfs_SetError(0);
1307                 if(dsc->nextReturn){
1308                         dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId;
1309                         dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
1310                         dsc->de.d_off = dsc->offset++;
1311                         yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
1312                         if(strlen(dsc->de.d_name) == 0)
1313                         {
1314                                 // this should not happen!
1315                                 strcpy(dsc->de.d_name,"zz");
1316                         }
1317                         dsc->de.d_reclen = sizeof(struct yaffs_dirent);
1318                         retVal = &dsc->de;
1319                         yaffsfs_DirAdvance(dsc);
1320                 } else
1321                         retVal = NULL;
1322         }
1323         else
1324         {
1325                 yaffsfs_SetError(-EBADF);
1326         }
1327         
1328         yaffsfs_Unlock();
1329         
1330         return retVal;
1331         
1332 }
1333
1334
1335 void yaffs_rewinddir(yaffs_DIR *dirp)
1336 {
1337         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1338         
1339         yaffsfs_Lock();
1340         
1341         yaffsfs_SetDirRewound(dsc);
1342
1343         yaffsfs_Unlock();
1344 }
1345
1346
1347 int yaffs_closedir(yaffs_DIR *dirp)
1348 {
1349         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1350                 
1351         yaffsfs_Lock();
1352         dsc->magic = 0;
1353         list_del(&dsc->others); /* unhook from list */
1354         YFREE(dsc);
1355         yaffsfs_Unlock();
1356         return 0;
1357 }
1358
1359 // end of directory stuff
1360
1361
1362 int yaffs_symlink(const char *oldpath, const char *newpath)
1363 {
1364         yaffs_Object *parent = NULL;
1365         yaffs_Object *obj;
1366         char *name;
1367         int retVal= -1;
1368         int mode = 0; // ignore for now
1369         
1370         yaffsfs_Lock();
1371         parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
1372         obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath);
1373         if(obj)
1374         {
1375                 retVal = 0;
1376         }
1377         else
1378         {
1379                 yaffsfs_SetError(-ENOSPC); // just assume no space for now
1380                 retVal = -1;
1381         }
1382         
1383         yaffsfs_Unlock();
1384         
1385         return retVal;
1386         
1387 }
1388
1389 int yaffs_readlink(const char *path, char *buf, int bufsiz)
1390 {
1391         yaffs_Object *obj = NULL;
1392         int retVal;
1393
1394                 
1395         yaffsfs_Lock();
1396         
1397         obj = yaffsfs_FindObject(NULL,path,0);
1398         
1399         if(!obj)
1400         {
1401                 yaffsfs_SetError(-ENOENT);
1402                 retVal = -1;
1403         }
1404         else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK)
1405         {
1406                 yaffsfs_SetError(-EINVAL);
1407                 retVal = -1;
1408         }
1409         else
1410         {
1411                 char *alias = obj->variant.symLinkVariant.alias;
1412                 memset(buf,0,bufsiz);
1413                 strncpy(buf,alias,bufsiz - 1);
1414                 retVal = 0;
1415         }
1416         yaffsfs_Unlock();
1417         return retVal;
1418 }
1419
1420 int yaffs_link(const char *oldpath, const char *newpath)
1421 {
1422         // Creates a link called newpath to existing oldpath
1423         yaffs_Object *obj = NULL;
1424         yaffs_Object *target = NULL;
1425         int retVal = 0;
1426
1427                 
1428         yaffsfs_Lock();
1429         
1430         obj = yaffsfs_FindObject(NULL,oldpath,0);
1431         target = yaffsfs_FindObject(NULL,newpath,0);
1432         
1433         if(!obj)
1434         {
1435                 yaffsfs_SetError(-ENOENT);
1436                 retVal = -1;
1437         }
1438         else if(target)
1439         {
1440                 yaffsfs_SetError(-EEXIST);
1441                 retVal = -1;
1442         }
1443         else    
1444         {
1445                 yaffs_Object *newdir = NULL;
1446                 yaffs_Object *link = NULL;
1447                 
1448                 char *newname;
1449                 
1450                 newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
1451                 
1452                 if(!newdir)
1453                 {
1454                         yaffsfs_SetError(-ENOTDIR);
1455                         retVal = -1;
1456                 }
1457                 else if(newdir->myDev != obj->myDev)
1458                 {
1459                         yaffsfs_SetError(-EXDEV);
1460                         retVal = -1;
1461                 }
1462                 if(newdir && strlen(newname) > 0)
1463                 {
1464                         link = yaffs_Link(newdir,newname,obj);
1465                         if(link)
1466                                 retVal = 0;
1467                         else
1468                         {
1469                                 yaffsfs_SetError(-ENOSPC);
1470                                 retVal = -1;
1471                         }
1472
1473                 }
1474         }
1475         yaffsfs_Unlock();
1476         
1477         return retVal;
1478 }
1479
1480 int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev);
1481
1482 int yaffs_DumpDevStruct(const char *path)
1483 {
1484         char *rest;
1485         
1486         yaffs_Object *obj = yaffsfs_FindRoot(path,&rest);
1487         
1488         if(obj)
1489         {
1490                 yaffs_Device *dev = obj->myDev;
1491                 
1492                 printf("\n"
1493                            "nPageWrites.......... %d\n"
1494                            "nPageReads........... %d\n"
1495                            "nBlockErasures....... %d\n"
1496                            "nGCCopies............ %d\n"
1497                            "garbageCollections... %d\n"
1498                            "passiveGarbageColl'ns %d\n"
1499                            "\n",
1500                                 dev->nPageWrites,
1501                                 dev->nPageReads,
1502                                 dev->nBlockErasures,
1503                                 dev->nGCCopies,
1504                                 dev->garbageCollections,
1505                                 dev->passiveGarbageCollections
1506                 );
1507                 
1508         }
1509         return 0;
1510 }