yaffs Move yaffscfg.h to where it should be
[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 #ifndef CONFIG_YAFFS_WINCE
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 #endif
1444
1445 #ifdef CONFIG_YAFFS_WINCE
1446 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1447 {
1448         yaffs_Object *obj;
1449
1450         int retVal = -1;
1451
1452         yaffsfs_Lock();
1453         obj = yaffsfs_GetHandleObject(fd);
1454
1455         if(obj){
1456
1457                 if(wctime){
1458                         wctime[0] = obj->win_ctime[0];
1459                         wctime[1] = obj->win_ctime[1];
1460                 }
1461                 if(watime){
1462                         watime[0] = obj->win_atime[0];
1463                         watime[1] = obj->win_atime[1];
1464                 }
1465                 if(wmtime){
1466                         wmtime[0] = obj->win_mtime[0];
1467                         wmtime[1] = obj->win_mtime[1];
1468                 }
1469
1470
1471                 retVal = 0;
1472         } else
1473                 /*  bad handle */
1474                 yaffsfs_SetError(-EBADF);               
1475         
1476         yaffsfs_Unlock();
1477         
1478         return retVal;
1479 }
1480
1481
1482 int yaffs_set_wince_times(int fd, 
1483                                                   const unsigned *wctime, 
1484                                                   const unsigned *watime, 
1485                                                   const unsigned *wmtime)
1486 {
1487         yaffs_Object *obj;
1488         int result;
1489         int retVal = -1;
1490
1491         yaffsfs_Lock();
1492         obj = yaffsfs_GetHandleObject(fd);
1493
1494         if(obj){
1495
1496                 if(wctime){
1497                         obj->win_ctime[0] = wctime[0];
1498                         obj->win_ctime[1] = wctime[1];
1499                 }
1500                 if(watime){
1501                         obj->win_atime[0] = watime[0];
1502                         obj->win_atime[1] = watime[1];
1503                 }
1504                 if(wmtime){
1505                         obj->win_mtime[0] = wmtime[0];
1506                         obj->win_mtime[1] = wmtime[1];
1507                 }
1508
1509                 obj->dirty = 1;
1510                 result = yaffs_FlushFile(obj,0,0);
1511                 retVal = 0;
1512         } else
1513                 /* bad handle */
1514                 yaffsfs_SetError(-EBADF);
1515
1516         yaffsfs_Unlock();
1517
1518         return retVal;
1519 }
1520
1521 #endif
1522
1523
1524 static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode)
1525 {
1526         int result = -1;
1527
1528         if(obj)
1529                 obj = yaffs_GetEquivalentObject(obj);
1530
1531         if(obj) {
1532                 obj->yst_mode = mode;
1533                 obj->dirty = 1;
1534                 result = yaffs_FlushFile(obj,0,0);
1535         }
1536
1537         return result == YAFFS_OK ? 0 : -1;
1538 }
1539
1540
1541 int yaffs_access(const YCHAR *path, int amode)
1542 {
1543         yaffs_Object *obj;
1544
1545         int retval = 0;
1546
1547         yaffsfs_Lock();
1548         obj = yaffsfs_FindObject(NULL,path,0);
1549
1550         if(obj) {
1551                 int access_ok = 1;
1552
1553                 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1554                         access_ok = 0;
1555                 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1556                         access_ok = 0;
1557                 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1558                         access_ok = 0;
1559
1560                 if(!access_ok) {
1561                         yaffsfs_SetError(-EACCES);
1562                         retval = -1;
1563                 }
1564         } else {
1565                 /* todo error not found */
1566                 yaffsfs_SetError(-ENOENT);
1567                 retval = -1;
1568         }
1569
1570         yaffsfs_Unlock();
1571
1572         return retval;
1573
1574 }
1575
1576
1577 int yaffs_chmod(const YCHAR *path, mode_t mode)
1578 {
1579         yaffs_Object *obj;
1580
1581         int retVal = -1;
1582
1583         yaffsfs_Lock();
1584         obj = yaffsfs_FindObject(NULL,path,0);
1585
1586         if(!obj)
1587                 yaffsfs_SetError(-ENOENT);
1588         else if(obj->myDev->readOnly)
1589                 yaffsfs_SetError(-EINVAL);
1590         else
1591                 retVal = yaffsfs_DoChMod(obj,mode);
1592
1593         yaffsfs_Unlock();
1594
1595         return retVal;
1596
1597 }
1598
1599
1600 int yaffs_fchmod(int fd, mode_t mode)
1601 {
1602         yaffs_Object *obj;
1603
1604         int retVal = -1;
1605
1606         yaffsfs_Lock();
1607         obj = yaffsfs_GetHandleObject(fd);
1608
1609         if(!obj)
1610                 yaffsfs_SetError(-ENOENT);
1611         else if(obj->myDev->readOnly)
1612                 yaffsfs_SetError(-EINVAL);
1613         else
1614                 retVal = yaffsfs_DoChMod(obj,mode);
1615
1616         yaffsfs_Unlock();
1617
1618         return retVal;
1619 }
1620
1621
1622 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1623 {
1624         yaffs_Object *parent = NULL;
1625         yaffs_Object *dir = NULL;
1626         YCHAR *name;
1627         int retVal= -1;
1628
1629         yaffsfs_Lock();
1630         parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1631         if(parent && parent->myDev->readOnly){
1632                 yaffsfs_SetError(-EINVAL);
1633         } else {
1634                 if(parent)
1635                         dir = yaffs_MknodDirectory(parent,name,mode,0,0);
1636                 if(dir)
1637                         retVal = 0;
1638                 else {
1639                         if(!parent)
1640                                 yaffsfs_SetError(-ENOENT); /* missing path */
1641                         else if (yaffs_FindObjectByName(parent,name))
1642                                 yaffsfs_SetError(-EEXIST); /* the name already exists */
1643                         else
1644                                 yaffsfs_SetError(-ENOSPC); /* just assume no space */
1645                         retVal = -1;
1646                 }
1647         }
1648
1649         yaffsfs_Unlock();
1650
1651         return retVal;
1652 }
1653
1654 int yaffs_mount2(const YCHAR *path,int readOnly)
1655 {
1656         int retVal=-1;
1657         int result=YAFFS_FAIL;
1658         yaffs_Device *dev=NULL;
1659         YCHAR *dummy;
1660
1661         T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Mounting %s" TENDSTR),path));
1662
1663         yaffsfs_Lock();
1664         dev = yaffsfs_FindDevice(path,&dummy);
1665         if(dev){
1666                 if(!dev->isMounted){
1667                         dev->readOnly = readOnly ? 1 : 0;
1668                         result = yaffs_GutsInitialise(dev);
1669                         if(result == YAFFS_FAIL)
1670                                 /* todo error - mount failed */
1671                                 yaffsfs_SetError(-ENOMEM);
1672                         retVal = result ? 0 : -1;
1673
1674                 }
1675                 else
1676                         /* todo error - already mounted. */
1677                         yaffsfs_SetError(-EBUSY);
1678         } else
1679                 /* todo error - no device */
1680                 yaffsfs_SetError(-ENODEV);
1681
1682         yaffsfs_Unlock();
1683         return retVal;
1684
1685 }
1686
1687 int yaffs_mount(const YCHAR *path)
1688 {
1689         return yaffs_mount2(path,0);
1690 }
1691
1692 int yaffs_sync(const YCHAR *path)
1693 {
1694         int retVal=-1;
1695         yaffs_Device *dev=NULL;
1696         YCHAR *dummy;
1697         
1698         yaffsfs_Lock();
1699         dev = yaffsfs_FindDevice(path,&dummy);
1700         if(dev){
1701                 if(dev->isMounted){
1702                         
1703                         yaffs_FlushEntireDeviceCache(dev);
1704                         yaffs_CheckpointSave(dev);
1705                         
1706                         
1707                 } else
1708                         /* todo error - not mounted. */
1709                         yaffsfs_SetError(-EINVAL);
1710                         
1711         }else
1712                 /* todo error - no device */
1713                 yaffsfs_SetError(-ENODEV);
1714
1715         yaffsfs_Unlock();
1716         return retVal;  
1717 }
1718
1719
1720 int yaffs_remount(const YCHAR *path, int force, int readOnly)
1721 {
1722         int retVal=-1;
1723         yaffs_Device *dev=NULL;
1724         YCHAR *dummy;
1725
1726         yaffsfs_Lock();
1727         dev = yaffsfs_FindDevice(path,&dummy);
1728         if(dev){
1729                 if(dev->isMounted){
1730                         int i;
1731                         int inUse;
1732
1733                         yaffs_FlushEntireDeviceCache(dev);
1734
1735                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse && !force; i++){
1736                                 if(yaffsfs_handle[i].useCount>0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->myDev == dev)
1737                                         inUse = 1; /* the device is in use, can't unmount */
1738                         }
1739
1740                         if(!inUse || force){
1741                                 if(readOnly)
1742                                         yaffs_CheckpointSave(dev);
1743                                 dev->readOnly =  readOnly ? 1 : 0;
1744                                 retVal = 0;
1745                         } else
1746                                 yaffsfs_SetError(-EBUSY);
1747
1748                 } else
1749                         yaffsfs_SetError(-EINVAL);
1750
1751         }
1752         else
1753                 yaffsfs_SetError(-ENODEV);
1754
1755         yaffsfs_Unlock();
1756         return retVal;
1757
1758 }
1759
1760 int yaffs_unmount2(const YCHAR *path, int force)
1761 {
1762         int retVal=-1;
1763         yaffs_Device *dev=NULL;
1764         YCHAR *dummy;
1765
1766         yaffsfs_Lock();
1767         dev = yaffsfs_FindDevice(path,&dummy);
1768         if(dev){
1769                 if(dev->isMounted){
1770                         int i;
1771                         int inUse;
1772
1773                         yaffs_FlushEntireDeviceCache(dev);
1774                         yaffs_CheckpointSave(dev);
1775
1776                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++){
1777                                 if(yaffsfs_handle[i].useCount > 0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->myDev == dev)
1778                                         inUse = 1; /* the device is in use, can't unmount */
1779                         }
1780
1781                         if(!inUse || force){
1782                                 yaffs_Deinitialise(dev);
1783
1784                                 retVal = 0;
1785                         } else
1786                                 /* todo error can't unmount as files are open */
1787                                 yaffsfs_SetError(-EBUSY);
1788
1789                 } else
1790                         /* todo error - not mounted. */
1791                         yaffsfs_SetError(-EINVAL);
1792
1793         }
1794         else
1795                 /* todo error - no device */
1796                 yaffsfs_SetError(-ENODEV);
1797
1798         yaffsfs_Unlock();
1799         return retVal;
1800
1801 }
1802
1803 int yaffs_unmount(const YCHAR *path)
1804 {
1805         return yaffs_unmount2(path,0);
1806 }
1807
1808 loff_t yaffs_freespace(const YCHAR *path)
1809 {
1810         loff_t retVal=-1;
1811         yaffs_Device *dev=NULL;
1812         YCHAR *dummy;
1813
1814         yaffsfs_Lock();
1815         dev = yaffsfs_FindDevice(path,&dummy);
1816         if(dev  && dev->isMounted){
1817                 retVal = yaffs_GetNumberOfFreeChunks(dev);
1818                 retVal *= dev->nDataBytesPerChunk;
1819
1820         } else
1821                 yaffsfs_SetError(-EINVAL);
1822
1823         yaffsfs_Unlock();
1824         return retVal;
1825 }
1826
1827 loff_t yaffs_totalspace(const YCHAR *path)
1828 {
1829         loff_t retVal=-1;
1830         yaffs_Device *dev=NULL;
1831         YCHAR *dummy;
1832
1833         yaffsfs_Lock();
1834         dev = yaffsfs_FindDevice(path,&dummy);
1835         if(dev  && dev->isMounted){
1836                 retVal = (dev->param.endBlock - dev->param.startBlock + 1) - dev->param.nReservedBlocks;
1837                 retVal *= dev->param.nChunksPerBlock;
1838                 retVal *= dev->nDataBytesPerChunk;
1839
1840         } else
1841                 yaffsfs_SetError(-EINVAL);
1842
1843         yaffsfs_Unlock();
1844         return retVal;
1845 }
1846
1847 int yaffs_inodecount(const YCHAR *path)
1848 {
1849         loff_t retVal= -1;
1850         yaffs_Device *dev=NULL;
1851         YCHAR *dummy;
1852
1853         yaffsfs_Lock();
1854         dev = yaffsfs_FindDevice(path,&dummy);
1855         if(dev  && dev->isMounted) {
1856            int nObjects = dev->nObjects;
1857            if(nObjects > dev->nHardLinks)
1858                 retVal = nObjects - dev->nHardLinks;
1859         }
1860         
1861         if(retVal < 0)
1862                 yaffsfs_SetError(-EINVAL);
1863         
1864         yaffsfs_Unlock();
1865         return retVal;  
1866 }
1867
1868
1869 void yaffs_AddDevice(yaffs_Device *dev)
1870 {
1871         dev->isMounted = 0;
1872         dev->param.removeObjectCallback = yaffsfs_RemoveObjectCallback;
1873
1874         if(!dev->devList.next)
1875                 YINIT_LIST_HEAD(&dev->devList);
1876
1877         ylist_add(&dev->devList,&yaffsfs_deviceList);
1878 }
1879
1880 void yaffs_RemoveDevice(yaffs_Device *dev)
1881 {
1882         ylist_del_init(&dev->devList);
1883 }
1884
1885
1886
1887
1888 /* Directory search stuff. */
1889
1890 /*
1891  * Directory search context
1892  *
1893  * NB this is an opaque structure.
1894  */
1895
1896
1897 typedef struct
1898 {
1899         __u32 magic;
1900         yaffs_dirent de;                /* directory entry being used by this dsc */
1901         YCHAR name[NAME_MAX+1];         /* name of directory being searched */
1902         yaffs_Object *dirObj;           /* ptr to directory being searched */
1903         yaffs_Object *nextReturn;       /* obj to be returned by next readddir */
1904         int offset;
1905         struct ylist_head others;       
1906 } yaffsfs_DirectorySearchContext;
1907
1908
1909
1910 static struct ylist_head search_contexts;
1911
1912
1913 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
1914 {
1915         if(dsc &&
1916            dsc->dirObj &&
1917            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1918
1919            dsc->offset = 0;
1920
1921            if( ylist_empty(&dsc->dirObj->variant.directoryVariant.children))
1922                 dsc->nextReturn = NULL;
1923            else
1924                 dsc->nextReturn = ylist_entry(dsc->dirObj->variant.directoryVariant.children.next,
1925                                                 yaffs_Object,siblings);
1926         } else {
1927                 /* Hey someone isn't playing nice! */
1928         }
1929 }
1930
1931 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
1932 {
1933         if(dsc &&
1934            dsc->dirObj &&
1935            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1936
1937            if( dsc->nextReturn == NULL ||
1938                ylist_empty(&dsc->dirObj->variant.directoryVariant.children))
1939                 dsc->nextReturn = NULL;
1940            else {
1941                    struct ylist_head *next = dsc->nextReturn->siblings.next;
1942
1943                    if( next == &dsc->dirObj->variant.directoryVariant.children)
1944                         dsc->nextReturn = NULL; /* end of list */
1945                    else
1946                         dsc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
1947            }
1948         } else {
1949                 /* Hey someone isn't playing nice! */
1950         }
1951 }
1952
1953 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj)
1954 {
1955
1956         struct ylist_head *i;
1957         yaffsfs_DirectorySearchContext *dsc;
1958
1959         /* if search contexts not initilised then skip */
1960         if(!search_contexts.next)
1961                 return;
1962
1963         /* Iterate through the directory search contexts.
1964          * If any are the one being removed, then advance the dsc to
1965          * the next one to prevent a hanging ptr.
1966          */
1967          ylist_for_each(i, &search_contexts) {
1968                 if (i) {
1969                         dsc = ylist_entry(i, yaffsfs_DirectorySearchContext,others);
1970                         if(dsc->nextReturn == obj)
1971                                 yaffsfs_DirAdvance(dsc);
1972                 }
1973         }
1974
1975 }
1976
1977 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
1978 {
1979         yaffs_DIR *dir = NULL;
1980         yaffs_Object *obj = NULL;
1981         yaffsfs_DirectorySearchContext *dsc = NULL;
1982
1983         yaffsfs_Lock();
1984
1985         obj = yaffsfs_FindObject(NULL,dirname,0);
1986
1987         if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1988
1989                 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
1990                 dir = (yaffs_DIR *)dsc;
1991
1992                 if(dsc){
1993                         memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
1994                         dsc->magic = YAFFS_MAGIC;
1995                         dsc->dirObj = obj;
1996                         yaffs_strncpy(dsc->name,dirname,NAME_MAX);
1997                         YINIT_LIST_HEAD(&dsc->others);
1998
1999                         if(!search_contexts.next)
2000                                 YINIT_LIST_HEAD(&search_contexts);
2001
2002                         ylist_add(&dsc->others,&search_contexts);       
2003                         yaffsfs_SetDirRewound(dsc);
2004                 }
2005
2006         }
2007
2008         yaffsfs_Unlock();
2009
2010         return dir;
2011 }
2012
2013 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
2014 {
2015         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2016         struct yaffs_dirent *retVal = NULL;
2017
2018         yaffsfs_Lock();
2019
2020         if(dsc && dsc->magic == YAFFS_MAGIC){
2021                 yaffsfs_SetError(0);
2022                 if(dsc->nextReturn){
2023                         dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId;
2024                         dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
2025                         dsc->de.d_off = dsc->offset++;
2026                         yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
2027                         if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
2028                         {
2029                                 /* this should not happen! */
2030                                 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
2031                         }
2032                         dsc->de.d_reclen = sizeof(struct yaffs_dirent);
2033                         retVal = &dsc->de;
2034                         yaffsfs_DirAdvance(dsc);
2035                 } else
2036                         retVal = NULL;
2037         } else
2038                 yaffsfs_SetError(-EBADF);
2039
2040         yaffsfs_Unlock();
2041
2042         return retVal;
2043
2044 }
2045
2046
2047 void yaffs_rewinddir(yaffs_DIR *dirp)
2048 {
2049         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2050
2051         yaffsfs_Lock();
2052
2053         yaffsfs_SetDirRewound(dsc);
2054
2055         yaffsfs_Unlock();
2056 }
2057
2058
2059 int yaffs_closedir(yaffs_DIR *dirp)
2060 {
2061         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
2062
2063         yaffsfs_Lock();
2064         dsc->magic = 0;
2065         ylist_del(&dsc->others); /* unhook from list */
2066         YFREE(dsc);
2067         yaffsfs_Unlock();
2068         return 0;
2069 }
2070
2071 /* End of directory stuff */
2072
2073
2074 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
2075 {
2076         yaffs_Object *parent = NULL;
2077         yaffs_Object *obj;
2078         YCHAR *name;
2079         int retVal= -1;
2080         int mode = 0; /* ignore for now */
2081
2082         yaffsfs_Lock();
2083         parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
2084         if(parent && parent->myDev->readOnly)
2085                 yaffsfs_SetError(-EINVAL);
2086         else if(parent){
2087                 obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath);
2088                 if(obj)
2089                         retVal = 0;
2090                 else{
2091                         yaffsfs_SetError(-ENOSPC); /* just assume no space for now */
2092                         retVal = -1;
2093                 }
2094         } else {
2095                 yaffsfs_SetError(-EINVAL);
2096                 retVal = -1;
2097         }
2098
2099         yaffsfs_Unlock();
2100
2101         return retVal;
2102
2103 }
2104
2105 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
2106 {
2107         yaffs_Object *obj = NULL;
2108         int retVal;
2109
2110
2111         yaffsfs_Lock();
2112
2113         obj = yaffsfs_FindObject(NULL,path,0);
2114
2115         if(!obj) {
2116                 yaffsfs_SetError(-ENOENT);
2117                 retVal = -1;
2118         } else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK) {
2119                 yaffsfs_SetError(-EINVAL);
2120                 retVal = -1;
2121         } else {
2122                 YCHAR *alias = obj->variant.symLinkVariant.alias;
2123                 memset(buf,0,bufsiz);
2124                 yaffs_strncpy(buf,alias,bufsiz - 1);
2125                 retVal = 0;
2126         }
2127         yaffsfs_Unlock();
2128         return retVal;
2129 }
2130
2131 int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath)
2132 {
2133         /* Creates a link called newpath to existing oldpath */
2134         yaffs_Object *obj = NULL;
2135         yaffs_Object *target = NULL;
2136         int retVal = 0;
2137         int newNameLength = 0;
2138
2139
2140         yaffsfs_Lock();
2141
2142         obj = yaffsfs_FindObject(NULL,oldpath,0);
2143         target = yaffsfs_FindObject(NULL,newpath,0);
2144
2145         if(!obj) {
2146                 yaffsfs_SetError(-ENOENT);
2147                 retVal = -1;
2148         } else if(obj->myDev->readOnly){
2149                 yaffsfs_SetError(-EINVAL);
2150                 retVal= -1;
2151         } else if(target) {
2152                 yaffsfs_SetError(-EEXIST);
2153                 retVal = -1;
2154         } else {
2155                 yaffs_Object *newdir = NULL;
2156                 yaffs_Object *link = NULL;
2157
2158                 YCHAR *newname;
2159
2160                 newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
2161
2162                 if(!newdir){
2163                         yaffsfs_SetError(-ENOTDIR);
2164                         retVal = -1;
2165                 }else if(newdir->myDev != obj->myDev){
2166                         yaffsfs_SetError(-EXDEV);
2167                         retVal = -1;
2168                 }
2169                 
2170                 newNameLength = yaffs_strnlen(newname,YAFFS_MAX_NAME_LENGTH+1);
2171                 
2172                 if(newNameLength == 0){
2173                         yaffsfs_SetError(-ENOENT);
2174                         retVal = -1;
2175                 } else if (newNameLength > YAFFS_MAX_NAME_LENGTH){
2176                         yaffsfs_SetError(-ENAMETOOLONG);
2177                         retVal = -1;
2178                 }
2179                 
2180                 if(retVal == 0) {
2181                         link = yaffs_Link(newdir,newname,obj);
2182                         if(link)
2183                                 retVal = 0;
2184                         else{
2185                                 yaffsfs_SetError(-ENOSPC);
2186                                 retVal = -1;
2187                         }
2188
2189                 }
2190         }
2191         yaffsfs_Unlock();
2192
2193         return retVal;
2194 }
2195
2196 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
2197 {
2198         return -1;
2199 }
2200
2201 int yaffs_DumpDevStruct(const YCHAR *path)
2202 {
2203 #if 0
2204         YCHAR *rest;
2205
2206         yaffs_Object *obj = yaffsfs_FindRoot(path,&rest);
2207
2208         if(obj){
2209                 yaffs_Device *dev = obj->myDev;
2210
2211                 printf("\n"
2212                            "nPageWrites.......... %d\n"
2213                            "nPageReads........... %d\n"
2214                            "nBlockErasures....... %d\n"
2215                            "nGCCopies............ %d\n"
2216                            "garbageCollections... %d\n"
2217                            "passiveGarbageColl'ns %d\n"
2218                            "\n",
2219                                 dev->nPageWrites,
2220                                 dev->nPageReads,
2221                                 dev->nBlockErasures,
2222                                 dev->nGCCopies,
2223                                 dev->garbageCollections,
2224                                 dev->passiveGarbageCollections
2225                 );
2226
2227         }
2228
2229 #endif
2230         return 0;
2231 }
2232