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