ddbdcdb65354743c00bc02efc70e8111044f6119
[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(isPwrite)
830                         startPos = offset;
831                 if(h->append)
832                         startPos = yaffs_GetObjectFileLength(obj);
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 #ifdef CONFIG_YAFFS_WINCE
1184 int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
1185 {
1186         yaffs_Object *obj;
1187
1188         int retVal = -1;
1189
1190         yaffsfs_Lock();
1191         obj = yaffsfs_GetHandleObject(fd);
1192
1193         if(obj){
1194
1195                 if(wctime){
1196                         wctime[0] = obj->win_ctime[0];
1197                         wctime[1] = obj->win_ctime[1];
1198                 }
1199                 if(watime){
1200                         watime[0] = obj->win_atime[0];
1201                         watime[1] = obj->win_atime[1];
1202                 }
1203                 if(wmtime){
1204                         wmtime[0] = obj->win_mtime[0];
1205                         wmtime[1] = obj->win_mtime[1];
1206                 }
1207
1208
1209                 retVal = 0;
1210         } else
1211                 /*  bad handle */
1212                 yaffsfs_SetError(-EBADF);               
1213         
1214         yaffsfs_Unlock();
1215         
1216         return retVal;
1217 }
1218
1219
1220 int yaffs_set_wince_times(int fd, 
1221                                                   const unsigned *wctime, 
1222                                                   const unsigned *watime, 
1223                                                   const unsigned *wmtime)
1224 {
1225         yaffs_Object *obj;
1226         int result;
1227         int retVal = -1;
1228
1229         yaffsfs_Lock();
1230         obj = yaffsfs_GetHandleObject(fd);
1231
1232         if(obj){
1233
1234                 if(wctime){
1235                         obj->win_ctime[0] = wctime[0];
1236                         obj->win_ctime[1] = wctime[1];
1237                 }
1238                 if(watime){
1239                         obj->win_atime[0] = watime[0];
1240                         obj->win_atime[1] = watime[1];
1241                 }
1242                 if(wmtime){
1243                         obj->win_mtime[0] = wmtime[0];
1244                         obj->win_mtime[1] = wmtime[1];
1245                 }
1246
1247                 obj->dirty = 1;
1248                 result = yaffs_FlushFile(obj,0,0);
1249                 retVal = 0;
1250         } else
1251                 /* bad handle */
1252                 yaffsfs_SetError(-EBADF);
1253
1254         yaffsfs_Unlock();
1255
1256         return retVal;
1257 }
1258
1259 #endif
1260
1261
1262 static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode)
1263 {
1264         int result = -1;
1265
1266         if(obj)
1267                 obj = yaffs_GetEquivalentObject(obj);
1268
1269         if(obj) {
1270                 obj->yst_mode = mode;
1271                 obj->dirty = 1;
1272                 result = yaffs_FlushFile(obj,0,0);
1273         }
1274
1275         return result == YAFFS_OK ? 0 : -1;
1276 }
1277
1278
1279 int yaffs_access(const YCHAR *path, int amode)
1280 {
1281         yaffs_Object *obj;
1282
1283         int retval = 0;
1284
1285         yaffsfs_Lock();
1286         obj = yaffsfs_FindObject(NULL,path,0);
1287
1288         if(obj) {
1289                 int access_ok = 1;
1290
1291                 if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
1292                         access_ok = 0;
1293                 if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
1294                         access_ok = 0;
1295                 if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
1296                         access_ok = 0;
1297
1298                 if(!access_ok) {
1299                         yaffsfs_SetError(-EACCES);
1300                         retval = -1;
1301                 }
1302         } else {
1303                 /* todo error not found */
1304                 yaffsfs_SetError(-ENOENT);
1305                 retval = -1;
1306         }
1307
1308         yaffsfs_Unlock();
1309
1310         return retval;
1311
1312 }
1313
1314
1315 int yaffs_chmod(const YCHAR *path, mode_t mode)
1316 {
1317         yaffs_Object *obj;
1318
1319         int retVal = -1;
1320
1321         yaffsfs_Lock();
1322         obj = yaffsfs_FindObject(NULL,path,0);
1323
1324         if(!obj)
1325                 yaffsfs_SetError(-ENOENT);
1326         else if(obj->myDev->readOnly)
1327                 yaffsfs_SetError(-EINVAL);
1328         else
1329                 retVal = yaffsfs_DoChMod(obj,mode);
1330
1331         yaffsfs_Unlock();
1332
1333         return retVal;
1334
1335 }
1336
1337
1338 int yaffs_fchmod(int fd, mode_t mode)
1339 {
1340         yaffs_Object *obj;
1341
1342         int retVal = -1;
1343
1344         yaffsfs_Lock();
1345         obj = yaffsfs_GetHandleObject(fd);
1346
1347         if(!obj)
1348                 yaffsfs_SetError(-ENOENT);
1349         else if(obj->myDev->readOnly)
1350                 yaffsfs_SetError(-EINVAL);
1351         else
1352                 retVal = yaffsfs_DoChMod(obj,mode);
1353
1354         yaffsfs_Unlock();
1355
1356         return retVal;
1357 }
1358
1359
1360 int yaffs_mkdir(const YCHAR *path, mode_t mode)
1361 {
1362         yaffs_Object *parent = NULL;
1363         yaffs_Object *dir = NULL;
1364         YCHAR *name;
1365         int retVal= -1;
1366
1367         yaffsfs_Lock();
1368         parent = yaffsfs_FindDirectory(NULL,path,&name,0);
1369         if(parent && parent->myDev->readOnly){
1370                 yaffsfs_SetError(-EINVAL);
1371         } else {
1372                 if(parent)
1373                         dir = yaffs_MknodDirectory(parent,name,mode,0,0);
1374                 if(dir)
1375                         retVal = 0;
1376                 else {
1377                         if(!parent)
1378                                 yaffsfs_SetError(-ENOENT); /* missing path */
1379                         else if (yaffs_FindObjectByName(parent,name))
1380                                 yaffsfs_SetError(-EEXIST); /* the name already exists */
1381                         else
1382                                 yaffsfs_SetError(-ENOSPC); /* just assume no space */
1383                         retVal = -1;
1384                 }
1385         }
1386
1387         yaffsfs_Unlock();
1388
1389         return retVal;
1390 }
1391
1392 int yaffs_mount2(const YCHAR *path,int readOnly)
1393 {
1394         int retVal=-1;
1395         int result=YAFFS_FAIL;
1396         yaffs_Device *dev=NULL;
1397         YCHAR *dummy;
1398
1399         T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Mounting %s" TENDSTR),path));
1400
1401         yaffsfs_Lock();
1402         dev = yaffsfs_FindDevice(path,&dummy);
1403         if(dev){
1404                 if(!dev->isMounted){
1405                         dev->readOnly = readOnly ? 1 : 0;
1406                         result = yaffs_GutsInitialise(dev);
1407                         if(result == YAFFS_FAIL)
1408                                 /* todo error - mount failed */
1409                                 yaffsfs_SetError(-ENOMEM);
1410                         retVal = result ? 0 : -1;
1411
1412                 }
1413                 else
1414                         /* todo error - already mounted. */
1415                         yaffsfs_SetError(-EBUSY);
1416         } else
1417                 /* todo error - no device */
1418                 yaffsfs_SetError(-ENODEV);
1419
1420         yaffsfs_Unlock();
1421         return retVal;
1422
1423 }
1424
1425 int yaffs_mount(const YCHAR *path)
1426 {
1427         return yaffs_mount2(path,0);
1428 }
1429
1430 int yaffs_sync(const YCHAR *path)
1431 {
1432         int retVal=-1;
1433         yaffs_Device *dev=NULL;
1434         YCHAR *dummy;
1435         
1436         yaffsfs_Lock();
1437         dev = yaffsfs_FindDevice(path,&dummy);
1438         if(dev){
1439                 if(dev->isMounted){
1440                         
1441                         yaffs_FlushEntireDeviceCache(dev);
1442                         yaffs_CheckpointSave(dev);
1443                         
1444                         
1445                 } else
1446                         /* todo error - not mounted. */
1447                         yaffsfs_SetError(-EINVAL);
1448                         
1449         }else
1450                 /* todo error - no device */
1451                 yaffsfs_SetError(-ENODEV);
1452
1453         yaffsfs_Unlock();
1454         return retVal;  
1455 }
1456
1457
1458 int yaffs_remount(const YCHAR *path, int force, int readOnly)
1459 {
1460         int retVal=-1;
1461         yaffs_Device *dev=NULL;
1462         YCHAR *dummy;
1463
1464         yaffsfs_Lock();
1465         dev = yaffsfs_FindDevice(path,&dummy);
1466         if(dev){
1467                 if(dev->isMounted){
1468                         int i;
1469                         int inUse;
1470
1471                         yaffs_FlushEntireDeviceCache(dev);
1472
1473                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse && !force; i++){
1474                                 if(yaffsfs_handle[i].useCount>0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->myDev == dev)
1475                                         inUse = 1; /* the device is in use, can't unmount */
1476                         }
1477
1478                         if(!inUse || force){
1479                                 if(readOnly)
1480                                         yaffs_CheckpointSave(dev);
1481                                 dev->readOnly =  readOnly ? 1 : 0;
1482                                 retVal = 0;
1483                         } else
1484                                 yaffsfs_SetError(-EBUSY);
1485
1486                 } else
1487                         yaffsfs_SetError(-EINVAL);
1488
1489         }
1490         else
1491                 yaffsfs_SetError(-ENODEV);
1492
1493         yaffsfs_Unlock();
1494         return retVal;
1495
1496 }
1497
1498 int yaffs_unmount2(const YCHAR *path, int force)
1499 {
1500         int retVal=-1;
1501         yaffs_Device *dev=NULL;
1502         YCHAR *dummy;
1503
1504         yaffsfs_Lock();
1505         dev = yaffsfs_FindDevice(path,&dummy);
1506         if(dev){
1507                 if(dev->isMounted){
1508                         int i;
1509                         int inUse;
1510
1511                         yaffs_FlushEntireDeviceCache(dev);
1512                         yaffs_CheckpointSave(dev);
1513
1514                         for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++){
1515                                 if(yaffsfs_handle[i].useCount > 0 && yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->myDev == dev)
1516                                         inUse = 1; /* the device is in use, can't unmount */
1517                         }
1518
1519                         if(!inUse || force){
1520                                 yaffs_Deinitialise(dev);
1521
1522                                 retVal = 0;
1523                         } else
1524                                 /* todo error can't unmount as files are open */
1525                                 yaffsfs_SetError(-EBUSY);
1526
1527                 } else
1528                         /* todo error - not mounted. */
1529                         yaffsfs_SetError(-EINVAL);
1530
1531         }
1532         else
1533                 /* todo error - no device */
1534                 yaffsfs_SetError(-ENODEV);
1535
1536         yaffsfs_Unlock();
1537         return retVal;
1538
1539 }
1540
1541 int yaffs_unmount(const YCHAR *path)
1542 {
1543         return yaffs_unmount2(path,0);
1544 }
1545
1546 loff_t yaffs_freespace(const YCHAR *path)
1547 {
1548         loff_t retVal=-1;
1549         yaffs_Device *dev=NULL;
1550         YCHAR *dummy;
1551
1552         yaffsfs_Lock();
1553         dev = yaffsfs_FindDevice(path,&dummy);
1554         if(dev  && dev->isMounted){
1555                 retVal = yaffs_GetNumberOfFreeChunks(dev);
1556                 retVal *= dev->nDataBytesPerChunk;
1557
1558         } else
1559                 yaffsfs_SetError(-EINVAL);
1560
1561         yaffsfs_Unlock();
1562         return retVal;
1563 }
1564
1565 loff_t yaffs_totalspace(const YCHAR *path)
1566 {
1567         loff_t retVal=-1;
1568         yaffs_Device *dev=NULL;
1569         YCHAR *dummy;
1570
1571         yaffsfs_Lock();
1572         dev = yaffsfs_FindDevice(path,&dummy);
1573         if(dev  && dev->isMounted){
1574                 retVal = (dev->param.endBlock - dev->param.startBlock + 1) - dev->param.nReservedBlocks;
1575                 retVal *= dev->param.nChunksPerBlock;
1576                 retVal *= dev->nDataBytesPerChunk;
1577
1578         } else
1579                 yaffsfs_SetError(-EINVAL);
1580
1581         yaffsfs_Unlock();
1582         return retVal;
1583 }
1584
1585 int yaffs_inodecount(const YCHAR *path)
1586 {
1587         loff_t retVal= -1;
1588         yaffs_Device *dev=NULL;
1589         YCHAR *dummy;
1590
1591         yaffsfs_Lock();
1592         dev = yaffsfs_FindDevice(path,&dummy);
1593         if(dev  && dev->isMounted) {
1594            int nObjects = dev->nObjectsCreated - dev->nFreeObjects;
1595            if(nObjects > dev->nHardLinks)
1596                 retVal = nObjects - dev->nHardLinks;
1597         }
1598         
1599         if(retVal < 0)
1600                 yaffsfs_SetError(-EINVAL);
1601         
1602         yaffsfs_Unlock();
1603         return retVal;  
1604 }
1605
1606
1607
1608 void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList)
1609 {
1610
1611         yaffsfs_DeviceConfiguration *cfg;
1612
1613         yaffsfs_configurationList = cfgList;
1614
1615         yaffsfs_InitHandles();
1616
1617         cfg = yaffsfs_configurationList;
1618
1619         while(cfg && cfg->prefix && cfg->dev){
1620                 cfg->dev->isMounted = 0;
1621                 cfg->dev->param.removeObjectCallback = yaffsfs_RemoveObjectCallback;
1622                 cfg++;
1623         }
1624
1625
1626 }
1627
1628
1629 /* Directory search stuff. */
1630
1631 /*
1632  * Directory search context
1633  *
1634  * NB this is an opaque structure.
1635  */
1636
1637
1638 typedef struct
1639 {
1640         __u32 magic;
1641         yaffs_dirent de;                /* directory entry being used by this dsc */
1642         YCHAR name[NAME_MAX+1];         /* name of directory being searched */
1643         yaffs_Object *dirObj;           /* ptr to directory being searched */
1644         yaffs_Object *nextReturn;       /* obj to be returned by next readddir */
1645         int offset;
1646         struct ylist_head others;       
1647 } yaffsfs_DirectorySearchContext;
1648
1649
1650
1651 static struct ylist_head search_contexts;
1652
1653
1654 static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
1655 {
1656         if(dsc &&
1657            dsc->dirObj &&
1658            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1659
1660            dsc->offset = 0;
1661
1662            if( ylist_empty(&dsc->dirObj->variant.directoryVariant.children))
1663                 dsc->nextReturn = NULL;
1664            else
1665                 dsc->nextReturn = ylist_entry(dsc->dirObj->variant.directoryVariant.children.next,
1666                                                 yaffs_Object,siblings);
1667         } else {
1668                 /* Hey someone isn't playing nice! */
1669         }
1670 }
1671
1672 static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
1673 {
1674         if(dsc &&
1675            dsc->dirObj &&
1676            dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1677
1678            if( dsc->nextReturn == NULL ||
1679                ylist_empty(&dsc->dirObj->variant.directoryVariant.children))
1680                 dsc->nextReturn = NULL;
1681            else {
1682                    struct ylist_head *next = dsc->nextReturn->siblings.next;
1683
1684                    if( next == &dsc->dirObj->variant.directoryVariant.children)
1685                         dsc->nextReturn = NULL; /* end of list */
1686                    else
1687                         dsc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
1688            }
1689         } else {
1690                 /* Hey someone isn't playing nice! */
1691         }
1692 }
1693
1694 static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj)
1695 {
1696
1697         struct ylist_head *i;
1698         yaffsfs_DirectorySearchContext *dsc;
1699
1700         /* if search contexts not initilised then skip */
1701         if(!search_contexts.next)
1702                 return;
1703
1704         /* Iterate through the directory search contexts.
1705          * If any are the one being removed, then advance the dsc to
1706          * the next one to prevent a hanging ptr.
1707          */
1708          ylist_for_each(i, &search_contexts) {
1709                 if (i) {
1710                         dsc = ylist_entry(i, yaffsfs_DirectorySearchContext,others);
1711                         if(dsc->nextReturn == obj)
1712                                 yaffsfs_DirAdvance(dsc);
1713                 }
1714         }
1715
1716 }
1717
1718 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
1719 {
1720         yaffs_DIR *dir = NULL;
1721         yaffs_Object *obj = NULL;
1722         yaffsfs_DirectorySearchContext *dsc = NULL;
1723
1724         yaffsfs_Lock();
1725
1726         obj = yaffsfs_FindObject(NULL,dirname,0);
1727
1728         if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){
1729
1730                 dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
1731                 dir = (yaffs_DIR *)dsc;
1732
1733                 if(dsc){
1734                         memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
1735                         dsc->magic = YAFFS_MAGIC;
1736                         dsc->dirObj = obj;
1737                         yaffs_strncpy(dsc->name,dirname,NAME_MAX);
1738                         YINIT_LIST_HEAD(&dsc->others);
1739
1740                         if(!search_contexts.next)
1741                                 YINIT_LIST_HEAD(&search_contexts);
1742
1743                         ylist_add(&dsc->others,&search_contexts);       
1744                         yaffsfs_SetDirRewound(dsc);
1745                 }
1746
1747         }
1748
1749         yaffsfs_Unlock();
1750
1751         return dir;
1752 }
1753
1754 struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
1755 {
1756         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1757         struct yaffs_dirent *retVal = NULL;
1758
1759         yaffsfs_Lock();
1760
1761         if(dsc && dsc->magic == YAFFS_MAGIC){
1762                 yaffsfs_SetError(0);
1763                 if(dsc->nextReturn){
1764                         dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId;
1765                         dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
1766                         dsc->de.d_off = dsc->offset++;
1767                         yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
1768                         if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
1769                         {
1770                                 /* this should not happen! */
1771                                 yaffs_strcpy(dsc->de.d_name,_Y("zz"));
1772                         }
1773                         dsc->de.d_reclen = sizeof(struct yaffs_dirent);
1774                         retVal = &dsc->de;
1775                         yaffsfs_DirAdvance(dsc);
1776                 } else
1777                         retVal = NULL;
1778         } else
1779                 yaffsfs_SetError(-EBADF);
1780
1781         yaffsfs_Unlock();
1782
1783         return retVal;
1784
1785 }
1786
1787
1788 void yaffs_rewinddir(yaffs_DIR *dirp)
1789 {
1790         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1791
1792         yaffsfs_Lock();
1793
1794         yaffsfs_SetDirRewound(dsc);
1795
1796         yaffsfs_Unlock();
1797 }
1798
1799
1800 int yaffs_closedir(yaffs_DIR *dirp)
1801 {
1802         yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
1803
1804         yaffsfs_Lock();
1805         dsc->magic = 0;
1806         ylist_del(&dsc->others); /* unhook from list */
1807         YFREE(dsc);
1808         yaffsfs_Unlock();
1809         return 0;
1810 }
1811
1812 /* End of directory stuff */
1813
1814
1815 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
1816 {
1817         yaffs_Object *parent = NULL;
1818         yaffs_Object *obj;
1819         YCHAR *name;
1820         int retVal= -1;
1821         int mode = 0; /* ignore for now */
1822
1823         yaffsfs_Lock();
1824         parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
1825         if(parent && parent->myDev->readOnly)
1826                 yaffsfs_SetError(-EINVAL);
1827         else if(parent){
1828                 obj = yaffs_MknodSymLink(parent,name,mode,0,0,oldpath);
1829                 if(obj)
1830                         retVal = 0;
1831                 else{
1832                         yaffsfs_SetError(-ENOSPC); /* just assume no space for now */
1833                         retVal = -1;
1834                 }
1835         } else {
1836                 yaffsfs_SetError(-EINVAL);
1837                 retVal = -1;
1838         }
1839
1840         yaffsfs_Unlock();
1841
1842         return retVal;
1843
1844 }
1845
1846 int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
1847 {
1848         yaffs_Object *obj = NULL;
1849         int retVal;
1850
1851
1852         yaffsfs_Lock();
1853
1854         obj = yaffsfs_FindObject(NULL,path,0);
1855
1856         if(!obj) {
1857                 yaffsfs_SetError(-ENOENT);
1858                 retVal = -1;
1859         } else if(obj->variantType != YAFFS_OBJECT_TYPE_SYMLINK) {
1860                 yaffsfs_SetError(-EINVAL);
1861                 retVal = -1;
1862         } else {
1863                 YCHAR *alias = obj->variant.symLinkVariant.alias;
1864                 memset(buf,0,bufsiz);
1865                 yaffs_strncpy(buf,alias,bufsiz - 1);
1866                 retVal = 0;
1867         }
1868         yaffsfs_Unlock();
1869         return retVal;
1870 }
1871
1872 int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath)
1873 {
1874         /* Creates a link called newpath to existing oldpath */
1875         yaffs_Object *obj = NULL;
1876         yaffs_Object *target = NULL;
1877         int retVal = 0;
1878         int newNameLength = 0;
1879
1880
1881         yaffsfs_Lock();
1882
1883         obj = yaffsfs_FindObject(NULL,oldpath,0);
1884         target = yaffsfs_FindObject(NULL,newpath,0);
1885
1886         if(!obj) {
1887                 yaffsfs_SetError(-ENOENT);
1888                 retVal = -1;
1889         } else if(obj->myDev->readOnly){
1890                 yaffsfs_SetError(-EINVAL);
1891                 retVal= -1;
1892         } else if(target) {
1893                 yaffsfs_SetError(-EEXIST);
1894                 retVal = -1;
1895         } else {
1896                 yaffs_Object *newdir = NULL;
1897                 yaffs_Object *link = NULL;
1898
1899                 YCHAR *newname;
1900
1901                 newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
1902
1903                 if(!newdir){
1904                         yaffsfs_SetError(-ENOTDIR);
1905                         retVal = -1;
1906                 }else if(newdir->myDev != obj->myDev){
1907                         yaffsfs_SetError(-EXDEV);
1908                         retVal = -1;
1909                 }
1910                 
1911                 newNameLength = yaffs_strnlen(newname,YAFFS_MAX_NAME_LENGTH+1);
1912                 
1913                 if(newNameLength == 0){
1914                         yaffsfs_SetError(-ENOENT);
1915                         retVal = -1;
1916                 } else if (newNameLength > YAFFS_MAX_NAME_LENGTH){
1917                         yaffsfs_SetError(-ENAMETOOLONG);
1918                         retVal = -1;
1919                 }
1920                 
1921                 if(retVal == 0) {
1922                         link = yaffs_Link(newdir,newname,obj);
1923                         if(link)
1924                                 retVal = 0;
1925                         else{
1926                                 yaffsfs_SetError(-ENOSPC);
1927                                 retVal = -1;
1928                         }
1929
1930                 }
1931         }
1932         yaffsfs_Unlock();
1933
1934         return retVal;
1935 }
1936
1937 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
1938 {
1939         return -1;
1940 }
1941
1942 int yaffs_DumpDevStruct(const YCHAR *path)
1943 {
1944 #if 0
1945         YCHAR *rest;
1946
1947         yaffs_Object *obj = yaffsfs_FindRoot(path,&rest);
1948
1949         if(obj){
1950                 yaffs_Device *dev = obj->myDev;
1951
1952                 printf("\n"
1953                            "nPageWrites.......... %d\n"
1954                            "nPageReads........... %d\n"
1955                            "nBlockErasures....... %d\n"
1956                            "nGCCopies............ %d\n"
1957                            "garbageCollections... %d\n"
1958                            "passiveGarbageColl'ns %d\n"
1959                            "\n",
1960                                 dev->nPageWrites,
1961                                 dev->nPageReads,
1962                                 dev->nBlockErasures,
1963                                 dev->nGCCopies,
1964                                 dev->garbageCollections,
1965                                 dev->passiveGarbageCollections
1966                 );
1967
1968         }
1969
1970 #endif
1971         return 0;
1972 }
1973