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