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