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