yaffs Refactor yaffs direct device list management, add nand abstraction, divide...
[yaffs2.git] / direct / yaffsfs.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2010 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 "yportenv.h"
18 #include "yaffs_trace.h"
19
20 #include <string.h> /* for memset */
21
22 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
23
24 #ifndef NULL
25 #define NULL ((void *)0)
26 #endif
27
28
29 /* YAFFSFS_RW_SIZE must be a power of 2 */
30 #define YAFFSFS_RW_SHIFT (13)
31 #define YAFFSFS_RW_SIZE  (1<<YAFFSFS_RW_SHIFT)
32
33 /* Some forward references */
34 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const YCHAR *path, int symDepth);
35 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj);
36
37 unsigned int yaffs_wr_attempts;
38
39 /*
40  * Handle management.
41  * There are open inodes in yaffsfs_Inode.
42  * There are open handles in yaffsfs_Handle.
43  *
44  * Things are structured this way to be like the Linux VFS model
45  * so that interactions with the yaffs guts calls are similar.
46  * That means more common code paths and less special code.
47  * That means better testing etc.
48  */
49
50 typedef struct {
51         int count;      /* Number of handles accessing this inode */
52         yaffs_Object *iObj;
53 } yaffsfs_Inode;
54
55 typedef struct{
56         __u8    readOnly:1;
57         __u8    append:1;
58         int     inodeId:13;     /* Index to corresponding yaffsfs_Inode */
59         int     useCount:16;    /* Use count for this handle */
60         __u32 position;         /* current position in file */
61 }yaffsfs_Handle;
62
63 static yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES];
64 static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
65
66 /*
67  * yaffsfs_InitHandle
68  * Inilitalise handle management on start-up.
69  */
70
71 static int yaffsfs_InitHandles(void)
72 {
73         int i;
74         memset(yaffsfs_inode,0,sizeof(yaffsfs_inode));
75         memset(yaffsfs_handle,0,sizeof(yaffsfs_handle));
76         for(i = 0; i < YAFFSFS_N_HANDLES; i++)
77                 yaffsfs_handle[i].inodeId = -1;
78
79         return 0;
80 }
81
82 yaffsfs_Handle *yaffsfs_GetHandlePointer(int h)
83 {
84         if(h < 0 || h >= YAFFSFS_N_HANDLES)
85                 return NULL;
86
87         return &yaffsfs_handle[h];
88 }
89
90 yaffsfs_Inode *yaffsfs_GetInodePointer(int handle)
91 {
92         yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
93
94         if(h && h->useCount > 0 && h->inodeId >= 0 && h->inodeId < YAFFSFS_N_HANDLES)
95                 return  &yaffsfs_inode[h->inodeId];
96
97         return NULL;
98 }
99
100 yaffs_Object *yaffsfs_GetHandleObject(int handle)
101 {
102         yaffsfs_Inode *in = yaffsfs_GetInodePointer(handle);
103
104         if(in)
105                 return in->iObj;
106
107         return NULL;
108 }
109
110 /*
111  * yaffsfs_GetInodeIdForObject
112  * Grab an inode entry when opening a new inode.
113  */
114
115 static int yaffsfs_GetInodeIdForObject(yaffs_Object *obj)
116 {
117         int i;
118         int ret = -1;
119         yaffsfs_Inode *in = NULL;
120         
121         if(obj)
122                 obj = yaffs_GetEquivalentObject(obj);
123
124         /* Look for it. If we can't find it then make one */
125         for(i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++){
126                 if(yaffsfs_inode[i].iObj == obj)
127                         ret = i;
128         }
129
130         for(i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++){
131                 if(!yaffsfs_inode[i].iObj)
132                         ret = i;
133         }
134         
135         
136         if(ret>=0){
137                 in = &yaffsfs_inode[ret];
138                 if(!in->iObj)
139                         in->count = 0;
140                 in->iObj = obj;
141                 in->count++;
142         }
143         
144         
145         return ret;
146 }
147
148 static void yaffsfs_ReleaseInode(yaffsfs_Inode *in)
149 {
150         yaffs_Object *obj;
151         
152         obj = in->iObj;
153
154         if(obj->unlinked)
155                 yaffs_DeleteObject(obj);
156         
157         obj->myInode = NULL;
158         in->iObj = NULL;
159
160 }
161
162 static void yaffsfs_PutInode(int inodeId)
163 {
164         if(inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES){
165                 yaffsfs_Inode *in = & yaffsfs_inode[inodeId];
166                 in->count--;
167                 if(in->count <= 0)
168                         yaffsfs_ReleaseInode(in);
169         }       
170 }
171
172
173 /*
174  * yaffsfs_GetHandle
175  * Grab a handle (when opening a file)
176  */
177
178 static int yaffsfs_GetNewHandle(void)
179 {
180         int i;
181         yaffsfs_Handle *h;
182
183         for(i = 0; i < YAFFSFS_N_HANDLES; i++){
184                 h = yaffsfs_GetHandlePointer(i);
185                 if(!h){
186                         /* todo bug: should never happen */
187                 }
188                 if(h->useCount < 1){
189                         memset(h,0,sizeof(yaffsfs_Handle));
190                         h->inodeId=-1;
191                         h->useCount=1;
192                         return i;
193                 }
194         }
195         return -1;
196 }
197
198 /*
199  * yaffs_GetHandle
200  * Increase use of handle when reading/writing a file
201  */
202 static int yaffsfs_GetHandle(int handle)
203 {
204         yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
205
206         if(h && h->useCount > 0){       
207                 h->useCount++;
208         }
209         return 0;
210 }
211
212 /*
213  * yaffs_PutHandle
214  * Let go of a handle when closing a file or aborting an open or
215  * ending a read or write.
216  */
217 static int yaffsfs_PutHandle(int handle)
218 {
219         yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
220
221         if(h && h->useCount > 0){       
222                 h->useCount--;
223                 if(h->useCount < 1){
224                         if(h->inodeId >= 0){
225                                 yaffsfs_PutInode(h->inodeId);
226                                 h->inodeId = -1;
227                         }
228                 }
229         }
230         return 0;
231 }
232
233
234
235
236 /*
237  *  Stuff to search for a directory from a path
238  */
239
240
241 int yaffsfs_Match(YCHAR a, YCHAR b)
242 {
243         /* case sensitive */
244         return (a == b);
245 }
246
247 int yaffsfs_IsPathDivider(YCHAR ch)
248 {
249         YCHAR *str = YAFFS_PATH_DIVIDERS;
250
251         while(*str){
252                 if(*str == ch)
253                         return 1;
254                 str++;
255         }
256
257         return 0;
258 }
259
260
261
262 YLIST_HEAD(yaffsfs_deviceList);
263
264 /*
265  * yaffsfs_FindDevice
266  * yaffsfs_FindRoot
267  * Scan the configuration list to find the root.
268  * Curveballs: Should match paths that end in '/' too
269  * Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
270  */
271 static yaffs_Device *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
272 {
273         struct ylist_head *cfg;
274         const YCHAR *leftOver;
275         const YCHAR *p;
276         yaffs_Device *retval = NULL;
277         yaffs_Device *dev = NULL;
278         int thisMatchLength;
279         int longestMatch = -1;
280         int matching;
281
282         /*
283          * Check all configs, choose the one that:
284          * 1) Actually matches a prefix (ie /a amd /abc will not match
285          * 2) Matches the longest.
286          */
287         ylist_for_each(cfg, &yaffsfs_deviceList){
288                 dev = ylist_entry(cfg, yaffs_Device, devList);
289                 leftOver = path;
290                 p = dev->param.name;
291                 thisMatchLength = 0;
292                 matching = 1;
293
294
295                 while(matching && *p && *leftOver){
296                         /* Skip over any /s */
297                         while(yaffsfs_IsPathDivider(*p))
298                               p++;
299
300                         /* Skip over any /s */
301                         while(yaffsfs_IsPathDivider(*leftOver))
302                               leftOver++;
303
304                         /* Now match the text part */
305                         while(matching &&
306                               *p && !yaffsfs_IsPathDivider(*p) &&
307                               *leftOver && !yaffsfs_IsPathDivider(*leftOver)){
308                                 if(yaffsfs_Match(*p,*leftOver)){
309                                         p++;
310                                         leftOver++;
311                                         thisMatchLength++;
312                                 } else {
313                                         matching = 0;
314                                 }
315                         }
316                 }
317
318                 /* Skip over any /s in leftOver */
319                 while(yaffsfs_IsPathDivider(*leftOver))
320                       leftOver++;
321
322                 // Skip over any /s in p
323                 while(yaffsfs_IsPathDivider(*p))
324                       p++;
325
326                 // p should now be at the end of the string (ie. fully matched)
327                 if(*p)
328                         matching = 0;
329
330                 if( matching && (thisMatchLength > longestMatch))
331                 {
332                         // Matched prefix
333                         *restOfPath = (YCHAR *)leftOver;
334                         retval = dev;
335                         longestMatch = thisMatchLength;
336                 }
337
338         }
339         return retval;
340 }
341
342 #if 0
343 static yaffs_Device *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
344 {
345         yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
346         const YCHAR *leftOver;
347         const YCHAR *p;
348         yaffs_Device *retval = NULL;
349         int thisMatchLength;
350         int longestMatch = -1;
351
352         /*
353          * Check all configs, choose the one that:
354          * 1) Actually matches a prefix (ie /a amd /abc will not match
355          * 2) Matches the longest.
356          */
357         while(cfg && cfg->prefix && cfg->dev){
358                 leftOver = path;
359                 p = cfg->prefix;
360                 thisMatchLength = 0;
361
362                 while(*p &&  /* unmatched part of prefix */
363                       !(yaffsfs_IsPathDivider(*p) && (p[1] == 0)) &&
364                       *leftOver && yaffsfs_Match(*p,*leftOver)){
365                         p++;
366                         leftOver++;
367                         thisMatchLength++;
368                 }
369
370
371                 if((!*p || (yaffsfs_IsPathDivider(*p) && (p[1] == 0))) &&  /* end of prefix */
372                    (!*leftOver || yaffsfs_IsPathDivider(*leftOver)) && /* no more in this path name part */
373                    (thisMatchLength > longestMatch)){
374                         /* Matched prefix */
375                         *restOfPath = (YCHAR *)leftOver;
376                         retval = cfg->dev;
377                         longestMatch = thisMatchLength;
378                 }
379                 cfg++;
380         }
381         return retval;
382 }
383 #endif
384
385 static yaffs_Object *yaffsfs_FindRoot(const YCHAR *path, YCHAR **restOfPath)
386 {
387
388         yaffs_Device *dev;
389
390         dev= yaffsfs_FindDevice(path,restOfPath);
391         if(dev && dev->isMounted){
392                 return dev->rootDir;
393         }
394         return NULL;
395 }
396
397 static yaffs_Object *yaffsfs_FollowLink(yaffs_Object *obj,int symDepth)
398 {
399
400         while(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
401                 YCHAR *alias = obj->variant.symLinkVariant.alias;
402
403                 if(yaffsfs_IsPathDivider(*alias))
404                         /* Starts with a /, need to scan from root up */
405                         obj = yaffsfs_FindObject(NULL,alias,symDepth++);
406                 else
407                         /* Relative to here, so use the parent of the symlink as a start */
408                         obj = yaffsfs_FindObject(obj->parent,alias,symDepth++);
409         }
410         return obj;
411 }
412
413
414 /*
415  * yaffsfs_FindDirectory
416  * Parse a path to determine the directory and the name within the directory.
417  *
418  * eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
419  */
420 static yaffs_Object *yaffsfs_DoFindDirectory(yaffs_Object *startDir,
421                                 const YCHAR *path, YCHAR **name, int symDepth)
422 {
423         yaffs_Object *dir;
424         YCHAR *restOfPath;
425         YCHAR str[YAFFS_MAX_NAME_LENGTH+1];
426         int i;
427
428         if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES)
429                 return NULL;
430
431         if(startDir){
432                 dir = startDir;
433                 restOfPath = (YCHAR *)path;
434         }
435         else
436                 dir = yaffsfs_FindRoot(path,&restOfPath);
437
438         while(dir){
439                 /*
440                  * parse off /.
441                  * curve ball: also throw away surplus '/'
442                  * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
443                  */
444                 while(yaffsfs_IsPathDivider(*restOfPath))
445                         restOfPath++; /* get rid of '/' */
446
447                 *name = restOfPath;
448                 i = 0;
449
450                 while(*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)){
451                         if (i < YAFFS_MAX_NAME_LENGTH){
452                                 str[i] = *restOfPath;
453                                 str[i+1] = '\0';
454                                 i++;
455                         }
456                         restOfPath++;
457                 }
458
459                 if(!*restOfPath)
460                         /* got to the end of the string */
461                         return dir;
462                 else{
463                         if(yaffs_strcmp(str,_Y(".")) == 0)
464                         {
465                                 /* Do nothing */
466                         }
467                         else if(yaffs_strcmp(str,_Y("..")) == 0)
468                                 dir = dir->parent;
469                         else{
470                                 dir = yaffs_FindObjectByName(dir,str);
471
472                                 while(dir && dir->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
473                                         dir = yaffsfs_FollowLink(dir,symDepth);
474
475
476                                 if(dir && dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
477                                         dir = NULL;
478                         }
479                 }
480         }
481         /* directory did not exist. */
482         return NULL;
483 }
484
485 static yaffs_Object *yaffsfs_FindDirectory(yaffs_Object *relativeDirectory,
486                                         const YCHAR *path,YCHAR **name,int symDepth)
487 {
488         return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);
489 }
490
491 /*
492  * yaffsfs_FindObject turns a path for an existing object into the object
493  */
494 static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const YCHAR *path,int symDepth)
495 {
496         yaffs_Object *dir;
497         YCHAR *name;
498
499         dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth);
500
501         if(dir && *name)
502                 return yaffs_FindObjectByName(dir,name);
503
504         return dir;
505 }
506
507
508 int yaffs_dup(int fd)
509 {
510         int newHandle = -1;
511         yaffsfs_Handle *oldPtr = NULL;
512         yaffsfs_Handle *newPtr = NULL;
513
514         yaffsfs_Lock();
515
516         oldPtr = yaffsfs_GetHandlePointer(fd);
517         if(oldPtr && oldPtr->useCount > 0)
518                 newHandle = yaffsfs_GetNewHandle();
519         if(newHandle >= 0)
520                 newPtr = yaffsfs_GetHandlePointer(newHandle);
521
522         if(newPtr){
523                 *newPtr = *oldPtr;
524                 return newHandle;
525         }
526
527         if(!oldPtr)
528                 yaffsfs_SetError(-EBADF);
529         else
530                 yaffsfs_SetError(-ENOMEM);
531
532         return -1;
533
534 }
535
536 int yaffs_open(const YCHAR *path, int oflag, int mode)
537 {
538         yaffs_Object *obj = NULL;
539         yaffs_Object *dir = NULL;
540         YCHAR *name;
541         int handle = -1;
542         yaffsfs_Handle *h = NULL;
543         int openDenied = 0;
544         int symDepth = 0;
545         int errorReported = 0;
546
547         /* O_EXCL only has meaning if O_CREAT is specified */
548         if(!(oflag & O_CREAT))
549                 oflag &= ~(O_EXCL);
550
551         /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
552         if( (oflag & O_CREAT) & (oflag & O_EXCL))
553                 oflag &= ~(O_TRUNC);
554
555         /* Todo: Are there any more flag combos to sanitise ? */
556
557
558         yaffsfs_Lock();
559
560         handle = yaffsfs_GetNewHandle();
561
562         if(handle >= 0){
563
564                 h = yaffsfs_GetHandlePointer(handle);
565
566
567                 /* try to find the exisiting object */
568                 obj = yaffsfs_FindObject(NULL,path,0);
569
570                 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
571                         obj = yaffsfs_FollowLink(obj,symDepth++);
572
573                 if(obj)
574                         obj = yaffs_GetEquivalentObject(obj);
575
576                 if(obj && obj->variantType != YAFFS_OBJECT_TYPE_FILE)
577                         obj = NULL;
578
579                 if(obj){
580
581                         /* The file already exists */
582
583                         /* Open should fail if O_CREAT and O_EXCL are specified since
584                          * the file exists
585                          */
586                         if((oflag & O_EXCL) && (oflag & O_CREAT)){
587                                 openDenied = 1;
588                                 yaffsfs_SetError(-EEXIST);
589                                 errorReported = 1;
590                         }
591
592                         /* Check file permissions */
593                         if( (oflag & (O_RDWR | O_WRONLY)) == 0 &&     /* ie O_RDONLY */
594                            !(obj->yst_mode & S_IREAD))
595                                 openDenied = 1;
596
597                         if( (oflag & O_RDWR) &&
598                            !(obj->yst_mode & S_IREAD))
599                                 openDenied = 1;
600
601                         if( (oflag & (O_RDWR | O_WRONLY)) &&
602                            !(obj->yst_mode & S_IWRITE))
603                                 openDenied = 1;
604
605                 } else if((oflag & O_CREAT)) {
606                         /* Let's see if we can create this file */
607                         dir = yaffsfs_FindDirectory(NULL,path,&name,0);
608                         if(dir  && dir->myDev->readOnly){
609                                 yaffsfs_SetError(-EINVAL);
610                                 errorReported = 1;
611                         } else if(dir)
612                                 obj = yaffs_MknodFile(dir,name,mode,0,0);
613                         else {
614                                 yaffsfs_SetError(-ENOTDIR);
615                                 errorReported = 1;
616                         }
617                 }
618
619                 if(obj && !openDenied) {
620                         int inodeId = yaffsfs_GetInodeIdForObject(obj);
621
622                         if(inodeId<0) {
623                                 /*
624                                  * Todo: Fix any problem if inodes run out, though that
625                                  * can't happen if the number of inode items >= number of handles. 
626                                  */
627                         }
628                         
629                         h->inodeId = inodeId;
630                         h->readOnly = (oflag & (O_WRONLY | O_RDWR)) ? 0 : 1;
631                         h->append =  (oflag & O_APPEND) ? 1 : 0;
632                         h->position = 0;
633
634                         /* Hook inode to object */
635                         obj->myInode = (void*) &yaffsfs_inode[inodeId];
636
637                         if((oflag & O_TRUNC) && !h->readOnly)
638                                 yaffs_ResizeFile(obj,0);
639                 } else {
640                         yaffsfs_PutHandle(handle);
641                         if(!errorReported) {
642                                 yaffsfs_SetError(-EACCES);
643                                 errorReported = 1;
644                         }
645                         handle = -1;
646                 }
647         }
648
649         yaffsfs_Unlock();
650
651         return handle;
652 }
653
654 int yaffs_Dofsync(int fd,int datasync)
655 {
656         yaffsfs_Handle *h = NULL;
657         int retVal = 0;
658
659         yaffsfs_Lock();
660
661         h = yaffsfs_GetHandlePointer(fd);
662
663         if(h && h->useCount > 0)
664                 /* flush the file */
665                 yaffs_FlushFile(yaffsfs_inode[h->inodeId].iObj,1,datasync);
666         else {
667                 /* bad handle */
668                 yaffsfs_SetError(-EBADF);
669                 retVal = -1;
670         }
671
672         yaffsfs_Unlock();
673
674         return retVal;
675 }
676
677 int yaffs_fsync(int fd)
678 {
679         return yaffs_Dofsync(fd,0);
680 }
681
682 int yaffs_flush(int fd)
683 {
684         return yaffs_fsync(fd);
685 }
686
687 int yaffs_fdatasync(int fd)
688 {
689         return yaffs_Dofsync(fd,1);
690 }
691
692 int yaffs_close(int fd)
693 {
694         yaffsfs_Handle *h = NULL;
695         int retVal = 0;
696
697         yaffsfs_Lock();
698
699         h = yaffsfs_GetHandlePointer(fd);
700
701         if(h && h->useCount > 0) {
702                 /* clean up */
703                 yaffs_FlushFile(yaffsfs_inode[h->inodeId].iObj,1,0);
704                 yaffsfs_PutHandle(fd);
705                 retVal = 0;
706         } else {
707                 /* bad handle */
708                 yaffsfs_SetError(-EBADF);
709                 retVal = -1;
710         }
711
712         yaffsfs_Unlock();
713
714         return retVal;
715 }
716
717
718
719 int yaffsfs_do_read(int fd, void *vbuf, unsigned int nbyte, int isPread, int offset)
720 {
721         yaffsfs_Handle *h = NULL;
722         yaffs_Object *obj = NULL;
723         int pos = 0;
724         int startPos = 0;
725         int nRead = 0;
726         int nToRead = 0;
727         int totalRead = 0;
728         unsigned int maxRead;
729         __u8 *buf = (__u8 *)vbuf;
730
731         yaffsfs_Lock();
732         h = yaffsfs_GetHandlePointer(fd);
733         obj = yaffsfs_GetHandleObject(fd);
734
735         if(!h || !obj){
736                 /* bad handle */
737                 yaffsfs_SetError(-EBADF);
738                 totalRead = -1;
739         } else if( h && obj){
740                 if(isPread)
741                         startPos = offset;
742                 else
743                         startPos = h->position;
744
745                 pos = startPos;
746                                         
747                 if(yaffs_GetObjectFileLength(obj) > pos)
748                         maxRead = yaffs_GetObjectFileLength(obj) - pos;
749                 else
750                         maxRead = 0;
751
752                 if(nbyte > maxRead)
753                         nbyte = maxRead;
754
755
756                 yaffsfs_GetHandle(fd);
757
758                 while(nbyte > 0) {
759                         nToRead = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
760                         if(nToRead > nbyte)
761                                 nToRead = nbyte;
762                         nRead = yaffs_ReadDataFromFile(obj,buf,pos,nToRead);
763
764                         if(nRead > 0){
765                                 totalRead += nRead;
766                                 pos += nRead;
767                                 buf += nRead;
768                         }
769
770                         if(nRead == nToRead)
771                                 nbyte-=nRead;
772                         else
773                                 nbyte = 0; /* no more to read */
774                                         
775                                         
776                         if(nbyte > 0){
777                                 yaffsfs_Unlock();
778                                 yaffsfs_Lock();
779                         }
780
781                 }
782
783                 yaffsfs_PutHandle(fd);
784
785                 if(!isPread) {
786                         if(totalRead >= 0)
787                                 h->position = startPos + totalRead;
788                         else {
789                                         /* todo error */
790                         }
791                 }
792
793         }
794
795         yaffsfs_Unlock();
796
797         return (totalRead >= 0) ? totalRead : -1;
798
799 }
800
801 int yaffs_read(int fd, void *buf, unsigned int nbyte)
802 {
803         return yaffsfs_do_read(fd, buf, nbyte, 0, 0);
804 }
805
806 int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset)
807 {
808         return yaffsfs_do_read(fd, buf, nbyte, 1, offset);
809 }
810
811 int yaffsfs_do_write(int fd, const void *vbuf, unsigned int nbyte, int isPwrite, int offset)
812 {
813         yaffsfs_Handle *h = NULL;
814         yaffs_Object *obj = NULL;
815         int pos = 0;
816         int startPos = 0;
817         int nWritten = 0;
818         int totalWritten = 0;
819         int writeThrough = 0;
820         int nToWrite = 0;
821         const __u8 *buf = (const __u8 *)vbuf;
822
823         yaffsfs_Lock();
824         h = yaffsfs_GetHandlePointer(fd);
825         obj = yaffsfs_GetHandleObject(fd);
826
827         if(!h || !obj){
828                 /* bad handle */
829                 yaffsfs_SetError(-EBADF);
830                 totalWritten = -1;
831         } else if( h && obj && (h->readOnly || obj->myDev->readOnly)){
832                 yaffsfs_SetError(-EINVAL);
833                 totalWritten=-1;
834         } else if( h && obj){
835                 if(h->append)
836                         startPos = yaffs_GetObjectFileLength(obj);
837                 else if(isPwrite)
838                         startPos = offset;
839                 else
840                         startPos = h->position;
841
842                 yaffsfs_GetHandle(fd);
843                 pos = startPos;
844                 while(nbyte > 0) {
845                         nToWrite = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
846                         if(nToWrite > nbyte)
847                                 nToWrite = nbyte;
848
849                         nWritten = yaffs_WriteDataToFile(obj,buf,pos,nToWrite,writeThrough);
850                         if(nWritten > 0){
851                                 totalWritten += nWritten;
852                                 pos += nWritten;
853                                 buf += nWritten;
854                         }
855
856                         if(nWritten == nToWrite)
857                                 nbyte -= nToWrite;
858                         else
859                                 nbyte = 0;
860
861                         if(nWritten < 1 && totalWritten < 1){
862                                 yaffsfs_SetError(-ENOSPC);
863                                 totalWritten = -1;
864                         }
865
866                         if(nbyte > 0){
867                                 yaffsfs_Unlock();
868                                 yaffsfs_Lock();
869                         }
870                 }
871
872                 yaffsfs_PutHandle(fd);
873
874                 if(!isPwrite){
875                         if(totalWritten > 0)
876                                 h->position = startPos + totalWritten;
877                         else {
878                                 /* todo error */
879                         }
880                 }
881         }
882
883         yaffsfs_Unlock();
884
885         return (totalWritten >= 0) ? totalWritten : -1;
886 }
887
888 int yaffs_write(int fd, const void *buf, unsigned int nbyte)
889 {
890         return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
891 }
892
893 int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset)
894 {
895         return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
896 }
897
898
899 int yaffs_truncate(const YCHAR *path,off_t newSize)
900 {
901         yaffs_Object *obj = NULL;
902         int result = YAFFS_FAIL;
903
904         yaffsfs_Lock();
905
906         obj = yaffsfs_FindObject(NULL,path,0);
907         if(obj)
908                 obj = yaffs_GetEquivalentObject(obj);
909
910         if(!obj)
911                 yaffsfs_SetError(-ENOENT);
912         else if(obj->variantType != YAFFS_OBJECT_TYPE_FILE)
913                 yaffsfs_SetError(-EISDIR);
914         else if(obj->myDev->readOnly)
915                 yaffsfs_SetError(-EINVAL);
916         else
917                 result = yaffs_ResizeFile(obj,newSize);
918
919         yaffsfs_Unlock();
920
921
922         return (result) ? 0 : -1;
923 }
924
925 int yaffs_ftruncate(int fd, off_t newSize)
926 {
927         yaffsfs_Handle *h = NULL;
928         yaffs_Object *obj = NULL;
929         int result = 0;
930
931         yaffsfs_Lock();
932         h = yaffsfs_GetHandlePointer(fd);
933         obj = yaffsfs_GetHandleObject(fd);
934
935         if(!h || !obj)
936                 /* bad handle */
937                 yaffsfs_SetError(-EBADF);
938         else if(obj->myDev->readOnly)
939                 yaffsfs_SetError(-EINVAL);
940         else
941                 /* resize the file */
942                 result = yaffs_ResizeFile(obj,newSize);
943         yaffsfs_Unlock();
944
945
946         return (result) ? 0 : -1;
947
948 }
949
950 off_t yaffs_lseek(int fd, off_t offset, int whence)
951 {
952         yaffsfs_Handle *h = NULL;
953         yaffs_Object *obj = NULL;
954         int pos = -1;
955         int fSize = -1;
956
957         yaffsfs_Lock();
958         h = yaffsfs_GetHandlePointer(fd);
959         obj = yaffsfs_GetHandleObject(fd);
960
961         if(!h || !obj)
962                 /* bad handle */
963                 yaffsfs_SetError(-EBADF);
964         else if(whence == SEEK_SET){
965                 if(offset >= 0)
966                         pos = offset;
967         }
968         else if(whence == SEEK_CUR) {
969                 if( (h->position + offset) >= 0)
970                         pos = (h->position + offset);
971         }
972         else if(whence == SEEK_END) {
973                 fSize = yaffs_GetObjectFileLength(obj);
974                 if(fSize >= 0 && (fSize + offset) >= 0)
975                         pos = fSize + offset;
976         }
977
978         if(pos >= 0)
979                 h->position = pos;
980         else {
981                 /* todo error */
982         }
983
984
985         yaffsfs_Unlock();
986
987         return pos;
988 }
989
990
991 int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
992 {
993         yaffs_Object *dir = NULL;
994         yaffs_Object *obj = NULL;
995         YCHAR *name;
996         int result = YAFFS_FAIL;
997
998         yaffsfs_Lock();
999
1000         obj = yaffsfs_FindObject(NULL,path,0);
1001         dir = yaffsfs_FindDirectory(NULL,path,&name,0);
1002         if(!dir)
1003                 yaffsfs_SetError(-ENOTDIR);
1004         else if(!obj)
1005                 yaffsfs_SetError(-ENOENT);
1006         else if(obj->myDev->readOnly)
1007                 yaffsfs_SetError(-EINVAL);
1008         else if(!isDirectory && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1009                 yaffsfs_SetError(-EISDIR);
1010         else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
1011                 yaffsfs_SetError(-ENOTDIR);
1012         else {
1013                 result = yaffs_Unlink(dir,name);
1014
1015                 if(result == YAFFS_FAIL && isDirectory)
1016                         yaffsfs_SetError(-ENOTEMPTY);
1017         }
1018
1019         yaffsfs_Unlock();
1020
1021         /* todo error */
1022
1023         return (result == YAFFS_FAIL) ? -1 : 0;
1024 }
1025
1026
1027 int yaffs_rmdir(const YCHAR *path)
1028 {
1029         return yaffsfs_DoUnlink(path,1);
1030 }
1031
1032 int yaffs_unlink(const YCHAR *path)
1033 {
1034         return yaffsfs_DoUnlink(path,0);
1035 }
1036
1037 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
1038 {
1039         yaffs_Object *olddir = NULL;
1040         yaffs_Object *newdir = NULL;
1041         yaffs_Object *obj = NULL;
1042         YCHAR *oldname;
1043         YCHAR *newname;
1044         int result= YAFFS_FAIL;
1045         int renameAllowed = 1;
1046
1047         yaffsfs_Lock();
1048
1049         olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
1050         newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
1051         obj = yaffsfs_FindObject(NULL,oldPath,0);
1052
1053         if(!olddir || !newdir || !obj) {
1054                 /* bad file */
1055                 yaffsfs_SetError(-EBADF);
1056                 renameAllowed = 0;
1057         } else if(obj->myDev->readOnly){
1058                 yaffsfs_SetError(-EINVAL);
1059                 renameAllowed = 0;
1060         } else if(olddir->myDev != newdir->myDev) {
1061                 /* oops must be on same device */
1062                 /* todo error */
1063                 yaffsfs_SetError(-EXDEV);
1064                 renameAllowed = 0;
1065         } else if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
1066                 /*
1067                  * It is a directory, check that it is not being renamed to
1068                  * being its own decendent.
1069                  * Do this by tracing from the new directory back to the root, checking for obj
1070                  */
1071
1072                 yaffs_Object *xx = newdir;
1073
1074                 while( renameAllowed && xx){
1075                         if(xx == obj)
1076                                 renameAllowed = 0;
1077                         xx = xx->parent;
1078                 }
1079                 if(!renameAllowed)
1080                         yaffsfs_SetError(-EACCES);
1081         }
1082
1083         if(renameAllowed)
1084                 result = yaffs_RenameObject(olddir,oldname,newdir,newname);
1085
1086         yaffsfs_Unlock();
1087
1088         return (result == YAFFS_FAIL) ? -1 : 0;
1089 }
1090
1091
1092 static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf)
1093 {
1094         int retVal = -1;
1095
1096         if(obj)
1097                 obj = yaffs_GetEquivalentObject(obj);
1098
1099         if(obj && buf){
1100                 buf->st_dev = (int)obj->myDev->osContext;
1101                 buf->st_ino = obj->objectId;
1102                 buf->st_mode = obj->yst_mode & ~S_IFMT; /* clear out file type bits */
1103
1104                 if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1105                         buf->st_mode |= S_IFDIR;
1106                 else if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
1107                         buf->st_mode |= S_IFLNK;
1108                 else if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
1109                         buf->st_mode |= S_IFREG;
1110
1111                 buf->st_nlink = yaffs_GetObjectLinkCount(obj);
1112                 buf->st_uid = 0;
1113                 buf->st_gid = 0;;
1114                 buf->st_rdev = obj->yst_rdev;
1115                 buf->st_size = yaffs_GetObjectFileLength(obj);
1116                 buf->st_blksize = obj->myDev->nDataBytesPerChunk;
1117                 buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
1118 #if CONFIG_YAFFS_WINCE
1119                 buf->yst_wince_atime[0] = obj->win_atime[0];
1120                 buf->yst_wince_atime[1] = obj->win_atime[1];
1121                 buf->yst_wince_ctime[0] = obj->win_ctime[0];
1122                 buf->yst_wince_ctime[1] = obj->win_ctime[1];
1123                 buf->yst_wince_mtime[0] = obj->win_mtime[0];
1124                 buf->yst_wince_mtime[1] = obj->win_mtime[1];
1125 #else
1126                 buf->yst_atime = obj->yst_atime;
1127                 buf->yst_ctime = obj->yst_ctime;
1128                 buf->yst_mtime = obj->yst_mtime;
1129 #endif
1130                 retVal = 0;
1131         }
1132         return retVal;
1133 }
1134
1135 static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
1136 {
1137         yaffs_Object *obj;
1138
1139         int retVal = -1;
1140
1141         yaffsfs_Lock();
1142         obj = yaffsfs_FindObject(NULL,path,0);
1143
1144         if(!doLStat && obj)
1145                 obj = yaffsfs_FollowLink(obj,0);
1146
1147         if(obj)
1148                 retVal = yaffsfs_DoStat(obj,buf);
1149         else
1150                 /* todo error not found */
1151                 yaffsfs_SetError(-ENOENT);
1152
1153         yaffsfs_Unlock();
1154
1155         return retVal;
1156
1157 }
1158
1159 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
1160 {
1161         return yaffsfs_DoStatOrLStat(path,buf,0);
1162 }
1163
1164 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
1165 {
1166         return yaffsfs_DoStatOrLStat(path,buf,1);
1167 }
1168
1169 int yaffs_fstat(int fd, struct yaffs_stat *buf)
1170 {
1171         yaffs_Object *obj;
1172
1173         int retVal = -1;
1174
1175         yaffsfs_Lock();
1176         obj = yaffsfs_GetHandleObject(fd);
1177
1178         if(obj)
1179                 retVal = yaffsfs_DoStat(obj,buf);
1180         else
1181                 /* bad handle */
1182                 yaffsfs_SetError(-EBADF);
1183
1184         yaffsfs_Unlock();
1185
1186         return retVal;
1187 }
1188
1189
1190 /* xattrib functions */
1191
1192
1193 static int yaffs_do_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags, int follow)
1194 {
1195         yaffs_Object *obj;
1196
1197         int retVal = -1;
1198
1199         yaffsfs_Lock();
1200         obj = yaffsfs_FindObject(NULL,path,0);
1201
1202         if(follow)
1203                 obj = yaffsfs_FollowLink(obj,0);
1204
1205         if(obj) {
1206                 retVal = yaffs_SetXAttribute(obj,name,data,size,flags);
1207                 if(retVal< 0){
1208                         yaffsfs_SetError(retVal);
1209                         retVal = -1;
1210                 }
1211         } else
1212                 /* todo error not found */
1213                 yaffsfs_SetError(-ENOENT);
1214
1215         yaffsfs_Unlock();
1216
1217         return retVal;
1218
1219 }
1220
1221 int yaffs_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1222 {
1223         return yaffs_do_setxattr(path, name, data, size, flags, 1);
1224 }
1225
1226 int yaffs_lsetxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
1227 {
1228         return yaffs_do_setxattr(path, name, data, size, flags, 0);
1229 }
1230
1231
1232
1233 int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int flags)
1234 {
1235         yaffs_Object *obj;
1236
1237         int retVal = -1;
1238
1239         yaffsfs_Lock();
1240         obj = yaffsfs_GetHandleObject(fd);
1241
1242         if(obj) {
1243                 retVal = yaffs_SetXAttribute(obj,name,data,size,flags);
1244                 if(retVal< 0){
1245                         yaffsfs_SetError(retVal);
1246                         retVal = -1;
1247                 }
1248         } else
1249                 /* bad handle */
1250                 yaffsfs_SetError(-EBADF);
1251
1252         yaffsfs_Unlock();
1253
1254         return retVal;
1255 }
1256
1257 static int yaffs_do_getxattr(const YCHAR *path, const char *name, void *data, int size, int follow)
1258 {
1259         yaffs_Object *obj;
1260
1261         int retVal = -1;
1262
1263         yaffsfs_Lock();
1264         obj = yaffsfs_FindObject(NULL,path,0);
1265
1266         if(follow)
1267                 obj = yaffsfs_FollowLink(obj,0);
1268
1269         if(obj) {
1270                 retVal = yaffs_GetXAttribute(obj,name,data,size);
1271                 if(retVal< 0){
1272                         yaffsfs_SetError(retVal);
1273                         retVal = -1;
1274                 }
1275         } else
1276                 /* todo error not found */
1277                 yaffsfs_SetError(-ENOENT);
1278
1279         yaffsfs_Unlock();
1280
1281         return retVal;
1282
1283 }
1284
1285 int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
1286 {
1287         return yaffs_do_getxattr( path, name, data, size, 1);
1288 }
1289 int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
1290 {
1291         return yaffs_do_getxattr( path, name, data, size, 0);
1292 }
1293
1294
1295
1296 int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
1297 {
1298         yaffs_Object *obj;
1299
1300         int retVal = -1;
1301
1302         yaffsfs_Lock();
1303         obj = yaffsfs_GetHandleObject(fd);
1304
1305         if(obj) {
1306                 retVal = yaffs_GetXAttribute(obj,name,data,size);
1307                 if(retVal< 0){
1308                         yaffsfs_SetError(retVal);
1309                         retVal = -1;
1310                 }
1311         } else
1312                 /* bad handle */
1313                 yaffsfs_SetError(-EBADF);
1314
1315         yaffsfs_Unlock();
1316
1317         return retVal;
1318 }
1319
1320 static int yaffs_do_listxattr(const YCHAR *path, char *data, int size, int follow)
1321 {
1322         yaffs_Object *obj;
1323
1324         int retVal = -1;
1325
1326         yaffsfs_Lock();
1327         obj = yaffsfs_FindObject(NULL,path,0);
1328
1329         if(follow)
1330                 obj = yaffsfs_FollowLink(obj,0);
1331
1332         if(obj) {
1333                 retVal = yaffs_ListXAttributes(obj, data,size);
1334                 if(retVal< 0){
1335                         yaffsfs_SetError(retVal);
1336                         retVal = -1;
1337                 }
1338         } else
1339                 /* todo error not found */
1340                 yaffsfs_SetError(-ENOENT);
1341
1342         yaffsfs_Unlock();
1343
1344         return retVal;
1345
1346 }
1347
1348 int yaffs_listxattr(const YCHAR *path, char *data, int size)
1349 {
1350         return yaffs_do_listxattr(path, data, size, 1);
1351 }
1352
1353 int yaffs_llistxattr(const YCHAR *path, char *data, int size)
1354 {
1355         return yaffs_do_listxattr(path, data, size, 0);
1356 }
1357
1358 int yaffs_flistxattr(int fd, char *data, int size)
1359 {
1360         yaffs_Object *obj;
1361
1362         int retVal = -1;
1363
1364         yaffsfs_Lock();
1365         obj = yaffsfs_GetHandleObject(fd);
1366
1367         if(obj) {
1368                 retVal = yaffs_ListXAttributes(obj,data,size);
1369                 if(retVal< 0){
1370                         yaffsfs_SetError(retVal);
1371                         retVal = -1;
1372                 }
1373         } else
1374                 /* bad handle */
1375                 yaffsfs_SetError(-EBADF);
1376
1377         yaffsfs_Unlock();
1378
1379         return retVal;
1380 }
1381
1382 static int yaffs_do_removexattr(const YCHAR *path, const char *name, int follow)
1383 {
1384         yaffs_Object *obj;
1385
1386         int retVal = -1;
1387
1388         yaffsfs_Lock();
1389         obj = yaffsfs_FindObject(NULL,path,0);
1390
1391         if(follow)
1392                 obj = yaffsfs_FollowLink(obj,0);
1393
1394         if(obj) {
1395                 retVal = yaffs_RemoveXAttribute(obj,name);
1396                 if(retVal< 0){
1397                         yaffsfs_SetError(retVal);
1398                         retVal = -1;
1399                 }
1400         } else
1401                 /* todo error not found */
1402                 yaffsfs_SetError(-ENOENT);
1403
1404         yaffsfs_Unlock();
1405
1406         return retVal;
1407
1408 }
1409
1410 int yaffs_removexattr(const YCHAR *path, const char *name)
1411 {
1412         return yaffs_do_removexattr(path, name, 1);
1413 }
1414
1415 int yaffs_lremovexattr(const YCHAR *path, const char *name)
1416 {
1417         return yaffs_do_removexattr(path, name, 0);
1418 }
1419
1420 int yaffs_fremovexattr(int fd, const char *name)
1421 {
1422         yaffs_Object *obj;
1423
1424         int retVal = -1;
1425
1426         yaffsfs_Lock();
1427         obj = yaffsfs_GetHandleObject(fd);
1428
1429         if(obj){
1430                 retVal = yaffs_RemoveXAttribute(obj,name);
1431                 if(retVal< 0){
1432                         yaffsfs_SetError(retVal);
1433                         retVal = -1;
1434                 }
1435         }else
1436                 /* bad handle */
1437                 yaffsfs_SetError(-EBADF);
1438
1439         yaffsfs_Unlock();
1440
1441         return retVal;
1442 }
1443
1444 #ifdef CONFIG_YAFFS_WINCE
1445 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1446 {
1447         yaffs_Object *obj;
1448
1449         int retVal = -1;
1450
1451         yaffsfs_Lock();
1452         obj = yaffsfs_GetHandleObject(fd);
1453
1454         if(obj){
1455
1456                 if(wctime){
1457                         wctime[0] = obj->win_ctime[0];
1458                         wctime[1] = obj->win_ctime[1];
1459                 }
1460                 if(watime){
1461                         watime[0] = obj->win_atime[0];
1462                         watime[1] = obj->win_atime[1];
1463                 }
1464                 if(wmtime){
1465                         wmtime[0] = obj->win_mtime[0];
1466                         wmtime[1] = obj->win_mtime[1];
1467                 }
1468
1469
1470                 retVal = 0;
1471         } else
1472                 /*  bad handle */
1473                 yaffsfs_SetError(-EBADF);               
1474         
1475         yaffsfs_Unlock();
1476         
1477         return retVal;
1478 }
1479
1480
1481 int yaffs_set_wince_times(int fd, 
1482                                                   const unsigned *wctime, 
1483                                                   const unsigned *watime, 
1484                                                   const unsigned *wmtime)
1485 {
1486         yaffs_Object *obj;
1487         int result;
1488         int retVal = -1;
1489
1490         yaffsfs_Lock();
1491         obj = yaffsfs_GetHandleObject(fd);
1492
1493         if(obj){
1494
1495                 if(wctime){
1496                         obj->win_ctime[0] = wctime[0];
1497                         obj->win_ctime[1] = wctime[1];
1498                 }
1499                 if(watime){
1500                         obj->win_atime[0] = watime[0];
1501                         obj->win_atime[1] = watime[1];
1502                 }
1503                 if(wmtime){
1504                         obj->win_mtime[0] = wmtime[0];
1505                         obj->win_mtime[1] = wmtime[1];
1506                 }
1507
1508                 obj->dirty = 1;
1509                 result = yaffs_FlushFile(obj,0,0);
1510                 retVal = 0;
1511         } else
1512                 /* bad handle */
1513                 yaffsfs_SetError(-EBADF);
1514
1515         yaffsfs_Unlock();
1516
1517         return retVal;
1518 }
1519
1520 #endif
1521
1522
1523 static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode)
1524 {
1525         int result = -1;
1526
1527         if(obj)
1528                 obj = yaffs_GetEquivalentObject(obj);
1529
1530         if(obj) {
1531                 obj->yst_mode = mode;
1532                 obj->dirty = 1;
1533                 result = yaffs_FlushFile(obj,0,0);
1534         }
1535
1536         return result == YAFFS_OK ? 0 : -1;
1537 }
1538
1539
1540 int yaffs_access(const YCHAR *path, int amode)
1541 {
1542         yaffs_Object *obj;
1543
1544         int retval = 0;
1545
1546         yaffsfs_Lock();
1547         obj = yaffsfs_FindObject(NULL,path,0);
1548
1549         if(obj) {
1550                 int access_ok = 1;
1551
1552                 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1553                         access_ok = 0;
1554                 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1555                         access_ok = 0;
1556                 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1557                         access_ok = 0;
1558
1559                 if(!access_ok) {
1560                         yaffsfs_SetError(-EACCES);
1561                         retval = -1;
1562                 }
1563         } else {
1564                 /* todo error not found */
1565                 yaffsfs_SetError(-ENOENT);
1566                 retval = -1;
1567         }
1568
1569         yaffsfs_Unlock();
1570
1571         return retval;
1572
1573 }
1574
1575
1576 int yaffs_chmod(const YCHAR *path, mode_t mode)
1577 {
1578         yaffs_Object *obj;
1579
1580         int retVal = -1;
1581
1582         yaffsfs_Lock();
1583         obj = yaffsfs_FindObject(NULL,path,0);
1584
1585         if(!obj)
1586                 yaffsfs_SetError(-ENOENT);
1587         else if(obj->myDev->readOnly)
1588                 yaffsfs_SetError(-EINVAL);
1589         else
1590                 retVal = yaffsfs_DoChMod(obj,mode);
1591
1592         yaffsfs_Unlock();
1593
1594         return retVal;
1595
1596 }
1597
1598
1599 int yaffs_fchmod(int fd, mode_t mode)
1600 {
1601         yaffs_Object *obj;
1602
1603         int retVal = -1;
1604
1605         yaffsfs_Lock();
1606         obj = yaffsfs_GetHandleObject(fd);
1607
1608         if(!obj)
1609                 yaffsfs_SetError(-ENOENT);
1610         else if(obj->myDev->readOnly)
1611                 yaffsfs_SetError(-EINVAL);
1612         else
1613                 retVal = yaffsfs_DoChMod(obj,mode);
1614
1615         yaffsfs_Unlock();
1616
1617         return retVal;
1618 }
1619
1620
1621 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1622 {
1623         yaffs_Object *parent = NULL;
1624         yaffs_Object *dir = NULL;
1625         YCHAR *name;
1626         int retVal= -1;
1627
1628         yaffsfs_Lock();
1629         parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1630         if(parent && parent->myDev->readOnly){
1631                 yaffsfs_SetError(-EINVAL);
1632         } else {
1633                 if(parent)
1634                         dir = yaffs_MknodDirectory(parent,name,mode,0,0);
1635                 if(dir)
1636                         retVal = 0;
1637                 else {
1638                         if(!parent)
1639                                 yaffsfs_SetError(-ENOENT); /* missing path */
1640                         else if (yaffs_FindObjectByName(parent,name))
1641                                 yaffsfs_SetError(-EEXIST); /* the name already exists */
1642                         else
1643                                 yaffsfs_SetError(-ENOSPC); /* just assume no space */
1644                         retVal = -1;
1645                 }
1646         }
1647
1648         yaffsfs_Unlock();
1649
1650         return retVal;
1651 }
1652
1653 int yaffs_mount2(const YCHAR *path,int readOnly)
1654 {
1655         int retVal=-1;
1656         int result=YAFFS_FAIL;
1657         yaffs_Device *dev=NULL;
1658         YCHAR *dummy;
1659
1660         T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Mounting %s" TENDSTR),path));
1661
1662         yaffsfs_Lock();
1663         dev = yaffsfs_FindDevice(path,&dummy);
1664         if(dev){
1665                 if(!dev->isMounted){
1666                         dev->readOnly = readOnly ? 1 : 0;
1667                         result = yaffs_GutsInitialise(dev);
1668                         if(result == YAFFS_FAIL)
1669                                 /* todo error - mount failed */
1670                                 yaffsfs_SetError(-ENOMEM);
1671                         retVal = result ? 0 : -1;
1672
1673                 }
1674                 else
1675                         /* todo error - already mounted. */
1676                         yaffsfs_SetError(-EBUSY);
1677         } else
1678                 /* todo error - no device */
1679                 yaffsfs_SetError(-ENODEV);
1680
1681         yaffsfs_Unlock();
1682         return retVal;
1683
1684 }
1685
1686 int yaffs_mount(const YCHAR *path)
1687 {
1688         return yaffs_mount2(path,0);
1689 }
1690
1691 int yaffs_sync(const YCHAR *path)
1692 {
1693         int retVal=-1;
1694         yaffs_Device *dev=NULL;
1695         YCHAR *dummy;
1696         
1697         yaffsfs_Lock();
1698         dev = yaffsfs_FindDevice(path,&dummy);
1699         if(dev){
1700                 if(dev->isMounted){
1701                         
1702                         yaffs_FlushEntireDeviceCache(dev);
1703                         yaffs_CheckpointSave(dev);
1704                         
1705                         
1706                 } else
1707                         /* todo error - not mounted. */
1708                         yaffsfs_SetError(-EINVAL);
1709                         
1710         }else
1711                 /* todo error - no device */
1712                 yaffsfs_SetError(-ENODEV);
1713
1714         yaffsfs_Unlock();
1715         return retVal;  
1716 }
1717
1718
1719 int yaffs_remount(const YCHAR *path, int force, int readOnly)
1720 {
1721         int retVal=-1;
1722         yaffs_Device *dev=NULL;
1723         YCHAR *dummy;
1724
1725         yaffsfs_Lock();
1726         dev = yaffsfs_FindDevice(path,&dummy);
1727         if(dev){
1728                 if(dev->isMounted){
1729                         int i;
1730                         int inUse;
1731
1732                         yaffs_FlushEntireDeviceCache(dev);
1733
1734                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse && !force; i++){
1735                                 if(yaffsfs_handle[i].useCount>0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->myDev == dev)
1736                                         inUse = 1; /* the device is in use, can't unmount */
1737                         }
1738
1739                         if(!inUse || force){
1740                                 if(readOnly)
1741                                         yaffs_CheckpointSave(dev);
1742                                 dev->readOnly =  readOnly ? 1 : 0;
1743                                 retVal = 0;
1744                         } else
1745                                 yaffsfs_SetError(-EBUSY);
1746
1747                 } else
1748                         yaffsfs_SetError(-EINVAL);
1749
1750         }
1751         else
1752                 yaffsfs_SetError(-ENODEV);
1753
1754         yaffsfs_Unlock();
1755         return retVal;
1756
1757 }
1758
1759 int yaffs_unmount2(const YCHAR *path, int force)
1760 {
1761         int retVal=-1;
1762         yaffs_Device *dev=NULL;
1763         YCHAR *dummy;
1764
1765         yaffsfs_Lock();
1766         dev = yaffsfs_FindDevice(path,&dummy);
1767         if(dev){
1768                 if(dev->isMounted){
1769                         int i;
1770                         int inUse;
1771
1772                         yaffs_FlushEntireDeviceCache(dev);
1773                         yaffs_CheckpointSave(dev);
1774
1775                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++){
1776                                 if(yaffsfs_handle[i].useCount > 0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->myDev == dev)
1777                                         inUse = 1; /* the device is in use, can't unmount */
1778                         }
1779
1780                         if(!inUse || force){
1781                                 yaffs_Deinitialise(dev);
1782
1783                                 retVal = 0;
1784                         } else
1785                                 /* todo error can't unmount as files are open */
1786                                 yaffsfs_SetError(-EBUSY);
1787
1788                 } else
1789                         /* todo error - not mounted. */
1790                         yaffsfs_SetError(-EINVAL);
1791
1792         }
1793         else
1794                 /* todo error - no device */
1795                 yaffsfs_SetError(-ENODEV);
1796
1797         yaffsfs_Unlock();
1798         return retVal;
1799
1800 }
1801
1802 int yaffs_unmount(const YCHAR *path)
1803 {
1804         return yaffs_unmount2(path,0);
1805 }
1806
1807 loff_t yaffs_freespace(const YCHAR *path)
1808 {
1809         loff_t retVal=-1;
1810         yaffs_Device *dev=NULL;
1811         YCHAR *dummy;
1812
1813         yaffsfs_Lock();
1814         dev = yaffsfs_FindDevice(path,&dummy);
1815         if(dev  && dev->isMounted){
1816                 retVal = yaffs_GetNumberOfFreeChunks(dev);
1817                 retVal *= dev->nDataBytesPerChunk;
1818
1819         } else
1820                 yaffsfs_SetError(-EINVAL);
1821
1822         yaffsfs_Unlock();
1823         return retVal;
1824 }
1825
1826 loff_t yaffs_totalspace(const YCHAR *path)
1827 {
1828         loff_t retVal=-1;
1829         yaffs_Device *dev=NULL;
1830         YCHAR *dummy;
1831
1832         yaffsfs_Lock();
1833         dev = yaffsfs_FindDevice(path,&dummy);
1834         if(dev  && dev->isMounted){
1835                 retVal = (dev->param.endBlock - dev->param.startBlock + 1) - dev->param.nReservedBlocks;
1836                 retVal *= dev->param.nChunksPerBlock;
1837                 retVal *= dev->nDataBytesPerChunk;
1838
1839         } else
1840                 yaffsfs_SetError(-EINVAL);
1841
1842         yaffsfs_Unlock();
1843         return retVal;
1844 }
1845
1846 int yaffs_inodecount(const YCHAR *path)
1847 {
1848         loff_t retVal= -1;
1849         yaffs_Device *dev=NULL;
1850         YCHAR *dummy;
1851
1852         yaffsfs_Lock();
1853         dev = yaffsfs_FindDevice(path,&dummy);
1854         if(dev  && dev->isMounted) {
1855            int nObjects = dev->nObjects;
1856            if(nObjects > dev->nHardLinks)
1857                 retVal = nObjects - dev->nHardLinks;
1858         }
1859         
1860         if(retVal < 0)
1861                 yaffsfs_SetError(-EINVAL);
1862         
1863         yaffsfs_Unlock();
1864         return retVal;  
1865 }
1866
1867
1868 void yaffs_AddDevice(yaffs_Device *dev)
1869 {
1870         dev->isMounted = 0;
1871         dev->param.removeObjectCallback = yaffsfs_RemoveObjectCallback;
1872
1873         if(!dev->devList.next)
1874                 YINIT_LIST_HEAD(&dev->devList);
1875
1876         ylist_add(&dev->devList,&yaffsfs_deviceList);
1877 }
1878
1879 void yaffs_RemoveDevice(yaffs_Device *dev)
1880 {
1881         ylist_del_init(&dev->devList);
1882 }
1883
1884
1885
1886
1887 /* Directory search stuff. */
1888
1889 /*
1890  * Directory search context
1891  *
1892  * NB this is an opaque structure.
1893  */
1894
1895
1896 typedef struct
1897 {
1898         __u32 magic;
1899         yaffs_dirent de;                /* directory entry being used by this dsc */
1900         YCHAR name[NAME_MAX+1];         /* name of directory being searched */
1901         yaffs_Object *dirObj;           /* ptr to directory being searched */
1902         yaffs_Object *nextReturn;       /* obj to be returned by next readddir */
1903         int offset;
1904         struct ylist_head others;       
1905 } yaffsfs_DirectorySearchContext;
1906
1907
1908
1909 static struct ylist_head search_contexts;
1910
1911
1912 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
1913 {
1914         if(dsc &&
1915            dsc->dirObj &&
1916            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1917
1918            dsc->offset = 0;
1919
1920            if( ylist_empty(&dsc->dirObj->variant.directoryVariant.children))
1921                 dsc->nextReturn = NULL;
1922            else
1923                 dsc->nextReturn = ylist_entry(dsc->dirObj->variant.directoryVariant.children.next,
1924                                                 yaffs_Object,siblings);
1925         } else {
1926                 /* Hey someone isn't playing nice! */
1927         }
1928 }
1929
1930 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
1931 {
1932         if(dsc &&
1933            dsc->dirObj &&
1934            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1935
1936            if( dsc->nextReturn == NULL ||
1937                ylist_empty(&dsc->dirObj->variant.directoryVariant.children))
1938                 dsc->nextReturn = NULL;
1939            else {
1940                    struct ylist_head *next = dsc->nextReturn->siblings.next;
1941
1942                    if( next == &dsc->dirObj->variant.directoryVariant.children)
1943                         dsc->nextReturn = NULL; /* end of list */
1944                    else
1945                         dsc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
1946            }
1947         } else {
1948                 /* Hey someone isn't playing nice! */
1949         }
1950 }
1951
1952 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj)
1953 {
1954
1955         struct ylist_head *i;
1956         yaffsfs_DirectorySearchContext *dsc;
1957
1958         /* if search contexts not initilised then skip */
1959         if(!search_contexts.next)
1960                 return;
1961
1962         /* Iterate through the directory search contexts.
1963          * If any are the one being removed, then advance the dsc to
1964          * the next one to prevent a hanging ptr.
1965          */
1966          ylist_for_each(i, &search_contexts) {
1967                 if (i) {
1968                         dsc = ylist_entry(i, yaffsfs_DirectorySearchContext,others);
1969                         if(dsc->nextReturn == obj)
1970                                 yaffsfs_DirAdvance(dsc);
1971                 }
1972         }
1973
1974 }
1975
1976 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
1977 {
1978         yaffs_DIR *dir = NULL;
1979         yaffs_Object *obj = NULL;
1980         yaffsfs_DirectorySearchContext *dsc = NULL;
1981
1982         yaffsfs_Lock();
1983
1984         obj = yaffsfs_FindObject(NULL,dirname,0);
1985
1986         if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1987
1988                 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
1989                 dir = (yaffs_DIR *)dsc;
1990
1991                 if(dsc){
1992                         memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
1993                         dsc->magic = YAFFS_MAGIC;
1994                         dsc->dirObj = obj;
1995                         yaffs_strncpy(dsc->name,dirname,NAME_MAX);
1996                         YINIT_LIST_HEAD(&dsc->others);
1997
1998                         if(!search_contexts.next)
1999                                 YINIT_LIST_HEAD(&search_contexts);
2000
2001                         ylist_add(&dsc->others,&search_contexts);       
2002                         yaffsfs_SetDirRewound(dsc);
2003                 }
2004
2005         }
2006
2007         yaffsfs_Unlock();
2008
2009         return dir;
2010 }
2011
2012 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
2013 {
2014         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2015         struct yaffs_dirent *retVal = NULL;
2016
2017         yaffsfs_Lock();
2018
2019         if(dsc && dsc->magic == YAFFS_MAGIC){
2020                 yaffsfs_SetError(0);
2021                 if(dsc->nextReturn){
2022                         dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId;
2023                         dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
2024                         dsc->de.d_off = dsc->offset++;
2025                         yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
2026                         if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
2027                         {
2028                                 /* this should not happen! */
2029                                 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
2030                         }
2031                         dsc->de.d_reclen = sizeof(struct yaffs_dirent);
2032                         retVal = &dsc->de;
2033                         yaffsfs_DirAdvance(dsc);
2034                 } else
2035                         retVal = NULL;
2036         } else
2037                 yaffsfs_SetError(-EBADF);
2038
2039         yaffsfs_Unlock();
2040
2041         return retVal;
2042
2043 }
2044
2045
2046 void yaffs_rewinddir(yaffs_DIR *dirp)
2047 {
2048         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2049
2050         yaffsfs_Lock();
2051
2052         yaffsfs_SetDirRewound(dsc);
2053
2054         yaffsfs_Unlock();
2055 }
2056
2057
2058 int yaffs_closedir(yaffs_DIR *dirp)
2059 {
2060         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2061
2062         yaffsfs_Lock();
2063         dsc->magic = 0;
2064         ylist_del(&dsc->others); /* unhook from list */
2065         YFREE(dsc);
2066         yaffsfs_Unlock();
2067         return 0;
2068 }
2069
2070 /* End of directory stuff */
2071
2072
2073 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
2074 {
2075         yaffs_Object *parent = NULL;
2076         yaffs_Object *obj;
2077         YCHAR *name;
2078         int retVal= -1;
2079         int mode = 0; /* ignore for now */
2080
2081         yaffsfs_Lock();
2082         parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
2083         if(parent && parent->myDev->readOnly)
2084                 yaffsfs_SetError(-EINVAL);
2085         else if(parent){
2086                 obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath);
2087                 if(obj)
2088                         retVal = 0;
2089                 else{
2090                         yaffsfs_SetError(-ENOSPC); /* just assume no space for now */
2091                         retVal = -1;
2092                 }
2093         } else {
2094                 yaffsfs_SetError(-EINVAL);
2095                 retVal = -1;
2096         }
2097
2098         yaffsfs_Unlock();
2099
2100         return retVal;
2101
2102 }
2103
2104 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
2105 {
2106         yaffs_Object *obj = NULL;
2107         int retVal;
2108
2109
2110         yaffsfs_Lock();
2111
2112         obj = yaffsfs_FindObject(NULL,path,0);
2113
2114         if(!obj) {
2115                 yaffsfs_SetError(-ENOENT);
2116                 retVal = -1;
2117         } else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK) {
2118                 yaffsfs_SetError(-EINVAL);
2119                 retVal = -1;
2120         } else {
2121                 YCHAR *alias = obj->variant.symLinkVariant.alias;
2122                 memset(buf,0,bufsiz);
2123                 yaffs_strncpy(buf,alias,bufsiz - 1);
2124                 retVal = 0;
2125         }
2126         yaffsfs_Unlock();
2127         return retVal;
2128 }
2129
2130 int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath)
2131 {
2132         /* Creates a link called newpath to existing oldpath */
2133         yaffs_Object *obj = NULL;
2134         yaffs_Object *target = NULL;
2135         int retVal = 0;
2136         int newNameLength = 0;
2137
2138
2139         yaffsfs_Lock();
2140
2141         obj = yaffsfs_FindObject(NULL,oldpath,0);
2142         target = yaffsfs_FindObject(NULL,newpath,0);
2143
2144         if(!obj) {
2145                 yaffsfs_SetError(-ENOENT);
2146                 retVal = -1;
2147         } else if(obj->myDev->readOnly){
2148                 yaffsfs_SetError(-EINVAL);
2149                 retVal= -1;
2150         } else if(target) {
2151                 yaffsfs_SetError(-EEXIST);
2152                 retVal = -1;
2153         } else {
2154                 yaffs_Object *newdir = NULL;
2155                 yaffs_Object *link = NULL;
2156
2157                 YCHAR *newname;
2158
2159                 newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
2160
2161                 if(!newdir){
2162                         yaffsfs_SetError(-ENOTDIR);
2163                         retVal = -1;
2164                 }else if(newdir->myDev != obj->myDev){
2165                         yaffsfs_SetError(-EXDEV);
2166                         retVal = -1;
2167                 }
2168                 
2169                 newNameLength = yaffs_strnlen(newname,YAFFS_MAX_NAME_LENGTH+1);
2170                 
2171                 if(newNameLength == 0){
2172                         yaffsfs_SetError(-ENOENT);
2173                         retVal = -1;
2174                 } else if (newNameLength > YAFFS_MAX_NAME_LENGTH){
2175                         yaffsfs_SetError(-ENAMETOOLONG);
2176                         retVal = -1;
2177                 }
2178                 
2179                 if(retVal == 0) {
2180                         link = yaffs_Link(newdir,newname,obj);
2181                         if(link)
2182                                 retVal = 0;
2183                         else{
2184                                 yaffsfs_SetError(-ENOSPC);
2185                                 retVal = -1;
2186                         }
2187
2188                 }
2189         }
2190         yaffsfs_Unlock();
2191
2192         return retVal;
2193 }
2194
2195 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
2196 {
2197         return -1;
2198 }
2199
2200 int yaffs_DumpDevStruct(const YCHAR *path)
2201 {
2202 #if 0
2203         YCHAR *rest;
2204
2205         yaffs_Object *obj = yaffsfs_FindRoot(path,&rest);
2206
2207         if(obj){
2208                 yaffs_Device *dev = obj->myDev;
2209
2210                 printf("\n"
2211                            "nPageWrites.......... %d\n"
2212                            "nPageReads........... %d\n"
2213                            "nBlockErasures....... %d\n"
2214                            "nGCCopies............ %d\n"
2215                            "garbageCollections... %d\n"
2216                            "passiveGarbageColl'ns %d\n"
2217                            "\n",
2218                                 dev->nPageWrites,
2219                                 dev->nPageReads,
2220                                 dev->nBlockErasures,
2221                                 dev->nGCCopies,
2222                                 dev->garbageCollections,
2223                                 dev->passiveGarbageCollections
2224                 );
2225
2226         }
2227
2228 #endif
2229         return 0;
2230 }
2231