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