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